2 * arch/arm/mach-tegra/suspend-t2.c
4 * BootROM LP0 scratch register preservation for Tegra 2
6 * Copyright (c) 2009-2010, NVIDIA Corporation.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 #include <linux/kernel.h>
24 #include <linux/init.h>
28 #include <mach/gpio.h>
29 #include <mach/iomap.h>
30 #include <mach/irqs.h>
31 #include <mach/suspend.h>
33 #include "gpio-names.h"
35 #define PMC_SCRATCH3 0x5c
36 #define PMC_SCRATCH5 0x64
37 #define PMC_SCRATCH6 0x68
38 #define PMC_SCRATCH7 0x6c
39 #define PMC_SCRATCH8 0x70
40 #define PMC_SCRATCH9 0x74
41 #define PMC_SCRATCH10 0x78
42 #define PMC_SCRATCH11 0x7c
43 #define PMC_SCRATCH12 0x80
44 #define PMC_SCRATCH13 0x84
45 #define PMC_SCRATCH14 0x88
46 #define PMC_SCRATCH15 0x8c
47 #define PMC_SCRATCH16 0x90
48 #define PMC_SCRATCH17 0x94
49 #define PMC_SCRATCH18 0x98
50 #define PMC_SCRATCH19 0x9c
51 #define PMC_SCRATCH20 0xa0
52 #define PMC_SCRATCH21 0xa4
53 #define PMC_SCRATCH22 0xa8
54 #define PMC_SCRATCH23 0xac
55 #define PMC_SCRATCH25 0x100
56 #define PMC_SCRATCH35 0x128
57 #define PMC_SCRATCH36 0x12c
58 #define PMC_SCRATCH40 0x13c
60 struct pmc_scratch_field {
67 #define field(module, offs, field, dst) \
69 .addr = IO_ADDRESS(TEGRA_##module##_BASE) + offs, \
70 .mask = 0xfffffffful >> (31 - ((1?field) - (0?field))), \
71 .shift_src = 0?field, \
75 static const struct pmc_scratch_field pllx[] __initdata = {
76 field(CLK_RESET, 0xe0, 22:20, 17:15), /* PLLX_DIVP */
77 field(CLK_RESET, 0xe0, 17:8, 14:5), /* PLLX_DIVN */
78 field(CLK_RESET, 0xe0, 4:0, 4:0), /* PLLX_DIVM */
79 field(CLK_RESET, 0xe4, 11:8, 25:22), /* PLLX_CPCON */
80 field(CLK_RESET, 0xe4, 7:4, 21:18), /* PLLX_LFCON */
81 field(APB_MISC, 0x8e4, 27:24, 30:27), /* XM2CFGC_VREF_DQ */
82 field(APB_MISC, 0x8c8, 3:3, 26:26), /* XM2CFGC_SCHMT_EN */
83 field(APB_MISC, 0x8d0, 2:2, 31:31), /* XM2CLKCFG_PREEMP_EN */
86 static const struct pmc_scratch_field emc_0[] __initdata = {
87 field(EMC, 0x3c, 4:0, 31:27), /* R2W */
88 field(EMC, 0x34, 5:0, 20:15), /* RAS */
89 field(EMC, 0x2c, 5:0, 5:0), /* RC */
90 field(EMC, 0x30, 8:0, 14:6), /* RFC */
91 field(EMC, 0x38, 5:0, 26:21), /* RP */
94 static const struct pmc_scratch_field emc_1[] __initdata = {
95 field(EMC, 0x44, 4:0, 9:5), /* R2P */
96 field(EMC, 0x4c, 5:0, 20:15), /* RD_RCD */
97 field(EMC, 0x54, 3:0, 30:27), /* RRD */
98 field(EMC, 0x48, 4:0, 14:10), /* W2P */
99 field(EMC, 0x40, 4:0, 4:0), /* W2R */
100 field(EMC, 0x50, 5:0, 26:21), /* WR_RCD */
103 static const struct pmc_scratch_field emc_2[] __initdata = {
104 field(EMC, 0x2b8, 2:2, 31:31), /* CLKCHANGE_SR_ENABLE */
105 field(EMC, 0x2b8, 10:10, 30:30), /* USE_ADDR_CLK */
106 field(EMC, 0x80, 4:0, 29:25), /* PCHG2PDEN */
107 field(EMC, 0x64, 3:0, 15:12), /* QRST */
108 field(EMC, 0x68, 3:0, 19:16), /* QSAFE */
109 field(EMC, 0x60, 3:0, 11:8), /* QUSE */
110 field(EMC, 0x6c, 4:0, 24:20), /* RDV */
111 field(EMC, 0x58, 3:0, 3:0), /* REXT */
112 field(EMC, 0x5c, 3:0, 7:4), /* WDV */
115 static const struct pmc_scratch_field emc_3[] __initdata = {
116 field(EMC, 0x74, 3:0, 19:16), /* BURST_REFRESH_NUM */
117 field(EMC, 0x7c, 3:0, 27:24), /* PDEX2RD */
118 field(EMC, 0x78, 3:0, 23:20), /* PDEX2WR */
119 field(EMC, 0x70, 4:0, 4:0), /* REFRESH_LO */
120 field(EMC, 0x70, 15:5, 15:5), /* REFRESH */
121 field(EMC, 0xa0, 3:0, 31:28), /* TCLKSTABLE */
124 static const struct pmc_scratch_field emc_4[] __initdata = {
125 field(EMC, 0x84, 4:0, 4:0), /* ACT2PDEN */
126 field(EMC, 0x88, 4:0, 9:5), /* AR2PDEN */
127 field(EMC, 0x8c, 5:0, 15:10), /* RW2PDEN */
128 field(EMC, 0x94, 3:0, 31:28), /* TCKE */
129 field(EMC, 0x90, 11:0, 27:16), /* TXSR */
132 static const struct pmc_scratch_field emc_5[] __initdata = {
133 field(EMC, 0x8, 10:10, 30:30), /* AP_REQ_BUSY_CTRL */
134 field(EMC, 0x8, 24:24, 31:31), /* CFG_PRIORITY */
135 field(EMC, 0x8, 2:2, 26:26), /* FORCE_UPDATE */
136 field(EMC, 0x8, 4:4, 27:27), /* MRS_WAIT */
137 field(EMC, 0x8, 5:5, 28:28), /* PERIODIC_QRST */
138 field(EMC, 0x8, 9:9, 29:29), /* READ_DQM_CTRL */
139 field(EMC, 0x8, 0:0, 24:24), /* READ_MUX */
140 field(EMC, 0x8, 1:1, 25:25), /* WRITE_MUX */
141 field(EMC, 0xa4, 3:0, 9:6), /* TCLKSTOP */
142 field(EMC, 0xa8, 13:0, 23:10), /* TREFBW */
143 field(EMC, 0x9c, 5:0, 5:0), /* TRPAB */
146 static const struct pmc_scratch_field emc_6[] __initdata = {
147 field(EMC, 0xfc, 1:0, 1:0), /* DQSIB_DLY_MSB_BYTE_0 */
148 field(EMC, 0xfc, 9:8, 3:2), /* DQSIB_DLY_MSB_BYTE_1 */
149 field(EMC, 0xfc, 17:16, 5:4), /* DQSIB_DLY_MSB_BYTE_2 */
150 field(EMC, 0xfc, 25:24, 7:6), /* DQSIB_DLY_MSB_BYTE_3 */
151 field(EMC, 0x110, 1:0, 9:8), /* QUSE_DLY_MSB_BYTE_0 */
152 field(EMC, 0x110, 9:8, 11:10), /* QUSE_DLY_MSB_BYTE_1 */
153 field(EMC, 0x110, 17:16, 13:12), /* QUSE_DLY_MSB_BYTE_2 */
154 field(EMC, 0x110, 25:24, 15:14), /* QUSE_DLY_MSB_BYTE_3 */
155 field(EMC, 0xac, 3:0, 25:22), /* QUSE_EXTRA */
156 field(EMC, 0x98, 5:0, 21:16), /* TFAW */
157 field(APB_MISC, 0x8e4, 5:5, 30:30), /* XM2CFGC_VREF_DQ_EN */
158 field(APB_MISC, 0x8e4, 19:16, 29:26), /* XM2CFGC_VREF_DQS */
161 static const struct pmc_scratch_field emc_dqsib_dly[] __initdata = {
162 field(EMC, 0xf8, 31:0, 31:0), /* DQSIB_DLY_BYTE_0 - DQSIB_DLY_BYTE_3*/
165 static const struct pmc_scratch_field emc_quse_dly[] __initdata = {
166 field(EMC, 0x10c, 31:0, 31:0), /* QUSE_DLY_BYTE_0 - QUSE_DLY_BYTE_3*/
169 static const struct pmc_scratch_field emc_clktrim[] __initdata = {
170 field(EMC, 0x2d0, 29:0, 29:0), /* DATA0_CLKTRIM - DATA3_CLKTRIM +
171 * MCLK_ADDR_CLKTRIM */
174 static const struct pmc_scratch_field emc_autocal_fbio[] __initdata = {
175 field(EMC, 0x2a4, 29:29, 29:29), /* AUTO_CAL_ENABLE */
176 field(EMC, 0x2a4, 30:30, 30:30), /* AUTO_CAL_OVERRIDE */
177 field(EMC, 0x2a4, 12:8, 18:14), /* AUTO_CAL_PD_OFFSET */
178 field(EMC, 0x2a4, 4:0, 13:9), /* AUTO_CAL_PU_OFFSET */
179 field(EMC, 0x2a4, 25:16, 28:19), /* AUTO_CAL_STEP */
180 field(EMC, 0xf4, 16:16, 0:0), /* CFG_DEN_EARLY */
181 field(EMC, 0x104, 8:8, 8:8), /* CTT_TERMINATION */
182 field(EMC, 0x104, 7:7, 7:7), /* DIFFERENTIAL_DQS */
183 field(EMC, 0x104, 9:9, 31:31), /* DQS_PULLD */
184 field(EMC, 0x104, 1:0, 5:4), /* DRAM_TYPE */
185 field(EMC, 0x104, 4:4, 6:6), /* DRAM_WIDTH */
186 field(EMC, 0x114, 2:0, 3:1), /* CFG_QUSE_LATE */
189 static const struct pmc_scratch_field emc_autocal_interval[] __initdata = {
190 field(EMC, 0x2a8, 27:0, 27:0), /* AUTOCAL_INTERVAL */
191 field(EMC, 0x2b8, 1:1, 29:29), /* CLKCHANGE_PD_ENABLE */
192 field(EMC, 0x2b8, 0:0, 28:28), /* CLKCHANGE_REQ_ENABLE */
193 field(EMC, 0x2b8, 9:8, 31:30), /* PIN_CONFIG */
196 static const struct pmc_scratch_field emc_cfgs[] __initdata = {
197 field(EMC, 0x10, 9:8, 4:3), /* EMEM_BANKWIDTH */
198 field(EMC, 0x10, 2:0, 2:0), /* EMEM_COLWIDTH */
199 field(EMC, 0x10, 19:16, 8:5), /* EMEM_DEVSIZE */
200 field(EMC, 0x10, 25:24, 10:9), /* EMEM_NUMDEV */
201 field(EMC, 0xc, 24:24, 21:21), /* AUTO_PRE_RD */
202 field(EMC, 0xc, 25:25, 22:22), /* AUTO_PRE_WR */
203 field(EMC, 0xc, 16:16, 20:20), /* CLEAR_AP_PREV_SPREQ */
204 field(EMC, 0xc, 29:29, 23:23), /* DRAM_ACPD */
205 field(EMC, 0xc, 30:30, 24:24), /* DRAM_CLKSTOP_PDSR_ONLY */
206 field(EMC, 0xc, 31:31, 25:25), /* DRAM_CLKSTOP */
207 field(EMC, 0xc, 15:8, 19:12), /* PRE_IDLE_CYCLES */
208 field(EMC, 0xc, 0:0, 11:11), /* PRE_IDLE_EN */
209 field(EMC, 0x2bc, 29:28, 29:28), /* CFG_DLL_LOCK_LIMIT */
210 field(EMC, 0x2bc, 7:6, 31:30), /* CFG_DLL_MODE */
211 field(MC, 0x10c, 0:0, 26:26), /* LL_CTRL */
212 field(MC, 0x10c, 1:1, 27:27), /* LL_SEND_BOTH */
215 static const struct pmc_scratch_field emc_adr_cfg1[] __initdata = {
216 field(EMC, 0x14, 9:8, 9:8), /* EMEM1_BANKWIDTH */
217 field(EMC, 0x14, 2:0, 7:5), /* EMEM1_COLWIDTH */
218 field(EMC, 0x14, 19:16, 13:10), /* EMEM1_DEVSIZE */
219 field(EMC, 0x2dc, 28:24, 4:0), /* TERM_DRVUP */
220 field(APB_MISC, 0x8d4, 3:0, 17:14), /* XM2COMP_VREF_SEL */
221 field(APB_MISC, 0x8d8, 18:16, 23:21), /* XM2VTTGEN_CAL_DRVDN */
222 field(APB_MISC, 0x8d8, 26:24, 20:18), /* XM2VTTGEN_CAL_DRVUP */
223 field(APB_MISC, 0x8d8, 1:1, 30:30), /* XM2VTTGEN_SHORT_PWRGND */
224 field(APB_MISC, 0x8d8, 0:0, 31:31), /* XM2VTTGEN_SHORT */
225 field(APB_MISC, 0x8d8, 14:12, 26:24), /* XM2VTTGEN_VAUXP_LEVEL */
226 field(APB_MISC, 0x8d8, 10:8, 29:27), /* XM2VTTGEN_VCLAMP_LEVEL */
229 static const struct pmc_scratch_field emc_digital_dll[] __initdata = {
230 field(EMC, 0x2bc, 1:1, 23:23), /* DLI_TRIMMER_EN */
231 field(EMC, 0x2bc, 0:0, 22:22), /* DLL_EN */
232 field(EMC, 0x2bc, 5:5, 27:27), /* DLL_LOWSPEED */
233 field(EMC, 0x2bc, 2:2, 24:24), /* DLL_OVERRIDE_EN */
234 field(EMC, 0x2bc, 11:8, 31:28), /* DLL_UDSET */
235 field(EMC, 0x2bc, 4:4, 26:26), /* PERBYTE_TRIMMER_OVERRIDE */
236 field(EMC, 0x2bc, 3:3, 25:25), /* USE_SINGLE_DLL */
237 field(MC, 0xc, 21:0, 21:0), /* EMEM_SIZE_KB */
240 static const struct pmc_scratch_field emc_dqs_clktrim[] __initdata = {
241 field(EMC, 0x2d4, 29:0, 29:0), /* DQS0_CLKTRIM - DQS3 + MCLK*/
242 field(APB_MISC, 0x8e4, 3:3, 31:31), /* XM2CFGC_CTT_HIZ_EN */
243 field(APB_MISC, 0x8e4, 4:4, 30:30), /* XM2CFGC_VREF_DQS_EN */
246 static const struct pmc_scratch_field emc_dq_clktrim[] __initdata = {
247 field(EMC, 0x2d8, 29:0, 29:0),
248 field(APB_MISC, 0x8e4, 2:2, 30:30), /* XM2CFGC_PREEMP_EN */
249 field(APB_MISC, 0x8e4, 0:0, 31:31), /* XM2CFGC_RX_FT_REC_EN */
252 static const struct pmc_scratch_field emc_dll_xform_dqs[] __initdata = {
253 field(EMC, 0x2bc, 25:16, 29:20), /* CFG_DLL_OVERRIDE_VAL */
254 field(EMC, 0x2c0, 4:0, 4:0), /* DQS_MULT */
255 field(EMC, 0x2c0, 22:8, 19:5), /* DQS_OFFS */
256 field(MC, 0x10c, 31:31, 30:30), /* LL_DRAM_INTERLEAVE */
259 static const struct pmc_scratch_field emc_odt_rw[] __initdata = {
260 field(EMC, 0x2c4, 4:0, 4:0), /* QUSE_MULT */
261 field(EMC, 0x2c4, 22:8, 19:5), /* QUSE_OFF */
262 field(EMC, 0xb4, 31:31, 29:29), /* DISABLE_ODT_DURING_READ */
263 field(EMC, 0xb4, 30:30, 28:28), /* B4_READ */
264 field(EMC, 0xb4, 2:0, 27:25), /* RD_DELAY */
265 field(EMC, 0xb0, 31:31, 24:24), /* ENABLE_ODT_DURING_WRITE */
266 field(EMC, 0xb0, 30:30, 23:23), /* B4_WRITE */
267 field(EMC, 0xb0, 2:0, 22:20), /* WR_DELAY */
270 static const struct pmc_scratch_field arbitration_xbar[] __initdata = {
271 field(AHB_GIZMO, 0xdc, 31:0, 31:0),
274 static const struct pmc_scratch_field emc_zcal[] __initdata = {
275 field(EMC, 0x2e0, 23:0, 23:0), /* ZCAL_REF_INTERVAL */
276 field(EMC, 0x2e4, 7:0, 31:24), /* ZCAL_WAIT_CNT */
279 static const struct pmc_scratch_field emc_ctt_term[] __initdata = {
280 field(EMC, 0x2dc, 19:15, 30:26), /* TERM_DRVDN */
281 field(EMC, 0x2dc, 12:8, 25:21), /* TERM_OFFSET */
282 field(EMC, 0x2dc, 31:31, 31:31), /* TERM_OVERRIDE */
283 field(EMC, 0x2dc, 2:0, 20:18), /* TERM_SLOPE */
284 field(EMC, 0x2e8, 23:16, 15:8), /* ZQ_MRW_MA */
285 field(EMC, 0x2e8, 7:0, 7:0), /* ZQ_MRW_OP */
288 static const struct pmc_scratch_field xm2_cfgd[] __initdata = {
289 field(APB_MISC, 0x8e8, 18:16, 11:9), /* CFGD0_DLYIN_TRM */
290 field(APB_MISC, 0x8e8, 22:20, 8:6), /* CFGD1_DLYIN_TRM */
291 field(APB_MISC, 0x8e8, 26:24, 5:3), /* CFGD2_DLYIN_TRM */
292 field(APB_MISC, 0x8e8, 30:28, 2:0), /* CFGD3_DLYIN_TRM */
293 field(APB_MISC, 0x8e8, 3:3, 12:12), /* XM2CFGD_CTT_HIZ_EN */
294 field(APB_MISC, 0x8e8, 2:2, 13:13), /* XM2CFGD_PREEMP_EN */
295 field(APB_MISC, 0x8e8, 0:0, 14:14), /* CM2CFGD_RX_FT_REC_EN */
298 struct pmc_scratch_reg {
299 const struct pmc_scratch_field *fields;
300 void __iomem *scratch_addr;
304 #define scratch(offs, field_list) \
306 .scratch_addr = IO_ADDRESS(TEGRA_PMC_BASE) + offs, \
307 .fields = field_list, \
308 .num_fields = ARRAY_SIZE(field_list), \
311 static const struct pmc_scratch_reg scratch[] __initdata = {
312 scratch(PMC_SCRATCH3, pllx),
313 scratch(PMC_SCRATCH5, emc_0),
314 scratch(PMC_SCRATCH6, emc_1),
315 scratch(PMC_SCRATCH7, emc_2),
316 scratch(PMC_SCRATCH8, emc_3),
317 scratch(PMC_SCRATCH9, emc_4),
318 scratch(PMC_SCRATCH10, emc_5),
319 scratch(PMC_SCRATCH11, emc_6),
320 scratch(PMC_SCRATCH12, emc_dqsib_dly),
321 scratch(PMC_SCRATCH13, emc_quse_dly),
322 scratch(PMC_SCRATCH14, emc_clktrim),
323 scratch(PMC_SCRATCH15, emc_autocal_fbio),
324 scratch(PMC_SCRATCH16, emc_autocal_interval),
325 scratch(PMC_SCRATCH17, emc_cfgs),
326 scratch(PMC_SCRATCH18, emc_adr_cfg1),
327 scratch(PMC_SCRATCH19, emc_digital_dll),
328 scratch(PMC_SCRATCH20, emc_dqs_clktrim),
329 scratch(PMC_SCRATCH21, emc_dq_clktrim),
330 scratch(PMC_SCRATCH22, emc_dll_xform_dqs),
331 scratch(PMC_SCRATCH23, emc_odt_rw),
332 scratch(PMC_SCRATCH25, arbitration_xbar),
333 scratch(PMC_SCRATCH35, emc_zcal),
334 scratch(PMC_SCRATCH36, emc_ctt_term),
335 scratch(PMC_SCRATCH40, xm2_cfgd),
338 void __init lp0_suspend_init(void)
342 for (i=0; i<ARRAY_SIZE(scratch); i++) {
346 for (j=0; j<scratch[i].num_fields; j++) {
347 unsigned int v = readl(scratch[i].fields[j].addr);
348 v >>= scratch[i].fields[j].shift_src;
349 v &= scratch[i].fields[j].mask;
350 v <<= scratch[i].fields[j].shift_dst;
354 writel(r, scratch[i].scratch_addr);
358 #define NUM_WAKE_EVENTS 31
360 static int tegra_wake_event_irq[NUM_WAKE_EVENTS] = {
361 TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PO5),
362 TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV3),
363 TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PL1),
364 TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PB6),
365 TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PN7),
366 TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PA0),
367 TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PU5),
368 TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PU6),
369 TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PC7),
370 TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS2),
371 TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PAA1),
372 TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PW3),
373 TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PW2),
374 TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PY6),
375 TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV6),
376 TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PJ7),
380 -EINVAL, /* TEGRA_USB1_VBUS, */
381 -EINVAL, /* TEGRA_USB3_VBUS, */
382 -EINVAL, /* TEGRA_USB1_ID, */
383 -EINVAL, /* TEGRA_USB3_ID, */
384 TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PI5),
385 TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV2),
386 TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS4),
387 TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS5),
388 TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS0),
389 TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PQ6),
390 TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PQ7),
391 TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PN2),
394 int tegra_irq_to_wake(int irq)
397 for (i = 0; i < NUM_WAKE_EVENTS; i++)
398 if (tegra_wake_event_irq[i] == irq)
404 int tegra_wake_to_irq(int wake)
409 if (wake >= NUM_WAKE_EVENTS)
412 return tegra_wake_event_irq[wake];