| /* |
| * Copyright (C) 2011 Broadcom Corporation |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 as |
| * published by the Free Software Foundation. |
| * |
| * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| */ |
| #include <stdarg.h> |
| #include <linux/kernel.h> |
| #include <linux/types.h> |
| |
| #include <linux/brcmstb/brcmstb.h> |
| |
| #if 1 |
| #define DBG printk |
| #else |
| #define DBG(...) do { } while (0) |
| #endif |
| |
| #if defined(CONFIG_BRCM_HAS_STANDBY) && defined(BCHP_MEMC_DDR_1_SSPD_CMD) |
| |
| #define MAX_CLIENT_INFO_NUM NUM_MEMC_CLIENTS |
| #define MAX_DDR_PARAMS_NUM 16 |
| #define MAX_DDR_APHY_PARAMS_NUM 16 |
| #define MAX_ARB_PARAMS_NUM 2 |
| |
| #define MEMC_STATE_UNKNOWN 0 |
| #define MEMC_STATE_ON 1 |
| #define MEMC_STATE_OFF 2 |
| |
| static int __brcm_pm_memc1_initialized(void); |
| static void __brcm_pm_memc1_clock_start(void); |
| static void __brcm_pm_memc1_clock_stop(void); |
| static int __brcm_pm_memc1_clock_running(void); |
| static void __brcm_pm_memc1_suspend(int mode); |
| static void __brcm_pm_memc1_resume(int mode); |
| static void __brcm_pm_memc1_powerdown(void); |
| static int __brcm_pm_memc1_powerup(void); |
| |
| struct memc_config { |
| u32 client_info[MAX_CLIENT_INFO_NUM]; |
| u32 ddr23_aphy_params[MAX_DDR_APHY_PARAMS_NUM]; |
| u32 ddr_params[MAX_DDR_PARAMS_NUM]; |
| u32 arb_params[MAX_ARB_PARAMS_NUM]; |
| |
| u32 vcdl[4]; |
| int shmoo_value[8]; |
| |
| int shmoo_valid; |
| int valid; |
| /* if CFE did not initialize non-primary MEMC we cannot touch it |
| because we do not have calibration capabilities. |
| _initalized_ and _clock_active_ are initially set to |
| 0: unknown |
| The first time any method is called it will set _initialized_ to |
| one of the following values: |
| 1: on |
| 2: off - unusable |
| */ |
| int initialized; |
| int clock_active; |
| }; |
| |
| static struct memc_config __maybe_unused memc1_config; |
| |
| static void brcm_pm_memc1_sspd_control(int enable) |
| { |
| if (enable) { |
| BDEV_WR_F_RB(MEMC_DDR_1_SSPD_CMD, SSPD, 1); |
| while (!BDEV_RD_F(MEMC_DDR_1_POWER_DOWN_STATUS, SSPD)) |
| udelay(1); |
| } else { |
| BDEV_WR_F_RB(MEMC_DDR_1_SSPD_CMD, SSPD, 0); |
| while (BDEV_RD_F(MEMC_DDR_1_POWER_DOWN_STATUS, SSPD)) |
| udelay(1); |
| } |
| } |
| |
| static void brcm_pm_memc1_ddr_params(int restore) |
| { |
| int ii = 0; |
| |
| if (restore) { |
| /* program ddr iobuf registers */ |
| BDEV_WR_RB(BCHP_MEMC_DDR_1_DRAM_MODE_2, |
| memc1_config.ddr_params[ii++]); |
| BDEV_WR_RB(BCHP_MEMC_DDR_1_DRAM_MODE_3, |
| memc1_config.ddr_params[ii++]); |
| BDEV_WR_RB(BCHP_MEMC_DDR_1_DRAM_TIMING_5, |
| memc1_config.ddr_params[ii++]); |
| BDEV_WR_RB(BCHP_MEMC_DDR_1_DRAM_MODE_0, |
| memc1_config.ddr_params[ii++]); |
| BDEV_WR_RB(BCHP_MEMC_DDR_1_DRAM_MODE_1, |
| memc1_config.ddr_params[ii++]); |
| BDEV_WR_RB(BCHP_MEMC_DDR_1_DRAM_TIMING_0, |
| memc1_config.ddr_params[ii++]); |
| BDEV_WR_RB(BCHP_MEMC_DDR_1_DRAM_TIMING_1, |
| memc1_config.ddr_params[ii++]); |
| BDEV_WR_RB(BCHP_MEMC_DDR_1_DRAM_TIMING_2, |
| memc1_config.ddr_params[ii++]); |
| BDEV_WR_RB(BCHP_MEMC_DDR_1_DRAM_TIMING_3, |
| memc1_config.ddr_params[ii++]); |
| BDEV_WR_RB(BCHP_MEMC_DDR_1_DRAM_TIMING_4, |
| memc1_config.ddr_params[ii++]); |
| BDEV_WR_RB(BCHP_MEMC_DDR_1_CNTRLR_CONFIG, |
| memc1_config.ddr_params[ii++]); |
| BDEV_WR_RB(BCHP_MEMC_DDR_1_DRAM_INIT_CNTRL, |
| memc1_config.ddr_params[ii++]); |
| } else { |
| memc1_config.ddr_params[ii++] = |
| BDEV_RD(BCHP_MEMC_DDR_1_DRAM_MODE_2); |
| memc1_config.ddr_params[ii++] = |
| BDEV_RD(BCHP_MEMC_DDR_1_DRAM_MODE_3); |
| memc1_config.ddr_params[ii++] = |
| BDEV_RD(BCHP_MEMC_DDR_1_DRAM_TIMING_5); |
| memc1_config.ddr_params[ii++] = |
| BDEV_RD(BCHP_MEMC_DDR_1_DRAM_MODE_0); |
| memc1_config.ddr_params[ii++] = |
| BDEV_RD(BCHP_MEMC_DDR_1_DRAM_MODE_1); |
| memc1_config.ddr_params[ii++] = |
| BDEV_RD(BCHP_MEMC_DDR_1_DRAM_TIMING_0); |
| memc1_config.ddr_params[ii++] = |
| BDEV_RD(BCHP_MEMC_DDR_1_DRAM_TIMING_1); |
| memc1_config.ddr_params[ii++] = |
| BDEV_RD(BCHP_MEMC_DDR_1_DRAM_TIMING_2); |
| memc1_config.ddr_params[ii++] = |
| BDEV_RD(BCHP_MEMC_DDR_1_DRAM_TIMING_3); |
| memc1_config.ddr_params[ii++] = |
| BDEV_RD(BCHP_MEMC_DDR_1_DRAM_TIMING_4); |
| memc1_config.ddr_params[ii++] = |
| BDEV_RD(BCHP_MEMC_DDR_1_CNTRLR_CONFIG); |
| memc1_config.ddr_params[ii++] = |
| BDEV_RD(BCHP_MEMC_DDR_1_DRAM_INIT_CNTRL); |
| } |
| BUG_ON(ii > MAX_DDR_PARAMS_NUM); |
| } |
| |
| static void brcm_pm_memc1_arb_params(int restore) |
| { |
| int ii = 0; |
| |
| if (restore) { |
| BDEV_WR_RB(BCHP_MEMC_ARB_1_FULLNESS_THRESHOLD, |
| memc1_config.arb_params[ii++]); |
| BDEV_WR_RB(BCHP_MEMC_ARB_1_MINIMUM_COMMAND_SIZE, |
| memc1_config.arb_params[ii++]); |
| } else { |
| memc1_config.arb_params[ii++] = |
| BDEV_RD(BCHP_MEMC_ARB_1_FULLNESS_THRESHOLD); |
| memc1_config.arb_params[ii++] = |
| BDEV_RD(BCHP_MEMC_ARB_1_MINIMUM_COMMAND_SIZE); |
| } |
| |
| BUG_ON(ii > MAX_ARB_PARAMS_NUM); |
| } |
| |
| static int brcm_pm_memc1_clock_running(void) |
| { |
| if (memc1_config.clock_active == MEMC_STATE_UNKNOWN) { |
| /* do this only once */ |
| memc1_config.clock_active = __brcm_pm_memc1_clock_running() ? |
| MEMC_STATE_ON : MEMC_STATE_OFF; |
| } |
| return memc1_config.clock_active == MEMC_STATE_ON; |
| } |
| |
| static void brcm_pm_memc1_clock_start(void) |
| { |
| if (!brcm_pm_memc1_clock_running()) |
| __brcm_pm_memc1_clock_start(); |
| memc1_config.clock_active = MEMC_STATE_ON; |
| } |
| |
| static void brcm_pm_memc1_clock_stop(void) |
| { |
| if (brcm_pm_memc1_clock_running()) |
| __brcm_pm_memc1_clock_stop(); |
| memc1_config.clock_active = MEMC_STATE_OFF; |
| } |
| |
| static int brcm_pm_memc1_initialized(void) |
| { |
| if (memc1_config.initialized == MEMC_STATE_UNKNOWN) { |
| brcm_pm_memc1_clock_start(); |
| /* do this only once */ |
| memc1_config.initialized = __brcm_pm_memc1_initialized() ? |
| MEMC_STATE_ON : MEMC_STATE_OFF; |
| } |
| return memc1_config.initialized == MEMC_STATE_ON; |
| } |
| |
| #define CHECK_MEMC1_INIT() \ |
| if (!brcm_pm_memc1_initialized()) { \ |
| printk(KERN_ERR "%s: not initialized\n", __func__); \ |
| return -1; \ |
| } |
| |
| int brcm_pm_memc1_suspend(void) |
| { |
| CHECK_MEMC1_INIT(); |
| |
| brcm_pm_save_restore_rts(BCHP_MEMC_ARB_1_REG_START, |
| memc1_config.client_info, 0); |
| brcm_pm_memc1_ddr_params(0); |
| brcm_pm_memc1_arb_params(0); |
| __brcm_pm_memc1_suspend(0); |
| /* Stop the clocks */ |
| brcm_pm_memc1_clock_stop(); |
| |
| return 0; |
| } |
| |
| int brcm_pm_memc1_resume(void) |
| { |
| CHECK_MEMC1_INIT(); |
| |
| /* Restart the clocks */ |
| brcm_pm_memc1_clock_start(); |
| __brcm_pm_memc1_resume(0); |
| brcm_pm_memc1_ddr_params(1); |
| brcm_pm_memc1_arb_params(1); |
| brcm_pm_save_restore_rts(BCHP_MEMC_ARB_1_REG_START, |
| memc1_config.client_info, 1); |
| brcm_pm_memc1_sspd_control(0); |
| |
| return 0; |
| } |
| |
| int brcm_pm_memc1_powerdown(void) |
| { |
| CHECK_MEMC1_INIT(); |
| |
| DBG(KERN_DEBUG "%s\n", __func__); |
| |
| brcm_pm_save_restore_rts(BCHP_MEMC_ARB_1_REG_START, |
| memc1_config.client_info, 0); |
| brcm_pm_memc1_ddr_params(0); |
| brcm_pm_memc1_arb_params(0); |
| __brcm_pm_memc1_powerdown(); |
| /* Stop the clocks */ |
| brcm_pm_memc1_clock_stop(); |
| memc1_config.valid = 1; |
| |
| return 0; |
| } |
| |
| int brcm_pm_memc1_powerup(void) |
| { |
| CHECK_MEMC1_INIT(); |
| |
| if (!memc1_config.valid || !memc1_config.shmoo_valid) { |
| printk(KERN_ERR "%s: no valid saved configuration %d %d\n", |
| __func__, memc1_config.valid, memc1_config.shmoo_valid); |
| return -1; |
| } |
| |
| DBG(KERN_DEBUG "%s\n", __func__); |
| |
| /* Restart the clocks */ |
| brcm_pm_memc1_clock_start(); |
| __brcm_pm_memc1_resume(1); |
| __brcm_pm_memc1_powerup(); |
| brcm_pm_memc1_ddr_params(1); |
| brcm_pm_memc1_arb_params(1); |
| brcm_pm_save_restore_rts(BCHP_MEMC_ARB_1_REG_START, |
| memc1_config.client_info, 1); |
| brcm_pm_memc1_sspd_control(0); |
| |
| return 0; |
| } |
| |
| #if defined(CONFIG_BCM7420) |
| static int __brcm_pm_memc1_initialized(void) |
| { |
| return BDEV_RD_F(MEMC_DDR_1_DRAM_INIT_STATUS, INIT_DONE); |
| } |
| |
| static void __brcm_pm_memc1_clock_start(void) |
| { |
| BDEV_WR_F_RB(CLK_DDR23_APHY_1_PM_CTRL, DIS_216M_CLK, 0); |
| BDEV_WR_F_RB(CLK_DDR23_APHY_1_PM_CTRL, DIS_108M_CLK, 0); |
| BDEV_WR_F_RB(CLK_MEMC_1_PM_CTRL, DIS_216M_CLK, 0); |
| BDEV_WR_F_RB(CLK_MEMC_1_PM_CTRL, DIS_108M_CLK, 0); |
| } |
| |
| static void __brcm_pm_memc1_clock_stop(void) |
| { |
| BDEV_WR_F_RB(CLK_DDR23_APHY_1_PM_CTRL, DIS_216M_CLK, 1); |
| BDEV_WR_F_RB(CLK_DDR23_APHY_1_PM_CTRL, DIS_108M_CLK, 1); |
| BDEV_WR_F_RB(CLK_MEMC_1_PM_CTRL, DIS_216M_CLK, 1); |
| BDEV_WR_F_RB(CLK_MEMC_1_PM_CTRL, DIS_108M_CLK, 1); |
| } |
| |
| static int __brcm_pm_memc1_clock_running(void) |
| { |
| return !(BDEV_RD_F(CLK_DDR23_APHY_1_PM_CTRL, DIS_216M_CLK) || |
| BDEV_RD_F(CLK_DDR23_APHY_1_PM_CTRL, DIS_108M_CLK) || |
| BDEV_RD_F(CLK_MEMC_1_PM_CTRL, DIS_216M_CLK) || |
| BDEV_RD_F(CLK_MEMC_1_PM_CTRL, DIS_108M_CLK)); |
| } |
| |
| static void __brcm_pm_memc1_suspend(int mode) |
| { |
| DBG(KERN_DEBUG "%s %d\n", __func__, mode); |
| |
| if (!memc1_config.shmoo_valid) { |
| memc1_config.shmoo_value[0] = |
| BDEV_RD(BCHP_MEMC_GEN_1_MSA_WR_DATA0); |
| memc1_config.shmoo_value[1] = |
| BDEV_RD(BCHP_MEMC_GEN_1_MSA_WR_DATA1); |
| memc1_config.shmoo_value[2] = |
| BDEV_RD(BCHP_MEMC_GEN_1_MSA_WR_DATA2); |
| memc1_config.shmoo_value[3] = |
| BDEV_RD(BCHP_MEMC_GEN_1_MSA_WR_DATA3); |
| memc1_config.shmoo_value[4] = |
| BDEV_RD(BCHP_MEMC_GEN_1_MSA_WR_DATA4); |
| memc1_config.shmoo_value[5] = |
| BDEV_RD(BCHP_MEMC_GEN_1_MSA_WR_DATA5); |
| memc1_config.shmoo_value[6] = |
| BDEV_RD(BCHP_MEMC_GEN_1_MSA_WR_DATA6); |
| memc1_config.shmoo_value[7] = |
| BDEV_RD(BCHP_MEMC_MISC_1_SCRATCH_0); |
| memc1_config.shmoo_valid = 1; |
| DBG(KERN_DEBUG "%s: SHMOO values saved\n", __func__); |
| } |
| |
| /* save VCDL values */ |
| memc1_config.vcdl[0] = |
| BDEV_RD(BCHP_MEMC_DDR23_APHY_WL0_1_BYTE0_VCDL_PHASE_CNTL); |
| memc1_config.vcdl[1] = |
| BDEV_RD(BCHP_MEMC_DDR23_APHY_WL0_1_BYTE1_VCDL_PHASE_CNTL); |
| memc1_config.vcdl[2] = |
| BDEV_RD(BCHP_MEMC_DDR23_APHY_WL1_1_BYTE0_VCDL_PHASE_CNTL); |
| memc1_config.vcdl[3] = |
| BDEV_RD(BCHP_MEMC_DDR23_APHY_WL1_1_BYTE1_VCDL_PHASE_CNTL); |
| |
| /* MEMC1 */ |
| BDEV_WR_F_RB(MEMC_DDR23_APHY_AC_1_DDR_PAD_CNTRL, |
| DEVCLK_OFF_ON_SELFREF, 1); |
| BDEV_WR_F_RB(MEMC_DDR23_APHY_AC_1_DDR_PAD_CNTRL, |
| HIZ_ON_SELFREF, 1); |
| BDEV_WR_F_RB(MEMC_DDR23_APHY_AC_1_DDR_PAD_CNTRL, |
| IDDQ_MODE_ON_SELFREF, 1); |
| BDEV_WR_F_RB(MEMC_DDR23_APHY_AC_1_POWERDOWN, |
| PLLCLKS_OFF_ON_SELFREF, 1); |
| BDEV_WR_F_RB(MEMC_DDR23_APHY_AC_1_POWERDOWN, |
| LOWPWR_EN, 1); |
| BDEV_WR_F_RB(MEMC_DDR23_APHY_WL0_1_DDR_PAD_CNTRL, |
| IDDQ_MODE_ON_SELFREF, 1); |
| BDEV_WR_F_RB(MEMC_DDR23_APHY_WL1_1_DDR_PAD_CNTRL, |
| IDDQ_MODE_ON_SELFREF, 1); |
| BDEV_WR_F_RB(MEMC_DDR23_APHY_WL0_1_WORDSLICE_CNTRL_1, |
| PWRDN_DLL_ON_SELFREF, 1); |
| BDEV_WR_F_RB(MEMC_DDR23_APHY_WL1_1_WORDSLICE_CNTRL_1, |
| PWRDN_DLL_ON_SELFREF, 1); |
| |
| brcm_pm_memc1_sspd_control(1); |
| |
| |
| if (mode) { |
| /* CKE_IDDQ */ |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_AC_1_DDR_PAD_CNTRL, |
| BDEV_RD(BCHP_MEMC_DDR23_APHY_AC_1_DDR_PAD_CNTRL) | 4); |
| |
| BDEV_WR_F_RB(MEMC_MISC_1_SOFT_RESET, |
| MEMC_DRAM_INIT, 1); |
| BDEV_WR_F_RB(MEMC_MISC_1_SOFT_RESET, |
| MEMC_CORE, 1); |
| BDEV_WR_F_RB(MEMC_DDR_1_DRAM_INIT_CNTRL, |
| DDR3_INIT_MODE, 1); |
| mdelay(1); |
| printk(KERN_DEBUG "memc1: powered down\n"); |
| } else |
| printk(KERN_DEBUG "memc1: suspended\n"); |
| |
| /* Power down LDOs */ |
| BDEV_WR_F_RB(MEMC_DDR23_APHY_AC_1_PLL_CTRL1_REG, |
| LDO_PWRDN, 1); |
| BDEV_WR_F_RB(MEMC_DDR23_APHY_WL0_1_WORDSLICE_CNTRL_1, |
| LDO_PWRDN, 1); |
| BDEV_WR_F_RB(MEMC_DDR23_APHY_WL1_1_WORDSLICE_CNTRL_1, |
| LDO_PWRDN, 1); |
| |
| } |
| |
| static void __brcm_pm_memc1_resume(int mode) |
| { |
| u32 val, cur_val; |
| s32 sval, scur_val, inc_val; |
| |
| DBG(KERN_DEBUG "%s %d\n", __func__, mode); |
| |
| /* power up LDOs */ |
| BDEV_WR_F_RB(MEMC_DDR23_APHY_AC_1_PLL_CTRL1_REG, |
| LDO_PWRDN, 0); |
| BDEV_WR_F_RB(MEMC_DDR23_APHY_WL0_1_WORDSLICE_CNTRL_1, |
| LDO_PWRDN, 0); |
| BDEV_WR_F_RB(MEMC_DDR23_APHY_WL1_1_WORDSLICE_CNTRL_1, |
| LDO_PWRDN, 0); |
| |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_AC_1_PLL_CH4_WL0_DQS0_PHASE_CNTRL, 0); |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_AC_1_PLL_CH5_WL0_DQS1_PHASE_CNTRL, 0); |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_AC_1_PLL_CH8_WL1_DQS0_PHASE_CNTRL, 0); |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_AC_1_PLL_CH9_WL1_DQS1_PHASE_CNTRL, 0); |
| |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_AC_1_PLL_CH3_WL0_DQ_PHASE_CNTRL, 0); |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_AC_1_PLL_CH7_WL1_DQ_PHASE_CNTRL, 0); |
| |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_AC_1_PLL_CH2_CLOCK_PHASE_CNTRL, 0); |
| BDEV_WR_F_RB(MEMC_DDR23_APHY_AC_1_DESKEW_DLL_CNTRL, BYPASS_PHASE, 0); |
| |
| BDEV_WR_F_RB(MEMC_DDR23_APHY_WL0_1_DDR_PAD_CNTRL, |
| IDDQ_MODE_ON_SELFREF, 0); |
| BDEV_WR_F_RB(MEMC_DDR23_APHY_WL1_1_DDR_PAD_CNTRL, |
| IDDQ_MODE_ON_SELFREF, 0); |
| BDEV_WR_F_RB(MEMC_DDR23_APHY_WL0_1_WORDSLICE_CNTRL_1, |
| PWRDN_DLL_ON_SELFREF, 0); |
| BDEV_WR_F_RB(MEMC_DDR23_APHY_WL1_1_WORDSLICE_CNTRL_1, |
| PWRDN_DLL_ON_SELFREF, 0); |
| |
| BDEV_UNSET(BCHP_MEMC_DDR23_APHY_AC_1_DDR_PAD_CNTRL, |
| BCHP_MEMC_DDR23_APHY_AC_1_DDR_PAD_CNTRL_DEVCLK_OFF_ON_SELFREF_MASK | |
| BCHP_MEMC_DDR23_APHY_AC_1_DDR_PAD_CNTRL_IDDQ_MODE_ON_SELFREF_MASK); |
| mdelay(1); |
| |
| /* reset the freq divider */ |
| BDEV_WR_F_RB(MEMC_DDR23_APHY_AC_1_RESET, FREQ_DIV_RESET, 1); |
| mdelay(1); |
| /* reset DATAPATH_216, RD_DATAPATH_RESET, RESET_DATAPATH_DDR */ |
| BDEV_SET_RB(BCHP_MEMC_DDR23_APHY_AC_1_RESET, |
| BCHP_MEMC_DDR23_APHY_AC_1_RESET_DATAPATH_216_RESET_MASK | |
| BCHP_MEMC_DDR23_APHY_AC_1_RESET_RD_DATAPATH_RESET_MASK | |
| BCHP_MEMC_DDR23_APHY_AC_1_RESET_DATAPATH_DDR_RESET_MASK); |
| mdelay(1); |
| /* reset the vcxo */ |
| BDEV_WR_F_RB(MEMC_DDR23_APHY_AC_1_RESET, VCXO_RESET, 1); |
| mdelay(1); |
| /* de-assert reset the vcxo */ |
| BDEV_WR_F_RB(MEMC_DDR23_APHY_AC_1_RESET, VCXO_RESET, 0); |
| |
| /* de-assert reset the freq divider */ |
| BDEV_WR_F_RB(MEMC_DDR23_APHY_AC_1_RESET, FREQ_DIV_RESET, 0); |
| mdelay(1); |
| |
| /* check for pll lock */ |
| while (!BDEV_RD_F(MEMC_DDR23_APHY_AC_1_DDR_PLL_LOCK_STATUS, |
| LOCK_STATUS)) |
| ; |
| |
| /* reload shmoo values */ |
| /* set wl0_dq phase */ |
| val = memc1_config.shmoo_value[4]; |
| cur_val = 0; |
| while (cur_val <= val) { |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_AC_1_PLL_CH3_WL0_DQ_PHASE_CNTRL, |
| cur_val); |
| cur_val++; |
| } |
| |
| /* set wl1_dq phase */ |
| val = memc1_config.shmoo_value[5]; |
| cur_val = 0; |
| while (cur_val <= val) { |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_AC_1_PLL_CH7_WL1_DQ_PHASE_CNTRL, |
| cur_val); |
| cur_val++; |
| } |
| /* set ch2 phase */ |
| val = memc1_config.shmoo_value[6]; |
| cur_val = 0; |
| while (cur_val < val) { |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_AC_1_PLL_CH2_CLOCK_PHASE_CNTRL, |
| cur_val); |
| cur_val++; |
| } |
| |
| /* set ch6 phase */ |
| val = memc1_config.shmoo_value[7]; |
| cur_val = 0; |
| while (cur_val < val) { |
| BDEV_WR_F_RB(MEMC_DDR23_APHY_AC_1_DESKEW_DLL_CNTRL, |
| BYPASS_PHASE, cur_val); |
| cur_val++; |
| } |
| |
| /* set wl0_dqs0 phases */ |
| sval = memc1_config.shmoo_value[0]; |
| scur_val = 0; |
| inc_val = sval > 0 ? 1 : -1; |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_AC_1_PLL_CH4_WL0_DQS0_PHASE_CNTRL, |
| 0); |
| while (sval != scur_val) { |
| scur_val += inc_val; |
| BDEV_WR_RB( |
| BCHP_MEMC_DDR23_APHY_AC_1_PLL_CH4_WL0_DQS0_PHASE_CNTRL, |
| scur_val); |
| } |
| |
| /* set wl0_dqs1 phases */ |
| sval = memc1_config.shmoo_value[1]; |
| scur_val = 0; |
| inc_val = sval > 0 ? 1 : -1; |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_AC_1_PLL_CH5_WL0_DQS1_PHASE_CNTRL, |
| 0); |
| while (sval != scur_val) { |
| scur_val += inc_val; |
| BDEV_WR_RB( |
| BCHP_MEMC_DDR23_APHY_AC_1_PLL_CH5_WL0_DQS1_PHASE_CNTRL, |
| scur_val); |
| } |
| |
| /* set wl1_dqs0 phases */ |
| sval = memc1_config.shmoo_value[2]; |
| scur_val = 0; |
| inc_val = sval > 0 ? 1 : -1; |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_AC_1_PLL_CH8_WL1_DQS0_PHASE_CNTRL, |
| 0); |
| while (sval != scur_val) { |
| scur_val += inc_val; |
| BDEV_WR_RB( |
| BCHP_MEMC_DDR23_APHY_AC_1_PLL_CH8_WL1_DQS0_PHASE_CNTRL, |
| scur_val); |
| } |
| |
| /* set wl1_dqs1 phases */ |
| sval = memc1_config.shmoo_value[3]; |
| scur_val = 0; |
| inc_val = sval > 0 ? 1 : -1; |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_AC_1_PLL_CH9_WL1_DQS1_PHASE_CNTRL, |
| 0); |
| while (sval != scur_val) { |
| scur_val += inc_val; |
| BDEV_WR_RB( |
| BCHP_MEMC_DDR23_APHY_AC_1_PLL_CH9_WL1_DQS1_PHASE_CNTRL, |
| scur_val); |
| } |
| |
| /* reset the word slice dll */ |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_WL0_1_WORD_SLICE_DLL_RESET, 1); |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_WL1_1_WORD_SLICE_DLL_RESET, 1); |
| mdelay(1); |
| |
| /* reset VCDL values */ |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_WL0_1_BYTE0_VCDL_PHASE_CNTL, 0); |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_WL0_1_BYTE1_VCDL_PHASE_CNTL, 0); |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_WL1_1_BYTE0_VCDL_PHASE_CNTL, 0); |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_WL1_1_BYTE1_VCDL_PHASE_CNTL, 0); |
| |
| /* de-assert reset of the word slice dll */ |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_WL0_1_WORD_SLICE_DLL_RESET, 0); |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_WL1_1_WORD_SLICE_DLL_RESET, 0); |
| mdelay(1); |
| |
| /* de-assert reset from DATAPATH_216_RESET */ |
| BDEV_WR_F_RB(MEMC_DDR23_APHY_AC_1_RESET, DATAPATH_216_RESET, 0); |
| /* de-assert reset from RD_DATAPATH_RESET */ |
| BDEV_WR_F_RB(MEMC_DDR23_APHY_AC_1_RESET, RD_DATAPATH_RESET, 0); |
| /* de-assert reset from DATAPATH_DDR_RESET */ |
| BDEV_WR_F_RB(MEMC_DDR23_APHY_AC_1_RESET, DATAPATH_DDR_RESET, 0); |
| mdelay(1); |
| |
| /* |
| * Reload VCDL values: |
| */ |
| cur_val = 0x0101; |
| while (cur_val <= memc1_config.vcdl[0]) { |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_WL0_1_BYTE0_VCDL_PHASE_CNTL, |
| cur_val); |
| cur_val += 0x0101; |
| } |
| cur_val = 0x0101; |
| while (cur_val <= memc1_config.vcdl[1]) { |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_WL0_1_BYTE1_VCDL_PHASE_CNTL, |
| cur_val); |
| cur_val += 0x0101; |
| } |
| cur_val = 0x0101; |
| while (cur_val <= memc1_config.vcdl[2]) { |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_WL1_1_BYTE0_VCDL_PHASE_CNTL, |
| cur_val); |
| cur_val += 0x0101; |
| } |
| cur_val = 0x0101; |
| while (cur_val <= memc1_config.vcdl[3]) { |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_WL1_1_BYTE1_VCDL_PHASE_CNTL, |
| cur_val); |
| cur_val += 0x0101; |
| } |
| |
| if (mode) { |
| /* Remove CKE_IDDQ */ |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_AC_1_DDR_PAD_CNTRL, |
| BDEV_RD(BCHP_MEMC_DDR23_APHY_AC_1_DDR_PAD_CNTRL) & ~4); |
| |
| BDEV_WR_F_RB(MEMC_MISC_1_SOFT_RESET, |
| MEMC_DRAM_INIT, 0); |
| BDEV_WR_F_RB(MEMC_MISC_1_SOFT_RESET, |
| MEMC_CORE, 0); |
| mdelay(1); |
| printk(KERN_DEBUG "memc1: powered up\n"); |
| } else |
| printk(KERN_DEBUG "memc1: resumed\n"); |
| |
| } |
| |
| static void __brcm_pm_memc1_powerdown(void) |
| { |
| int ii = 0; |
| |
| memc1_config.ddr23_aphy_params[ii++] = |
| BDEV_RD(BCHP_MEMC_DDR23_APHY_AC_1_PLL_CTRL1_REG); |
| memc1_config.ddr23_aphy_params[ii++] = |
| BDEV_RD(BCHP_MEMC_DDR23_APHY_AC_1_PLL_FREQ_CNTL); |
| memc1_config.ddr23_aphy_params[ii++] = |
| BDEV_RD(BCHP_MEMC_DDR23_APHY_AC_1_CONFIG); |
| memc1_config.ddr23_aphy_params[ii++] = |
| BDEV_RD(BCHP_MEMC_DDR23_APHY_AC_1_PAD_SSTL_DDR2_MODE); |
| memc1_config.ddr23_aphy_params[ii++] = |
| BDEV_RD(BCHP_MEMC_DDR23_APHY_WL1_1_PAD_SSTL_DDR2_MODE); |
| memc1_config.ddr23_aphy_params[ii++] = |
| BDEV_RD(BCHP_MEMC_DDR23_APHY_WL0_1_PAD_SSTL_DDR2_MODE); |
| memc1_config.ddr23_aphy_params[ii++] = |
| BDEV_RD(BCHP_MEMC_DDR23_APHY_AC_1_ODT_CONFIG); |
| |
| BUG_ON(ii > MAX_DDR_APHY_PARAMS_NUM); |
| |
| __brcm_pm_memc1_suspend(1); |
| } |
| |
| static int __brcm_pm_memc1_powerup(void) |
| { |
| int ii = 0; |
| |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_AC_1_PLL_CTRL1_REG, |
| memc1_config.ddr23_aphy_params[ii++]); |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_AC_1_PLL_FREQ_CNTL, |
| memc1_config.ddr23_aphy_params[ii++]); |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_AC_1_CONFIG, |
| memc1_config.ddr23_aphy_params[ii++]); |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_AC_1_PAD_SSTL_DDR2_MODE, |
| memc1_config.ddr23_aphy_params[ii++]); |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_WL1_1_PAD_SSTL_DDR2_MODE, |
| memc1_config.ddr23_aphy_params[ii++]); |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_WL0_1_PAD_SSTL_DDR2_MODE, |
| memc1_config.ddr23_aphy_params[ii++]); |
| BDEV_WR_RB(BCHP_MEMC_DDR23_APHY_AC_1_ODT_CONFIG, |
| memc1_config.ddr23_aphy_params[ii++]); |
| |
| return 0; |
| } |
| #endif |
| |
| #if defined(CONFIG_BCM7425) || defined(CONFIG_BCM7435) |
| static int __brcm_pm_memc1_initialized(void) |
| { |
| return BDEV_RD_F(MEMC_DDR_1_DRAM_INIT_STATUS, INIT_DONE); |
| } |
| |
| static void __brcm_pm_memc1_clock_start(void) |
| { |
| BDEV_WR_F_RB(CLKGEN_MEMSYS_32_1_INST_CLOCK_ENABLE, |
| DDR1_SCB_CLOCK_ENABLE, 1); |
| BDEV_WR_F_RB(CLKGEN_MEMSYS_32_1_INST_CLOCK_ENABLE, |
| DDR1_108_CLOCK_ENABLE, 1); |
| } |
| |
| static void __brcm_pm_memc1_clock_stop(void) |
| { |
| BDEV_WR_F_RB(CLKGEN_MEMSYS_32_1_INST_CLOCK_ENABLE, |
| DDR1_SCB_CLOCK_ENABLE, 0); |
| BDEV_WR_F_RB(CLKGEN_MEMSYS_32_1_INST_CLOCK_ENABLE, |
| DDR1_108_CLOCK_ENABLE, 0); |
| } |
| |
| static int __brcm_pm_memc1_clock_running(void) |
| { |
| return BDEV_RD_F(CLKGEN_MEMSYS_32_1_INST_CLOCK_ENABLE, |
| DDR1_SCB_CLOCK_ENABLE) && |
| BDEV_RD_F(CLKGEN_MEMSYS_32_1_INST_CLOCK_ENABLE, |
| DDR1_108_CLOCK_ENABLE); |
| } |
| |
| static void __brcm_pm_memc1_suspend(int mode) |
| { |
| DBG(KERN_DEBUG "%s %d\n", __func__, mode); |
| |
| memc1_config.shmoo_valid = 1; |
| |
| /* power down the pads */ |
| BDEV_WR_F_RB(MEMC_DDR23_SHIM_ADDR_CNTL_1_DDR_PAD_CNTRL, |
| IDDQ_MODE_ON_SELFREF, 0); |
| BDEV_WR_F_RB(MEMC_DDR23_SHIM_ADDR_CNTL_1_DDR_PAD_CNTRL, |
| PHY_IDLE_ENABLE, 1); |
| BDEV_WR_F_RB(MEMC_DDR23_SHIM_ADDR_CNTL_1_DDR_PAD_CNTRL, |
| HIZ_ON_SELFREF, 1); |
| BDEV_WR_RB(BCHP_DDR40_PHY_CONTROL_REGS_1_IDLE_PAD_CONTROL, |
| 0x132); |
| BDEV_WR_RB(BCHP_DDR40_PHY_WORD_LANE_0_1_IDLE_PAD_CONTROL, |
| BDEV_RD(BCHP_DDR40_PHY_WORD_LANE_0_1_IDLE_PAD_CONTROL) | |
| 0xFFFFF); |
| BDEV_WR_RB(BCHP_DDR40_PHY_WORD_LANE_1_1_IDLE_PAD_CONTROL, |
| BDEV_RD(BCHP_DDR40_PHY_WORD_LANE_1_1_IDLE_PAD_CONTROL) | |
| 0xFFFFF); |
| |
| /* enter SSPD */ |
| brcm_pm_memc1_sspd_control(1); |
| |
| /* power down the PLLs */ |
| BDEV_WR_F_RB(MEMC_DDR23_SHIM_ADDR_CNTL_1_SYS_PLL_PWRDN_ref_clk_sel, |
| PWRDN, 1); |
| BDEV_WR_RB(BCHP_DDR40_PHY_CONTROL_REGS_1_PLL_CONFIG, 3); |
| |
| BDEV_WR_F_RB(CLKGEN_MEMSYS_32_1_INST_POWER_SWITCH_MEMORY, |
| DDR1_POWER_SWITCH_MEMORY, 3); |
| BDEV_WR_F_RB(CLKGEN_MEMSYS_32_1_INST_MEMORY_STANDBY_ENABLE, |
| DDR1_MEMORY_STANDBY_ENABLE, 1); |
| |
| #if defined(BCHP_CLKGEN_MEMSYS_1_32_POWER_MANAGEMENT) |
| BDEV_WR_F_RB(CLKGEN_MEMSYS_1_32_POWER_MANAGEMENT, |
| MEMSYS_PLL_PWRDN_POWER_MANAGEMENT, 1); |
| #endif |
| |
| if (mode) { |
| DBG(KERN_DEBUG "%s reset\n", __func__); |
| BDEV_WR_F_RB(MEMC_MISC_1_SOFT_RESET, MEMC_DRAM_INIT, 1); |
| BDEV_WR_F_RB(MEMC_MISC_1_SOFT_RESET, MEMC_CORE, 1); |
| BDEV_WR_F_RB(MEMC_DDR_1_DRAM_INIT_CNTRL, DDR3_INIT_MODE, 1); |
| mdelay(1); |
| } else |
| DBG(KERN_DEBUG "%s suspended\n", __func__); |
| |
| memc1_config.valid = 1; |
| } |
| |
| static void __brcm_pm_memc1_powerdown(void) |
| { |
| __brcm_pm_memc1_suspend(1); |
| } |
| |
| static void __brcm_pm_memc1_resume(int mode) |
| { |
| DBG(KERN_DEBUG "%s %d\n", __func__, mode); |
| |
| BDEV_WR_F_RB(MEMC_DDR23_SHIM_ADDR_CNTL_1_SYS_PLL_PWRDN_ref_clk_sel, |
| PWRDN, 0); |
| BDEV_WR_RB(BCHP_DDR40_PHY_CONTROL_REGS_1_PLL_CONFIG, 0); |
| |
| BDEV_WR_F_RB(CLKGEN_MEMSYS_32_1_INST_POWER_SWITCH_MEMORY, |
| DDR1_POWER_SWITCH_MEMORY, 2); |
| mdelay(1); |
| BDEV_WR_F_RB(CLKGEN_MEMSYS_32_1_INST_POWER_SWITCH_MEMORY, |
| DDR1_POWER_SWITCH_MEMORY, 0); |
| |
| BDEV_WR_F_RB(CLKGEN_MEMSYS_32_1_INST_MEMORY_STANDBY_ENABLE, |
| DDR1_MEMORY_STANDBY_ENABLE, 0); |
| #if defined(BCHP_CLKGEN_MEMSYS_1_32_POWER_MANAGEMENT) |
| BDEV_WR_F_RB(CLKGEN_MEMSYS_1_32_POWER_MANAGEMENT, |
| MEMSYS_PLL_PWRDN_POWER_MANAGEMENT, 0); |
| #endif |
| |
| /* power up the pads */ |
| BDEV_WR_F_RB(MEMC_DDR23_SHIM_ADDR_CNTL_1_DDR_PAD_CNTRL, |
| IDDQ_MODE_ON_SELFREF, 0); |
| BDEV_WR_F_RB(MEMC_DDR23_SHIM_ADDR_CNTL_1_DDR_PAD_CNTRL, |
| HIZ_ON_SELFREF, 0); |
| BDEV_WR_RB(BCHP_DDR40_PHY_CONTROL_REGS_1_IDLE_PAD_CONTROL, |
| 0); |
| BDEV_WR_RB(BCHP_DDR40_PHY_WORD_LANE_0_1_IDLE_PAD_CONTROL, |
| BDEV_RD(BCHP_DDR40_PHY_WORD_LANE_0_1_IDLE_PAD_CONTROL) | |
| 0); |
| BDEV_WR_RB(BCHP_DDR40_PHY_WORD_LANE_1_1_IDLE_PAD_CONTROL, |
| BDEV_RD(BCHP_DDR40_PHY_WORD_LANE_1_1_IDLE_PAD_CONTROL) | |
| 0); |
| |
| brcm_pm_memc1_sspd_control(0); |
| |
| if (mode) { |
| BDEV_WR_F_RB(MEMC_MISC_1_SOFT_RESET, MEMC_DRAM_INIT, 0); |
| BDEV_WR_F_RB(MEMC_MISC_1_SOFT_RESET, MEMC_CORE, 0); |
| mdelay(1); |
| printk(KERN_DEBUG "memc1: powered up\n"); |
| } else |
| printk(KERN_DEBUG "memc1: resumed\n"); |
| } |
| |
| static int __brcm_pm_memc1_powerup(void) |
| { |
| DBG(KERN_DEBUG "%s\n", __func__); |
| |
| return 0; |
| } |
| |
| #endif |
| |
| #endif |