1 /* 2 * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> 3 * 4 * (C) Copyright 2002 5 * Wolfgang Denk, DENX Software Engineering, <wd@denx.de> 6 * 7 * (C) Copyright 2002 8 * Sysgo Real-Time Solutions, GmbH <www.elinos.com> 9 * Marius Groeger <mgroeger@sysgo.de> 10 * 11 * (C) Copyright 2002 12 * Sysgo Real-Time Solutions, GmbH <www.elinos.com> 13 * Alex Zuepke <azu@sysgo.de> 14 * 15 * Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl) 16 * 17 * This program is free software; you can redistribute it and/or modify 18 * it under the terms of the GNU General Public License as published by 19 * the Free Software Foundation; either version 2 of the License, or 20 * (at your option) any later version. 21 * 22 * This program is distributed in the hope that it will be useful, 23 * but WITHOUT ANY WARRANTY; without even the implied warranty of 24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 * GNU General Public License for more details. 26 * 27 * You should have received a copy of the GNU General Public License 28 * along with this program; if not, write to the Free Software 29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 30 * 31 */ 32 33 #include <common.h> 34 #include <watchdog.h> 35 #include <serial.h> 36 #include <asm/arch/pxa-regs.h> 37 #include <asm/arch/regs-uart.h> 38 #include <asm/io.h> 39 #include <linux/compiler.h> 40 41 DECLARE_GLOBAL_DATA_PTR; 42 43 /* 44 * The numbering scheme differs here for PXA25x, PXA27x and PXA3xx so we can 45 * easily handle enabling of clock. 46 */ 47 #ifdef CONFIG_CPU_MONAHANS 48 #define UART_CLK_BASE CKENA_21_BTUART 49 #define UART_CLK_REG CKENA 50 #define BTUART_INDEX 0 51 #define FFUART_INDEX 1 52 #define STUART_INDEX 2 53 #elif CONFIG_CPU_PXA25X 54 #define UART_CLK_BASE (1 << 4) /* HWUART */ 55 #define UART_CLK_REG CKEN 56 #define HWUART_INDEX 0 57 #define STUART_INDEX 1 58 #define FFUART_INDEX 2 59 #define BTUART_INDEX 3 60 #else /* PXA27x */ 61 #define UART_CLK_BASE CKEN5_STUART 62 #define UART_CLK_REG CKEN 63 #define STUART_INDEX 0 64 #define FFUART_INDEX 1 65 #define BTUART_INDEX 2 66 #endif 67 68 /* 69 * Only PXA250 has HWUART, to avoid poluting the code with more macros, 70 * artificially introduce this. 71 */ 72 #ifndef CONFIG_CPU_PXA25X 73 #define HWUART_INDEX 0xff 74 #endif 75 76 #ifndef CONFIG_SERIAL_MULTI 77 #if defined(CONFIG_FFUART) 78 #define UART_INDEX FFUART_INDEX 79 #elif defined(CONFIG_BTUART) 80 #define UART_INDEX BTUART_INDEX 81 #elif defined(CONFIG_STUART) 82 #define UART_INDEX STUART_INDEX 83 #elif defined(CONFIG_HWUART) 84 #define UART_INDEX HWUART_INDEX 85 #else 86 #error "Please select CONFIG_(FF|BT|ST|HW)UART in board config file." 87 #endif 88 #endif 89 90 static uint32_t pxa_uart_get_baud_divider(void) 91 { 92 if (gd->baudrate == 1200) 93 return 768; 94 else if (gd->baudrate == 9600) 95 return 96; 96 else if (gd->baudrate == 19200) 97 return 48; 98 else if (gd->baudrate == 38400) 99 return 24; 100 else if (gd->baudrate == 57600) 101 return 16; 102 else if (gd->baudrate == 115200) 103 return 8; 104 else /* Unsupported baudrate */ 105 return 0; 106 } 107 108 static struct pxa_uart_regs *pxa_uart_index_to_regs(uint32_t uart_index) 109 { 110 switch (uart_index) { 111 case FFUART_INDEX: return (struct pxa_uart_regs *)FFUART_BASE; 112 case BTUART_INDEX: return (struct pxa_uart_regs *)BTUART_BASE; 113 case STUART_INDEX: return (struct pxa_uart_regs *)STUART_BASE; 114 case HWUART_INDEX: return (struct pxa_uart_regs *)HWUART_BASE; 115 default: 116 return NULL; 117 } 118 } 119 120 static void pxa_uart_toggle_clock(uint32_t uart_index, int enable) 121 { 122 uint32_t clk_reg, clk_offset, reg; 123 124 clk_reg = UART_CLK_REG; 125 clk_offset = UART_CLK_BASE << uart_index; 126 127 reg = readl(clk_reg); 128 129 if (enable) 130 reg |= clk_offset; 131 else 132 reg &= ~clk_offset; 133 134 writel(reg, clk_reg); 135 } 136 137 /* 138 * Enable clock and set baud rate, parity etc. 139 */ 140 void pxa_setbrg_dev(uint32_t uart_index) 141 { 142 uint32_t divider = 0; 143 struct pxa_uart_regs *uart_regs; 144 145 divider = pxa_uart_get_baud_divider(); 146 if (!divider) 147 hang(); 148 149 uart_regs = pxa_uart_index_to_regs(uart_index); 150 if (!uart_regs) 151 hang(); 152 153 pxa_uart_toggle_clock(uart_index, 1); 154 155 /* Disable interrupts and FIFOs */ 156 writel(0, &uart_regs->ier); 157 writel(0, &uart_regs->fcr); 158 159 /* Set baud rate */ 160 writel(LCR_WLS0 | LCR_WLS1 | LCR_DLAB, &uart_regs->lcr); 161 writel(divider & 0xff, &uart_regs->dll); 162 writel(divider >> 8, &uart_regs->dlh); 163 writel(LCR_WLS0 | LCR_WLS1, &uart_regs->lcr); 164 165 /* Enable UART */ 166 writel(IER_UUE, &uart_regs->ier); 167 } 168 169 /* 170 * Initialise the serial port with the given baudrate. The settings 171 * are always 8 data bits, no parity, 1 stop bit, no start bits. 172 */ 173 int pxa_init_dev(unsigned int uart_index) 174 { 175 pxa_setbrg_dev (uart_index); 176 return 0; 177 } 178 179 /* 180 * Output a single byte to the serial port. 181 */ 182 void pxa_putc_dev(unsigned int uart_index, const char c) 183 { 184 struct pxa_uart_regs *uart_regs; 185 186 uart_regs = pxa_uart_index_to_regs(uart_index); 187 if (!uart_regs) 188 hang(); 189 190 while (!(readl(&uart_regs->lsr) & LSR_TEMT)) 191 WATCHDOG_RESET(); 192 writel(c, &uart_regs->thr); 193 194 /* If \n, also do \r */ 195 if (c == '\n') 196 pxa_putc_dev (uart_index,'\r'); 197 } 198 199 /* 200 * Read a single byte from the serial port. Returns 1 on success, 0 201 * otherwise. When the function is succesfull, the character read is 202 * written into its argument c. 203 */ 204 int pxa_tstc_dev(unsigned int uart_index) 205 { 206 struct pxa_uart_regs *uart_regs; 207 208 uart_regs = pxa_uart_index_to_regs(uart_index); 209 if (!uart_regs) 210 return -1; 211 212 return readl(&uart_regs->lsr) & LSR_DR; 213 } 214 215 /* 216 * Read a single byte from the serial port. Returns 1 on success, 0 217 * otherwise. When the function is succesfull, the character read is 218 * written into its argument c. 219 */ 220 int pxa_getc_dev(unsigned int uart_index) 221 { 222 struct pxa_uart_regs *uart_regs; 223 224 uart_regs = pxa_uart_index_to_regs(uart_index); 225 if (!uart_regs) 226 return -1; 227 228 while (!(readl(&uart_regs->lsr) & LSR_DR)) 229 WATCHDOG_RESET(); 230 return readl(&uart_regs->rbr) & 0xff; 231 } 232 233 void pxa_puts_dev(unsigned int uart_index, const char *s) 234 { 235 while (*s) 236 pxa_putc_dev(uart_index, *s++); 237 } 238 239 #define pxa_uart(uart, UART) \ 240 int uart##_init(void) \ 241 { \ 242 return pxa_init_dev(UART##_INDEX); \ 243 } \ 244 \ 245 void uart##_setbrg(void) \ 246 { \ 247 return pxa_setbrg_dev(UART##_INDEX); \ 248 } \ 249 \ 250 void uart##_putc(const char c) \ 251 { \ 252 return pxa_putc_dev(UART##_INDEX, c); \ 253 } \ 254 \ 255 void uart##_puts(const char *s) \ 256 { \ 257 return pxa_puts_dev(UART##_INDEX, s); \ 258 } \ 259 \ 260 int uart##_getc(void) \ 261 { \ 262 return pxa_getc_dev(UART##_INDEX); \ 263 } \ 264 \ 265 int uart##_tstc(void) \ 266 { \ 267 return pxa_tstc_dev(UART##_INDEX); \ 268 } \ 269 270 #define pxa_uart_desc(uart) \ 271 struct serial_device serial_##uart##_device = \ 272 { \ 273 .name = "serial_"#uart, \ 274 .start = uart##_init, \ 275 .stop = NULL, \ 276 .setbrg = uart##_setbrg, \ 277 .getc = uart##_getc, \ 278 .tstc = uart##_tstc, \ 279 .putc = uart##_putc, \ 280 .puts = uart##_puts, \ 281 }; 282 283 #define pxa_uart_multi(uart, UART) \ 284 pxa_uart(uart, UART) \ 285 pxa_uart_desc(uart) 286 287 #if defined(CONFIG_HWUART) 288 pxa_uart_multi(hwuart, HWUART) 289 #endif 290 #if defined(CONFIG_STUART) 291 pxa_uart_multi(stuart, STUART) 292 #endif 293 #if defined(CONFIG_FFUART) 294 pxa_uart_multi(ffuart, FFUART) 295 #endif 296 #if defined(CONFIG_BTUART) 297 pxa_uart_multi(btuart, BTUART) 298 #endif 299 300 #ifndef CONFIG_SERIAL_MULTI 301 pxa_uart(serial, UART) 302 #else 303 __weak struct serial_device *default_serial_console(void) 304 { 305 #if CONFIG_CONS_INDEX == 1 306 return &serial_hwuart_device; 307 #elif CONFIG_CONS_INDEX == 2 308 return &serial_stuart_device; 309 #elif CONFIG_CONS_INDEX == 3 310 return &serial_ffuart_device; 311 #elif CONFIG_CONS_INDEX == 4 312 return &serial_btuart_device; 313 #else 314 #error "Bad CONFIG_CONS_INDEX." 315 #endif 316 } 317 #endif 318