12bd806feSTsiChungLiew /* 22bd806feSTsiChungLiew * (C) Copyright 2004-2007 Freescale Semiconductor, Inc. 32bd806feSTsiChungLiew * TsiChung Liew, Tsi-Chung.Liew@freescale.com. 42bd806feSTsiChungLiew * 5*e27802afSangelo@sysam.it * Modified to add device model (DM) support 6*e27802afSangelo@sysam.it * (C) Copyright 2015 Angelo Dureghello <angelo@sysam.it> 7*e27802afSangelo@sysam.it * 81a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 92bd806feSTsiChungLiew */ 102bd806feSTsiChungLiew 112bd806feSTsiChungLiew /* 122bd806feSTsiChungLiew * Minimal serial functions needed to use one of the uart ports 132bd806feSTsiChungLiew * as serial console interface. 142bd806feSTsiChungLiew */ 152bd806feSTsiChungLiew 162bd806feSTsiChungLiew #include <common.h> 17*e27802afSangelo@sysam.it #include <dm.h> 18*e27802afSangelo@sysam.it #include <dm/platform_data/serial_coldfire.h> 1939c7a263SAlison Wang #include <serial.h> 2039c7a263SAlison Wang #include <linux/compiler.h> 212bd806feSTsiChungLiew #include <asm/immap.h> 222bd806feSTsiChungLiew #include <asm/uart.h> 232bd806feSTsiChungLiew 242bd806feSTsiChungLiew DECLARE_GLOBAL_DATA_PTR; 252bd806feSTsiChungLiew 26fa9da596STsiChung Liew extern void uart_port_conf(int port); 278d1d66afSTsiChungLiew 28*e27802afSangelo@sysam.it static int mcf_serial_init_common(uart_t *uart, int port_idx, int baudrate) 292bd806feSTsiChungLiew { 302bd806feSTsiChungLiew u32 counter; 312bd806feSTsiChungLiew 32*e27802afSangelo@sysam.it uart_port_conf(port_idx); 338d1d66afSTsiChungLiew 342bd806feSTsiChungLiew /* write to SICR: SIM2 = uart mode,dcd does not affect rx */ 35*e27802afSangelo@sysam.it writeb(UART_UCR_RESET_RX, &uart->ucr); 36*e27802afSangelo@sysam.it writeb(UART_UCR_RESET_TX, &uart->ucr); 37*e27802afSangelo@sysam.it writeb(UART_UCR_RESET_ERROR, &uart->ucr); 38*e27802afSangelo@sysam.it writeb(UART_UCR_RESET_MR, &uart->ucr); 392bd806feSTsiChungLiew __asm__("nop"); 402bd806feSTsiChungLiew 41*e27802afSangelo@sysam.it writeb(0, &uart->uimr); 422bd806feSTsiChungLiew 432bd806feSTsiChungLiew /* write to CSR: RX/TX baud rate from timers */ 44*e27802afSangelo@sysam.it writeb(UART_UCSR_RCS_SYS_CLK | UART_UCSR_TCS_SYS_CLK, &uart->ucsr); 452bd806feSTsiChungLiew 46*e27802afSangelo@sysam.it writeb(UART_UMR_BC_8 | UART_UMR_PM_NONE, &uart->umr); 47*e27802afSangelo@sysam.it writeb(UART_UMR_SB_STOP_BITS_1, &uart->umr); 482bd806feSTsiChungLiew 492bd806feSTsiChungLiew /* Setting up BaudRate */ 50*e27802afSangelo@sysam.it counter = (u32) ((gd->bus_clk / 32) + (baudrate / 2)); 51*e27802afSangelo@sysam.it counter = counter / baudrate; 522bd806feSTsiChungLiew 532bd806feSTsiChungLiew /* write to CTUR: divide counter upper byte */ 54*e27802afSangelo@sysam.it writeb((u8)((counter & 0xff00) >> 8), &uart->ubg1); 552bd806feSTsiChungLiew /* write to CTLR: divide counter lower byte */ 56*e27802afSangelo@sysam.it writeb((u8)(counter & 0x00ff), &uart->ubg2); 572bd806feSTsiChungLiew 58*e27802afSangelo@sysam.it writeb(UART_UCR_RX_ENABLED | UART_UCR_TX_ENABLED, &uart->ucr); 592bd806feSTsiChungLiew 602bd806feSTsiChungLiew return (0); 612bd806feSTsiChungLiew } 622bd806feSTsiChungLiew 63*e27802afSangelo@sysam.it static void mcf_serial_setbrg_common(uart_t *uart, int baudrate) 64*e27802afSangelo@sysam.it { 65*e27802afSangelo@sysam.it u32 counter; 66*e27802afSangelo@sysam.it 67*e27802afSangelo@sysam.it /* Setting up BaudRate */ 68*e27802afSangelo@sysam.it counter = (u32) ((gd->bus_clk / 32) + (baudrate / 2)); 69*e27802afSangelo@sysam.it counter = counter / baudrate; 70*e27802afSangelo@sysam.it 71*e27802afSangelo@sysam.it /* write to CTUR: divide counter upper byte */ 72*e27802afSangelo@sysam.it writeb(((counter & 0xff00) >> 8), &uart->ubg1); 73*e27802afSangelo@sysam.it /* write to CTLR: divide counter lower byte */ 74*e27802afSangelo@sysam.it writeb((counter & 0x00ff), &uart->ubg2); 75*e27802afSangelo@sysam.it 76*e27802afSangelo@sysam.it writeb(UART_UCR_RESET_RX, &uart->ucr); 77*e27802afSangelo@sysam.it writeb(UART_UCR_RESET_TX, &uart->ucr); 78*e27802afSangelo@sysam.it 79*e27802afSangelo@sysam.it writeb(UART_UCR_RX_ENABLED | UART_UCR_TX_ENABLED, &uart->ucr); 80*e27802afSangelo@sysam.it } 81*e27802afSangelo@sysam.it 82*e27802afSangelo@sysam.it #ifndef CONFIG_DM_SERIAL 83*e27802afSangelo@sysam.it 84*e27802afSangelo@sysam.it static int mcf_serial_init(void) 85*e27802afSangelo@sysam.it { 86*e27802afSangelo@sysam.it uart_t *uart_base; 87*e27802afSangelo@sysam.it int port_idx; 88*e27802afSangelo@sysam.it 89*e27802afSangelo@sysam.it uart_base = (uart_t *)CONFIG_SYS_UART_BASE; 90*e27802afSangelo@sysam.it port_idx = CONFIG_SYS_UART_PORT; 91*e27802afSangelo@sysam.it 92*e27802afSangelo@sysam.it return mcf_serial_init_common(uart_base, port_idx, gd->baudrate); 93*e27802afSangelo@sysam.it } 94*e27802afSangelo@sysam.it 95abaef69fSMarek Vasut static void mcf_serial_putc(const char c) 962bd806feSTsiChungLiew { 97*e27802afSangelo@sysam.it uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE; 982bd806feSTsiChungLiew 992bd806feSTsiChungLiew if (c == '\n') 1002bd806feSTsiChungLiew serial_putc('\r'); 1012bd806feSTsiChungLiew 1022bd806feSTsiChungLiew /* Wait for last character to go. */ 103*e27802afSangelo@sysam.it while (!(readb(&uart->usr) & UART_USR_TXRDY)) 104*e27802afSangelo@sysam.it ; 1052bd806feSTsiChungLiew 106*e27802afSangelo@sysam.it writeb(c, &uart->utb); 1072bd806feSTsiChungLiew } 1082bd806feSTsiChungLiew 109abaef69fSMarek Vasut static int mcf_serial_getc(void) 1102bd806feSTsiChungLiew { 111*e27802afSangelo@sysam.it uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE; 1122bd806feSTsiChungLiew 1132bd806feSTsiChungLiew /* Wait for a character to arrive. */ 114*e27802afSangelo@sysam.it while (!(readb(&uart->usr) & UART_USR_RXRDY)) 115*e27802afSangelo@sysam.it ; 1162bd806feSTsiChungLiew 117*e27802afSangelo@sysam.it return readb(&uart->urb); 1182bd806feSTsiChungLiew } 1192bd806feSTsiChungLiew 120abaef69fSMarek Vasut static void mcf_serial_setbrg(void) 1212bd806feSTsiChungLiew { 122*e27802afSangelo@sysam.it uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE; 1232bd806feSTsiChungLiew 124*e27802afSangelo@sysam.it mcf_serial_setbrg_common(uart, gd->baudrate); 125*e27802afSangelo@sysam.it } 1262bd806feSTsiChungLiew 127*e27802afSangelo@sysam.it static int mcf_serial_tstc(void) 128*e27802afSangelo@sysam.it { 129*e27802afSangelo@sysam.it uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE; 1302bd806feSTsiChungLiew 131*e27802afSangelo@sysam.it return readb(&uart->usr) & UART_USR_RXRDY; 1322bd806feSTsiChungLiew } 133abaef69fSMarek Vasut 134abaef69fSMarek Vasut static struct serial_device mcf_serial_drv = { 135abaef69fSMarek Vasut .name = "mcf_serial", 136abaef69fSMarek Vasut .start = mcf_serial_init, 137abaef69fSMarek Vasut .stop = NULL, 138abaef69fSMarek Vasut .setbrg = mcf_serial_setbrg, 139abaef69fSMarek Vasut .putc = mcf_serial_putc, 140ec3fd689SMarek Vasut .puts = default_serial_puts, 141abaef69fSMarek Vasut .getc = mcf_serial_getc, 142abaef69fSMarek Vasut .tstc = mcf_serial_tstc, 143abaef69fSMarek Vasut }; 144abaef69fSMarek Vasut 145abaef69fSMarek Vasut void mcf_serial_initialize(void) 146abaef69fSMarek Vasut { 147abaef69fSMarek Vasut serial_register(&mcf_serial_drv); 148abaef69fSMarek Vasut } 149abaef69fSMarek Vasut 150abaef69fSMarek Vasut __weak struct serial_device *default_serial_console(void) 151abaef69fSMarek Vasut { 152abaef69fSMarek Vasut return &mcf_serial_drv; 153abaef69fSMarek Vasut } 154*e27802afSangelo@sysam.it 155*e27802afSangelo@sysam.it #endif 156*e27802afSangelo@sysam.it 157*e27802afSangelo@sysam.it #ifdef CONFIG_DM_SERIAL 158*e27802afSangelo@sysam.it 159*e27802afSangelo@sysam.it static int coldfire_serial_probe(struct udevice *dev) 160*e27802afSangelo@sysam.it { 161*e27802afSangelo@sysam.it struct coldfire_serial_platdata *plat = dev->platdata; 162*e27802afSangelo@sysam.it 163*e27802afSangelo@sysam.it return mcf_serial_init_common((uart_t *)plat->base, 164*e27802afSangelo@sysam.it plat->port, plat->baudrate); 165*e27802afSangelo@sysam.it } 166*e27802afSangelo@sysam.it 167*e27802afSangelo@sysam.it static int coldfire_serial_putc(struct udevice *dev, const char ch) 168*e27802afSangelo@sysam.it { 169*e27802afSangelo@sysam.it struct coldfire_serial_platdata *plat = dev->platdata; 170*e27802afSangelo@sysam.it uart_t *uart = (uart_t *)plat->base; 171*e27802afSangelo@sysam.it 172*e27802afSangelo@sysam.it /* Wait for last character to go. */ 173*e27802afSangelo@sysam.it if (!(readb(&uart->usr) & UART_USR_TXRDY)) 174*e27802afSangelo@sysam.it return -EAGAIN; 175*e27802afSangelo@sysam.it 176*e27802afSangelo@sysam.it writeb(ch, &uart->utb); 177*e27802afSangelo@sysam.it 178*e27802afSangelo@sysam.it return 0; 179*e27802afSangelo@sysam.it } 180*e27802afSangelo@sysam.it 181*e27802afSangelo@sysam.it static int coldfire_serial_getc(struct udevice *dev) 182*e27802afSangelo@sysam.it { 183*e27802afSangelo@sysam.it struct coldfire_serial_platdata *plat = dev->platdata; 184*e27802afSangelo@sysam.it uart_t *uart = (uart_t *)(plat->base); 185*e27802afSangelo@sysam.it 186*e27802afSangelo@sysam.it /* Wait for a character to arrive. */ 187*e27802afSangelo@sysam.it if (!(readb(&uart->usr) & UART_USR_RXRDY)) 188*e27802afSangelo@sysam.it return -EAGAIN; 189*e27802afSangelo@sysam.it 190*e27802afSangelo@sysam.it return readb(&uart->urb); 191*e27802afSangelo@sysam.it } 192*e27802afSangelo@sysam.it 193*e27802afSangelo@sysam.it int coldfire_serial_setbrg(struct udevice *dev, int baudrate) 194*e27802afSangelo@sysam.it { 195*e27802afSangelo@sysam.it struct coldfire_serial_platdata *plat = dev->platdata; 196*e27802afSangelo@sysam.it uart_t *uart = (uart_t *)(plat->base); 197*e27802afSangelo@sysam.it 198*e27802afSangelo@sysam.it mcf_serial_setbrg_common(uart, baudrate); 199*e27802afSangelo@sysam.it 200*e27802afSangelo@sysam.it return 0; 201*e27802afSangelo@sysam.it } 202*e27802afSangelo@sysam.it 203*e27802afSangelo@sysam.it static int coldfire_serial_pending(struct udevice *dev, bool input) 204*e27802afSangelo@sysam.it { 205*e27802afSangelo@sysam.it struct coldfire_serial_platdata *plat = dev->platdata; 206*e27802afSangelo@sysam.it uart_t *uart = (uart_t *)(plat->base); 207*e27802afSangelo@sysam.it 208*e27802afSangelo@sysam.it if (input) 209*e27802afSangelo@sysam.it return readb(&uart->usr) & UART_USR_RXRDY ? 1 : 0; 210*e27802afSangelo@sysam.it else 211*e27802afSangelo@sysam.it return readb(&uart->usr) & UART_USR_TXRDY ? 0 : 1; 212*e27802afSangelo@sysam.it 213*e27802afSangelo@sysam.it return 0; 214*e27802afSangelo@sysam.it } 215*e27802afSangelo@sysam.it 216*e27802afSangelo@sysam.it static const struct dm_serial_ops coldfire_serial_ops = { 217*e27802afSangelo@sysam.it .putc = coldfire_serial_putc, 218*e27802afSangelo@sysam.it .pending = coldfire_serial_pending, 219*e27802afSangelo@sysam.it .getc = coldfire_serial_getc, 220*e27802afSangelo@sysam.it .setbrg = coldfire_serial_setbrg, 221*e27802afSangelo@sysam.it }; 222*e27802afSangelo@sysam.it 223*e27802afSangelo@sysam.it U_BOOT_DRIVER(serial_coldfire) = { 224*e27802afSangelo@sysam.it .name = "serial_coldfire", 225*e27802afSangelo@sysam.it .id = UCLASS_SERIAL, 226*e27802afSangelo@sysam.it .probe = coldfire_serial_probe, 227*e27802afSangelo@sysam.it .ops = &coldfire_serial_ops, 228*e27802afSangelo@sysam.it .flags = DM_FLAG_PRE_RELOC, 229*e27802afSangelo@sysam.it }; 230*e27802afSangelo@sysam.it #endif 231