blob: 5bdbc42e42a6f345fe247ece62b8553f49369525 [file] [log] [blame]
Tony Lindgren1dbae812005-11-10 14:26:51 +00001/*
Uwe Zeisbergerf30c2262006-10-03 23:01:26 +02002 * arch/arm/mach-omap2/serial.c
Tony Lindgren1dbae812005-11-10 14:26:51 +00003 *
4 * OMAP2 serial support.
5 *
Jouni Hogander6e811762008-10-06 15:49:15 +03006 * Copyright (C) 2005-2008 Nokia Corporation
Tony Lindgren1dbae812005-11-10 14:26:51 +00007 * Author: Paul Mundt <paul.mundt@nokia.com>
8 *
Kevin Hilman4af40162009-02-04 10:51:40 -08009 * Major rework for PM support by Kevin Hilman
10 *
Tony Lindgren1dbae812005-11-10 14:26:51 +000011 * Based off of arch/arm/mach-omap/omap1/serial.c
12 *
Santosh Shilimkar44169072009-05-28 14:16:04 -070013 * Copyright (C) 2009 Texas Instruments
14 * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com
15 *
Tony Lindgren1dbae812005-11-10 14:26:51 +000016 * This file is subject to the terms and conditions of the GNU General Public
17 * License. See the file "COPYING" in the main directory of this archive
18 * for more details.
19 */
20#include <linux/kernel.h>
21#include <linux/init.h>
Russell Kingf8ce2542006-01-07 16:15:52 +000022#include <linux/clk.h>
Russell Kingfced80c2008-09-06 12:10:45 +010023#include <linux/io.h>
Santosh Shilimkare03d37d2010-02-18 08:59:06 +000024#include <linux/delay.h>
Kevin Hilman6f251e92010-09-27 20:19:38 +053025#include <linux/platform_device.h>
26#include <linux/slab.h>
Kevin Hilman3244fcd2010-09-27 20:19:53 +053027#include <linux/pm_runtime.h>
Paul Walmsley0d8e2d02010-11-24 16:49:05 -070028#include <linux/console.h>
Kevin Hilman6f251e92010-09-27 20:19:38 +053029
Kevin Hilman6f251e92010-09-27 20:19:38 +053030#include <plat/omap-serial.h>
Tony Lindgren4e653312011-11-10 22:45:17 +010031#include "common.h"
Tony Lindgrence491cf2009-10-20 09:40:47 -070032#include <plat/board.h>
Kevin Hilman6f251e92010-09-27 20:19:38 +053033#include <plat/dma.h>
34#include <plat/omap_hwmod.h>
35#include <plat/omap_device.h>
Tony Lindgren1dbae812005-11-10 14:26:51 +000036
Paul Walmsley59fb6592010-12-21 15:30:55 -070037#include "prm2xxx_3xxx.h"
Kevin Hilman4af40162009-02-04 10:51:40 -080038#include "pm.h"
Paul Walmsley59fb6592010-12-21 15:30:55 -070039#include "cm2xxx_3xxx.h"
Kevin Hilman4af40162009-02-04 10:51:40 -080040#include "prm-regbits-34xx.h"
Paul Walmsley4814ced2010-10-08 11:40:20 -060041#include "control.h"
Tony Lindgren40e44392010-12-22 18:42:35 -080042#include "mux.h"
Kevin Hilman4af40162009-02-04 10:51:40 -080043
44#define UART_OMAP_WER 0x17 /* Wake-up enable register */
45
Deepak K00034502010-08-02 13:18:12 +030046#define UART_ERRATA_i202_MDR1_ACCESS (0x1 << 1)
Nishanth Menon5a927b32010-08-02 13:18:12 +030047
Tony Lindgren301fe8e2010-02-01 12:34:31 -080048/*
49 * NOTE: By default the serial timeout is disabled as it causes lost characters
50 * over the serial ports. This means that the UART clocks will stay on until
51 * disabled via sysfs. This also causes that any deeper omap sleep states are
52 * blocked.
53 */
54#define DEFAULT_TIMEOUT 0
Kevin Hilman4af40162009-02-04 10:51:40 -080055
Kevin Hilman6f251e92010-09-27 20:19:38 +053056#define MAX_UART_HWMOD_NAME_LEN 16
57
Kevin Hilman4af40162009-02-04 10:51:40 -080058struct omap_uart_state {
59 int num;
60 int can_sleep;
Kevin Hilman4af40162009-02-04 10:51:40 -080061
62 void __iomem *wk_st;
63 void __iomem *wk_en;
64 u32 wk_mask;
65 u32 padconf;
Kevin Hilman6f251e92010-09-27 20:19:38 +053066 u32 dma_enabled;
Kevin Hilman4af40162009-02-04 10:51:40 -080067
Kevin Hilman4af40162009-02-04 10:51:40 -080068 int clocked;
69
Kevin Hilman6f251e92010-09-27 20:19:38 +053070 int regshift;
Kevin Hilman6f251e92010-09-27 20:19:38 +053071 void __iomem *membase;
72 resource_size_t mapbase;
73
Kevin Hilman4af40162009-02-04 10:51:40 -080074 struct list_head node;
Kevin Hilman6f251e92010-09-27 20:19:38 +053075 struct omap_hwmod *oh;
76 struct platform_device *pdev;
Kevin Hilman4af40162009-02-04 10:51:40 -080077
Nishanth Menon5a927b32010-08-02 13:18:12 +030078 u32 errata;
Kevin Hilman4af40162009-02-04 10:51:40 -080079#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
80 int context_valid;
81
82 /* Registers to be saved/restored for OFF-mode */
83 u16 dll;
84 u16 dlh;
85 u16 ier;
86 u16 sysc;
87 u16 scr;
88 u16 wer;
Govindraj R5ade4ff2010-08-02 13:18:11 +030089 u16 mcr;
Kevin Hilman4af40162009-02-04 10:51:40 -080090#endif
91};
92
Kevin Hilman4af40162009-02-04 10:51:40 -080093static LIST_HEAD(uart_list);
Kevin Hilman6f251e92010-09-27 20:19:38 +053094static u8 num_uarts;
Tony Lindgren1dbae812005-11-10 14:26:51 +000095
Alexander Shishkin92303722010-01-08 10:29:06 -080096static inline unsigned int __serial_read_reg(struct uart_port *up,
Kevin Hilman6f251e92010-09-27 20:19:38 +053097 int offset)
Alexander Shishkin92303722010-01-08 10:29:06 -080098{
99 offset <<= up->regshift;
100 return (unsigned int)__raw_readb(up->membase + offset);
101}
102
Kevin Hilman6f251e92010-09-27 20:19:38 +0530103static inline unsigned int serial_read_reg(struct omap_uart_state *uart,
Tony Lindgren1dbae812005-11-10 14:26:51 +0000104 int offset)
105{
Kevin Hilman6f251e92010-09-27 20:19:38 +0530106 offset <<= uart->regshift;
107 return (unsigned int)__raw_readb(uart->membase + offset);
Tony Lindgren1dbae812005-11-10 14:26:51 +0000108}
109
Santosh Shilimkare03d37d2010-02-18 08:59:06 +0000110static inline void __serial_write_reg(struct uart_port *up, int offset,
111 int value)
112{
113 offset <<= up->regshift;
114 __raw_writeb(value, up->membase + offset);
115}
116
Kevin Hilman6f251e92010-09-27 20:19:38 +0530117static inline void serial_write_reg(struct omap_uart_state *uart, int offset,
Tony Lindgren1dbae812005-11-10 14:26:51 +0000118 int value)
119{
Kevin Hilman6f251e92010-09-27 20:19:38 +0530120 offset <<= uart->regshift;
121 __raw_writeb(value, uart->membase + offset);
Tony Lindgren1dbae812005-11-10 14:26:51 +0000122}
123
124/*
125 * Internal UARTs need to be initialized for the 8250 autoconfig to work
126 * properly. Note that the TX watermark initialization may not be needed
127 * once the 8250.c watermark handling code is merged.
128 */
Kevin Hilman6f251e92010-09-27 20:19:38 +0530129
Kevin Hilman4af40162009-02-04 10:51:40 -0800130static inline void __init omap_uart_reset(struct omap_uart_state *uart)
Tony Lindgren1dbae812005-11-10 14:26:51 +0000131{
Andrei Emeltchenko498cb952010-11-30 14:11:49 -0800132 serial_write_reg(uart, UART_OMAP_MDR1, UART_OMAP_MDR1_DISABLE);
Kevin Hilman6f251e92010-09-27 20:19:38 +0530133 serial_write_reg(uart, UART_OMAP_SCR, 0x08);
Andrei Emeltchenko498cb952010-11-30 14:11:49 -0800134 serial_write_reg(uart, UART_OMAP_MDR1, UART_OMAP_MDR1_16X_MODE);
Tony Lindgren1dbae812005-11-10 14:26:51 +0000135}
136
Kevin Hilman4af40162009-02-04 10:51:40 -0800137#if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3)
138
Deepak K00034502010-08-02 13:18:12 +0300139/*
140 * Work Around for Errata i202 (3430 - 1.12, 3630 - 1.6)
141 * The access to uart register after MDR1 Access
142 * causes UART to corrupt data.
143 *
144 * Need a delay =
145 * 5 L4 clock cycles + 5 UART functional clock cycle (@48MHz = ~0.2uS)
146 * give 10 times as much
147 */
148static void omap_uart_mdr1_errataset(struct omap_uart_state *uart, u8 mdr1_val,
149 u8 fcr_val)
150{
Deepak K00034502010-08-02 13:18:12 +0300151 u8 timeout = 255;
152
Kevin Hilman6f251e92010-09-27 20:19:38 +0530153 serial_write_reg(uart, UART_OMAP_MDR1, mdr1_val);
Deepak K00034502010-08-02 13:18:12 +0300154 udelay(2);
Kevin Hilman6f251e92010-09-27 20:19:38 +0530155 serial_write_reg(uart, UART_FCR, fcr_val | UART_FCR_CLEAR_XMIT |
Deepak K00034502010-08-02 13:18:12 +0300156 UART_FCR_CLEAR_RCVR);
157 /*
158 * Wait for FIFO to empty: when empty, RX_FIFO_E bit is 0 and
159 * TX_FIFO_E bit is 1.
160 */
Kevin Hilman6f251e92010-09-27 20:19:38 +0530161 while (UART_LSR_THRE != (serial_read_reg(uart, UART_LSR) &
Deepak K00034502010-08-02 13:18:12 +0300162 (UART_LSR_THRE | UART_LSR_DR))) {
163 timeout--;
164 if (!timeout) {
165 /* Should *never* happen. we warn and carry on */
Kevin Hilman6f251e92010-09-27 20:19:38 +0530166 dev_crit(&uart->pdev->dev, "Errata i202: timedout %x\n",
167 serial_read_reg(uart, UART_LSR));
Deepak K00034502010-08-02 13:18:12 +0300168 break;
169 }
170 udelay(1);
171 }
172}
173
Kevin Hilman4af40162009-02-04 10:51:40 -0800174static void omap_uart_save_context(struct omap_uart_state *uart)
Jouni Hogander6e811762008-10-06 15:49:15 +0300175{
Kevin Hilman4af40162009-02-04 10:51:40 -0800176 u16 lcr = 0;
Kevin Hilman4af40162009-02-04 10:51:40 -0800177
178 if (!enable_off_mode)
179 return;
180
Kevin Hilman6f251e92010-09-27 20:19:38 +0530181 lcr = serial_read_reg(uart, UART_LCR);
Andrei Emeltchenko662b083a2010-11-30 14:11:49 -0800182 serial_write_reg(uart, UART_LCR, UART_LCR_CONF_MODE_B);
Kevin Hilman6f251e92010-09-27 20:19:38 +0530183 uart->dll = serial_read_reg(uart, UART_DLL);
184 uart->dlh = serial_read_reg(uart, UART_DLM);
185 serial_write_reg(uart, UART_LCR, lcr);
186 uart->ier = serial_read_reg(uart, UART_IER);
187 uart->sysc = serial_read_reg(uart, UART_OMAP_SYSC);
188 uart->scr = serial_read_reg(uart, UART_OMAP_SCR);
189 uart->wer = serial_read_reg(uart, UART_OMAP_WER);
Andrei Emeltchenko662b083a2010-11-30 14:11:49 -0800190 serial_write_reg(uart, UART_LCR, UART_LCR_CONF_MODE_A);
Kevin Hilman6f251e92010-09-27 20:19:38 +0530191 uart->mcr = serial_read_reg(uart, UART_MCR);
192 serial_write_reg(uart, UART_LCR, lcr);
Kevin Hilman4af40162009-02-04 10:51:40 -0800193
194 uart->context_valid = 1;
195}
196
197static void omap_uart_restore_context(struct omap_uart_state *uart)
198{
199 u16 efr = 0;
Kevin Hilman4af40162009-02-04 10:51:40 -0800200
201 if (!enable_off_mode)
202 return;
203
204 if (!uart->context_valid)
205 return;
206
207 uart->context_valid = 0;
208
Deepak K00034502010-08-02 13:18:12 +0300209 if (uart->errata & UART_ERRATA_i202_MDR1_ACCESS)
Andrei Emeltchenko498cb952010-11-30 14:11:49 -0800210 omap_uart_mdr1_errataset(uart, UART_OMAP_MDR1_DISABLE, 0xA0);
Deepak K00034502010-08-02 13:18:12 +0300211 else
Andrei Emeltchenko498cb952010-11-30 14:11:49 -0800212 serial_write_reg(uart, UART_OMAP_MDR1, UART_OMAP_MDR1_DISABLE);
213
Andrei Emeltchenko662b083a2010-11-30 14:11:49 -0800214 serial_write_reg(uart, UART_LCR, UART_LCR_CONF_MODE_B);
Kevin Hilman6f251e92010-09-27 20:19:38 +0530215 efr = serial_read_reg(uart, UART_EFR);
216 serial_write_reg(uart, UART_EFR, UART_EFR_ECB);
217 serial_write_reg(uart, UART_LCR, 0x0); /* Operational mode */
218 serial_write_reg(uart, UART_IER, 0x0);
Andrei Emeltchenko662b083a2010-11-30 14:11:49 -0800219 serial_write_reg(uart, UART_LCR, UART_LCR_CONF_MODE_B);
Kevin Hilman6f251e92010-09-27 20:19:38 +0530220 serial_write_reg(uart, UART_DLL, uart->dll);
221 serial_write_reg(uart, UART_DLM, uart->dlh);
222 serial_write_reg(uart, UART_LCR, 0x0); /* Operational mode */
223 serial_write_reg(uart, UART_IER, uart->ier);
Andrei Emeltchenko662b083a2010-11-30 14:11:49 -0800224 serial_write_reg(uart, UART_LCR, UART_LCR_CONF_MODE_A);
Kevin Hilman6f251e92010-09-27 20:19:38 +0530225 serial_write_reg(uart, UART_MCR, uart->mcr);
Andrei Emeltchenko662b083a2010-11-30 14:11:49 -0800226 serial_write_reg(uart, UART_LCR, UART_LCR_CONF_MODE_B);
Kevin Hilman6f251e92010-09-27 20:19:38 +0530227 serial_write_reg(uart, UART_EFR, efr);
228 serial_write_reg(uart, UART_LCR, UART_LCR_WLEN8);
229 serial_write_reg(uart, UART_OMAP_SCR, uart->scr);
230 serial_write_reg(uart, UART_OMAP_WER, uart->wer);
231 serial_write_reg(uart, UART_OMAP_SYSC, uart->sysc);
Andrei Emeltchenko498cb952010-11-30 14:11:49 -0800232
Deepak K00034502010-08-02 13:18:12 +0300233 if (uart->errata & UART_ERRATA_i202_MDR1_ACCESS)
Andrei Emeltchenko498cb952010-11-30 14:11:49 -0800234 omap_uart_mdr1_errataset(uart, UART_OMAP_MDR1_16X_MODE, 0xA1);
Deepak K00034502010-08-02 13:18:12 +0300235 else
Kevin Hilman6f251e92010-09-27 20:19:38 +0530236 /* UART 16x mode */
Andrei Emeltchenko498cb952010-11-30 14:11:49 -0800237 serial_write_reg(uart, UART_OMAP_MDR1,
238 UART_OMAP_MDR1_16X_MODE);
Kevin Hilman4af40162009-02-04 10:51:40 -0800239}
240#else
241static inline void omap_uart_save_context(struct omap_uart_state *uart) {}
242static inline void omap_uart_restore_context(struct omap_uart_state *uart) {}
243#endif /* CONFIG_PM && CONFIG_ARCH_OMAP3 */
244
245static inline void omap_uart_enable_clocks(struct omap_uart_state *uart)
246{
247 if (uart->clocked)
248 return;
249
Kevin Hilman6f251e92010-09-27 20:19:38 +0530250 omap_device_enable(uart->pdev);
Kevin Hilman4af40162009-02-04 10:51:40 -0800251 uart->clocked = 1;
252 omap_uart_restore_context(uart);
253}
254
255#ifdef CONFIG_PM
256
257static inline void omap_uart_disable_clocks(struct omap_uart_state *uart)
258{
259 if (!uart->clocked)
260 return;
261
262 omap_uart_save_context(uart);
263 uart->clocked = 0;
Kevin Hilman6f251e92010-09-27 20:19:38 +0530264 omap_device_idle(uart->pdev);
Kevin Hilman4af40162009-02-04 10:51:40 -0800265}
266
Kevin Hilmanfd455ea2009-04-27 12:27:36 -0700267static void omap_uart_enable_wakeup(struct omap_uart_state *uart)
268{
269 /* Set wake-enable bit */
270 if (uart->wk_en && uart->wk_mask) {
271 u32 v = __raw_readl(uart->wk_en);
272 v |= uart->wk_mask;
273 __raw_writel(v, uart->wk_en);
274 }
275
276 /* Ensure IOPAD wake-enables are set */
277 if (cpu_is_omap34xx() && uart->padconf) {
278 u16 v = omap_ctrl_readw(uart->padconf);
279 v |= OMAP3_PADCONF_WAKEUPENABLE0;
280 omap_ctrl_writew(v, uart->padconf);
281 }
282}
283
284static void omap_uart_disable_wakeup(struct omap_uart_state *uart)
285{
286 /* Clear wake-enable bit */
287 if (uart->wk_en && uart->wk_mask) {
288 u32 v = __raw_readl(uart->wk_en);
289 v &= ~uart->wk_mask;
290 __raw_writel(v, uart->wk_en);
291 }
292
293 /* Ensure IOPAD wake-enables are cleared */
294 if (cpu_is_omap34xx() && uart->padconf) {
295 u16 v = omap_ctrl_readw(uart->padconf);
296 v &= ~OMAP3_PADCONF_WAKEUPENABLE0;
297 omap_ctrl_writew(v, uart->padconf);
298 }
299}
300
Kevin Hilman4af40162009-02-04 10:51:40 -0800301static void omap_uart_smart_idle_enable(struct omap_uart_state *uart,
Kevin Hilman6f251e92010-09-27 20:19:38 +0530302 int enable)
Kevin Hilman4af40162009-02-04 10:51:40 -0800303{
Kevin Hilman6f251e92010-09-27 20:19:38 +0530304 u8 idlemode;
Kevin Hilman4af40162009-02-04 10:51:40 -0800305
Kevin Hilman6f251e92010-09-27 20:19:38 +0530306 if (enable) {
307 /**
308 * Errata 2.15: [UART]:Cannot Acknowledge Idle Requests
309 * in Smartidle Mode When Configured for DMA Operations.
310 */
311 if (uart->dma_enabled)
312 idlemode = HWMOD_IDLEMODE_FORCE;
313 else
314 idlemode = HWMOD_IDLEMODE_SMART;
315 } else {
316 idlemode = HWMOD_IDLEMODE_NO;
317 }
Kevin Hilman4af40162009-02-04 10:51:40 -0800318
Kevin Hilman6f251e92010-09-27 20:19:38 +0530319 omap_hwmod_set_slave_idlemode(uart->oh, idlemode);
Kevin Hilman4af40162009-02-04 10:51:40 -0800320}
321
322static void omap_uart_block_sleep(struct omap_uart_state *uart)
323{
324 omap_uart_enable_clocks(uart);
325
326 omap_uart_smart_idle_enable(uart, 0);
327 uart->can_sleep = 0;
Kevin Hilman4af40162009-02-04 10:51:40 -0800328}
329
Kevin Hilman4af40162009-02-04 10:51:40 -0800330int omap_uart_can_sleep(void)
331{
332 struct omap_uart_state *uart;
333 int can_sleep = 1;
334
335 list_for_each_entry(uart, &uart_list, node) {
336 if (!uart->clocked)
337 continue;
338
339 if (!uart->can_sleep) {
340 can_sleep = 0;
341 continue;
342 }
343
344 /* This UART can now safely sleep. */
345 omap_uart_allow_sleep(uart);
346 }
347
348 return can_sleep;
349}
350
Kevin Hilman4af40162009-02-04 10:51:40 -0800351static void omap_uart_idle_init(struct omap_uart_state *uart)
352{
Kevin Hilman4af40162009-02-04 10:51:40 -0800353 int ret;
354
355 uart->can_sleep = 0;
Kevin Hilman4af40162009-02-04 10:51:40 -0800356 omap_uart_smart_idle_enable(uart, 0);
357
Hemant Pedanekara9203602011-12-13 10:46:44 -0800358 if (cpu_is_omap34xx() && !(cpu_is_ti81xx() || cpu_is_am33xx())) {
Govindraj.R52663ae2010-09-27 20:20:41 +0530359 u32 mod = (uart->num > 1) ? OMAP3430_PER_MOD : CORE_MOD;
Kevin Hilman4af40162009-02-04 10:51:40 -0800360 u32 wk_mask = 0;
361 u32 padconf = 0;
362
Paul Walmsleyc4d7e582010-12-21 21:05:14 -0700363 /* XXX These PRM accesses do not belong here */
Kevin Hilman4af40162009-02-04 10:51:40 -0800364 uart->wk_en = OMAP34XX_PRM_REGADDR(mod, PM_WKEN1);
365 uart->wk_st = OMAP34XX_PRM_REGADDR(mod, PM_WKST1);
366 switch (uart->num) {
367 case 0:
368 wk_mask = OMAP3430_ST_UART1_MASK;
369 padconf = 0x182;
370 break;
371 case 1:
372 wk_mask = OMAP3430_ST_UART2_MASK;
373 padconf = 0x17a;
374 break;
375 case 2:
376 wk_mask = OMAP3430_ST_UART3_MASK;
377 padconf = 0x19e;
378 break;
Govindraj.R52663ae2010-09-27 20:20:41 +0530379 case 3:
380 wk_mask = OMAP3630_ST_UART4_MASK;
381 padconf = 0x0d2;
382 break;
Kevin Hilman4af40162009-02-04 10:51:40 -0800383 }
384 uart->wk_mask = wk_mask;
385 uart->padconf = padconf;
386 } else if (cpu_is_omap24xx()) {
387 u32 wk_mask = 0;
Kevin Hilmancb74f022010-10-20 23:19:03 +0000388 u32 wk_en = PM_WKEN1, wk_st = PM_WKST1;
Kevin Hilman4af40162009-02-04 10:51:40 -0800389
Kevin Hilman4af40162009-02-04 10:51:40 -0800390 switch (uart->num) {
391 case 0:
392 wk_mask = OMAP24XX_ST_UART1_MASK;
393 break;
394 case 1:
395 wk_mask = OMAP24XX_ST_UART2_MASK;
396 break;
397 case 2:
Kevin Hilmancb74f022010-10-20 23:19:03 +0000398 wk_en = OMAP24XX_PM_WKEN2;
399 wk_st = OMAP24XX_PM_WKST2;
Kevin Hilman4af40162009-02-04 10:51:40 -0800400 wk_mask = OMAP24XX_ST_UART3_MASK;
401 break;
402 }
403 uart->wk_mask = wk_mask;
Kevin Hilmancb74f022010-10-20 23:19:03 +0000404 if (cpu_is_omap2430()) {
405 uart->wk_en = OMAP2430_PRM_REGADDR(CORE_MOD, wk_en);
406 uart->wk_st = OMAP2430_PRM_REGADDR(CORE_MOD, wk_st);
407 } else if (cpu_is_omap2420()) {
408 uart->wk_en = OMAP2420_PRM_REGADDR(CORE_MOD, wk_en);
409 uart->wk_st = OMAP2420_PRM_REGADDR(CORE_MOD, wk_st);
410 }
Kevin Hilman4af40162009-02-04 10:51:40 -0800411 } else {
Nishanth Menonc54bae12010-08-02 13:18:11 +0300412 uart->wk_en = NULL;
413 uart->wk_st = NULL;
Kevin Hilman4af40162009-02-04 10:51:40 -0800414 uart->wk_mask = 0;
415 uart->padconf = 0;
416 }
Kevin Hilman4af40162009-02-04 10:51:40 -0800417}
418
419#else
420static inline void omap_uart_idle_init(struct omap_uart_state *uart) {}
Santosh Shilimkara1b04cc2010-10-11 11:05:18 +0000421static void omap_uart_block_sleep(struct omap_uart_state *uart)
422{
423 /* Needed to enable UART clocks when built without CONFIG_PM */
424 omap_uart_enable_clocks(uart);
425}
Kevin Hilman4af40162009-02-04 10:51:40 -0800426#endif /* CONFIG_PM */
427
Tony Lindgren3e16f922011-02-14 15:40:20 -0800428static int __init omap_serial_early_init(void)
Tony Lindgren1dbae812005-11-10 14:26:51 +0000429{
Kevin Hilman6f251e92010-09-27 20:19:38 +0530430 int i = 0;
Tony Lindgren1dbae812005-11-10 14:26:51 +0000431
Kevin Hilman6f251e92010-09-27 20:19:38 +0530432 do {
433 char oh_name[MAX_UART_HWMOD_NAME_LEN];
434 struct omap_hwmod *oh;
435 struct omap_uart_state *uart;
Thomas Weber21b90342010-02-25 09:40:19 +0000436
Kevin Hilman6f251e92010-09-27 20:19:38 +0530437 snprintf(oh_name, MAX_UART_HWMOD_NAME_LEN,
438 "uart%d", i + 1);
439 oh = omap_hwmod_lookup(oh_name);
440 if (!oh)
441 break;
Tony Lindgren1dbae812005-11-10 14:26:51 +0000442
Kevin Hilman6f251e92010-09-27 20:19:38 +0530443 uart = kzalloc(sizeof(struct omap_uart_state), GFP_KERNEL);
444 if (WARN_ON(!uart))
Tony Lindgren3e16f922011-02-14 15:40:20 -0800445 return -ENODEV;
Tony Lindgren1dbae812005-11-10 14:26:51 +0000446
Kevin Hilman6f251e92010-09-27 20:19:38 +0530447 uart->oh = oh;
448 uart->num = i++;
449 list_add_tail(&uart->node, &uart_list);
450 num_uarts++;
451
Tony Lindgren84f90c92009-10-16 09:53:00 -0700452 /*
Paul Walmsley550c8092011-02-28 11:58:14 -0700453 * NOTE: omap_hwmod_setup*() has not yet been called,
Kevin Hilman6f251e92010-09-27 20:19:38 +0530454 * so no hwmod functions will work yet.
Tony Lindgren84f90c92009-10-16 09:53:00 -0700455 */
Tony Lindgren84f90c92009-10-16 09:53:00 -0700456
Kevin Hilman6f251e92010-09-27 20:19:38 +0530457 /*
458 * During UART early init, device need to be probed
459 * to determine SoC specific init before omap_device
460 * is ready. Therefore, don't allow idle here
461 */
462 uart->oh->flags |= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET;
463 } while (1);
Tony Lindgren3e16f922011-02-14 15:40:20 -0800464
465 return 0;
Paul Walmsleyb3c6df32009-09-03 20:14:02 +0300466}
Tony Lindgren3e16f922011-02-14 15:40:20 -0800467core_initcall(omap_serial_early_init);
Paul Walmsleyb3c6df32009-09-03 20:14:02 +0300468
Mika Westerbergf62349e2009-12-11 16:16:35 -0800469/**
470 * omap_serial_init_port() - initialize single serial port
Tony Lindgren40e44392010-12-22 18:42:35 -0800471 * @bdata: port specific board data pointer
Mika Westerbergf62349e2009-12-11 16:16:35 -0800472 *
Tony Lindgren40e44392010-12-22 18:42:35 -0800473 * This function initialies serial driver for given port only.
Mika Westerbergf62349e2009-12-11 16:16:35 -0800474 * Platforms can call this function instead of omap_serial_init()
475 * if they don't plan to use all available UARTs as serial ports.
476 *
477 * Don't mix calls to omap_serial_init_port() and omap_serial_init(),
478 * use only one of the two.
479 */
Tony Lindgren40e44392010-12-22 18:42:35 -0800480void __init omap_serial_init_port(struct omap_board_data *bdata)
Mika Westerbergf62349e2009-12-11 16:16:35 -0800481{
482 struct omap_uart_state *uart;
Kevin Hilman6f251e92010-09-27 20:19:38 +0530483 struct omap_hwmod *oh;
Kevin Hilman3528c582011-07-21 13:48:45 -0700484 struct platform_device *pdev;
Kevin Hilman6f251e92010-09-27 20:19:38 +0530485 void *pdata = NULL;
486 u32 pdata_size = 0;
487 char *name;
Kevin Hilman6f251e92010-09-27 20:19:38 +0530488 struct omap_uart_port_info omap_up;
Mika Westerbergf62349e2009-12-11 16:16:35 -0800489
Tony Lindgren40e44392010-12-22 18:42:35 -0800490 if (WARN_ON(!bdata))
Sergio Aguirree88d5562010-02-27 14:13:43 -0600491 return;
Tony Lindgren40e44392010-12-22 18:42:35 -0800492 if (WARN_ON(bdata->id < 0))
493 return;
494 if (WARN_ON(bdata->id >= num_uarts))
Mika Westerbergf62349e2009-12-11 16:16:35 -0800495 return;
496
Kevin Hilman6f251e92010-09-27 20:19:38 +0530497 list_for_each_entry(uart, &uart_list, node)
Tony Lindgren40e44392010-12-22 18:42:35 -0800498 if (bdata->id == uart->num)
Kevin Hilman6f251e92010-09-27 20:19:38 +0530499 break;
500
501 oh = uart->oh;
502 uart->dma_enabled = 0;
Kevin Hilman6f251e92010-09-27 20:19:38 +0530503 name = DRIVER_NAME;
504
505 omap_up.dma_enabled = uart->dma_enabled;
506 omap_up.uartclk = OMAP24XX_BASE_BAUD * 16;
507 omap_up.mapbase = oh->slaves[0]->addr->pa_start;
508 omap_up.membase = omap_hwmod_get_mpu_rt_va(oh);
Govindraj.R273558b2011-09-13 14:01:01 +0530509 omap_up.flags = UPF_BOOT_AUTOCONF;
Kevin Hilman6f251e92010-09-27 20:19:38 +0530510
511 pdata = &omap_up;
512 pdata_size = sizeof(struct omap_uart_port_info);
Kevin Hilman6f251e92010-09-27 20:19:38 +0530513
514 if (WARN_ON(!oh))
515 return;
516
Kevin Hilman3528c582011-07-21 13:48:45 -0700517 pdev = omap_device_build(name, uart->num, oh, pdata, pdata_size,
Benoit Coussonf718e2c2011-08-10 15:30:09 +0200518 NULL, 0, false);
Kevin Hilman3528c582011-07-21 13:48:45 -0700519 WARN(IS_ERR(pdev), "Could not build omap_device for %s: %s.\n",
Kevin Hilman6f251e92010-09-27 20:19:38 +0530520 name, oh->name);
521
Kevin Hilman9f8b6942011-08-01 09:33:13 -0700522 omap_device_disable_idle_on_suspend(pdev);
Tony Lindgren40e44392010-12-22 18:42:35 -0800523 oh->mux = omap_hwmod_mux_init(bdata->pads, bdata->pads_cnt);
524
Kevin Hilman6f251e92010-09-27 20:19:38 +0530525 uart->regshift = 2;
526 uart->mapbase = oh->slaves[0]->addr->pa_start;
527 uart->membase = omap_hwmod_get_mpu_rt_va(oh);
Kevin Hilman3528c582011-07-21 13:48:45 -0700528 uart->pdev = pdev;
Kevin Hilman6f251e92010-09-27 20:19:38 +0530529
530 oh->dev_attr = uart;
531
Torben Hohnac751ef2011-01-25 15:07:35 -0800532 console_lock(); /* in case the earlycon is on the UART */
Paul Walmsley0d8e2d02010-11-24 16:49:05 -0700533
Kevin Hilman6f251e92010-09-27 20:19:38 +0530534 /*
535 * Because of early UART probing, UART did not get idled
536 * on init. Now that omap_device is ready, ensure full idle
537 * before doing omap_device_enable().
538 */
539 omap_hwmod_idle(uart->oh);
540
541 omap_device_enable(uart->pdev);
542 omap_uart_idle_init(uart);
543 omap_uart_reset(uart);
544 omap_hwmod_enable_wakeup(uart->oh);
545 omap_device_idle(uart->pdev);
546
Kevin Hilman6f251e92010-09-27 20:19:38 +0530547 omap_uart_block_sleep(uart);
Torben Hohnac751ef2011-01-25 15:07:35 -0800548 console_unlock();
Paul Walmsley0d8e2d02010-11-24 16:49:05 -0700549
Kevin Hilman6f251e92010-09-27 20:19:38 +0530550 if ((cpu_is_omap34xx() && uart->padconf) ||
Govindraj.R273558b2011-09-13 14:01:01 +0530551 (uart->wk_en && uart->wk_mask))
Kevin Hilman3528c582011-07-21 13:48:45 -0700552 device_init_wakeup(&pdev->dev, true);
Deepak K00034502010-08-02 13:18:12 +0300553
554 /* Enable the MDR1 errata for OMAP3 */
Hemant Pedanekara9203602011-12-13 10:46:44 -0800555 if (cpu_is_omap34xx() && !(cpu_is_ti81xx() || cpu_is_am33xx()))
Deepak K00034502010-08-02 13:18:12 +0300556 uart->errata |= UART_ERRATA_i202_MDR1_ACCESS;
Mika Westerbergf62349e2009-12-11 16:16:35 -0800557}
558
559/**
Uwe Kleine-Königb5950762010-11-01 15:38:34 -0400560 * omap_serial_init() - initialize all supported serial ports
Mika Westerbergf62349e2009-12-11 16:16:35 -0800561 *
562 * Initializes all available UARTs as serial ports. Platforms
563 * can call this function when they want to have default behaviour
564 * for serial ports (e.g initialize them all as serial ports).
565 */
Paul Walmsleyb3c6df32009-09-03 20:14:02 +0300566void __init omap_serial_init(void)
567{
Kevin Hilman6f251e92010-09-27 20:19:38 +0530568 struct omap_uart_state *uart;
Tony Lindgren40e44392010-12-22 18:42:35 -0800569 struct omap_board_data bdata;
Paul Walmsleyb3c6df32009-09-03 20:14:02 +0300570
Tony Lindgren40e44392010-12-22 18:42:35 -0800571 list_for_each_entry(uart, &uart_list, node) {
572 bdata.id = uart->num;
573 bdata.flags = 0;
574 bdata.pads = NULL;
575 bdata.pads_cnt = 0;
576 omap_serial_init_port(&bdata);
577
578 }
Tony Lindgren1dbae812005-11-10 14:26:51 +0000579}