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> 9da2f838dSThomas Chou #include <dm.h> 10da2f838dSThomas Chou #include <errno.h> 11b207d645SMarek Vasut #include <serial.h> 1289241482SThomas Chou #include <asm/io.h> 1389241482SThomas Chou 1489241482SThomas Chou DECLARE_GLOBAL_DATA_PTR; 1589241482SThomas Chou 1689241482SThomas Chou /* status register */ 1789241482SThomas Chou #define ALTERA_UART_TMT BIT(5) /* tx empty */ 1889241482SThomas Chou #define ALTERA_UART_TRDY BIT(6) /* tx ready */ 1989241482SThomas Chou #define ALTERA_UART_RRDY BIT(7) /* rx ready */ 20c9d4f46bSScott McNutt 21da2f838dSThomas Chou struct altera_uart_regs { 22da2f838dSThomas Chou u32 rxdata; /* Rx data reg */ 23da2f838dSThomas Chou u32 txdata; /* Tx data reg */ 24da2f838dSThomas Chou u32 status; /* Status reg */ 25da2f838dSThomas Chou u32 control; /* Control reg */ 26da2f838dSThomas Chou u32 divisor; /* Baud rate divisor reg */ 27da2f838dSThomas Chou u32 endofpacket; /* End-of-packet reg */ 28da2f838dSThomas Chou }; 29da2f838dSThomas Chou 30da2f838dSThomas Chou struct altera_uart_platdata { 31da2f838dSThomas Chou struct altera_uart_regs *regs; 32da2f838dSThomas Chou unsigned int uartclk; 33da2f838dSThomas Chou }; 3486450710SThomas Chou 35da2f838dSThomas Chou static int altera_uart_setbrg(struct udevice *dev, int baudrate) 36b207d645SMarek Vasut { 37da2f838dSThomas Chou struct altera_uart_platdata *plat = dev->platdata; 38da2f838dSThomas Chou struct altera_uart_regs *const regs = plat->regs; 39da2f838dSThomas Chou u32 div; 40da2f838dSThomas Chou 41da2f838dSThomas Chou div = (plat->uartclk / baudrate) - 1; 42da2f838dSThomas Chou writel(div, ®s->divisor); 43da2f838dSThomas Chou 44da2f838dSThomas Chou return 0; 45b207d645SMarek Vasut } 46b207d645SMarek Vasut 47da2f838dSThomas Chou static int altera_uart_putc(struct udevice *dev, const char ch) 48da2f838dSThomas Chou { 49da2f838dSThomas Chou struct altera_uart_platdata *plat = dev->platdata; 50da2f838dSThomas Chou struct altera_uart_regs *const regs = plat->regs; 51da2f838dSThomas Chou 52da2f838dSThomas Chou if (!(readl(®s->status) & ALTERA_UART_TRDY)) 53da2f838dSThomas Chou return -EAGAIN; 54da2f838dSThomas Chou 55da2f838dSThomas Chou writel(ch, ®s->txdata); 56da2f838dSThomas Chou 57da2f838dSThomas Chou return 0; 58da2f838dSThomas Chou } 59da2f838dSThomas Chou 60da2f838dSThomas Chou static int altera_uart_pending(struct udevice *dev, bool input) 61da2f838dSThomas Chou { 62da2f838dSThomas Chou struct altera_uart_platdata *plat = dev->platdata; 63da2f838dSThomas Chou struct altera_uart_regs *const regs = plat->regs; 64da2f838dSThomas Chou u32 st = readl(®s->status); 65da2f838dSThomas Chou 66da2f838dSThomas Chou if (input) 67da2f838dSThomas Chou return st & ALTERA_UART_RRDY ? 1 : 0; 68da2f838dSThomas Chou else 69da2f838dSThomas Chou return !(st & ALTERA_UART_TMT); 70da2f838dSThomas Chou } 71da2f838dSThomas Chou 72da2f838dSThomas Chou static int altera_uart_getc(struct udevice *dev) 73da2f838dSThomas Chou { 74da2f838dSThomas Chou struct altera_uart_platdata *plat = dev->platdata; 75da2f838dSThomas Chou struct altera_uart_regs *const regs = plat->regs; 76da2f838dSThomas Chou 77da2f838dSThomas Chou if (!(readl(®s->status) & ALTERA_UART_RRDY)) 78da2f838dSThomas Chou return -EAGAIN; 79da2f838dSThomas Chou 80da2f838dSThomas Chou return readl(®s->rxdata) & 0xff; 81da2f838dSThomas Chou } 82da2f838dSThomas Chou 83da2f838dSThomas Chou static int altera_uart_probe(struct udevice *dev) 84b207d645SMarek Vasut { 85b207d645SMarek Vasut return 0; 86b207d645SMarek Vasut } 87c9d4f46bSScott McNutt 88da2f838dSThomas Chou static int altera_uart_ofdata_to_platdata(struct udevice *dev) 89c9d4f46bSScott McNutt { 90da2f838dSThomas Chou struct altera_uart_platdata *plat = dev_get_platdata(dev); 91c9d4f46bSScott McNutt 921ec60b93SThomas Chou plat->regs = map_physmem(dev_get_addr(dev), 931ec60b93SThomas Chou sizeof(struct altera_uart_regs), 941ec60b93SThomas Chou MAP_NOCACHE); 95*e160f7d4SSimon Glass plat->uartclk = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), 96da2f838dSThomas Chou "clock-frequency", 0); 97c9d4f46bSScott McNutt 98b207d645SMarek Vasut return 0; 99c9d4f46bSScott McNutt } 100c9d4f46bSScott McNutt 101da2f838dSThomas Chou static const struct dm_serial_ops altera_uart_ops = { 102da2f838dSThomas Chou .putc = altera_uart_putc, 103da2f838dSThomas Chou .pending = altera_uart_pending, 104da2f838dSThomas Chou .getc = altera_uart_getc, 105da2f838dSThomas Chou .setbrg = altera_uart_setbrg, 106b207d645SMarek Vasut }; 107b207d645SMarek Vasut 108da2f838dSThomas Chou static const struct udevice_id altera_uart_ids[] = { 10989241482SThomas Chou { .compatible = "altr,uart-1.0" }, 110da2f838dSThomas Chou {} 111da2f838dSThomas Chou }; 112da2f838dSThomas Chou 113da2f838dSThomas Chou U_BOOT_DRIVER(altera_uart) = { 114da2f838dSThomas Chou .name = "altera_uart", 115da2f838dSThomas Chou .id = UCLASS_SERIAL, 116da2f838dSThomas Chou .of_match = altera_uart_ids, 117da2f838dSThomas Chou .ofdata_to_platdata = altera_uart_ofdata_to_platdata, 118da2f838dSThomas Chou .platdata_auto_alloc_size = sizeof(struct altera_uart_platdata), 119da2f838dSThomas Chou .probe = altera_uart_probe, 120da2f838dSThomas Chou .ops = &altera_uart_ops, 121da2f838dSThomas Chou .flags = DM_FLAG_PRE_RELOC, 122da2f838dSThomas Chou }; 123da2f838dSThomas Chou 124da2f838dSThomas Chou #ifdef CONFIG_DEBUG_UART_ALTERA_UART 125da2f838dSThomas Chou 126da2f838dSThomas Chou #include <debug_uart.h> 127da2f838dSThomas Chou 128e03c17d0SThomas Chou static inline void _debug_uart_init(void) 129b207d645SMarek Vasut { 130da2f838dSThomas Chou struct altera_uart_regs *regs = (void *)CONFIG_DEBUG_UART_BASE; 131da2f838dSThomas Chou u32 div; 132da2f838dSThomas Chou 133da2f838dSThomas Chou div = (CONFIG_DEBUG_UART_CLOCK / CONFIG_BAUDRATE) - 1; 134da2f838dSThomas Chou writel(div, ®s->divisor); 135b207d645SMarek Vasut } 136b207d645SMarek Vasut 137da2f838dSThomas Chou static inline void _debug_uart_putc(int ch) 138b207d645SMarek Vasut { 139da2f838dSThomas Chou struct altera_uart_regs *regs = (void *)CONFIG_DEBUG_UART_BASE; 140da2f838dSThomas Chou 141da2f838dSThomas Chou while (1) { 142da2f838dSThomas Chou u32 st = readl(®s->status); 143da2f838dSThomas Chou 144da2f838dSThomas Chou if (st & ALTERA_UART_TRDY) 145da2f838dSThomas Chou break; 146b207d645SMarek Vasut } 147da2f838dSThomas Chou 148da2f838dSThomas Chou writel(ch, ®s->txdata); 149da2f838dSThomas Chou } 150da2f838dSThomas Chou 151da2f838dSThomas Chou DEBUG_UART_FUNCS 152da2f838dSThomas Chou 153da2f838dSThomas Chou #endif 154