]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/arm/mach-omap2/pm-debug.c
0832e05520e403149fe3b2ad11fc241d42ee11b8
[linux-2.6-omap-h63xx.git] / arch / arm / mach-omap2 / pm-debug.c
1 /*
2  * linux/arch/arm/mach-omap2/pm_debug.c
3  *
4  * OMAP Power Management debug routines
5  *
6  * Copyright (C) 2005 Texas Instruments, Inc.
7  * Copyright (C) 2006-2008 Nokia Corporation
8  *
9  * Written by:
10  * Richard Woodruff <r-woodruff2@ti.com>
11  * Tony Lindgren
12  * Juha Yrjola
13  * Amit Kucheria <amit.kucheria@nokia.com>
14  * Igor Stoppa <igor.stoppa@nokia.com>
15  * Jouni Hogander
16  *
17  * Based on pm.c for omap2
18  *
19  * This program is free software; you can redistribute it and/or modify
20  * it under the terms of the GNU General Public License version 2 as
21  * published by the Free Software Foundation.
22  */
23
24 #include <linux/kernel.h>
25 #include <linux/timer.h>
26 #include <linux/clk.h>
27 #include <linux/err.h>
28 #include <linux/io.h>
29
30 #include <mach/clock.h>
31 #include <mach/board.h>
32
33 #include "prm.h"
34 #include "cm.h"
35 #include "pm.h"
36
37 #ifdef CONFIG_PM_DEBUG
38 int omap2_pm_debug = 0;
39
40 static int serial_console_clock_disabled;
41 static int serial_console_uart;
42 static unsigned int serial_console_next_disable;
43
44 static struct clk *console_iclk, *console_fclk;
45
46 static void serial_console_kick(void)
47 {
48         serial_console_next_disable = omap2_read_32k_sync_counter();
49         /* Keep the clocks on for 4 secs */
50         serial_console_next_disable += 4 * 32768;
51 }
52
53 static void serial_wait_tx(void)
54 {
55         static const unsigned long uart_bases[3] = {
56                 0x4806a000, 0x4806c000, 0x4806e000
57         };
58         unsigned long lsr_reg;
59         int looped = 0;
60
61         /* Wait for TX FIFO and THR to get empty */
62         lsr_reg = IO_ADDRESS(uart_bases[serial_console_uart - 1] + (5 << 2));
63         while ((__raw_readb(lsr_reg) & 0x60) != 0x60)
64                 looped = 1;
65         if (looped)
66                 serial_console_kick();
67 }
68
69 u32 omap2_read_32k_sync_counter(void)
70 {
71         return omap_readl(OMAP2_32KSYNCT_BASE + 0x0010);
72 }
73
74 void serial_console_fclk_mask(u32 *f1, u32 *f2)
75 {
76         switch (serial_console_uart)  {
77         case 1:
78                 *f1 &= ~(1 << 21);
79                 break;
80         case 2:
81                 *f1 &= ~(1 << 22);
82                 break;
83         case 3:
84                 *f2 &= ~(1 << 2);
85                 break;
86         }
87 }
88
89 void serial_console_sleep(int enable)
90 {
91         if (console_iclk == NULL || console_fclk == NULL)
92                 return;
93
94         if (enable) {
95                 BUG_ON(serial_console_clock_disabled);
96                 if (console_fclk->usecount == 0)
97                         return;
98                 if ((int) serial_console_next_disable - (int) omap2_read_32k_sync_counter() >= 0)
99                         return;
100                 serial_wait_tx();
101                 clk_disable(console_iclk);
102                 clk_disable(console_fclk);
103                 serial_console_clock_disabled = 1;
104         } else {
105                 int serial_wakeup = 0;
106                 u32 l;
107
108                 switch (serial_console_uart)  {
109                 case 1:
110                         l = prm_read_mod_reg(CORE_MOD, PM_WKST1);
111                         if (l & OMAP24XX_ST_UART1_MASK)
112                                 serial_wakeup = 1;
113                         break;
114                 case 2:
115                         l = prm_read_mod_reg(CORE_MOD, PM_WKST1);
116                         if (l & OMAP24XX_ST_UART2_MASK)
117                                 serial_wakeup = 1;
118                         break;
119                 case 3:
120                         l = prm_read_mod_reg(CORE_MOD, OMAP24XX_PM_WKST2);
121                         if (l & OMAP24XX_ST_UART3_MASK)
122                                 serial_wakeup = 1;
123                         break;
124                 }
125                 if (serial_wakeup)
126                         serial_console_kick();
127                 if (!serial_console_clock_disabled)
128                         return;
129                 clk_enable(console_iclk);
130                 clk_enable(console_fclk);
131                 serial_console_clock_disabled = 0;
132         }
133 }
134
135 void pm_init_serial_console(void)
136 {
137         const struct omap_serial_console_config *conf;
138         char name[16];
139
140         conf = omap_get_config(OMAP_TAG_SERIAL_CONSOLE,
141                                struct omap_serial_console_config);
142         if (conf == NULL)
143                 return;
144         if (conf->console_uart > 3 || conf->console_uart < 1)
145                 return;
146         serial_console_uart = conf->console_uart;
147         sprintf(name, "uart%d_fck", conf->console_uart);
148         console_fclk = clk_get(NULL, name);
149         if (IS_ERR(console_fclk))
150                 console_fclk = NULL;
151         name[6] = 'i';
152         console_iclk = clk_get(NULL, name);
153         if (IS_ERR(console_fclk))
154                 console_iclk = NULL;
155         if (console_fclk == NULL || console_iclk == NULL) {
156                 serial_console_uart = 0;
157                 return;
158         }
159         switch (serial_console_uart) {
160         case 1:
161                 prm_set_mod_reg_bits(OMAP24XX_ST_UART1_MASK, CORE_MOD,
162                                      PM_WKEN1);
163                 break;
164         case 2:
165                 prm_set_mod_reg_bits(OMAP24XX_ST_UART2_MASK, CORE_MOD,
166                                      PM_WKEN1);
167                 break;
168         case 3:
169                 prm_set_mod_reg_bits(OMAP24XX_ST_UART3_MASK, CORE_MOD,
170                                      OMAP24XX_PM_WKEN2);
171                 break;
172         }
173 }
174
175 #define DUMP_PRM_MOD_REG(mod, reg)    \
176         regs[reg_count].name = #mod "." #reg; \
177         regs[reg_count++].val = prm_read_mod_reg(mod, reg)
178 #define DUMP_CM_MOD_REG(mod, reg)     \
179         regs[reg_count].name = #mod "." #reg; \
180         regs[reg_count++].val = cm_read_mod_reg(mod, reg)
181 #define DUMP_PRM_REG(reg) \
182         regs[reg_count].name = #reg; \
183         regs[reg_count++].val = __raw_readl(reg)
184 #define DUMP_CM_REG(reg) \
185         regs[reg_count].name = #reg; \
186         regs[reg_count++].val = __raw_readl(reg)
187 #define DUMP_INTC_REG(reg, off) \
188         regs[reg_count].name = #reg; \
189         regs[reg_count++].val = __raw_readl(IO_ADDRESS(0x480fe000 + (off)))
190
191 void omap2_pm_dump(int mode, int resume, unsigned int us)
192 {
193         struct reg {
194                 const char *name;
195                 u32 val;
196         } regs[32];
197         int reg_count = 0, i;
198         const char *s1 = NULL, *s2 = NULL;
199
200         if (!resume) {
201 #if 0
202                 /* MPU */
203                 DUMP_PRM_MOD_REG(OCP_MOD, OMAP2_PRM_IRQENABLE_MPU_OFFSET);
204                 DUMP_CM_MOD_REG(MPU_MOD, CM_CLKSTCTRL);
205                 DUMP_PRM_MOD_REG(MPU_MOD, PM_PWSTCTRL);
206                 DUMP_PRM_MOD_REG(MPU_MOD, PM_PWSTST);
207                 DUMP_PRM_MOD_REG(MPU_MOD, PM_WKDEP);
208 #endif
209 #if 0
210                 /* INTC */
211                 DUMP_INTC_REG(INTC_MIR0, 0x0084);
212                 DUMP_INTC_REG(INTC_MIR1, 0x00a4);
213                 DUMP_INTC_REG(INTC_MIR2, 0x00c4);
214 #endif
215 #if 0
216                 DUMP_CM_MOD_REG(CORE_MOD, CM_FCLKEN1);
217                 if (cpu_is_omap24xx()) {
218                         DUMP_CM_MOD_REG(CORE_MOD, OMAP24XX_CM_FCLKEN2);
219                         DUMP_PRM_MOD_REG(OMAP24XX_GR_MOD,
220                                         OMAP24XX_PRCM_CLKEMUL_CTRL_OFFSET);
221                         DUMP_PRM_MOD_REG(OMAP24XX_GR_MOD,
222                                         OMAP24XX_PRCM_CLKSRC_CTRL_OFFSET);
223                 }
224                 DUMP_CM_MOD_REG(WKUP_MOD, CM_FCLKEN);
225                 DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN1);
226                 DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN2);
227                 DUMP_CM_MOD_REG(WKUP_MOD, CM_ICLKEN);
228                 DUMP_CM_MOD_REG(PLL_MOD, CM_CLKEN);
229                 DUMP_CM_MOD_REG(PLL_MOD, CM_AUTOIDLE);
230                 DUMP_PRM_MOD_REG(CORE_MOD, PM_PWSTST);
231 #endif
232 #if 0
233                 /* DSP */
234                 if (cpu_is_omap24xx()) {
235                         DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_FCLKEN);
236                         DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_ICLKEN);
237                         DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_IDLEST);
238                         DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_AUTOIDLE);
239                         DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSEL);
240                         DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSTCTRL);
241                         DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, RM_RSTCTRL);
242                         DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, RM_RSTST);
243                         DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, PM_PWSTCTRL);
244                         DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, PM_PWSTST);
245                 }
246 #endif
247         } else {
248                 DUMP_PRM_MOD_REG(CORE_MOD, PM_WKST1);
249                 if (cpu_is_omap24xx())
250                         DUMP_PRM_MOD_REG(CORE_MOD, OMAP24XX_PM_WKST2);
251                 DUMP_PRM_MOD_REG(WKUP_MOD, PM_WKST);
252                 DUMP_PRM_MOD_REG(OCP_MOD, OMAP2_PRM_IRQSTATUS_MPU_OFFSET);
253 #if 1
254                 DUMP_INTC_REG(INTC_PENDING_IRQ0, 0x0098);
255                 DUMP_INTC_REG(INTC_PENDING_IRQ1, 0x00b8);
256                 DUMP_INTC_REG(INTC_PENDING_IRQ2, 0x00d8);
257 #endif
258         }
259
260         switch (mode) {
261         case 0:
262                 s1 = "full";
263                 s2 = "retention";
264                 break;
265         case 1:
266                 s1 = "MPU";
267                 s2 = "retention";
268                 break;
269         case 2:
270                 s1 = "MPU";
271                 s2 = "idle";
272                 break;
273         }
274
275         if (!resume)
276 #if defined(CONFIG_NO_IDLE_HZ) || defined(CONFIG_NO_HZ)
277                 printk("--- Going to %s %s (next timer after %u ms)\n", s1, s2,
278                        jiffies_to_msecs(get_next_timer_interrupt(jiffies) -
279                                         jiffies));
280 #else
281                 printk("--- Going to %s %s\n", s1, s2);
282 #endif
283         else
284                 printk("--- Woke up (slept for %u.%03u ms)\n",
285                         us / 1000, us % 1000);
286
287         for (i = 0; i < reg_count; i++)
288                 printk("%-20s: 0x%08x\n", regs[i].name, regs[i].val);
289 }
290
291 #endif