diff options
author | Gary King <gking@nvidia.com> | 2010-06-04 16:33:23 -0700 |
---|---|---|
committer | Gary King <gking@nvidia.com> | 2010-06-11 17:15:19 -0700 |
commit | 52801e076864241721455e14e860b8a0c51dee5c (patch) | |
tree | 06448a8cd4fa71a60104cbaac64f992a68c3b895 /arch/arm/mach-tegra/suspend-t2.c | |
parent | e8df23df7b474cd4612e0f2d084c55b911b2173f (diff) |
[ARM/tegra] suspend: add scratch register mapping for tegra 2 LP0
to restore from LP0, a large number of memory, arbitration and PLL
settings need to be preserved in scratch registers in the AO domain
for the boot ROM to reload them after exiting LP0.
Change-Id: Ic446ef47c3cba9b792dd7b86b176157757504bde
Reviewed-on: http://git-master/r/2154
Reviewed-by: Gary King <gking@nvidia.com>
Tested-by: Gary King <gking@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra/suspend-t2.c')
-rw-r--r-- | arch/arm/mach-tegra/suspend-t2.c | 349 |
1 files changed, 349 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/suspend-t2.c b/arch/arm/mach-tegra/suspend-t2.c new file mode 100644 index 000000000000..88aed2664489 --- /dev/null +++ b/arch/arm/mach-tegra/suspend-t2.c @@ -0,0 +1,349 @@ +/* + * arch/arm/mach-tegra/suspend-t2.c + * + * BootROM LP0 scratch register preservation for Tegra 2 + * + * Copyright (c) 2009-2010, NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <asm/io.h> +#include <mach/iomap.h> + +#define PMC_SCRATCH3 0x5c +#define PMC_SCRATCH5 0x64 +#define PMC_SCRATCH6 0x68 +#define PMC_SCRATCH7 0x6c +#define PMC_SCRATCH8 0x70 +#define PMC_SCRATCH9 0x74 +#define PMC_SCRATCH10 0x78 +#define PMC_SCRATCH11 0x7c +#define PMC_SCRATCH12 0x80 +#define PMC_SCRATCH13 0x84 +#define PMC_SCRATCH14 0x88 +#define PMC_SCRATCH15 0x8c +#define PMC_SCRATCH16 0x90 +#define PMC_SCRATCH17 0x94 +#define PMC_SCRATCH18 0x98 +#define PMC_SCRATCH19 0x9c +#define PMC_SCRATCH20 0xa0 +#define PMC_SCRATCH21 0xa4 +#define PMC_SCRATCH22 0xa8 +#define PMC_SCRATCH23 0xac +#define PMC_SCRATCH25 0x100 +#define PMC_SCRATCH35 0x128 +#define PMC_SCRATCH36 0x12c +#define PMC_SCRATCH40 0x13c + +struct pmc_scratch_field { + void __iomem *addr; + unsigned int mask; + int shift_src; + int shift_dst; +}; + +#define field(module, offs, field, dst) \ + { \ + .addr = IO_ADDRESS(TEGRA_##module##_BASE) + offs, \ + .mask = 0xfffffffful >> (31 - (1?field - 0?field)), \ + .shift_src = 0?field, \ + .shift_dst = 0?dst, \ + } + +static const struct pmc_scratch_field pllx[] __initdata = { + field(CLK_RESET, 0xe0, 22:20, 17:15), /* PLLX_DIVP */ + field(CLK_RESET, 0xe0, 17:8, 14:5), /* PLLX_DIVN */ + field(CLK_RESET, 0xe0, 4:0, 4:0), /* PLLX_DIVM */ + field(CLK_RESET, 0xe4, 11:8, 25:22), /* PLLX_CPCON */ + field(CLK_RESET, 0xe4, 7:4, 21:18), /* PLLX_LFCON */ + field(APB_MISC, 0x8e4, 27:24, 30:27), /* XM2CFGC_VREF_DQ */ + field(APB_MISC, 0x8c8, 3:3, 26:26), /* XM2CFGC_SCHMT_EN */ + field(APB_MISC, 0x8c8, 2:2, 31:31), /* XM2CLKCFG_PREEMP_EN */ +}; + +static const struct pmc_scratch_field emc_0[] __initdata = { + field(EMC, 0x3c, 4:0, 31:27), /* R2W */ + field(EMC, 0x34, 5:0, 20:15), /* RAS */ + field(EMC, 0x2c, 5:0, 5:0), /* RC */ + field(EMC, 0x30, 8:0, 14:6), /* RFC */ + field(EMC, 0x38, 5:0, 26:21), /* RP */ +}; + +static const struct pmc_scratch_field emc_1[] __initdata = { + field(EMC, 0x44, 4:0, 9:5), /* R2P */ + field(EMC, 0x4c, 5:0, 20:15), /* RD_RCD */ + field(EMC, 0x54, 3:0, 30:27), /* RRD */ + field(EMC, 0x48, 4:0, 14:10), /* W2P */ + field(EMC, 0x40, 4:0, 4:0), /* W2R */ + field(EMC, 0x50, 5:0, 26:21), /* WR_RCD */ +}; + +static const struct pmc_scratch_field emc_2[] __initdata = { + field(EMC, 0x2b8, 2:2, 31:31), /* CLKCHANGE_SR_ENABLE */ + field(EMC, 0x2b8, 10:10, 30:30), /* USE_ADDR_CLK */ + field(EMC, 0x80, 4:0, 29:25), /* PCHG2PDEN */ + field(EMC, 0x64, 3:0, 15:12), /* QRST */ + field(EMC, 0x68, 3:0, 19:16), /* QSAFE */ + field(EMC, 0x60, 3:0, 11:8), /* QUSE */ + field(EMC, 0x6c, 4:0, 24:20), /* RDV */ + field(EMC, 0x58, 3:0, 3:0), /* REXT */ + field(EMC, 0x5c, 3:0, 7:4), /* WDV */ +}; + +static const struct pmc_scratch_field emc_3[] __initdata = { + field(EMC, 0x74, 3:0, 19:16), /* BURST_REFRESH_NUM */ + field(EMC, 0x7c, 3:0, 27:24), /* PDEX2RD */ + field(EMC, 0x78, 3:0, 23:20), /* PDEX2WR */ + field(EMC, 0x70, 4:0, 4:0), /* REFRESH_LO */ + field(EMC, 0x70, 15:5, 15:5), /* REFRESH */ + field(EMC, 0xa0, 3:0, 31:28), /* TCLKSTABLE */ +}; + +static const struct pmc_scratch_field emc_4[] __initdata = { + field(EMC, 0x84, 4:0, 4:0), /* ACT2PDEN */ + field(EMC, 0x88, 4:0, 9:5), /* AR2PDEN */ + field(EMC, 0x8c, 5:0, 15:10), /* RW2PDEN */ + field(EMC, 0x94, 3:0, 31:28), /* TCKE */ + field(EMC, 0x90, 11:0, 27:16), /* TXSR */ +}; + +static const struct pmc_scratch_field emc_5[] __initdata = { + field(EMC, 0x8, 10:10, 30:30), /* AP_REQ_BUSY_CTRL */ + field(EMC, 0x8, 24:24, 31:31), /* CFG_PRIORITY */ + field(EMC, 0x8, 2:2, 26:26), /* FORCE_UPDATE */ + field(EMC, 0x8, 4:4, 27:27), /* MRS_WAIT */ + field(EMC, 0x8, 5:5, 28:28), /* PERIODIC_QRST */ + field(EMC, 0x8, 9:9, 29:29), /* READ_DQM_CTRL */ + field(EMC, 0x8, 0:0, 24:24), /* READ_MUX */ + field(EMC, 0x8, 1:1, 25:25), /* WRITE_MUX */ + field(EMC, 0xa4, 3:0, 9:6), /* TCLKSTOP */ + field(EMC, 0xa8, 13:0, 23:10), /* TREFBW */ + field(EMC, 0x9c, 5:0, 5:0), /* TRPAB */ +}; + +static const struct pmc_scratch_field emc_6[] __initdata = { + field(EMC, 0xfc, 1:0, 1:0), /* DQSIB_DLY_MSB_BYTE_0 */ + field(EMC, 0xfc, 9:8, 3:2), /* DQSIB_DLY_MSB_BYTE_1 */ + field(EMC, 0xfc, 17:16, 5:4), /* DQSIB_DLY_MSB_BYTE_2 */ + field(EMC, 0xfc, 25:24, 7:6), /* DQSIB_DLY_MSB_BYTE_3 */ + field(EMC, 0x110, 1:0, 9:8), /* QUSE_DLY_MSB_BYTE_0 */ + field(EMC, 0x110, 9:8, 11:10), /* QUSE_DLY_MSB_BYTE_1 */ + field(EMC, 0x110, 17:16, 13:12), /* QUSE_DLY_MSB_BYTE_2 */ + field(EMC, 0x110, 25:24, 15:14), /* QUSE_DLY_MSB_BYTE_3 */ + field(EMC, 0xac, 3:0, 25:22), /* QUSE_EXTRA */ + field(EMC, 0x98, 5:0, 21:16), /* TFAW */ + field(APB_MISC, 0x8e4, 5:5, 30:30), /* XM2CFGC_VREF_DQ_EN */ + field(APB_MISC, 0x8e4, 7:7, 29:26), /* XM2CFGC_VREF_DQS */ +}; + +static const struct pmc_scratch_field emc_dqsib_dly[] __initdata = { + field(EMC, 0xf8, 31:0, 31:0), /* DQSIB_DLY_BYTE_0 - DQSIB_DLY_BYTE_3*/ +}; + +static const struct pmc_scratch_field emc_quse_dly[] __initdata = { + field(EMC, 0x10c, 31:0, 31:0), /* QUSE_DLY_BYTE_0 - QUSE_DLY_BYTE_3*/ +}; + +static const struct pmc_scratch_field emc_clktrim[] __initdata = { + field(EMC, 0x2d0, 29:0, 29:0), /* DATA0_CLKTRIM - DATA3_CLKTRIM + + * MCLK_ADDR_CLKTRIM */ +}; + +static const struct pmc_scratch_field emc_autocal_fbio[] __initdata = { + field(EMC, 0x2a4, 29:29, 29:29), /* AUTO_CAL_ENABLE */ + field(EMC, 0x2a4, 30:30, 30:30), /* AUTO_CAL_OVERRIDE */ + field(EMC, 0x2a4, 12:8, 18:14), /* AUTO_CAL_PD_OFFSET */ + field(EMC, 0x2a4, 4:0, 13:9), /* AUTO_CAL_PU_OFFSET */ + field(EMC, 0x2a4, 25:16, 28:19), /* AUTO_CAL_STEP */ + field(EMC, 0xf4, 16:16, 0:0), /* CFG_DEN_EARLY */ + field(EMC, 0x104, 8:8, 8:8), /* CTT_TERMINATION */ + field(EMC, 0x104, 7:7, 7:7), /* DIFFERENTIAL_DQS */ + field(EMC, 0x104, 9:9, 31:31), /* DQS_PULLD */ + field(EMC, 0x104, 1:0, 5:4), /* DRAM_TYPE */ + field(EMC, 0x104, 4:4, 6:6), /* DRAM_WIDTH */ + field(EMC, 0x114, 2:0, 3:1), /* CFG_QUSE_LATE */ +}; + +static const struct pmc_scratch_field emc_autocal_interval[] __initdata = { + field(EMC, 0x2a8, 27:0, 27:8), /* AUTOCAL_INTERVAL */ + field(EMC, 0x2b8, 1:1, 29:29), /* CLKCHANGE_PD_ENABLE */ + field(EMC, 0x2b8, 0:0, 28:28), /* CLKCHANGE_REQ_ENABLE */ + field(EMC, 0x2b8, 9:8, 31:30), /* PIN_CONFIG */ +}; + +static const struct pmc_scratch_field emc_cfgs[] __initdata = { + field(EMC, 0x10, 9:8, 4:3), /* EMEM_BANKWIDTH */ + field(EMC, 0x10, 2:0, 2:0), /* EMEM_COLWIDTH */ + field(EMC, 0x10, 19:16, 8:5), /* EMEM_DEVSIZE */ + field(EMC, 0x10, 25:24, 10:9), /* EMEM_NUMDEV */ + field(EMC, 0xc, 24:24, 21:21), /* AUTO_PRE_RD */ + field(EMC, 0xc, 25:25, 22:22), /* AUTO_PRE_WR */ + field(EMC, 0xc, 16:16, 20:20), /* CLEAR_AP_PREV_SPREQ */ + field(EMC, 0xc, 29:29, 23:23), /* DRAM_ACPD */ + field(EMC, 0xc, 30:30, 24:24), /* DRAM_CLKSTOP_PDSR_ONLY */ + field(EMC, 0xc, 31:31, 25:25), /* DRAM_CLKSTOP */ + field(EMC, 0xc, 15:8, 19:12), /* PRE_IDLE_CYCLES */ + field(EMC, 0xc, 0:0, 11:11), /* PRE_IDLE_EN */ + field(EMC, 0x2bc, 29:28, 29:28), /* CFG_DLL_LOCK_LIMIT */ + field(EMC, 0x2bc, 7:6, 31:30), /* CFG_DLL_MODE */ + field(MC, 0x10c, 0:0, 26:26), /* LL_CTRL */ + field(MC, 0x10c, 1:1, 27:27), /* LL_SEND_BOTH */ +}; + +static const struct pmc_scratch_field emc_adr_cfg1[] __initdata = { + field(EMC, 0x14, 9:8, 9:8), /* EMEM1_BANKWIDTH */ + field(EMC, 0x14, 2:0, 7:5), /* EMEM1_COLWIDTH */ + field(EMC, 0x14, 19:16, 13:10), /* EMEM1_DEVSIZE */ + field(EMC, 0x2dc, 28:24, 4:0), /* TERM_DRVUP */ + field(APB_MISC, 0x8d4, 3:0, 17:14), /* XM2COMP_VREF_SEL */ + field(APB_MISC, 0x8d8, 18:16, 23:21), /* XM2VTTGEN_CAL_DRVDN */ + field(APB_MISC, 0x8d8, 26:24, 20:18), /* XM2VTTGEN_CAL_DRVUP */ + field(APB_MISC, 0x8d8, 1:1, 30:30), /* XM2VTTGEN_SHORT_PWRGND */ + field(APB_MISC, 0x8d8, 0:0, 31:31), /* XM2VTTGEN_SHORT */ + field(APB_MISC, 0x8d8, 14:12, 26:24), /* XM2VTTGEN_VAUXP_LEVEL */ + field(APB_MISC, 0x8d8, 10:8, 29:27), /* XM2VTTGEN_VCLAMP_LEVEL */ +}; + +static const struct pmc_scratch_field emc_digital_dll[] __initdata = { + field(EMC, 0x2bc, 1:1, 23:23), /* DLI_TRIMMER_EN */ + field(EMC, 0x2bc, 0:0, 22:22), /* DLL_EN */ + field(EMC, 0x2bc, 5:5, 27:27), /* DLL_LOWSPEED */ + field(EMC, 0x2bc, 2:2, 24:24), /* DLL_OVERRIDE_EN */ + field(EMC, 0x2bc, 11:8, 31:28), /* DLL_UDSET */ + field(EMC, 0x2bc, 4:4, 26:26), /* PERBYTE_TRIMMER_OVERRIDE */ + field(EMC, 0x2bc, 3:3, 25:25), /* USE_SINGLE_DLL */ + field(MC, 0xc, 21:0, 21:0), /* EMEM_SIZE_KB */ +}; + +static const struct pmc_scratch_field emc_dqs_clktrim[] __initdata = { + field(EMC, 0x2d4, 29:0, 29:0), /* DQS0_CLKTRIM - DQS3 + MCLK*/ + field(APB_MISC, 0x8e4, 3:3, 31:31), /* XM2CFGC_CTT_HIZ_EN */ + field(APB_MISC, 0x8e4, 4:4, 30:30), /* XM2CFGC_VREF_DQS_EN */ +}; + +static const struct pmc_scratch_field emc_dq_clktrim[] __initdata = { + field(EMC, 0x2d8, 29:0, 29:0), + field(APB_MISC, 0x8e4, 2:2, 30:30), /* XM2CFGC_PREEMP_EN */ + field(APB_MISC, 0x8e4, 0:0, 31:31), /* XM2CFGC_RX_FT_REC_EN */ +}; + +static const struct pmc_scratch_field emc_dll_xform_dqs[] __initdata = { + field(EMC, 0x2bc, 25:16, 29:20), /* CFG_DLL_OVERRIDE_VAL */ + field(EMC, 0x2c0, 4:0, 4:0), /* DQS_MULT */ + field(EMC, 0x2c0, 22:8, 19:5), /* DQS_OFFS */ + field(MC, 0x10c, 31:31, 30:30), /* LL_DRAM_INTERLEAVE */ +}; + +static const struct pmc_scratch_field emc_odt_rw[] __initdata = { + field(EMC, 0x2c4, 4:0, 4:0), /* QUSE_MULT */ + field(EMC, 0x2c4, 22:8, 19:5), /* QUSE_OFF */ + field(EMC, 0xb4, 31:31, 29:29), /* DISABLE_ODT_DURING_READ */ + field(EMC, 0xb4, 30:30, 28:28), /* B4_READ */ + field(EMC, 0xb4, 2:0, 27:25), /* RD_DELAY */ + field(EMC, 0xb0, 31:31, 24:24), /* ENABLE_ODT_DURING_WRITE */ + field(EMC, 0xb0, 30:30, 23:23), /* B4_WRITE */ + field(EMC, 0xb0, 2:0, 22:20), /* WR_DELAY */ +}; + +static const struct pmc_scratch_field arbitration_xbar[] __initdata = { + field(AHB_GIZMO, 0xdc, 31:0, 31:0), +}; + +static const struct pmc_scratch_field emc_zcal[] __initdata = { + field(EMC, 0x2e0, 23:0, 23:0), /* ZCAL_REF_INTERVAL */ + field(EMC, 0x2e4, 7:0, 31:24), /* ZCAL_WAIT_CNT */ +}; + +static const struct pmc_scratch_field emc_ctt_term[] __initdata = { + field(EMC, 0x2dc, 19:15, 30:26), /* TERM_DRVDN */ + field(EMC, 0x2dc, 12:8, 25:21), /* TERM_OFFSET */ + field(EMC, 0x2dc, 31:31, 31:31), /* TERM_OVERRIDE */ + field(EMC, 0x2dc, 2:0, 20:18), /* TERM_SLOPE */ + field(EMC, 0x2e8, 23:16, 15:8), /* ZQ_MRW_MA */ + field(EMC, 0x2e8, 7:0, 7:0), /* ZQ_MRW_OP */ +}; + +static const struct pmc_scratch_field xm2_cfgd[] __initdata = { + field(APB_MISC, 0x8e8, 18:16, 11:9), /* CFGD0_DLYIN_TRM */ + field(APB_MISC, 0x8e8, 22:20, 8:6), /* CFGD1_DLYIN_TRM */ + field(APB_MISC, 0x8e8, 26:24, 5:3), /* CFGD2_DLYIN_TRM */ + field(APB_MISC, 0x8e8, 30:28, 2:0), /* CFGD3_DLYIN_TRM */ + field(APB_MISC, 0x8e8, 3:3, 12:12), /* XM2CFGD_CTT_HIZ_EN */ + field(APB_MISC, 0x8e8, 2:2, 13:13), /* XM2CFGD_PREEMP_EN */ + field(APB_MISC, 0x8e8, 0:0, 14:14), /* CM2CFGD_RX_FT_REC_EN */ +}; + +struct pmc_scratch_reg { + const struct pmc_scratch_field *fields; + void __iomem *scratch_addr; + int num_fields; +}; + +#define scratch(offs, field_list) \ + { \ + .scratch_addr = IO_ADDRESS(TEGRA_PMC_BASE) + offs, \ + .fields = field_list, \ + .num_fields = ARRAY_SIZE(field_list), \ + } + +static const struct pmc_scratch_reg scratch[] __initdata = { + scratch(PMC_SCRATCH3, pllx), + scratch(PMC_SCRATCH5, emc_0), + scratch(PMC_SCRATCH6, emc_1), + scratch(PMC_SCRATCH7, emc_2), + scratch(PMC_SCRATCH8, emc_3), + scratch(PMC_SCRATCH9, emc_4), + scratch(PMC_SCRATCH10, emc_5), + scratch(PMC_SCRATCH11, emc_6), + scratch(PMC_SCRATCH12, emc_dqsib_dly), + scratch(PMC_SCRATCH13, emc_quse_dly), + scratch(PMC_SCRATCH14, emc_clktrim), + scratch(PMC_SCRATCH15, emc_autocal_fbio), + scratch(PMC_SCRATCH16, emc_autocal_interval), + scratch(PMC_SCRATCH17, emc_cfgs), + scratch(PMC_SCRATCH18, emc_adr_cfg1), + scratch(PMC_SCRATCH19, emc_digital_dll), + scratch(PMC_SCRATCH20, emc_dqs_clktrim), + scratch(PMC_SCRATCH21, emc_dq_clktrim), + scratch(PMC_SCRATCH22, emc_dll_xform_dqs), + scratch(PMC_SCRATCH23, emc_odt_rw), + scratch(PMC_SCRATCH25, arbitration_xbar), + scratch(PMC_SCRATCH35, emc_zcal), + scratch(PMC_SCRATCH36, emc_ctt_term), + scratch(PMC_SCRATCH40, xm2_cfgd), +}; + +void __init lp0_suspend_init(void) +{ + int i; + + for (i=0; i<ARRAY_SIZE(scratch); i++) { + unsigned int r = 0; + int j; + + for (j=0; j<scratch[i].num_fields; j++) { + unsigned int v = readl(scratch[i].fields[j].addr); + v >>= scratch[i].fields[j].shift_src; + v &= scratch[i].fields[j].mask; + v <<= scratch[i].fields[j].shift_dst; + r |= v; + } + + writel(r, scratch[i].scratch_addr); + } +} |