PM / devfreq: rk3399_dmc: Support new *-ns properties
authorBrian Norris <briannorris@chromium.org>
Tue, 8 Mar 2022 19:08:56 +0000 (11:08 -0800)
committerChanwoo Choi <cw00.choi@samsung.com>
Wed, 13 Apr 2022 22:18:12 +0000 (07:18 +0900)
We want to keep the idle time fixed, so compute based on the current DDR
frequency.

The old properties were deprecated and never used, so we can safely drop
them from the driver.

This is a rewritten version of work by Lin Huang <hl@rock-chips.com>.

Signed-off-by: Brian Norris <briannorris@chromium.org>
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
drivers/devfreq/rk3399_dmc.c

index fc740c1f67470cc906fde8ad47c7c424a69fc673..f778564cab49ddfb800c369ea99ec80290d7d555 100644 (file)
@@ -24,6 +24,8 @@
 #include <soc/rockchip/rk3399_grf.h>
 #include <soc/rockchip/rockchip_sip.h>
 
+#define NS_TO_CYCLE(NS, MHz)                           (((NS) * (MHz)) / NSEC_PER_USEC)
+
 #define RK3399_SET_ODT_PD_0_SR_IDLE                    GENMASK(7, 0)
 #define RK3399_SET_ODT_PD_0_SR_MC_GATE_IDLE            GENMASK(15, 8)
 #define RK3399_SET_ODT_PD_0_STANDBY_IDLE               GENMASK(31, 16)
