aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/serial.c
diff options
context:
space:
mode:
authorKevin Hilman <khilman@deeprootsystems.com>2009-02-04 13:51:40 -0500
committerKevin Hilman <khilman@deeprootsystems.com>2009-05-28 13:59:06 -0400
commit4af4016c53f52b26461b8030211f8427a58fa5ed (patch)
tree984ffcb57bcc8158332c10ef799203bd905d7147 /arch/arm/mach-omap2/serial.c
parent5a1a5abdb2e9a301f1ac62feb37228f3f4d3117c (diff)
OMAP3: PM: UART: disable clocks when idle and off-mode support
This patch allows the UART clocks to be disabled when the OMAP UARTs are inactive, thus permitting the chip to hit retention in idle. After the expiration of an activity timer, each UART is allowed to disable its clocks so the system can enter retention. The activity timer is (re)activated on any UART interrupt, UART wake event or any IO pad wakeup. The actual disable of the UART clocks is done in the 'prepare_idle' hook called from the OMAP idle loop. While the activity timer is active, the smart-idle mode of the UART is also disabled. This is due to a "feature" of the UART module that after a UART wakeup, the smart-idle mode may be entered before the UART has communicated the interrupt, or upon TX, an idle mode may be entered before the TX FIFOs are emptied. Upon suspend, the 'prepare_suspend' hook cancels any pending activity timers and allows the clocks to be disabled immediately. In addition, upon disabling clocks the UART state is saved in case of an off-mode transition while clocks are off. Special thanks to Tero Kristo for the initial ideas and first versions of UART idle support, and to Jouni Hogander for extra testing and bugfixes. Tested on OMAP3 (Beagle, RX51, SDP, EVM) and OMAP2 (n810) Cc: Tero Kristo <tero.kristo@nokia.com> Cc: Jouni Hogander <jouni.hogander@nokia.com> Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
Diffstat (limited to 'arch/arm/mach-omap2/serial.c')
-rw-r--r--arch/arm/mach-omap2/serial.c390
1 files changed, 366 insertions, 24 deletions
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 4dcf39c285b9..53cbe0620286 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -6,6 +6,8 @@
6 * Copyright (C) 2005-2008 Nokia Corporation 6 * Copyright (C) 2005-2008 Nokia Corporation
7 * Author: Paul Mundt <paul.mundt@nokia.com> 7 * Author: Paul Mundt <paul.mundt@nokia.com>
8 * 8 *
9 * Major rework for PM support by Kevin Hilman
10 *
9 * Based off of arch/arm/mach-omap/omap1/serial.c 11 * Based off of arch/arm/mach-omap/omap1/serial.c
10 * 12 *
11 * This file is subject to the terms and conditions of the GNU General Public 13 * This file is subject to the terms and conditions of the GNU General Public
@@ -21,9 +23,50 @@
21 23
22#include <mach/common.h> 24#include <mach/common.h>
23#include <mach/board.h> 25#include <mach/board.h>
26#include <mach/clock.h>
27#include <mach/control.h>
28
29#include "prm.h"
30#include "pm.h"
31#include "prm-regbits-34xx.h"
32
33#define UART_OMAP_WER 0x17 /* Wake-up enable register */
34
35#define DEFAULT_TIMEOUT (2 * HZ)
36
37struct omap_uart_state {
38 int num;
39 int can_sleep;
40 struct timer_list timer;
41 u32 timeout;
42
43 void __iomem *wk_st;
44 void __iomem *wk_en;
45 u32 wk_mask;
46 u32 padconf;
47
48 struct clk *ick;
49 struct clk *fck;
50 int clocked;
51
52 struct plat_serial8250_port *p;
53 struct list_head node;
24 54
25static struct clk *uart_ick[OMAP_MAX_NR_PORTS]; 55#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
26static struct clk *uart_fck[OMAP_MAX_NR_PORTS]; 56 int context_valid;
57
58 /* Registers to be saved/restored for OFF-mode */
59 u16 dll;
60 u16 dlh;
61 u16 ier;
62 u16 sysc;
63 u16 scr;
64 u16 wer;
65#endif
66};
67
68static struct omap_uart_state omap_uart[OMAP_MAX_NR_PORTS];
69static LIST_HEAD(uart_list);
27 70
28static struct plat_serial8250_port serial_platform_data[] = { 71static struct plat_serial8250_port serial_platform_data[] = {
29 { 72 {
@@ -74,30 +117,320 @@ static inline void serial_write_reg(struct plat_serial8250_port *p, int offset,
74 * properly. Note that the TX watermark initialization may not be needed 117 * properly. Note that the TX watermark initialization may not be needed
75 * once the 8250.c watermark handling code is merged. 118 * once the 8250.c watermark handling code is merged.
76 */ 119 */
77static inline void __init omap_serial_reset(struct plat_serial8250_port *p) 120static inline void __init omap_uart_reset(struct omap_uart_state *uart)
78{ 121{
122 struct plat_serial8250_port *p = uart->p;
123
79 serial_write_reg(p, UART_OMAP_MDR1, 0x07); 124 serial_write_reg(p, UART_OMAP_MDR1, 0x07);
80 serial_write_reg(p, UART_OMAP_SCR, 0x08); 125 serial_write_reg(p, UART_OMAP_SCR, 0x08);
81 serial_write_reg(p, UART_OMAP_MDR1, 0x00); 126 serial_write_reg(p, UART_OMAP_MDR1, 0x00);
82 serial_write_reg(p, UART_OMAP_SYSC, (0x02 << 3) | (1 << 2) | (1 << 0)); 127 serial_write_reg(p, UART_OMAP_SYSC, (0x02 << 3) | (1 << 2) | (1 << 0));
83} 128}
84 129
85void omap_serial_enable_clocks(int enable) 130#if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3)
131
132static int enable_off_mode; /* to be removed by full off-mode patches */
133
134static void omap_uart_save_context(struct omap_uart_state *uart)
86{ 135{
87 int i; 136 u16 lcr = 0;
88 for (i = 0; i < OMAP_MAX_NR_PORTS; i++) { 137 struct plat_serial8250_port *p = uart->p;
89 if (uart_ick[i] && uart_fck[i]) { 138
90 if (enable) { 139 if (!enable_off_mode)
91 clk_enable(uart_ick[i]); 140 return;
92 clk_enable(uart_fck[i]); 141
93 } else { 142 lcr = serial_read_reg(p, UART_LCR);
94 clk_disable(uart_ick[i]); 143 serial_write_reg(p, UART_LCR, 0xBF);
95 clk_disable(uart_fck[i]); 144 uart->dll = serial_read_reg(p, UART_DLL);
145 uart->dlh = serial_read_reg(p, UART_DLM);
146 serial_write_reg(p, UART_LCR, lcr);
147 uart->ier = serial_read_reg(p, UART_IER);
148 uart->sysc = serial_read_reg(p, UART_OMAP_SYSC);
149 uart->scr = serial_read_reg(p, UART_OMAP_SCR);
150 uart->wer = serial_read_reg(p, UART_OMAP_WER);
151
152 uart->context_valid = 1;
153}
154
155static void omap_uart_restore_context(struct omap_uart_state *uart)
156{
157 u16 efr = 0;
158 struct plat_serial8250_port *p = uart->p;
159
160 if (!enable_off_mode)
161 return;
162
163 if (!uart->context_valid)
164 return;
165
166 uart->context_valid = 0;
167
168 serial_write_reg(p, UART_OMAP_MDR1, 0x7);
169 serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
170 efr = serial_read_reg(p, UART_EFR);
171 serial_write_reg(p, UART_EFR, UART_EFR_ECB);
172 serial_write_reg(p, UART_LCR, 0x0); /* Operational mode */
173 serial_write_reg(p, UART_IER, 0x0);
174 serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
175 serial_write_reg(p, UART_DLL, uart->dll);
176 serial_write_reg(p, UART_DLM, uart->dlh);
177 serial_write_reg(p, UART_LCR, 0x0); /* Operational mode */
178 serial_write_reg(p, UART_IER, uart->ier);
179 serial_write_reg(p, UART_FCR, 0xA1);
180 serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
181 serial_write_reg(p, UART_EFR, efr);
182 serial_write_reg(p, UART_LCR, UART_LCR_WLEN8);
183 serial_write_reg(p, UART_OMAP_SCR, uart->scr);
184 serial_write_reg(p, UART_OMAP_WER, uart->wer);
185 serial_write_reg(p, UART_OMAP_SYSC, uart->sysc);
186 serial_write_reg(p, UART_OMAP_MDR1, 0x00); /* UART 16x mode */
187}
188#else
189static inline void omap_uart_save_context(struct omap_uart_state *uart) {}
190static inline void omap_uart_restore_context(struct omap_uart_state *uart) {}
191#endif /* CONFIG_PM && CONFIG_ARCH_OMAP3 */
192
193static inline void omap_uart_enable_clocks(struct omap_uart_state *uart)
194{
195 if (uart->clocked)
196 return;
197
198 clk_enable(uart->ick);
199 clk_enable(uart->fck);
200 uart->clocked = 1;
201 omap_uart_restore_context(uart);
202}
203
204#ifdef CONFIG_PM
205
206static inline void omap_uart_disable_clocks(struct omap_uart_state *uart)
207{
208 if (!uart->clocked)
209 return;
210
211 omap_uart_save_context(uart);
212 uart->clocked = 0;
213 clk_disable(uart->ick);
214 clk_disable(uart->fck);
215}
216
217static void omap_uart_smart_idle_enable(struct omap_uart_state *uart,
218 int enable)
219{
220 struct plat_serial8250_port *p = uart->p;
221 u16 sysc;
222
223 sysc = serial_read_reg(p, UART_OMAP_SYSC) & 0x7;
224 if (enable)
225 sysc |= 0x2 << 3;
226 else
227 sysc |= 0x1 << 3;
228
229 serial_write_reg(p, UART_OMAP_SYSC, sysc);
230}
231
232static void omap_uart_block_sleep(struct omap_uart_state *uart)
233{
234 omap_uart_enable_clocks(uart);
235
236 omap_uart_smart_idle_enable(uart, 0);
237 uart->can_sleep = 0;
238 mod_timer(&uart->timer, jiffies + uart->timeout);
239}
240
241static void omap_uart_allow_sleep(struct omap_uart_state *uart)
242{
243 if (!uart->clocked)
244 return;
245
246 omap_uart_smart_idle_enable(uart, 1);
247 uart->can_sleep = 1;
248 del_timer(&uart->timer);
249}
250
251static void omap_uart_idle_timer(unsigned long data)
252{
253 struct omap_uart_state *uart = (struct omap_uart_state *)data;
254
255 omap_uart_allow_sleep(uart);
256}
257
258void omap_uart_prepare_idle(int num)
259{
260 struct omap_uart_state *uart;
261
262 list_for_each_entry(uart, &uart_list, node) {
263 if (num == uart->num && uart->can_sleep) {
264 omap_uart_disable_clocks(uart);
265 return;
266 }
267 }
268}
269
270void omap_uart_resume_idle(int num)
271{
272 struct omap_uart_state *uart;
273
274 list_for_each_entry(uart, &uart_list, node) {
275 if (num == uart->num) {
276 omap_uart_enable_clocks(uart);
277
278 /* Check for IO pad wakeup */
279 if (cpu_is_omap34xx() && uart->padconf) {
280 u16 p = omap_ctrl_readw(uart->padconf);
281
282 if (p & OMAP3_PADCONF_WAKEUPEVENT0)
283 omap_uart_block_sleep(uart);
96 } 284 }
285
286 /* Check for normal UART wakeup */
287 if (__raw_readl(uart->wk_st) & uart->wk_mask)
288 omap_uart_block_sleep(uart);
289
290 return;
291 }
292 }
293}
294
295void omap_uart_prepare_suspend(void)
296{
297 struct omap_uart_state *uart;
298
299 list_for_each_entry(uart, &uart_list, node) {
300 omap_uart_allow_sleep(uart);
301 }
302}
303
304int omap_uart_can_sleep(void)
305{
306 struct omap_uart_state *uart;
307 int can_sleep = 1;
308
309 list_for_each_entry(uart, &uart_list, node) {
310 if (!uart->clocked)
311 continue;
312
313 if (!uart->can_sleep) {
314 can_sleep = 0;
315 continue;
97 } 316 }
317
318 /* This UART can now safely sleep. */
319 omap_uart_allow_sleep(uart);
98 } 320 }
321
322 return can_sleep;
99} 323}
100 324
325/**
326 * omap_uart_interrupt()
327 *
328 * This handler is used only to detect that *any* UART interrupt has
329 * occurred. It does _nothing_ to handle the interrupt. Rather,
330 * any UART interrupt will trigger the inactivity timer so the
331 * UART will not idle or sleep for its timeout period.
332 *
333 **/
334static irqreturn_t omap_uart_interrupt(int irq, void *dev_id)
335{
336 struct omap_uart_state *uart = dev_id;
337
338 omap_uart_block_sleep(uart);
339
340 return IRQ_NONE;
341}
342
343static void omap_uart_idle_init(struct omap_uart_state *uart)
344{
345 u32 v;
346 struct plat_serial8250_port *p = uart->p;
347 int ret;
348
349 uart->can_sleep = 0;
350 uart->timeout = DEFAULT_TIMEOUT;
351 setup_timer(&uart->timer, omap_uart_idle_timer,
352 (unsigned long) uart);
353 mod_timer(&uart->timer, jiffies + uart->timeout);
354 omap_uart_smart_idle_enable(uart, 0);
355
356 if (cpu_is_omap34xx()) {
357 u32 mod = (uart->num == 2) ? OMAP3430_PER_MOD : CORE_MOD;
358 u32 wk_mask = 0;
359 u32 padconf = 0;
360
361 uart->wk_en = OMAP34XX_PRM_REGADDR(mod, PM_WKEN1);
362 uart->wk_st = OMAP34XX_PRM_REGADDR(mod, PM_WKST1);
363 switch (uart->num) {
364 case 0:
365 wk_mask = OMAP3430_ST_UART1_MASK;
366 padconf = 0x182;
367 break;
368 case 1:
369 wk_mask = OMAP3430_ST_UART2_MASK;
370 padconf = 0x17a;
371 break;
372 case 2:
373 wk_mask = OMAP3430_ST_UART3_MASK;
374 padconf = 0x19e;
375 break;
376 }
377 uart->wk_mask = wk_mask;
378 uart->padconf = padconf;
379 } else if (cpu_is_omap24xx()) {
380 u32 wk_mask = 0;
381
382 if (cpu_is_omap2430()) {
383 uart->wk_en = OMAP2430_PRM_REGADDR(CORE_MOD, PM_WKEN1);
384 uart->wk_st = OMAP2430_PRM_REGADDR(CORE_MOD, PM_WKST1);
385 } else if (cpu_is_omap2420()) {
386 uart->wk_en = OMAP2420_PRM_REGADDR(CORE_MOD, PM_WKEN1);
387 uart->wk_st = OMAP2420_PRM_REGADDR(CORE_MOD, PM_WKST1);
388 }
389 switch (uart->num) {
390 case 0:
391 wk_mask = OMAP24XX_ST_UART1_MASK;
392 break;
393 case 1:
394 wk_mask = OMAP24XX_ST_UART2_MASK;
395 break;
396 case 2:
397 wk_mask = OMAP24XX_ST_UART3_MASK;
398 break;
399 }
400 uart->wk_mask = wk_mask;
401 } else {
402 uart->wk_en = 0;
403 uart->wk_st = 0;
404 uart->wk_mask = 0;
405 uart->padconf = 0;
406 }
407
408 /* Set wake-enable bit */
409 if (uart->wk_en && uart->wk_mask) {
410 v = __raw_readl(uart->wk_en);
411 v |= uart->wk_mask;
412 __raw_writel(v, uart->wk_en);
413 }
414
415 /* Ensure IOPAD wake-enables are set */
416 if (cpu_is_omap34xx() && uart->padconf) {
417 u16 v;
418
419 v = omap_ctrl_readw(uart->padconf);
420 v |= OMAP3_PADCONF_WAKEUPENABLE0;
421 omap_ctrl_writew(v, uart->padconf);
422 }
423
424 p->flags |= UPF_SHARE_IRQ;
425 ret = request_irq(p->irq, omap_uart_interrupt, IRQF_SHARED,
426 "serial idle", (void *)uart);
427 WARN_ON(ret);
428}
429
430#else
431static inline void omap_uart_idle_init(struct omap_uart_state *uart) {}
432#endif /* CONFIG_PM */
433
101void __init omap_serial_init(void) 434void __init omap_serial_init(void)
102{ 435{
103 int i; 436 int i;
@@ -117,6 +450,7 @@ void __init omap_serial_init(void)
117 450
118 for (i = 0; i < OMAP_MAX_NR_PORTS; i++) { 451 for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
119 struct plat_serial8250_port *p = serial_platform_data + i; 452 struct plat_serial8250_port *p = serial_platform_data + i;
453 struct omap_uart_state *uart = &omap_uart[i];
120 454
121 if (!(info->enabled_uarts & (1 << i))) { 455 if (!(info->enabled_uarts & (1 << i))) {
122 p->membase = NULL; 456 p->membase = NULL;
@@ -125,22 +459,30 @@ void __init omap_serial_init(void)
125 } 459 }
126 460
127 sprintf(name, "uart%d_ick", i+1); 461 sprintf(name, "uart%d_ick", i+1);
128 uart_ick[i] = clk_get(NULL, name); 462 uart->ick = clk_get(NULL, name);
129 if (IS_ERR(uart_ick[i])) { 463 if (IS_ERR(uart->ick)) {
130 printk(KERN_ERR "Could not get uart%d_ick\n", i+1); 464 printk(KERN_ERR "Could not get uart%d_ick\n", i+1);
131 uart_ick[i] = NULL; 465 uart->ick = NULL;
132 } else 466 }
133 clk_enable(uart_ick[i]);
134 467
135 sprintf(name, "uart%d_fck", i+1); 468 sprintf(name, "uart%d_fck", i+1);
136 uart_fck[i] = clk_get(NULL, name); 469 uart->fck = clk_get(NULL, name);
137 if (IS_ERR(uart_fck[i])) { 470 if (IS_ERR(uart->fck)) {
138 printk(KERN_ERR "Could not get uart%d_fck\n", i+1); 471 printk(KERN_ERR "Could not get uart%d_fck\n", i+1);
139 uart_fck[i] = NULL; 472 uart->fck = NULL;
140 } else 473 }
141 clk_enable(uart_fck[i]); 474
475 if (!uart->ick || !uart->fck)
476 continue;
477
478 uart->num = i;
479 p->private_data = uart;
480 uart->p = p;
481 list_add(&uart->node, &uart_list);
142 482
143 omap_serial_reset(p); 483 omap_uart_enable_clocks(uart);
484 omap_uart_reset(uart);
485 omap_uart_idle_init(uart);
144 } 486 }
145} 487}
146 488