From 91a2fadf7a90096501b30bc260e424d35919ec6f Mon Sep 17 00:00:00 2001 From: wdc Date: Thu, 28 Aug 2014 15:51:20 +0800 Subject: [PATCH] rk3036: Add pll slow mode, clock gating Signed-off-by: wdc --- arch/arm/boot/dts/rk3036-clocks.dtsi | 18 +- arch/arm/boot/dts/rk3036-sdk.dts | 20 +-- arch/arm/boot/dts/rk3036.dtsi | 24 +++ arch/arm/mach-rockchip/rk3036.c | 249 +++++++++++++++++++++++++-- include/linux/rockchip/cru.h | 26 ++- 5 files changed, 293 insertions(+), 44 deletions(-) diff --git a/arch/arm/boot/dts/rk3036-clocks.dtsi b/arch/arm/boot/dts/rk3036-clocks.dtsi index 81691f1a83ea..e249c0172d9e 100755 --- a/arch/arm/boot/dts/rk3036-clocks.dtsi +++ b/arch/arm/boot/dts/rk3036-clocks.dtsi @@ -1174,7 +1174,7 @@ "clk_cryto", "clk_i2s_out", "clk_i2s", "clk_testout"; - rockchip,suspend-clkgating-setting=<0x0 0x0>; + rockchip,suspend-clkgating-setting=<0xe600 0xe600>; #clock-cells = <1>; }; @@ -1208,7 +1208,7 @@ "clk_uart2_div", "uart2_frac", "reserved", "reserved"; - rockchip,suspend-clkgating-setting=<0x0 0x0>; + rockchip,suspend-clkgating-setting=<0x0F78 0x0F78>; #clock-cells = <1>; }; @@ -1240,7 +1240,7 @@ "spdif_frac", "clk_sdio", "clk_emmc", "reserved"; - rockchip,suspend-clkgating-setting=<0x0 0x0>; + rockchip,suspend-clkgating-setting=<0x7E40 0x7E40>; #clock-cells = <1>; }; @@ -1273,7 +1273,7 @@ "hclk_vcodec", "clk_gpu", "g_hclk_sfc", "reserved"; - rockchip,suspend-clkgating-setting=<0x0000 0x0000>; + rockchip,suspend-clkgating-setting=<0x5804 0x5804>; #clock-cells = <1>; }; @@ -1341,7 +1341,7 @@ "reserved", "g_hclk_otg0", "g_pclk_acodec", "reserved"; - rockchip,suspend-clkgating-setting = <0x0000 0x0000>; + rockchip,suspend-clkgating-setting = <0x6e02 0x6e02>; #clock-cells = <1>; }; @@ -1409,7 +1409,7 @@ "g_pclk_spi", "reserved", "reserved", "g_pclk_wdt"; - rockchip,suspend-clkgating-setting = <0x0000 0x0000>; + rockchip,suspend-clkgating-setting = <0x900d 0x900d>; #clock-cells = <1>; }; @@ -1443,7 +1443,7 @@ "reserved", "reserved", "reserved", "reserved"; - rockchip,suspend-clkgating-setting=<0x0000 0x0000>; + rockchip,suspend-clkgating-setting=<0x0c73 0x0c73>; #clock-cells = <1>; }; @@ -1476,7 +1476,7 @@ "reserved", "g_hclk_usb_peri", "g_hclk_pe_arbi", "g_aclk_peri_niu"; - rockchip,suspend-clkgating-setting=<0x0 0x0>; + rockchip,suspend-clkgating-setting=<0x2060 0x2060>; #clock-cells = <1>; }; @@ -1510,7 +1510,7 @@ "reserved", "reserved", "reserved", "reserved"; - rockchip,suspend-clkgating-setting = <0x0 0x0>; /* pwm logic vol */ + rockchip,suspend-clkgating-setting = <0x0077 0x0077>; /* pwm logic vol */ #clock-cells = <1>; }; diff --git a/arch/arm/boot/dts/rk3036-sdk.dts b/arch/arm/boot/dts/rk3036-sdk.dts index a7db2827173d..72b8862a4ca4 100644 --- a/arch/arm/boot/dts/rk3036-sdk.dts +++ b/arch/arm/boot/dts/rk3036-sdk.dts @@ -37,7 +37,7 @@ wireless-wlan { compatible = "wlan-platdata"; - wifi_chip_type = "esp8089"; + wifi_chip_type = ""; sdio_vref = <0>; //1800mv or 3300mv //power_ctrl_by_pmu; @@ -56,24 +56,6 @@ status = "okay"; }; - wireless-bluetooth { - compatible = "bluetooth-platdata"; - - //wifi-bt-power-toggle; - - uart_rts_gpios = <&gpio0 GPIO_C2 GPIO_ACTIVE_LOW>; - pinctrl-names = "default","rts_gpio"; - pinctrl-0 = <&uart0_rts>; - pinctrl-1 = <&uart0_rts_gpio>; - - //BT,power_gpio = <&gpio4 GPIO_D3 GPIO_ACTIVE_HIGH>; - BT,reset_gpio = <&gpio2 GPIO_D5 GPIO_ACTIVE_HIGH>; - BT,wake_gpio = <&gpio2 GPIO_C5 GPIO_ACTIVE_HIGH>; - BT,wake_host_irq = <&gpio0 GPIO_A0 GPIO_ACTIVE_LOW>; - - status = "okay"; - }; - usb_control { compatible = "rockchip,rk3036-usb-control"; host_drv_gpio = <&gpio2 GPIO_C7 GPIO_ACTIVE_LOW>; diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi index 65e865e9e790..648d4aa17a90 100755 --- a/arch/arm/boot/dts/rk3036.dtsi +++ b/arch/arm/boot/dts/rk3036.dtsi @@ -3,6 +3,7 @@ #include "skeleton.dtsi" #include "rk3036-clocks.dtsi" #include "rk3036-pinctrl.dtsi" +#include / { compatible = "rockchip,rk3036"; @@ -692,6 +693,29 @@ interrupt-names = "vpu_mmu"; }; + rockchip_suspend { + rockchip,ctrbits = < + (0 + //|RKPM_CTR_PWR_DMNS + |RKPM_CTR_GTCLKS + |RKPM_CTR_PLLS + //|RKPM_CTR_GPIOS + //|RKPM_CTR_SYSCLK_DIV + //|RKPM_CTR_IDLEAUTO_MD + //|RKPM_CTR_ARMOFF_LPMD + //|RKPM_CTR_ARMOFF_LOGDP_LPMD + ) + >; +/* + rockchip,pmic-suspend_gpios = < + RKPM_PINGPIO_BITS_OUTPUT(GPIO7_A1,RKPM_GPIO_OUT_H) + >; + rockchip,pmic-resume_gpios = < + RKPM_PINGPIO_BITS_FUN(PWM1,RKPM_GPIO_PULL_DN) + >; +*/ + }; + vmac: eth@10200000 { compatible = "rockchip,vmac"; reg = <0x10200000 0x4000>; diff --git a/arch/arm/mach-rockchip/rk3036.c b/arch/arm/mach-rockchip/rk3036.c index e4bdd330fb37..2f927632bce1 100755 --- a/arch/arm/mach-rockchip/rk3036.c +++ b/arch/arm/mach-rockchip/rk3036.c @@ -132,12 +132,12 @@ static int rk3036_sys_set_power_domain(enum pmu_power_domain pd, bool on) if (on) { #ifdef CONFIG_SMP if (PD_CPU_1 == pd) { - writel_relaxed(0x20000, - RK_CRU_VIRT + RK3036_CRU_SOFTRST0_CON); + writel_relaxed(0x20000 + , RK_CRU_VIRT + RK3036_CRU_SOFTRST0_CON); dsb(); udelay(10); writel_relaxed(virt_to_phys(secondary_startup), - RK3036_IMEM_VIRT + 8); + RK3036_IMEM_VIRT + 8); writel_relaxed(0xDEADBEAF, RK3036_IMEM_VIRT + 4); dsb_sev(); } @@ -145,8 +145,8 @@ static int rk3036_sys_set_power_domain(enum pmu_power_domain pd, bool on) } else { #ifdef CONFIG_SMP if (PD_CPU_1 == pd) { - writel_relaxed(0x20002, - RK_CRU_VIRT + RK3036_CRU_SOFTRST0_CON); + writel_relaxed(0x20002 + , RK_CRU_VIRT + RK3036_CRU_SOFTRST0_CON); dsb(); } #endif @@ -203,19 +203,26 @@ static void rk3036_ddr_printch(char byte) } } +enum rk_plls_id { + APLL_ID = 0, + DPLL_ID, + GPLL_ID, + RK3036_END_PLL_ID, +}; + #define GPIO_INTEN 0x30 #define GPIO_INT_STATUS 0x40 #define GIC_DIST_PENDING_SET 0x200 static void rk3036_pm_dump_irq(void) { - u32 irq_gpio = - (readl_relaxed(RK_GIC_VIRT + GIC_DIST_PENDING_SET + 8) >> 4) & 7; + u32 irq_gpio = (readl_relaxed(RK_GIC_VIRT + + GIC_DIST_PENDING_SET + 8) >> 4) & 7; u32 irq[4]; int i; for (i = 0; i < ARRAY_SIZE(irq); i++) { irq[i] = readl_relaxed(RK_GIC_VIRT + GIC_DIST_PENDING_SET + - (1 + i) * 4); + (1 + i) * 4); if (irq[i]) log_wakeup_reason(32 * (i + 1) + fls(irq[i]) - 1); } @@ -225,7 +232,7 @@ static void rk3036_pm_dump_irq(void) if (irq_gpio & (1 << i)) pr_info("wakeup gpio%d: %08x\n", i, readl_relaxed(RK_GPIO_VIRT(i) + - GPIO_INT_STATUS)); + GPIO_INT_STATUS)); } } @@ -244,9 +251,224 @@ static void rk3036_pm_dump_inten(void) DUMP_GPIO_INTEN(2); } +static u32 clk_ungt_msk[RK3036_CRU_CLKGATES_CON_CNT]; +/*first clk gating setting*/ + +static u32 clk_ungt_msk_1[RK3036_CRU_CLKGATES_CON_CNT]; +/* first clk gating setting*/ + +static u32 clk_ungt_save[RK3036_CRU_CLKGATES_CON_CNT]; +/*first clk gating value saveing*/ + +static u32 *p_rkpm_clkgt_last_set; +#define CLK_MSK_GATING(msk, con) cru_writel((0xffff << 16) | msk, con) +#define CLK_MSK_UNGATING(msk, con) cru_writel(((~msk) << 16) | 0xffff, con) + +static void gtclks_suspend(void) +{ + int i; + + for (i = 0; i < RK3036_CRU_CLKGATES_CON_CNT; i++) { + clk_ungt_save[i] = cru_readl(RK3036_CRU_CLKGATES_CON(i)); + if (i != 10) + CLK_MSK_GATING(clk_ungt_msk[i] + , RK3036_CRU_CLKGATES_CON(i)); + else + cru_writel(clk_ungt_msk[i], RK3036_CRU_CLKGATES_CON(i)); + } +} + +static void gtclks_resume(void) +{ + int i; + + for (i = 0; i < RK3036_CRU_CLKGATES_CON_CNT; i++) { + if (i != 10) + cru_writel(clk_ungt_save[i] | 0xffff0000 + , RK3036_CRU_CLKGATES_CON(i)); + else + cru_writel(clk_ungt_msk[i] + , RK3036_CRU_CLKGATES_CON(i)); + } +} + +static void clks_gating_suspend_init(void) +{ + p_rkpm_clkgt_last_set = &clk_ungt_msk_1[0]; + if (clk_suspend_clkgt_info_get(clk_ungt_msk, p_rkpm_clkgt_last_set + , RK3036_CRU_CLKGATES_CON_CNT) == RK3036_CRU_CLKGATES_CON(0)) + rkpm_set_ops_gtclks(gtclks_suspend, gtclks_resume); +} + +#define RK3036_PLL_BYPASS CRU_W_MSK_SETBITS(1, 0xF, 0x01) +#define RK3036_PLL_NOBYPASS CRU_W_MSK_SETBITS(0, 0xF, 0x01) + +#define grf_readl(offset) readl_relaxed(RK_GRF_VIRT + offset) +#define grf_writel(v, offset) do { writel_relaxed(v, \ + RK_GRF_VIRT + offset); dsb(); } while (0) + +#define gpio0_readl(offset) readl_relaxed(RK_GPIO_VIRT(0) + offset) +#define gpio0_writel(v, offset) do { writel_relaxed(v, RK_GPIO_VIRT(0) \ + + offset); dsb(); } while (0) + +static u32 plls_con0_save[RK3036_END_PLL_ID]; +static u32 plls_con1_save[RK3036_END_PLL_ID]; +static u32 plls_con2_save[RK3036_END_PLL_ID]; + +static u32 cru_mode_con; +static u32 clk_sel0, clk_sel1, clk_sel10; +static int goio0_pin_iomux, gpio0_pin_data, gpio0_pin_dir; + +static void pm_pll_wait_lock(u32 pll_idx) +{ + u32 delay = 600000U; + + dsb(); + dsb(); + dsb(); + dsb(); + dsb(); + dsb(); + while (delay > 0) { + if ((cru_readl(RK3036_PLL_CONS(pll_idx, 1)) & (0x1 << 10))) + break; + delay--; + } + if (delay == 0) { + rkpm_ddr_printascii("unlock-pll:"); + rkpm_ddr_printhex(pll_idx); + rkpm_ddr_printch('\n'); + } +} + +static void pll_udelay(u32 udelay) +{ + u32 mode; + + mode = cru_readl(RK3036_CRU_MODE_CON); + cru_writel(RK3036_PLL_MODE_SLOW(APLL_ID), RK3036_CRU_MODE_CON); + rkpm_udelay(udelay * 5); + cru_writel(mode|(RK3036_PLL_MODE_MSK(APLL_ID) + << 16), RK3036_CRU_MODE_CON); +} + +static inline void plls_suspend(u32 pll_id) +{ + plls_con0_save[pll_id] = cru_readl(RK3036_PLL_CONS((pll_id), 0)); + plls_con1_save[pll_id] = cru_readl(RK3036_PLL_CONS((pll_id), 1)); + plls_con2_save[pll_id] = cru_readl(RK3036_PLL_CONS((pll_id), 2)); + + cru_writel(RK3036_PLL_BYPASS, RK3036_PLL_CONS((pll_id), 0)); +} +static inline void plls_resume(u32 pll_id) +{ + u32 pllcon0, pllcon1, pllcon2; + + pllcon0 = plls_con0_save[pll_id]; + pllcon1 = plls_con1_save[pll_id]; + pllcon2 = plls_con2_save[pll_id]; + + cru_writel(pllcon0 | 0xffff0000, RK3036_PLL_CONS(pll_id, 0)); + cru_writel(pllcon1 | 0xf5ff0000, RK3036_PLL_CONS(pll_id, 1)); + cru_writel(pllcon2, RK3036_PLL_CONS(pll_id, 2)); + + pll_udelay(5); + + pll_udelay(168); + pm_pll_wait_lock(pll_id); +} + +static void pm_plls_suspend(void) +{ + cru_mode_con = cru_readl(RK3036_CRU_MODE_CON); + + clk_sel0 = cru_readl(RK3036_CRU_CLKSELS_CON(0)); + clk_sel1 = cru_readl(RK3036_CRU_CLKSELS_CON(1)); + clk_sel10 = cru_readl(RK3036_CRU_CLKSELS_CON(10)); + + cru_writel(RK3036_PLL_MODE_SLOW(GPLL_ID), RK3036_CRU_MODE_CON); + cru_writel(0 + |CRU_W_MSK_SETBITS(0, 0, 0x1f) + |CRU_W_MSK_SETBITS(0, 8, 0x3) + |CRU_W_MSK_SETBITS(0, 12, 0x3) + , RK3036_CRU_CLKSELS_CON(10)); + plls_suspend(GPLL_ID); + + + cru_writel(RK3036_PLL_MODE_SLOW(APLL_ID), RK3036_CRU_MODE_CON); + + cru_writel(0 + |CRU_W_MSK_SETBITS(0, 0, 0x1f) + |CRU_W_MSK_SETBITS(0, 8, 0x1f) + , RK3036_CRU_CLKSELS_CON(0)); + + cru_writel(0 + |CRU_W_MSK_SETBITS(0, 0, 0xf) + |CRU_W_MSK_SETBITS(0, 4, 0x7) + |CRU_W_MSK_SETBITS(0, 8, 0x3) + |CRU_W_MSK_SETBITS(0, 12, 0x7) + , RK3036_CRU_CLKSELS_CON(1)); + + plls_suspend(APLL_ID); + + goio0_pin_iomux = grf_readl(0xa8); + grf_writel(0x000c0000, 0xa8); + + gpio0_pin_data = gpio0_readl(0x0); + gpio0_pin_dir = gpio0_readl(0x04); + + gpio0_writel(gpio0_pin_dir|0x2, 0x04); + gpio0_writel(gpio0_pin_data|0x2, 0x00); +} + +static void pm_plls_resume(void) +{ + gpio0_writel(gpio0_pin_dir, 0x04); + gpio0_writel(gpio0_pin_data, 0x00); + grf_writel(0x000c0008, 0xa8); + + cru_writel(clk_sel0 | (CRU_W_MSK(0, 0x1f) | CRU_W_MSK(8, 0x1f)) + , RK3036_CRU_CLKSELS_CON(0)); + cru_writel(clk_sel1 | (CRU_W_MSK(0, 0xf) | CRU_W_MSK(4, 0x7) + |CRU_W_MSK(8, 0x3) | CRU_W_MSK(12, 0x7)) + , RK3036_CRU_CLKSELS_CON(1)); + + plls_resume(APLL_ID); + cru_writel(cru_mode_con | (RK3036_PLL_MODE_MSK(APLL_ID) << 16) + , RK3036_CRU_MODE_CON); + cru_writel(clk_sel1 | (CRU_W_MSK(0, 0x1f) | CRU_W_MSK(8, 0x3) + | CRU_W_MSK(12, 0x3)), RK3036_CRU_CLKSELS_CON(10)); + plls_resume(GPLL_ID); + cru_writel(cru_mode_con | (RK3036_PLL_MODE_MSK(GPLL_ID) + << 16), RK3036_CRU_MODE_CON); +} + static void __init rk3036_suspend_init(void) { - rkpm_set_ops_prepare_finish(rk3036_pm_dump_inten, rk3036_pm_dump_irq); + struct device_node *parent; + u32 pm_ctrbits; + + PM_LOG("%s enter\n", __func__); + + parent = of_find_node_by_name(NULL, "rockchip_suspend"); + + if (IS_ERR_OR_NULL(parent)) { + PM_ERR("%s dev node err\n", __func__); + return; + } + + if (of_property_read_u32_array(parent, "rockchip,ctrbits" + , &pm_ctrbits, 1)) { + PM_ERR("%s:get pm ctr error\n", __func__); + return; + } + PM_LOG("%s: pm_ctrbits =%x\n", __func__, pm_ctrbits); + rkpm_set_ctrbits(pm_ctrbits); + + clks_gating_suspend_init(); + rkpm_set_ops_plls(pm_plls_suspend, pm_plls_resume); + rkpm_set_ops_prepare_finish(rk3036_pm_dump_inten + , rk3036_pm_dump_irq); rkpm_set_ops_printch(rk3036_ddr_printch); rockchip_suspend_init(); } @@ -270,9 +492,10 @@ static void rk3036_restart(char mode, const char *cmd) u32 boot_flag, boot_mode; rockchip_restart_get_boot_mode(cmd, &boot_flag, &boot_mode); - - writel_relaxed(boot_flag, RK_GRF_VIRT + RK3036_GRF_OS_REG4); // for loader - writel_relaxed(boot_mode, RK_GRF_VIRT + RK3036_GRF_OS_REG5); // for linux + /* for loader */ + writel_relaxed(boot_flag, RK_GRF_VIRT + RK3036_GRF_OS_REG4); + /* for linux */ + writel_relaxed(boot_mode, RK_GRF_VIRT + RK3036_GRF_OS_REG5); dsb(); /* pll enter slow mode */ diff --git a/include/linux/rockchip/cru.h b/include/linux/rockchip/cru.h index 2d8c941f3eb3..3b0d9f67aaa0 100755 --- a/include/linux/rockchip/cru.h +++ b/include/linux/rockchip/cru.h @@ -59,7 +59,7 @@ #define RK3288_CRU_CLKGATES_CON(i) (RK3288_CRU_CLKGATE_CON + ((i) * 4)) /******************PLL MODE BITS*******************/ -// apll dpll,cpll,gpll,npll 0~4 +/*************apll dpll,cpll,gpll,npll 0~4************/ #define RK3288_PLLS_MODE_OFFSET(id) ((id)<=3 ? (id*4) : 14) #define RK3288_PLL_MODE_MSK(id) (0x3 << RK3288_PLLS_MODE_OFFSET(id)) #define RK3288_PLL_MODE_SLOW(id) ((0x0<