@@ -45,13 +47,12 @@ struct rk3399_dmcfreq {
        unsigned long rate, target_rate;
        unsigned long volt, target_volt;
        unsigned int odt_dis_freq;
-       int odt_pd_arg0, odt_pd_arg1;
 
-       unsigned int pd_idle;
-       unsigned int sr_idle;
-       unsigned int sr_mc_gate_idle;
-       unsigned int srpd_lite_idle;
-       unsigned int standby_idle;
+       unsigned int pd_idle_ns;
+       unsigned int sr_idle_ns;
+       unsigned int sr_mc_gate_idle_ns;
+       unsigned int srpd_lite_idle_ns;
+       unsigned int standby_idle_ns;
        unsigned int ddr3_odt_dis_freq;
        unsigned int lpddr3_odt_dis_freq;
        unsigned int lpddr4_odt_dis_freq;
@@ -70,9 +71,14 @@ static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq,
        struct dev_pm_opp *opp;
        unsigned long old_clk_rate = dmcfreq->rate;
        unsigned long target_volt, target_rate;
+       unsigned int ddrcon_mhz;
        struct arm_smccc_res res;
        int err;
 
+       u32 odt_pd_arg0 = 0;
+       u32 odt_pd_arg1 = 0;
+       u32 odt_pd_arg2 = 0;
+
        opp = devfreq_recommended_opp(dev, freq, flags);
        if (IS_ERR(opp))
                return PTR_ERR(opp);
@@ -86,11 +92,35 @@ static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq,
 
        mutex_lock(&dmcfreq->lock);
 
-       if (dmcfreq->regmap_pmu) {
-               unsigned int odt_pd_arg0 = dmcfreq->odt_pd_arg0;
-               unsigned int odt_pd_arg1 = dmcfreq->odt_pd_arg1;
-               unsigned int odt_pd_arg2 = 0;
+       /*
+        * Some idle parameters may be based on the DDR controller clock, which
+        * is half of the DDR frequency.
+        * pd_idle and standby_idle are based on the controller clock cycle.
+        * sr_idle_cycle, sr_mc_gate_idle_cycle, and srpd_lite_idle_cycle
+        * are based on the 1024 controller clock cycle
+        */
+       ddrcon_mhz = target_rate / USEC_PER_SEC / 2;
+
+       u32p_replace_bits(&odt_pd_arg1,
+                         NS_TO_CYCLE(dmcfreq->pd_idle_ns, ddrcon_mhz),
+                         RK3399_SET_ODT_PD_1_PD_IDLE);
+       u32p_replace_bits(&odt_pd_arg0,
+                         NS_TO_CYCLE(dmcfreq->standby_idle_ns, ddrcon_mhz),
+                         RK3399_SET_ODT_PD_0_STANDBY_IDLE);
+       u32p_replace_bits(&odt_pd_arg0,
+                         DIV_ROUND_UP(NS_TO_CYCLE(dmcfreq->sr_idle_ns,
+                                                  ddrcon_mhz), 1024),
+                         RK3399_SET_ODT_PD_0_SR_IDLE);
+       u32p_replace_bits(&odt_pd_arg0,
+                         DIV_ROUND_UP(NS_TO_CYCLE(dmcfreq->sr_mc_gate_idle_ns,
+                                                  ddrcon_mhz), 1024),
+                         RK3399_SET_ODT_PD_0_SR_MC_GATE_IDLE);
+       u32p_replace_bits(&odt_pd_arg1,
+                         DIV_ROUND_UP(NS_TO_CYCLE(dmcfreq->srpd_lite_idle_ns,
+                                                  ddrcon_mhz), 1024),
+                         RK3399_SET_ODT_PD_1_SRPD_LITE_IDLE);
 
+       if (dmcfreq->regmap_pmu) {
                if (target_rate >= dmcfreq->sr_idle_dis_freq)
                        odt_pd_arg0 &= ~RK3399_SET_ODT_PD_0_SR_IDLE;
 
@@ -262,16 +292,16 @@ static int rk3399_dmcfreq_of_props(struct rk3399_dmcfreq *data,
                data->srpd_lite_idle_dis_freq =
                data->standby_idle_dis_freq = UINT_MAX;
 
-       ret |= of_property_read_u32(np, "rockchip,pd_idle",
-                                   &data->pd_idle);
-       ret |= of_property_read_u32(np, "rockchip,sr_idle",
-                                   &data->sr_idle);
-       ret |= of_property_read_u32(np, "rockchip,sr_mc_gate_idle",
-                                   &data->sr_mc_gate_idle);
-       ret |= of_property_read_u32(np, "rockchip,srpd_lite_idle",
-                                   &data->srpd_lite_idle);
-       ret |= of_property_read_u32(np, "rockchip,standby_idle",
-                                   &data->standby_idle);
+       ret |= of_property_read_u32(np, "rockchip,pd-idle-ns",
+                                   &data->pd_idle_ns);
+       ret |= of_property_read_u32(np, "rockchip,sr-idle-ns",
+                                   &data->sr_idle_ns);
+       ret |= of_property_read_u32(np, "rockchip,sr-mc-gate-idle-ns",
+                                   &data->sr_mc_gate_idle_ns);
+       ret |= of_property_read_u32(np, "rockchip,srpd-lite-idle-ns",
+                                   &data->srpd_lite_idle_ns);
+       ret |= of_property_read_u32(np, "rockchip,standby-idle-ns",
+                                   &data->standby_idle_ns);
        ret |= of_property_read_u32(np, "rockchip,ddr3_odt_dis_freq",
                                    &data->ddr3_odt_dis_freq);
        ret |= of_property_read_u32(np, "rockchip,lpddr3_odt_dis_freq",
@@ -367,21 +397,6 @@ no_pmu:
                      ROCKCHIP_SIP_CONFIG_DRAM_INIT,
                      0, 0, 0, 0, &res);
 
-       /*
-        * In TF-A there is a platform SIP call to set the PD (power-down)
-        * timings and to enable or disable the ODT (on-die termination).
-        */
-       data->odt_pd_arg0 =
-               FIELD_PREP(RK3399_SET_ODT_PD_0_SR_IDLE, data->sr_idle) |
-               FIELD_PREP(RK3399_SET_ODT_PD_0_SR_MC_GATE_IDLE,
-                          data->sr_mc_gate_idle) |
-               FIELD_PREP(RK3399_SET_ODT_PD_0_STANDBY_IDLE,
-                          data->standby_idle);
-       data->odt_pd_arg1 =
-               FIELD_PREP(RK3399_SET_ODT_PD_1_PD_IDLE, data->pd_idle) |
-               FIELD_PREP(RK3399_SET_ODT_PD_1_SRPD_LITE_IDLE,
-                          data->srpd_lite_idle);
-
        /*
         * We add a devfreq driver to our parent since it has a device tree node
         * with operating points.