1c9d4f46bSScott McNutt /* 2c9d4f46bSScott McNutt * (C) Copyright 2004, Psyent Corporation <www.psyent.com> 3c9d4f46bSScott McNutt * Scott McNutt <smcnutt@psyent.com> 4c9d4f46bSScott McNutt * 51a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 6c9d4f46bSScott McNutt */ 7c9d4f46bSScott McNutt 8c9d4f46bSScott McNutt #include <common.h> 9*da2f838dSThomas Chou #include <dm.h> 10*da2f838dSThomas Chou #include <errno.h> 11c9d4f46bSScott McNutt #include <asm/io.h> 12b207d645SMarek Vasut #include <linux/compiler.h> 13b207d645SMarek Vasut #include <serial.h> 14c9d4f46bSScott McNutt 15*da2f838dSThomas Chou struct altera_uart_regs { 16*da2f838dSThomas Chou u32 rxdata; /* Rx data reg */ 17*da2f838dSThomas Chou u32 txdata; /* Tx data reg */ 18*da2f838dSThomas Chou u32 status; /* Status reg */ 19*da2f838dSThomas Chou u32 control; /* Control reg */ 20*da2f838dSThomas Chou u32 divisor; /* Baud rate divisor reg */ 21*da2f838dSThomas Chou u32 endofpacket; /* End-of-packet reg */ 22*da2f838dSThomas Chou }; 23*da2f838dSThomas Chou 24*da2f838dSThomas Chou struct altera_uart_platdata { 25*da2f838dSThomas Chou struct altera_uart_regs *regs; 26*da2f838dSThomas Chou unsigned int uartclk; 27*da2f838dSThomas Chou }; 2886450710SThomas Chou 2986450710SThomas Chou /* status register */ 30*da2f838dSThomas Chou #define ALTERA_UART_TMT (1 << 5) /* tx empty */ 31*da2f838dSThomas Chou #define ALTERA_UART_TRDY (1 << 6) /* tx ready */ 32*da2f838dSThomas Chou #define ALTERA_UART_RRDY (1 << 7) /* rx ready */ 3386450710SThomas Chou 34c9d4f46bSScott McNutt DECLARE_GLOBAL_DATA_PTR; 35c9d4f46bSScott McNutt 36*da2f838dSThomas Chou static int altera_uart_setbrg(struct udevice *dev, int baudrate) 37b207d645SMarek Vasut { 38*da2f838dSThomas Chou struct altera_uart_platdata *plat = dev->platdata; 39*da2f838dSThomas Chou struct altera_uart_regs *const regs = plat->regs; 40*da2f838dSThomas Chou u32 div; 41*da2f838dSThomas Chou 42*da2f838dSThomas Chou div = (plat->uartclk / baudrate) - 1; 43*da2f838dSThomas Chou writel(div, ®s->divisor); 44*da2f838dSThomas Chou 45*da2f838dSThomas Chou return 0; 46b207d645SMarek Vasut } 47b207d645SMarek Vasut 48*da2f838dSThomas Chou static int altera_uart_putc(struct udevice *dev, const char ch) 49*da2f838dSThomas Chou { 50*da2f838dSThomas Chou struct altera_uart_platdata *plat = dev->platdata; 51*da2f838dSThomas Chou struct altera_uart_regs *const regs = plat->regs; 52*da2f838dSThomas Chou 53*da2f838dSThomas Chou if (!(readl(®s->status) & ALTERA_UART_TRDY)) 54*da2f838dSThomas Chou return -EAGAIN; 55*da2f838dSThomas Chou 56*da2f838dSThomas Chou writel(ch, ®s->txdata); 57*da2f838dSThomas Chou 58*da2f838dSThomas Chou return 0; 59*da2f838dSThomas Chou } 60*da2f838dSThomas Chou 61*da2f838dSThomas Chou static int altera_uart_pending(struct udevice *dev, bool input) 62*da2f838dSThomas Chou { 63*da2f838dSThomas Chou struct altera_uart_platdata *plat = dev->platdata; 64*da2f838dSThomas Chou struct altera_uart_regs *const regs = plat->regs; 65*da2f838dSThomas Chou u32 st = readl(®s->status); 66*da2f838dSThomas Chou 67*da2f838dSThomas Chou if (input) 68*da2f838dSThomas Chou return st & ALTERA_UART_RRDY ? 1 : 0; 69*da2f838dSThomas Chou else 70*da2f838dSThomas Chou return !(st & ALTERA_UART_TMT); 71*da2f838dSThomas Chou } 72*da2f838dSThomas Chou 73*da2f838dSThomas Chou static int altera_uart_getc(struct udevice *dev) 74*da2f838dSThomas Chou { 75*da2f838dSThomas Chou struct altera_uart_platdata *plat = dev->platdata; 76*da2f838dSThomas Chou struct altera_uart_regs *const regs = plat->regs; 77*da2f838dSThomas Chou 78*da2f838dSThomas Chou if (!(readl(®s->status) & ALTERA_UART_RRDY)) 79*da2f838dSThomas Chou return -EAGAIN; 80*da2f838dSThomas Chou 81*da2f838dSThomas Chou return readl(®s->rxdata) & 0xff; 82*da2f838dSThomas Chou } 83*da2f838dSThomas Chou 84*da2f838dSThomas Chou static int altera_uart_probe(struct udevice *dev) 85b207d645SMarek Vasut { 86b207d645SMarek Vasut return 0; 87b207d645SMarek Vasut } 88c9d4f46bSScott McNutt 89*da2f838dSThomas Chou static int altera_uart_ofdata_to_platdata(struct udevice *dev) 90c9d4f46bSScott McNutt { 91*da2f838dSThomas Chou struct altera_uart_platdata *plat = dev_get_platdata(dev); 92c9d4f46bSScott McNutt 93*da2f838dSThomas Chou plat->regs = ioremap(dev_get_addr(dev), 94*da2f838dSThomas Chou sizeof(struct altera_uart_regs)); 95*da2f838dSThomas Chou plat->uartclk = fdtdec_get_int(gd->fdt_blob, dev->of_offset, 96*da2f838dSThomas Chou "clock-frequency", 0); 97c9d4f46bSScott McNutt 98b207d645SMarek Vasut return 0; 99c9d4f46bSScott McNutt } 100c9d4f46bSScott McNutt 101*da2f838dSThomas Chou static const struct dm_serial_ops altera_uart_ops = { 102*da2f838dSThomas Chou .putc = altera_uart_putc, 103*da2f838dSThomas Chou .pending = altera_uart_pending, 104*da2f838dSThomas Chou .getc = altera_uart_getc, 105*da2f838dSThomas Chou .setbrg = altera_uart_setbrg, 106b207d645SMarek Vasut }; 107b207d645SMarek Vasut 108*da2f838dSThomas Chou static const struct udevice_id altera_uart_ids[] = { 109*da2f838dSThomas Chou { .compatible = "altr,uart-1.0", }, 110*da2f838dSThomas Chou { } 111*da2f838dSThomas Chou }; 112*da2f838dSThomas Chou 113*da2f838dSThomas Chou U_BOOT_DRIVER(altera_uart) = { 114*da2f838dSThomas Chou .name = "altera_uart", 115*da2f838dSThomas Chou .id = UCLASS_SERIAL, 116*da2f838dSThomas Chou .of_match = altera_uart_ids, 117*da2f838dSThomas Chou .ofdata_to_platdata = altera_uart_ofdata_to_platdata, 118*da2f838dSThomas Chou .platdata_auto_alloc_size = sizeof(struct altera_uart_platdata), 119*da2f838dSThomas Chou .probe = altera_uart_probe, 120*da2f838dSThomas Chou .ops = &altera_uart_ops, 121*da2f838dSThomas Chou .flags = DM_FLAG_PRE_RELOC, 122*da2f838dSThomas Chou }; 123*da2f838dSThomas Chou 124*da2f838dSThomas Chou #ifdef CONFIG_DEBUG_UART_ALTERA_UART 125*da2f838dSThomas Chou 126*da2f838dSThomas Chou #include <debug_uart.h> 127*da2f838dSThomas Chou 128*da2f838dSThomas Chou void debug_uart_init(void) 129b207d645SMarek Vasut { 130*da2f838dSThomas Chou struct altera_uart_regs *regs = (void *)CONFIG_DEBUG_UART_BASE; 131*da2f838dSThomas Chou u32 div; 132*da2f838dSThomas Chou 133*da2f838dSThomas Chou div = (CONFIG_DEBUG_UART_CLOCK / CONFIG_BAUDRATE) - 1; 134*da2f838dSThomas Chou writel(div, ®s->divisor); 135b207d645SMarek Vasut } 136b207d645SMarek Vasut 137*da2f838dSThomas Chou static inline void _debug_uart_putc(int ch) 138b207d645SMarek Vasut { 139*da2f838dSThomas Chou struct altera_uart_regs *regs = (void *)CONFIG_DEBUG_UART_BASE; 140*da2f838dSThomas Chou 141*da2f838dSThomas Chou while (1) { 142*da2f838dSThomas Chou u32 st = readl(®s->status); 143*da2f838dSThomas Chou 144*da2f838dSThomas Chou if (st & ALTERA_UART_TRDY) 145*da2f838dSThomas Chou break; 146b207d645SMarek Vasut } 147*da2f838dSThomas Chou 148*da2f838dSThomas Chou writel(ch, ®s->txdata); 149*da2f838dSThomas Chou } 150*da2f838dSThomas Chou 151*da2f838dSThomas Chou DEBUG_UART_FUNCS 152*da2f838dSThomas Chou 153*da2f838dSThomas Chou #endif 154