| /* |
| * (C) Copyright 2004, Psyent Corporation <www.psyent.com> |
| * Scott McNutt <smcnutt@psyent.com> |
| * |
| * SPDX-License-Identifier: GPL-2.0+ |
| */ |
| |
| #include <common.h> |
| #include <dm.h> |
| #include <errno.h> |
| #include <serial.h> |
| #include <asm/io.h> |
| |
| DECLARE_GLOBAL_DATA_PTR; |
| |
| /* data register */ |
| #define ALTERA_JTAG_RVALID BIT(15) /* Read valid */ |
| |
| /* control register */ |
| #define ALTERA_JTAG_AC BIT(10) /* activity indicator */ |
| #define ALTERA_JTAG_RRDY BIT(12) /* read available */ |
| #define ALTERA_JTAG_WSPACE(d) ((d) >> 16) /* Write space avail */ |
| /* Write fifo size. FIXME: this should be extracted with sopc2dts */ |
| #define ALTERA_JTAG_WRITE_DEPTH 64 |
| |
| struct altera_jtaguart_regs { |
| u32 data; /* Data register */ |
| u32 control; /* Control register */ |
| }; |
| |
| struct altera_jtaguart_platdata { |
| struct altera_jtaguart_regs *regs; |
| }; |
| |
| static int altera_jtaguart_setbrg(struct udevice *dev, int baudrate) |
| { |
| return 0; |
| } |
| |
| static int altera_jtaguart_putc(struct udevice *dev, const char ch) |
| { |
| struct altera_jtaguart_platdata *plat = dev->platdata; |
| struct altera_jtaguart_regs *const regs = plat->regs; |
| u32 st = readl(®s->control); |
| |
| #ifdef CONFIG_ALTERA_JTAG_UART_BYPASS |
| if (!(st & ALTERA_JTAG_AC)) /* no connection yet */ |
| return -ENETUNREACH; |
| #endif |
| |
| if (ALTERA_JTAG_WSPACE(st) == 0) |
| return -EAGAIN; |
| |
| writel(ch, ®s->data); |
| |
| return 0; |
| } |
| |
| static int altera_jtaguart_pending(struct udevice *dev, bool input) |
| { |
| struct altera_jtaguart_platdata *plat = dev->platdata; |
| struct altera_jtaguart_regs *const regs = plat->regs; |
| u32 st = readl(®s->control); |
| |
| if (input) |
| return st & ALTERA_JTAG_RRDY ? 1 : 0; |
| else |
| return !(ALTERA_JTAG_WSPACE(st) == ALTERA_JTAG_WRITE_DEPTH); |
| } |
| |
| static int altera_jtaguart_getc(struct udevice *dev) |
| { |
| struct altera_jtaguart_platdata *plat = dev->platdata; |
| struct altera_jtaguart_regs *const regs = plat->regs; |
| u32 val; |
| |
| val = readl(®s->data); |
| |
| if (!(val & ALTERA_JTAG_RVALID)) |
| return -EAGAIN; |
| |
| return val & 0xff; |
| } |
| |
| static int altera_jtaguart_probe(struct udevice *dev) |
| { |
| #ifdef CONFIG_ALTERA_JTAG_UART_BYPASS |
| struct altera_jtaguart_platdata *plat = dev->platdata; |
| struct altera_jtaguart_regs *const regs = plat->regs; |
| |
| writel(ALTERA_JTAG_AC, ®s->control); /* clear AC flag */ |
| #endif |
| return 0; |
| } |
| |
| static int altera_jtaguart_ofdata_to_platdata(struct udevice *dev) |
| { |
| struct altera_jtaguart_platdata *plat = dev_get_platdata(dev); |
| |
| plat->regs = map_physmem(dev_get_addr(dev), |
| sizeof(struct altera_jtaguart_regs), |
| MAP_NOCACHE); |
| |
| return 0; |
| } |
| |
| static const struct dm_serial_ops altera_jtaguart_ops = { |
| .putc = altera_jtaguart_putc, |
| .pending = altera_jtaguart_pending, |
| .getc = altera_jtaguart_getc, |
| .setbrg = altera_jtaguart_setbrg, |
| }; |
| |
| static const struct udevice_id altera_jtaguart_ids[] = { |
| { .compatible = "altr,juart-1.0" }, |
| {} |
| }; |
| |
| U_BOOT_DRIVER(altera_jtaguart) = { |
| .name = "altera_jtaguart", |
| .id = UCLASS_SERIAL, |
| .of_match = altera_jtaguart_ids, |
| .ofdata_to_platdata = altera_jtaguart_ofdata_to_platdata, |
| .platdata_auto_alloc_size = sizeof(struct altera_jtaguart_platdata), |
| .probe = altera_jtaguart_probe, |
| .ops = &altera_jtaguart_ops, |
| .flags = DM_FLAG_PRE_RELOC, |
| }; |
| |
| #ifdef CONFIG_DEBUG_UART_ALTERA_JTAGUART |
| |
| #include <debug_uart.h> |
| |
| static inline void _debug_uart_init(void) |
| { |
| } |
| |
| static inline void _debug_uart_putc(int ch) |
| { |
| struct altera_jtaguart_regs *regs = (void *)CONFIG_DEBUG_UART_BASE; |
| |
| while (1) { |
| u32 st = readl(®s->control); |
| |
| if (ALTERA_JTAG_WSPACE(st)) |
| break; |
| } |
| |
| writel(ch, ®s->data); |
| } |
| |
| DEBUG_UART_FUNCS |
| |
| #endif |