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