1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2004, Psyent Corporation <www.psyent.com> 4 * Scott McNutt <smcnutt@psyent.com> 5 */ 6 7 #include <common.h> 8 #include <dm.h> 9 #include <errno.h> 10 #include <serial.h> 11 #include <asm/io.h> 12 13 /* data register */ 14 #define ALTERA_JTAG_RVALID BIT(15) /* Read valid */ 15 16 /* control register */ 17 #define ALTERA_JTAG_AC BIT(10) /* activity indicator */ 18 #define ALTERA_JTAG_RRDY BIT(12) /* read available */ 19 #define ALTERA_JTAG_WSPACE(d) ((d) >> 16) /* Write space avail */ 20 /* Write fifo size. FIXME: this should be extracted with sopc2dts */ 21 #define ALTERA_JTAG_WRITE_DEPTH 64 22 23 struct altera_jtaguart_regs { 24 u32 data; /* Data register */ 25 u32 control; /* Control register */ 26 }; 27 28 struct altera_jtaguart_platdata { 29 struct altera_jtaguart_regs *regs; 30 }; 31 32 static int altera_jtaguart_setbrg(struct udevice *dev, int baudrate) 33 { 34 return 0; 35 } 36 37 static int altera_jtaguart_putc(struct udevice *dev, const char ch) 38 { 39 struct altera_jtaguart_platdata *plat = dev->platdata; 40 struct altera_jtaguart_regs *const regs = plat->regs; 41 u32 st = readl(®s->control); 42 43 #ifdef CONFIG_ALTERA_JTAG_UART_BYPASS 44 if (!(st & ALTERA_JTAG_AC)) /* no connection yet */ 45 return -ENETUNREACH; 46 #endif 47 48 if (ALTERA_JTAG_WSPACE(st) == 0) 49 return -EAGAIN; 50 51 writel(ch, ®s->data); 52 53 return 0; 54 } 55 56 static int altera_jtaguart_pending(struct udevice *dev, bool input) 57 { 58 struct altera_jtaguart_platdata *plat = dev->platdata; 59 struct altera_jtaguart_regs *const regs = plat->regs; 60 u32 st = readl(®s->control); 61 62 if (input) 63 return st & ALTERA_JTAG_RRDY ? 1 : 0; 64 else 65 return !(ALTERA_JTAG_WSPACE(st) == ALTERA_JTAG_WRITE_DEPTH); 66 } 67 68 static int altera_jtaguart_getc(struct udevice *dev) 69 { 70 struct altera_jtaguart_platdata *plat = dev->platdata; 71 struct altera_jtaguart_regs *const regs = plat->regs; 72 u32 val; 73 74 val = readl(®s->data); 75 76 if (!(val & ALTERA_JTAG_RVALID)) 77 return -EAGAIN; 78 79 return val & 0xff; 80 } 81 82 static int altera_jtaguart_probe(struct udevice *dev) 83 { 84 #ifdef CONFIG_ALTERA_JTAG_UART_BYPASS 85 struct altera_jtaguart_platdata *plat = dev->platdata; 86 struct altera_jtaguart_regs *const regs = plat->regs; 87 88 writel(ALTERA_JTAG_AC, ®s->control); /* clear AC flag */ 89 #endif 90 return 0; 91 } 92 93 static int altera_jtaguart_ofdata_to_platdata(struct udevice *dev) 94 { 95 struct altera_jtaguart_platdata *plat = dev_get_platdata(dev); 96 97 plat->regs = map_physmem(devfdt_get_addr(dev), 98 sizeof(struct altera_jtaguart_regs), 99 MAP_NOCACHE); 100 101 return 0; 102 } 103 104 static const struct dm_serial_ops altera_jtaguart_ops = { 105 .putc = altera_jtaguart_putc, 106 .pending = altera_jtaguart_pending, 107 .getc = altera_jtaguart_getc, 108 .setbrg = altera_jtaguart_setbrg, 109 }; 110 111 static const struct udevice_id altera_jtaguart_ids[] = { 112 { .compatible = "altr,juart-1.0" }, 113 {} 114 }; 115 116 U_BOOT_DRIVER(altera_jtaguart) = { 117 .name = "altera_jtaguart", 118 .id = UCLASS_SERIAL, 119 .of_match = altera_jtaguart_ids, 120 .ofdata_to_platdata = altera_jtaguart_ofdata_to_platdata, 121 .platdata_auto_alloc_size = sizeof(struct altera_jtaguart_platdata), 122 .probe = altera_jtaguart_probe, 123 .ops = &altera_jtaguart_ops, 124 }; 125 126 #ifdef CONFIG_DEBUG_UART_ALTERA_JTAGUART 127 128 #include <debug_uart.h> 129 130 static inline void _debug_uart_init(void) 131 { 132 } 133 134 static inline void _debug_uart_putc(int ch) 135 { 136 struct altera_jtaguart_regs *regs = (void *)CONFIG_DEBUG_UART_BASE; 137 138 while (1) { 139 u32 st = readl(®s->control); 140 141 if (ALTERA_JTAG_WSPACE(st)) 142 break; 143 } 144 145 writel(ch, ®s->data); 146 } 147 148 DEBUG_UART_FUNCS 149 150 #endif 151