X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fserial%2Fserial_pxa.c;h=cf4d8f64427240d03d12def7b43e991a29074070;hb=99ced5331baf1254232e3f73e113fb7ecedebad2;hp=68469a4f358409673d4882061bd461784ad6906c;hpb=9023ae305919d0aecb4a22726b9d08c6b08189d7;p=oweals%2Fu-boot.git diff --git a/drivers/serial/serial_pxa.c b/drivers/serial/serial_pxa.c index 68469a4f35..cf4d8f6442 100644 --- a/drivers/serial/serial_pxa.c +++ b/drivers/serial/serial_pxa.c @@ -1,4 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0+ /* + * Copyright (C) 2011 Marek Vasut + * * (C) Copyright 2002 * Wolfgang Denk, DENX Software Engineering, * @@ -12,172 +15,123 @@ * * Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl) * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * Modified to add driver model (DM) support + * (C) Copyright 2016 Marcel Ziswiler */ #include -#include -#include #include +#include #include +#include +#include +#include +#include +#include DECLARE_GLOBAL_DATA_PTR; -#define FFUART_INDEX 0 -#define BTUART_INDEX 1 -#define STUART_INDEX 2 - -#ifndef CONFIG_SERIAL_MULTI -#if defined (CONFIG_FFUART) -#define UART_INDEX FFUART_INDEX -#elif defined (CONFIG_BTUART) -#define UART_INDEX BTUART_INDEX -#elif defined (CONFIG_STUART) -#define UART_INDEX STUART_INDEX -#else -#error "Bad: you didn't configure serial ..." -#endif -#endif - -void pxa_setbrg_dev (unsigned int uart_index) +static uint32_t pxa_uart_get_baud_divider(int baudrate) { - unsigned int quot = 0; - - if (gd->baudrate == 1200) - quot = 768; - else if (gd->baudrate == 9600) - quot = 96; - else if (gd->baudrate == 19200) - quot = 48; - else if (gd->baudrate == 38400) - quot = 24; - else if (gd->baudrate == 57600) - quot = 16; - else if (gd->baudrate == 115200) - quot = 8; - else - hang (); - - switch (uart_index) { - case FFUART_INDEX: -#ifdef CONFIG_CPU_MONAHANS - writel(readl(CKENA) | CKENA_22_FFUART, CKENA); -#else - writel(readl(CKEN) | CKEN6_FFUART, CKEN); -#endif /* CONFIG_CPU_MONAHANS */ + return 921600 / baudrate; +} - writel(0, FFIER); /* Disable for now */ - writel(0, FFFCR); /* No fifos enabled */ +static void pxa_uart_toggle_clock(uint32_t uart_index, int enable) +{ + uint32_t clk_reg, clk_offset, reg; - /* set baud rate */ - writel(LCR_WLS0 | LCR_WLS1 | LCR_DLAB, FFLCR); - writel(quot & 0xff, FFDLL); - writel(quot >> 8, FFDLH); - writel(LCR_WLS0 | LCR_WLS1, FFLCR); + clk_reg = UART_CLK_REG; + clk_offset = UART_CLK_BASE << uart_index; - writel(IER_UUE, FFIER); /* Enable FFUART */ - break; + reg = readl(clk_reg); - case BTUART_INDEX: -#ifdef CONFIG_CPU_MONAHANS - writel(readl(CKENA) | CKENA_21_BTUART, CKENA); -#else - writel(readl(CKEN) | CKEN7_BTUART, CKEN); -#endif /* CONFIG_CPU_MONAHANS */ + if (enable) + reg |= clk_offset; + else + reg &= ~clk_offset; - writel(0, BTIER); - writel(0, BTFCR); + writel(reg, clk_reg); +} - /* set baud rate */ - writel(LCR_DLAB, BTLCR); - writel(quot & 0xff, BTDLL); - writel(quot >> 8, BTDLH); - writel(LCR_WLS0 | LCR_WLS1, BTLCR); +/* + * Enable clock and set baud rate, parity etc. + */ +void pxa_setbrg_common(struct pxa_uart_regs *uart_regs, int port, int baudrate) +{ + uint32_t divider = pxa_uart_get_baud_divider(baudrate); + if (!divider) + hang(); - writel(IER_UUE, BTIER); /* Enable BFUART */ - break; + pxa_uart_toggle_clock(port, 1); - case STUART_INDEX: -#ifdef CONFIG_CPU_MONAHANS - writel(readl(CKENA) | CKENA_23_STUART, CKENA); -#else - writel(readl(CKEN) | CKEN5_STUART, CKEN); -#endif /* CONFIG_CPU_MONAHANS */ + /* Disable interrupts and FIFOs */ + writel(0, &uart_regs->ier); + writel(0, &uart_regs->fcr); - writel(0, STIER); - writel(0, STFCR); + /* Set baud rate */ + writel(LCR_WLS0 | LCR_WLS1 | LCR_DLAB, &uart_regs->lcr); + writel(divider & 0xff, &uart_regs->dll); + writel(divider >> 8, &uart_regs->dlh); + writel(LCR_WLS0 | LCR_WLS1, &uart_regs->lcr); - /* set baud rate */ - writel(LCR_DLAB, STLCR); - writel(quot & 0xff, STDLL); - writel(quot >> 8, STDLH); - writel(LCR_WLS0 | LCR_WLS1, STLCR); - - writel(IER_UUE, STIER); /* Enable STUART */ - break; + /* Enable UART */ + writel(IER_UUE, &uart_regs->ier); +} - default: - hang(); +#ifndef CONFIG_DM_SERIAL +static struct pxa_uart_regs *pxa_uart_index_to_regs(uint32_t uart_index) +{ + switch (uart_index) { + case FFUART_INDEX: return (struct pxa_uart_regs *)FFUART_BASE; + case BTUART_INDEX: return (struct pxa_uart_regs *)BTUART_BASE; + case STUART_INDEX: return (struct pxa_uart_regs *)STUART_BASE; + case HWUART_INDEX: return (struct pxa_uart_regs *)HWUART_BASE; + default: + return NULL; } } +/* + * Enable clock and set baud rate, parity etc. + */ +void pxa_setbrg_dev(uint32_t uart_index) +{ + struct pxa_uart_regs *uart_regs = pxa_uart_index_to_regs(uart_index); + if (!uart_regs) + panic("Failed getting UART registers\n"); + + pxa_setbrg_common(uart_regs, uart_index, gd->baudrate); +} /* * Initialise the serial port with the given baudrate. The settings * are always 8 data bits, no parity, 1 stop bit, no start bits. - * */ -int pxa_init_dev (unsigned int uart_index) +int pxa_init_dev(unsigned int uart_index) { - pxa_setbrg_dev (uart_index); - - return (0); + pxa_setbrg_dev(uart_index); + return 0; } - /* * Output a single byte to the serial port. */ -void pxa_putc_dev (unsigned int uart_index,const char c) +void pxa_putc_dev(unsigned int uart_index, const char c) { - switch (uart_index) { - case FFUART_INDEX: - /* wait for room in the tx FIFO on FFUART */ - while ((readl(FFLSR) & LSR_TEMT) == 0) - WATCHDOG_RESET (); /* Reset HW Watchdog, if needed */ - writel(c, FFTHR); - break; - - case BTUART_INDEX: - while ((readl(BTLSR) & LSR_TEMT) == 0) - WATCHDOG_RESET (); /* Reset HW Watchdog, if needed */ - writel(c, BTTHR); - break; - - case STUART_INDEX: - while ((readl(STLSR) & LSR_TEMT) == 0) - WATCHDOG_RESET (); /* Reset HW Watchdog, if needed */ - writel(c, STTHR); - break; - } + struct pxa_uart_regs *uart_regs; /* If \n, also do \r */ if (c == '\n') - pxa_putc_dev (uart_index,'\r'); + pxa_putc_dev(uart_index, '\r'); + + uart_regs = pxa_uart_index_to_regs(uart_index); + if (!uart_regs) + hang(); + + while (!(readl(&uart_regs->lsr) & LSR_TEMT)) + WATCHDOG_RESET(); + writel(c, &uart_regs->thr); } /* @@ -185,17 +139,15 @@ void pxa_putc_dev (unsigned int uart_index,const char c) * otherwise. When the function is succesfull, the character read is * written into its argument c. */ -int pxa_tstc_dev (unsigned int uart_index) +int pxa_tstc_dev(unsigned int uart_index) { - switch (uart_index) { - case FFUART_INDEX: - return readl(FFLSR) & LSR_DR; - case BTUART_INDEX: - return readl(BTLSR) & LSR_DR; - case STUART_INDEX: - return readl(STLSR) & LSR_DR; - } - return -1; + struct pxa_uart_regs *uart_regs; + + uart_regs = pxa_uart_index_to_regs(uart_index); + if (!uart_regs) + return -1; + + return readl(&uart_regs->lsr) & LSR_DR; } /* @@ -203,187 +155,187 @@ int pxa_tstc_dev (unsigned int uart_index) * otherwise. When the function is succesfull, the character read is * written into its argument c. */ -int pxa_getc_dev (unsigned int uart_index) -{ - switch (uart_index) { - case FFUART_INDEX: - while (!(readl(FFLSR) & LSR_DR)) - /* Reset HW Watchdog, if needed */ - WATCHDOG_RESET(); - return (char) readl(FFRBR) & 0xff; - - case BTUART_INDEX: - while (!(readl(BTLSR) & LSR_DR)) - /* Reset HW Watchdog, if needed */ - WATCHDOG_RESET(); - return (char) readl(BTRBR) & 0xff; - case STUART_INDEX: - while (!(readl(STLSR) & LSR_DR)) - /* Reset HW Watchdog, if needed */ - WATCHDOG_RESET(); - return (char) readl(STRBR) & 0xff; - } - return -1; -} - -void -pxa_puts_dev (unsigned int uart_index,const char *s) +int pxa_getc_dev(unsigned int uart_index) { - while (*s) { - pxa_putc_dev (uart_index,*s++); - } -} + struct pxa_uart_regs *uart_regs; -#if defined (CONFIG_FFUART) -static int ffuart_init(void) -{ - return pxa_init_dev(FFUART_INDEX); -} + uart_regs = pxa_uart_index_to_regs(uart_index); + if (!uart_regs) + return -1; -static void ffuart_setbrg(void) -{ - return pxa_setbrg_dev(FFUART_INDEX); + while (!(readl(&uart_regs->lsr) & LSR_DR)) + WATCHDOG_RESET(); + return readl(&uart_regs->rbr) & 0xff; } -static void ffuart_putc(const char c) +void pxa_puts_dev(unsigned int uart_index, const char *s) { - return pxa_putc_dev(FFUART_INDEX,c); + while (*s) + pxa_putc_dev(uart_index, *s++); } -static void ffuart_puts(const char *s) -{ - return pxa_puts_dev(FFUART_INDEX,s); -} +#define pxa_uart(uart, UART) \ + int uart##_init(void) \ + { \ + return pxa_init_dev(UART##_INDEX); \ + } \ + \ + void uart##_setbrg(void) \ + { \ + return pxa_setbrg_dev(UART##_INDEX); \ + } \ + \ + void uart##_putc(const char c) \ + { \ + return pxa_putc_dev(UART##_INDEX, c); \ + } \ + \ + void uart##_puts(const char *s) \ + { \ + return pxa_puts_dev(UART##_INDEX, s); \ + } \ + \ + int uart##_getc(void) \ + { \ + return pxa_getc_dev(UART##_INDEX); \ + } \ + \ + int uart##_tstc(void) \ + { \ + return pxa_tstc_dev(UART##_INDEX); \ + } \ + +#define pxa_uart_desc(uart) \ + struct serial_device serial_##uart##_device = \ + { \ + .name = "serial_"#uart, \ + .start = uart##_init, \ + .stop = NULL, \ + .setbrg = uart##_setbrg, \ + .getc = uart##_getc, \ + .tstc = uart##_tstc, \ + .putc = uart##_putc, \ + .puts = uart##_puts, \ + }; + +#define pxa_uart_multi(uart, UART) \ + pxa_uart(uart, UART) \ + pxa_uart_desc(uart) + +#if defined(CONFIG_HWUART) + pxa_uart_multi(hwuart, HWUART) +#endif +#if defined(CONFIG_STUART) + pxa_uart_multi(stuart, STUART) +#endif +#if defined(CONFIG_FFUART) + pxa_uart_multi(ffuart, FFUART) +#endif +#if defined(CONFIG_BTUART) + pxa_uart_multi(btuart, BTUART) +#endif -static int ffuart_getc(void) +__weak struct serial_device *default_serial_console(void) { - return pxa_getc_dev(FFUART_INDEX); +#if CONFIG_CONS_INDEX == 1 + return &serial_hwuart_device; +#elif CONFIG_CONS_INDEX == 2 + return &serial_stuart_device; +#elif CONFIG_CONS_INDEX == 3 + return &serial_ffuart_device; +#elif CONFIG_CONS_INDEX == 4 + return &serial_btuart_device; +#else +#error "Bad CONFIG_CONS_INDEX." +#endif } -static int ffuart_tstc(void) +void pxa_serial_initialize(void) { - return pxa_tstc_dev(FFUART_INDEX); +#if defined(CONFIG_FFUART) + serial_register(&serial_ffuart_device); +#endif +#if defined(CONFIG_BTUART) + serial_register(&serial_btuart_device); +#endif +#if defined(CONFIG_STUART) + serial_register(&serial_stuart_device); +#endif } +#endif /* CONFIG_DM_SERIAL */ -struct serial_device serial_ffuart_device = +#ifdef CONFIG_DM_SERIAL +static int pxa_serial_probe(struct udevice *dev) { - "serial_ffuart", - ffuart_init, - NULL, - ffuart_setbrg, - ffuart_getc, - ffuart_tstc, - ffuart_putc, - ffuart_puts, -}; -#endif + struct pxa_serial_platdata *plat = dev->platdata; -#if defined (CONFIG_BTUART) -static int btuart_init(void) -{ - return pxa_init_dev(BTUART_INDEX); + pxa_setbrg_common((struct pxa_uart_regs *)plat->base, plat->port, + plat->baudrate); + return 0; } -static void btuart_setbrg(void) +static int pxa_serial_putc(struct udevice *dev, const char ch) { - return pxa_setbrg_dev(BTUART_INDEX); -} + struct pxa_serial_platdata *plat = dev->platdata; + struct pxa_uart_regs *uart_regs = (struct pxa_uart_regs *)plat->base; -static void btuart_putc(const char c) -{ - return pxa_putc_dev(BTUART_INDEX,c); -} + /* Wait for last character to go. */ + if (!(readl(&uart_regs->lsr) & LSR_TEMT)) + return -EAGAIN; -static void btuart_puts(const char *s) -{ - return pxa_puts_dev(BTUART_INDEX,s); -} + writel(ch, &uart_regs->thr); -static int btuart_getc(void) -{ - return pxa_getc_dev(BTUART_INDEX); + return 0; } -static int btuart_tstc(void) +static int pxa_serial_getc(struct udevice *dev) { - return pxa_tstc_dev(BTUART_INDEX); -} + struct pxa_serial_platdata *plat = dev->platdata; + struct pxa_uart_regs *uart_regs = (struct pxa_uart_regs *)plat->base; -struct serial_device serial_btuart_device = -{ - "serial_btuart", - btuart_init, - NULL, - btuart_setbrg, - btuart_getc, - btuart_tstc, - btuart_putc, - btuart_puts, -}; -#endif + /* Wait for a character to arrive. */ + if (!(readl(&uart_regs->lsr) & LSR_DR)) + return -EAGAIN; -#if defined (CONFIG_STUART) -static int stuart_init(void) -{ - return pxa_init_dev(STUART_INDEX); + return readl(&uart_regs->rbr) & 0xff; } -static void stuart_setbrg(void) +int pxa_serial_setbrg(struct udevice *dev, int baudrate) { - return pxa_setbrg_dev(STUART_INDEX); -} + struct pxa_serial_platdata *plat = dev->platdata; + struct pxa_uart_regs *uart_regs = (struct pxa_uart_regs *)plat->base; + int port = plat->port; -static void stuart_putc(const char c) -{ - return pxa_putc_dev(STUART_INDEX,c); -} + pxa_setbrg_common(uart_regs, port, baudrate); -static void stuart_puts(const char *s) -{ - return pxa_puts_dev(STUART_INDEX,s); + return 0; } -static int stuart_getc(void) +static int pxa_serial_pending(struct udevice *dev, bool input) { - return pxa_getc_dev(STUART_INDEX); -} + struct pxa_serial_platdata *plat = dev->platdata; + struct pxa_uart_regs *uart_regs = (struct pxa_uart_regs *)plat->base; -static int stuart_tstc(void) -{ - return pxa_tstc_dev(STUART_INDEX); + if (input) + return readl(&uart_regs->lsr) & LSR_DR ? 1 : 0; + else + return readl(&uart_regs->lsr) & LSR_TEMT ? 0 : 1; + + return 0; } -struct serial_device serial_stuart_device = -{ - "serial_stuart", - stuart_init, - NULL, - stuart_setbrg, - stuart_getc, - stuart_tstc, - stuart_putc, - stuart_puts, +static const struct dm_serial_ops pxa_serial_ops = { + .putc = pxa_serial_putc, + .pending = pxa_serial_pending, + .getc = pxa_serial_getc, + .setbrg = pxa_serial_setbrg, }; -#endif - -#ifndef CONFIG_SERIAL_MULTI -inline int serial_init(void) { - return (pxa_init_dev(UART_INDEX)); -} -void serial_setbrg(void) { - pxa_setbrg_dev(UART_INDEX); -} -int serial_getc(void) { - return(pxa_getc_dev(UART_INDEX)); -} -int serial_tstc(void) { - return(pxa_tstc_dev(UART_INDEX)); -} -void serial_putc(const char c) { - pxa_putc_dev(UART_INDEX,c); -} -void serial_puts(const char *s) { - pxa_puts_dev(UART_INDEX,s); -} -#endif /* CONFIG_SERIAL_MULTI */ +U_BOOT_DRIVER(serial_pxa) = { + .name = "serial_pxa", + .id = UCLASS_SERIAL, + .probe = pxa_serial_probe, + .ops = &pxa_serial_ops, + .flags = DM_FLAG_PRE_RELOC, +}; +#endif /* CONFIG_DM_SERIAL */