aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2018-05-25 18:58:14 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2018-05-25 18:58:14 +0000
commit8c97d368fc30ce8bcb5e44e0af8f594edf1f1d55 (patch)
tree126a52e2303a9f6bc2ef842bcb413220663219b9
parente1656ead165d4d90dbc07263c60f6231b23b3a52 (diff)
parent4db961ab5d9e2838fed5dd8bd839d478afb21c6a (diff)
downloadrk-v4.4-8c97d368fc30ce8bcb5e44e0af8f594edf1f1d55.tar.gz
Snap for 4803987 from 4db961ab5d9e2838fed5dd8bd839d478afb21c6a to nyc-iot-release
Change-Id: I418c7864dde90c687a39b19112c248ff2f6c2ca4
-rw-r--r--arch/arm/boot/dts/rk3229-cpu-opp.dtsi22
-rw-r--r--arch/arm/boot/dts/rk322x-dram-default-timing.dtsi35
-rw-r--r--arch/arm/boot/dts/rk322x.dtsi104
-rw-r--r--drivers/clk/rockchip/clk-pll.c25
-rw-r--r--drivers/clk/rockchip/clk-rk3228.c13
-rw-r--r--drivers/clk/rockchip/clk.h1
-rw-r--r--drivers/cpufreq/rockchip-cpufreq.c281
-rw-r--r--drivers/devfreq/rockchip_dmc.c12
-rwxr-xr-xdrivers/gpu/arm/mali400/mali/linux/mali_kernel_linux.c14
-rw-r--r--drivers/gpu/arm/midgard/platform/rk/mali_kbase_config_rk.c282
-rw-r--r--drivers/soc/rockchip/Makefile1
-rw-r--r--drivers/soc/rockchip/rockchip_opp_select.c433
-rw-r--r--include/dt-bindings/clock/rk3228-cru.h1
-rw-r--r--include/dt-bindings/dram/rockchip,rk322x.h90
-rw-r--r--include/soc/rockchip/rockchip_opp_select.h16
15 files changed, 780 insertions, 550 deletions
diff --git a/arch/arm/boot/dts/rk3229-cpu-opp.dtsi b/arch/arm/boot/dts/rk3229-cpu-opp.dtsi
index 5c7cb6150f37..e025b05788ce 100644
--- a/arch/arm/boot/dts/rk3229-cpu-opp.dtsi
+++ b/arch/arm/boot/dts/rk3229-cpu-opp.dtsi
@@ -47,42 +47,64 @@
compatible = "operating-points-v2";
opp-shared;
+ clocks = <&cru PLL_APLL>;
+ rockchip,max-volt = <1350000>;
+ rockchip,leakage-voltage-sel = <
+ 1 4 0
+ 5 254 1
+ >;
nvmem-cells = <&cpu_leakage>;
nvmem-cell-names = "cpu_leakage";
opp-408000000 {
opp-hz = /bits/ 64 <408000000>;
opp-microvolt = <950000>;
+ opp-microvolt-L0 = <950000>;
+ opp-microvolt-L1 = <950000>;
clock-latency-ns = <40000>;
opp-suspend;
};
opp-600000000 {
opp-hz = /bits/ 64 <600000000>;
opp-microvolt = <975000>;
+ opp-microvolt-L0 = <975000>;
+ opp-microvolt-L1 = <975000>;
};
opp-816000000 {
opp-hz = /bits/ 64 <816000000>;
opp-microvolt = <1000000>;
+ opp-microvolt-L0 = <1000000>;
+ opp-microvolt-L1 = <1000000>;
};
opp-1008000000 {
opp-hz = /bits/ 64 <1008000000>;
opp-microvolt = <1175000>;
+ opp-microvolt-L0 = <1175000>;
+ opp-microvolt-L1 = <1125000>;
};
opp-1200000000 {
opp-hz = /bits/ 64 <1200000000>;
opp-microvolt = <1275000>;
+ opp-microvolt-L0 = <1275000>;
+ opp-microvolt-L1 = <1225000>;
};
opp-1296000000 {
opp-hz = /bits/ 64 <1296000000>;
opp-microvolt = <1325000>;
+ opp-microvolt-L0 = <1325000>;
+ opp-microvolt-L1 = <1275000>;
};
opp-1392000000 {
opp-hz = /bits/ 64 <1392000000>;
opp-microvolt = <1375000>;
+ opp-microvolt-L0 = <1375000>;
+ opp-microvolt-L1 = <1325000>;
};
opp-1464000000 {
opp-hz = /bits/ 64 <1464000000>;
opp-microvolt = <1400000>;
+ opp-microvolt-L0 = <1400000>;
+ opp-microvolt-L1 = <1350000>;
};
};
};
diff --git a/arch/arm/boot/dts/rk322x-dram-default-timing.dtsi b/arch/arm/boot/dts/rk322x-dram-default-timing.dtsi
new file mode 100644
index 000000000000..cd5d080ed732
--- /dev/null
+++ b/arch/arm/boot/dts/rk322x-dram-default-timing.dtsi
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd
+ *
+ * SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+ */
+
+#include <dt-bindings/clock/rockchip-ddr.h>
+#include <dt-bindings/dram/rockchip,rk322x.h>
+
+/ {
+ dram_timing: dram_timing {
+ compatible = "rockchip,dram-timing";
+ dram_spd_bin = <DDR3_DEFAULT>;
+ sr_idle = <0x18>;
+ pd_idle = <0x20>;
+ dram_dll_disb_freq = <300>;
+ phy_dll_disb_freq = <400>;
+ dram_odt_disb_freq = <333>;
+ phy_odt_disb_freq = <333>;
+ ddr3_drv = <DDR3_DS_40ohm>;
+ ddr3_odt = <DDR3_ODT_120ohm>;
+ lpddr3_drv = <LP3_DS_34ohm>;
+ lpddr3_odt = <LP3_ODT_240ohm>;
+ lpddr2_drv = <LP2_DS_34ohm>;
+ /* lpddr2 not supported odt */
+ phy_ddr3_clk_drv = <PHY_DDR3_RON_RTT_45ohm>;
+ phy_ddr3_cmd_drv = <PHY_DDR3_RON_RTT_45ohm>;
+ phy_ddr3_dqs_drv = <PHY_DDR3_RON_RTT_34ohm>;
+ phy_ddr3_odt = <PHY_DDR3_RON_RTT_225ohm>;
+ phy_lp23_clk_drv = <PHY_LP23_RON_RTT_43ohm>;
+ phy_lp23_cmd_drv = <PHY_LP23_RON_RTT_34ohm>;
+ phy_lp23_dqs_drv = <PHY_LP23_RON_RTT_34ohm>;
+ phy_lp3_odt = <PHY_LP23_RON_RTT_240ohm>;
+ };
+};
diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi
index 79be4056cd8b..cdb9ddcb3f84 100644
--- a/arch/arm/boot/dts/rk322x.dtsi
+++ b/arch/arm/boot/dts/rk322x.dtsi
@@ -46,6 +46,8 @@
#include <dt-bindings/suspend/rockchip-rk322x.h>
#include <dt-bindings/soc/rockchip,boot-mode.h>
#include <dt-bindings/thermal/thermal.h>
+#include <dt-bindings/soc/rockchip-system-status.h>
+#include <rk322x-dram-default-timing.dtsi>
#include "skeleton.dtsi"
/ {
@@ -103,30 +105,46 @@
compatible = "operating-points-v2";
opp-shared;
+ clocks = <&cru PLL_APLL>;
+ rockchip,max-volt = <1350000>;
+ rockchip,leakage-voltage-sel = <
+ 1 4 0
+ 5 254 1
+ >;
nvmem-cells = <&cpu_leakage>;
nvmem-cell-names = "cpu_leakage";
opp-408000000 {
opp-hz = /bits/ 64 <408000000>;
opp-microvolt = <950000>;
+ opp-microvolt-L0 = <950000>;
+ opp-microvolt-L1 = <950000>;
clock-latency-ns = <40000>;
opp-suspend;
};
opp-600000000 {
opp-hz = /bits/ 64 <600000000>;
opp-microvolt = <975000>;
+ opp-microvolt-L0 = <975000>;
+ opp-microvolt-L1 = <975000>;
};
opp-816000000 {
opp-hz = /bits/ 64 <816000000>;
opp-microvolt = <1000000>;
+ opp-microvolt-L0 = <1000000>;
+ opp-microvolt-L1 = <1000000>;
};
opp-1008000000 {
opp-hz = /bits/ 64 <1008000000>;
opp-microvolt = <1175000>;
+ opp-microvolt-L0 = <1175000>;
+ opp-microvolt-L1 = <1125000>;
};
opp-1200000000 {
opp-hz = /bits/ 64 <1200000000>;
opp-microvolt = <1275000>;
+ opp-microvolt-L0 = <1275000>;
+ opp-microvolt-L1 = <1225000>;
};
};
@@ -157,6 +175,76 @@
interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
};
+ dmc: dmc {
+ compatible = "rockchip,rk3228-dmc", "rockchip,rk322x-dram";
+ clocks = <&cru SCLK_DDRC>;
+ clock-names = "dmc_clk";
+ operating-points-v2 = <&dmc_opp_table>;
+ system-status-freq = <
+ /*system status freq(KHz)*/
+ SYS_STATUS_NORMAL 400000
+ SYS_STATUS_VIDEO_4K 600000
+ SYS_STATUS_VIDEO_4K_10B 786000
+ >;
+ dram_freq = <786000000>;
+ rockchip,dram_timing = <&dram_timing>;
+ status = "disabled";
+ };
+
+ dmc_opp_table: dmc-opp-table {
+ compatible = "operating-points-v2";
+
+ rockchip,leakage-voltage-sel = <
+ 1 5 0
+ 6 254 1
+ >;
+ nvmem-cells = <&logic_leakage>;
+ nvmem-cell-names = "ddr_leakage";
+
+ opp-300000000 {
+ opp-hz = /bits/ 64 <300000000>;
+ opp-microvolt = <1050000>;
+ opp-microvolt-L0 = <1050000>;
+ opp-microvolt-L1 = <1000000>;
+ };
+ opp-400000000 {
+ opp-hz = /bits/ 64 <400000000>;
+ opp-microvolt = <1050000>;
+ opp-microvolt-L0 = <1050000>;
+ opp-microvolt-L1 = <1000000>;
+ };
+ opp-600000000 {
+ opp-hz = /bits/ 64 <600000000>;
+ opp-microvolt = <1100000>;
+ opp-microvolt-L0 = <1100000>;
+ opp-microvolt-L1 = <1050000>;
+ };
+ opp-666000000 {
+ opp-hz = /bits/ 64 <666000000>;
+ opp-microvolt = <1150000>;
+ opp-microvolt-L0 = <1150000>;
+ opp-microvolt-L1 = <1100000>;
+ };
+ opp-700000000 {
+ opp-hz = /bits/ 64 <700000000>;
+ opp-microvolt = <1150000>;
+ opp-microvolt-L0 = <1150000>;
+ opp-microvolt-L1 = <1100000>;
+ };
+ opp-786000000 {
+ opp-hz = /bits/ 64 <786000000>;
+ opp-microvolt = <1150000>;
+ opp-microvolt-L0 = <1150000>;
+ opp-microvolt-L1 = <1100000>;
+ };
+ opp-800000000 {
+ opp-hz = /bits/ 64 <800000000>;
+ opp-microvolt = <1150000>;
+ opp-microvolt-L0 = <1150000>;
+ opp-microvolt-L1 = <1100000>;
+ };
+ };
+
timer {
compatible = "arm,armv7-timer";
arm,cpu-registers-not-fw-configured;
@@ -359,6 +447,9 @@
cpu_leakage: cpu_leakage@17 {
reg = <0x17 0x1>;
};
+ logic_leakage: logic-leakage@19 {
+ reg = <0x19 0x1>;
+ };
};
i2c0: i2c@11050000 {
@@ -639,17 +730,30 @@
gpu_opp_table: opp-table2 {
compatible = "operating-points-v2";
+ rockchip,leakage-voltage-sel = <
+ 1 5 0
+ 6 254 1
+ >;
+ nvmem-cells = <&logic_leakage>;
+ nvmem-cell-names = "gpu_leakage";
+
opp-200000000 {
opp-hz = /bits/ 64 <200000000>;
opp-microvolt = <1050000>;
+ opp-microvolt-L0 = <1050000>;
+ opp-microvolt-L1 = <1000000>;
};
opp-300000000 {
opp-hz = /bits/ 64 <300000000>;
opp-microvolt = <1050000>;
+ opp-microvolt-L0 = <1050000>;
+ opp-microvolt-L1 = <1000000>;
};
opp-500000000 {
opp-hz = /bits/ 64 <500000000>;
opp-microvolt = <1150000>;
+ opp-microvolt-L0 = <1150000>;
+ opp-microvolt-L1 = <1100000>;
};
};
diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c
index 5fc83de66528..043ff25e07f7 100644
--- a/drivers/clk/rockchip/clk-pll.c
+++ b/drivers/clk/rockchip/clk-pll.c
@@ -103,6 +103,31 @@ int rockchip_pll_clk_adaptive_scaling(struct clk *clk, int sel)
return 0;
}
+int rockchip_pll_clk_adaptive_rate(struct clk *clk, unsigned long rate)
+{
+ const struct rockchip_pll_rate_table *rate_table;
+ struct clk *parent = clk_get_parent(clk);
+ struct rockchip_clk_pll *pll;
+ int i;
+
+ if (IS_ERR_OR_NULL(parent))
+ return -EINVAL;
+
+ pll = to_rockchip_clk_pll(__clk_get_hw(parent));
+ if (!pll)
+ return -EINVAL;
+
+ rate_table = pll->rate_table;
+ for (i = 0; i < pll->rate_count; i++) {
+ if (rate >= rate_table[i].rate) {
+ pll->sel = i;
+ break;
+ }
+ }
+
+ return 0;
+}
+
static struct rockchip_pll_rate_table *rk_pll_rate_table_get(void)
{
return &auto_table;
diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c
index f60796329785..276e4b421dd7 100644
--- a/drivers/clk/rockchip/clk-rk3228.c
+++ b/drivers/clk/rockchip/clk-rk3228.c
@@ -222,15 +222,12 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = {
RK2928_CLKSEL_CON(4), 8, 5, DFLAGS),
/* PD_DDR */
- COMPOSITE(0, "clk_ddrphy_src", mux_ddrphy_p, CLK_IGNORE_UNUSED,
- RK2928_CLKSEL_CON(26), 8, 2, MFLAGS, 0, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO,
- RK2928_CLKGATE_CON(0), 2, GFLAGS),
- GATE(0, "ddrphy4x", "clk_ddrphy_src", CLK_IGNORE_UNUSED,
+ COMPOSITE_DDRCLK(SCLK_DDRC, "clk_ddrc", mux_ddrphy_p, 0,
+ RK2928_CLKSEL_CON(26), 8, 2, 0, 2,
+ ROCKCHIP_DDRCLK_SIP_V2),
+ FACTOR(0, "clk_ddrphy", "clk_ddrc", 0, 1, 4),
+ GATE(0, "ddrphy4x", "clk_ddrc", CLK_IGNORE_UNUSED,
RK2928_CLKGATE_CON(7), 1, GFLAGS),
- FACTOR_GATE(0, "ddrc", "clk_ddrphy_src", CLK_IGNORE_UNUSED, 1, 4,
- RK2928_CLKGATE_CON(8), 5, GFLAGS),
- FACTOR_GATE(0, "ddrphy", "clk_ddrphy_src", CLK_IGNORE_UNUSED, 1, 4,
- RK2928_CLKGATE_CON(7), 0, GFLAGS),
/* PD_CORE */
COMPOSITE_NOMUX(0, "pclk_dbg", "armclk", CLK_IGNORE_UNUSED,
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
index 76ca224002cb..8ec02626129c 100644
--- a/drivers/clk/rockchip/clk.h
+++ b/drivers/clk/rockchip/clk.h
@@ -698,6 +698,7 @@ void rockchip_clk_register_armclk(struct rockchip_clk_provider *ctx,
int nrates);
void rockchip_clk_protect_critical(const char *const clocks[], int nclocks);
int rockchip_pll_clk_adaptive_scaling(struct clk *clk, int sel);
+int rockchip_pll_clk_adaptive_rate(struct clk *clk, unsigned long rate);
void rockchip_register_restart_notifier(struct rockchip_clk_provider *ctx,
unsigned int reg, void (*cb)(void));
diff --git a/drivers/cpufreq/rockchip-cpufreq.c b/drivers/cpufreq/rockchip-cpufreq.c
index ce4aca66dbe1..7584bdbd5fec 100644
--- a/drivers/cpufreq/rockchip-cpufreq.c
+++ b/drivers/cpufreq/rockchip-cpufreq.c
@@ -29,21 +29,14 @@
#include <linux/slab.h>
#include <linux/soc/rockchip/pvtm.h>
#include <linux/thermal.h>
+#include <soc/rockchip/rockchip_opp_select.h>
#include "../clk/rockchip/clk.h"
#define MAX_PROP_NAME_LEN 3
-#define LEAKAGE_TABLE_END ~1
#define LEAKAGE_INVALID 0xff
-
#define REBOOT_FREQ 816000 /* kHz */
-struct volt_sel_table {
- int min;
- int max;
- int sel;
-};
-
struct cluster_info {
struct list_head list_head;
cpumask_t cpus;
@@ -55,20 +48,6 @@ struct cluster_info {
unsigned int reboot_freq;
bool rebooting;
};
-
-struct pvtm_config {
- unsigned int freq;
- unsigned int volt;
- unsigned int ch[2];
- unsigned int sample_time;
- unsigned int num;
- unsigned int err;
- unsigned int ref_temp;
- int temp_prop[2];
- const char *tz_name;
- struct thermal_zone_device *tz;
-};
-
static LIST_HEAD(cluster_info_list);
static struct cluster_info *rockchip_cluster_info_lookup(int cpu)
@@ -136,204 +115,14 @@ static const struct of_device_id rockchip_cpufreq_of_match[] = {
{},
};
-static int rockchip_get_volt_sel_table(struct device_node *np, char *porp_name,
- struct volt_sel_table **table)
-{
- struct volt_sel_table *sel_table;
- const struct property *prop;
- int count, i;
-
- prop = of_find_property(np, porp_name, NULL);
- if (!prop)
- return -EINVAL;
-
- if (!prop->value)
- return -ENODATA;
-
- count = of_property_count_u32_elems(np, porp_name);
- if (count < 0)
- return -EINVAL;
-
- if (count % 3)
- return -EINVAL;
-
- sel_table = kzalloc(sizeof(*sel_table) * (count / 3 + 1), GFP_KERNEL);
- if (!sel_table)
- return -ENOMEM;
-
- for (i = 0; i < count / 3; i++) {
- of_property_read_u32_index(np, porp_name, 3 * i,
- &sel_table[i].min);
- of_property_read_u32_index(np, porp_name, 3 * i + 1,
- &sel_table[i].max);
- of_property_read_u32_index(np, porp_name, 3 * i + 2,
- &sel_table[i].sel);
- }
- sel_table[i].min = 0;
- sel_table[i].max = 0;
- sel_table[i].sel = LEAKAGE_TABLE_END;
-
- *table = sel_table;
-
- return 0;
-}
-
-static int rockchip_get_volt_sel(struct device_node *np, char *name,
- int value, int *sel)
-{
- struct volt_sel_table *table;
- int i, j = -1, ret;
-
- ret = rockchip_get_volt_sel_table(np, name, &table);
- if (ret)
- return -EINVAL;
-
- for (i = 0; table[i].sel != LEAKAGE_TABLE_END; i++) {
- if (value >= table[i].min)
- j = i;
- }
- if (j != -1)
- *sel = table[j].sel;
- else
- ret = -EINVAL;
-
- kfree(table);
-
- return ret;
-}
-
-static int rockchip_parse_pvtm_config(struct device_node *np,
- struct pvtm_config *pvtm)
-{
- if (!of_find_property(np, "rockchip,pvtm-voltage-sel", NULL))
- return -EINVAL;
- if (of_property_read_u32(np, "rockchip,pvtm-freq", &pvtm->freq))
- return -EINVAL;
- if (of_property_read_u32(np, "rockchip,pvtm-volt", &pvtm->volt))
- return -EINVAL;
- if (of_property_read_u32_array(np, "rockchip,pvtm-ch", pvtm->ch, 2))
- return -EINVAL;
- if (of_property_read_u32(np, "rockchip,pvtm-sample-time",
- &pvtm->sample_time))
- return -EINVAL;
- if (of_property_read_u32(np, "rockchip,pvtm-number", &pvtm->num))
- return -EINVAL;
- if (of_property_read_u32(np, "rockchip,pvtm-error", &pvtm->err))
- return -EINVAL;
- if (of_property_read_u32(np, "rockchip,pvtm-ref-temp", &pvtm->ref_temp))
- return -EINVAL;
- if (of_property_read_u32_array(np, "rockchip,pvtm-temp-prop",
- pvtm->temp_prop, 2))
- return -EINVAL;
- if (of_property_read_string(np, "rockchip,pvtm-thermal-zone",
- &pvtm->tz_name))
- return -EINVAL;
- pvtm->tz = thermal_zone_get_zone_by_name(pvtm->tz_name);
- if (IS_ERR(pvtm->tz))
- return -EINVAL;
- if (!pvtm->tz->ops->get_temp)
- return -EINVAL;
-
- return 0;
-}
-
-static int rockchip_get_pvtm_specific_value(struct device *dev,
- struct device_node *np,
- struct clk *clk,
- struct regulator *reg,
- int *target_value)
-{
- struct pvtm_config *pvtm;
- unsigned long old_freq;
- unsigned int old_volt;
- int cur_temp, diff_temp;
- int cur_value, total_value, avg_value, diff_value;
- int min_value, max_value;
- int ret = 0, i = 0, retry = 2;
-
- pvtm = kzalloc(sizeof(*pvtm), GFP_KERNEL);
- if (!pvtm)
- return -ENOMEM;
-
- ret = rockchip_parse_pvtm_config(np, pvtm);
- if (ret)
- goto pvtm_value_out;
-
- old_freq = clk_get_rate(clk);
- old_volt = regulator_get_voltage(reg);
-
- /*
- * Set pvtm_freq to the lowest frequency in dts,
- * so change frequency first.
- */
- ret = clk_set_rate(clk, pvtm->freq * 1000);
- if (ret) {
- dev_err(dev, "Failed to set pvtm freq\n");
- goto pvtm_value_out;
- }
-
- ret = regulator_set_voltage(reg, pvtm->volt, pvtm->volt);
- if (ret) {
- dev_err(dev, "Failed to set pvtm_volt\n");
- goto restore_clk;
- }
-
- /* The first few values may be fluctuant, if error is too big, retry*/
- while (retry--) {
- total_value = 0;
- min_value = INT_MAX;
- max_value = 0;
-
- for (i = 0; i < pvtm->num; i++) {
- cur_value = rockchip_get_pvtm_value(pvtm->ch[0],
- pvtm->ch[1],
- pvtm->sample_time);
- if (!cur_value)
- goto resetore_volt;
- if (cur_value < min_value)
- min_value = cur_value;
- if (cur_value > max_value)
- max_value = cur_value;
- total_value += cur_value;
- }
- if (max_value - min_value < pvtm->err)
- break;
- }
- avg_value = total_value / pvtm->num;
-
- /*
- * As pvtm is influenced by temperature, compute difference between
- * current temperature and reference temperature
- */
- pvtm->tz->ops->get_temp(pvtm->tz, &cur_temp);
- diff_temp = (cur_temp / 1000 - pvtm->ref_temp);
- diff_value = diff_temp *
- (diff_temp < 0 ? pvtm->temp_prop[0] : pvtm->temp_prop[1]);
- *target_value = avg_value + diff_value;
-
- dev_info(dev, "temp=%d, pvtm=%d (%d + %d)\n",
- cur_temp, *target_value, avg_value, diff_value);
-
-resetore_volt:
- regulator_set_voltage(reg, old_volt, old_volt);
-restore_clk:
- clk_set_rate(clk, old_freq);
-pvtm_value_out:
- kfree(pvtm);
-
- return ret;
-}
-
static int rockchip_cpufreq_cluster_init(int cpu, struct cluster_info *cluster)
{
int (*get_soc_version)(struct device_node *np, int *soc_version);
const struct of_device_id *match;
struct device_node *node, *np;
struct clk *clk;
- struct clk *cpu_clk;
- struct regulator *cpu_reg;
struct device *dev;
- int lkg_volt_sel = -1, pvtm_volt_sel = -1, lkg_scale_sel = -1;
+ int lkg_volt_sel, pvtm_volt_sel, lkg_scale_sel;
int ret;
dev = get_cpu_device(cpu);
@@ -366,63 +155,25 @@ static int rockchip_cpufreq_cluster_init(int cpu, struct cluster_info *cluster)
&cluster->reboot_freq))
cluster->reboot_freq = REBOOT_FREQ;
- cluster->volt_sel = -1;
- ret = rockchip_get_efuse_value(np, "cpu_leakage", &cluster->leakage);
- if (!ret) {
- dev_info(dev, "leakage=%d\n", cluster->leakage);
- ret = rockchip_get_volt_sel(np, "rockchip,leakage-voltage-sel",
- cluster->leakage, &lkg_volt_sel);
- if (!ret) {
- dev_info(dev, "leakage-sel=%d\n", lkg_volt_sel);
- cluster->volt_sel = lkg_volt_sel;
+ lkg_scale_sel = rockchip_of_get_lkg_scale_sel(dev, "cpu_leakage");
+ if (lkg_scale_sel > 0) {
+ clk = of_clk_get_by_name(np, NULL);
+ if (IS_ERR(clk)) {
+ dev_err(dev, "Failed to get opp clk");
+ return PTR_ERR(clk);
}
-
- ret = rockchip_get_volt_sel(np, "rockchip,leakage-scaling-sel",
- cluster->leakage,
- &lkg_scale_sel);
- if (!ret) {
- dev_info(dev, "scale-sel=%d\n", lkg_scale_sel);
- clk = of_clk_get_by_name(np, NULL);
- if (IS_ERR(clk)) {
- dev_err(dev, "Failed to get opp clk");
- return PTR_ERR(clk);
- }
- ret = rockchip_pll_clk_adaptive_scaling(clk,
- lkg_scale_sel);
- if (ret) {
- dev_err(dev, "Failed to adaptive scaling\n");
- return ret;
- }
+ ret = rockchip_pll_clk_adaptive_scaling(clk,
+ lkg_scale_sel);
+ if (ret) {
+ dev_err(dev, "Failed to adaptive scaling\n");
+ return ret;
}
}
- cpu_clk = clk_get(dev, NULL);
- if (IS_ERR_OR_NULL(cpu_clk)) {
- dev_err(dev, "Failed to get clk\n");
- goto parse_dt_out;
- }
- cpu_reg = regulator_get_optional(dev, "cpu");
- if (IS_ERR_OR_NULL(cpu_reg)) {
- dev_err(dev, "Failed to get cpu_reg\n");
- goto put_clk;
- }
- ret = rockchip_get_pvtm_specific_value(dev, np, cpu_clk, cpu_reg,
- &cluster->pvtm);
- if (!ret) {
- ret = rockchip_get_volt_sel(np, "rockchip,pvtm-voltage-sel",
- cluster->pvtm, &pvtm_volt_sel);
- if (!ret) {
- dev_info(dev, "pvtm-sel=%d\n", pvtm_volt_sel);
- if (cluster->volt_sel < 0 ||
- cluster->volt_sel > pvtm_volt_sel)
- cluster->volt_sel = pvtm_volt_sel;
- }
- }
+ lkg_volt_sel = rockchip_of_get_lkg_volt_sel(dev, "cpu_leakage");
+ pvtm_volt_sel = rockchip_of_get_pvtm_volt_sel(dev, NULL, "cpu");
- regulator_put(cpu_reg);
-put_clk:
- clk_put(cpu_clk);
-parse_dt_out:
+ cluster->volt_sel = max(lkg_volt_sel, pvtm_volt_sel);
return 0;
}
diff --git a/drivers/devfreq/rockchip_dmc.c b/drivers/devfreq/rockchip_dmc.c
index 5dc02d41715b..515af17c61fa 100644
--- a/drivers/devfreq/rockchip_dmc.c
+++ b/drivers/devfreq/rockchip_dmc.c
@@ -42,6 +42,7 @@
#include <soc/rockchip/rockchip_dmc.h>
#include <soc/rockchip/rockchip_sip.h>
#include <soc/rockchip/rockchip-system-status.h>
+#include <soc/rockchip/rockchip_opp_select.h>
#include <soc/rockchip/scpi.h>
#include <uapi/drm/drm_mode.h>
@@ -1390,6 +1391,9 @@ static int rockchip_dmcfreq_probe(struct platform_device *pdev)
const struct of_device_id *match;
int (*init)(struct platform_device *pdev,
struct rockchip_dmcfreq *data);
+#define MAX_PROP_NAME_LEN 3
+ char name[MAX_PROP_NAME_LEN];
+ int lkg_volt_sel;
int ret;
data = devm_kzalloc(dev, sizeof(struct rockchip_dmcfreq), GFP_KERNEL);
@@ -1435,6 +1439,14 @@ static int rockchip_dmcfreq_probe(struct platform_device *pdev)
* We add a devfreq driver to our parent since it has a device tree node
* with operating points.
*/
+ lkg_volt_sel = rockchip_of_get_lkg_volt_sel(dev, "ddr_leakage");
+ if (lkg_volt_sel >= 0) {
+ snprintf(name, MAX_PROP_NAME_LEN, "L%d", lkg_volt_sel);
+ ret = dev_pm_opp_set_prop_name(dev, name);
+ if (ret)
+ dev_err(dev, "Failed to set prop name\n");
+ }
+
if (dev_pm_opp_of_add_table(dev)) {
dev_err(dev, "Invalid operating-points in device tree.\n");
return -EINVAL;
diff --git a/drivers/gpu/arm/mali400/mali/linux/mali_kernel_linux.c b/drivers/gpu/arm/mali400/mali/linux/mali_kernel_linux.c
index 5839a483453a..06ac9e69c0b7 100755
--- a/drivers/gpu/arm/mali400/mali/linux/mali_kernel_linux.c
+++ b/drivers/gpu/arm/mali400/mali/linux/mali_kernel_linux.c
@@ -30,8 +30,9 @@
#include <linux/of.h>
#include <linux/clk.h>
#include <linux/regulator/consumer.h>
-
#include <linux/mali/mali_utgard.h>
+#include <soc/rockchip/rockchip_opp_select.h>
+
#include "mali_kernel_common.h"
#include "mali_session.h"
#include "mali_kernel_core.h"
@@ -517,7 +518,10 @@ static int mali_probe(struct platform_device *pdev)
{
int err;
#ifdef CONFIG_MALI_DEVFREQ
+#define MAX_PROP_NAME_LEN 3
struct mali_device *mdev;
+ char name[MAX_PROP_NAME_LEN];
+ int lkg_volt_sel;
#endif
MALI_DEBUG_PRINT(2, ("mali_probe(): Called for platform device %s\n", pdev->name));
@@ -563,6 +567,14 @@ static int mali_probe(struct platform_device *pdev)
mdev->dev = &pdev->dev;
dev_set_drvdata(mdev->dev, mdev);
+ lkg_volt_sel = rockchip_of_get_lkg_volt_sel(mdev->dev, "gpu_leakage");
+ if (lkg_volt_sel >= 0) {
+ snprintf(name, MAX_PROP_NAME_LEN, "L%d", lkg_volt_sel);
+ err = dev_pm_opp_set_prop_name(mdev->dev, name);
+ if (err)
+ dev_err(mdev->dev, "Failed to set prop name\n");
+ }
+
/*Initilization clock and regulator*/
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) && defined(CONFIG_OF) \
&& defined(CONFIG_REGULATOR)
diff --git a/drivers/gpu/arm/midgard/platform/rk/mali_kbase_config_rk.c b/drivers/gpu/arm/midgard/platform/rk/mali_kbase_config_rk.c
index da3c47b0bb90..de986153f40d 100644
--- a/drivers/gpu/arm/midgard/platform/rk/mali_kbase_config_rk.c
+++ b/drivers/gpu/arm/midgard/platform/rk/mali_kbase_config_rk.c
@@ -23,32 +23,10 @@
#include <linux/nvmem-consumer.h>
#include <linux/soc/rockchip/pvtm.h>
#include <linux/thermal.h>
+#include <soc/rockchip/rockchip_opp_select.h>
#include "mali_kbase_rk.h"
-#define MAX_PROP_NAME_LEN 3
-#define LEAKAGE_TABLE_END ~1
-#define LEAKAGE_INVALID 0xff
-
-struct pvtm_config {
- unsigned int freq;
- unsigned int volt;
- unsigned int ch[2];
- unsigned int sample_time;
- unsigned int num;
- unsigned int err;
- unsigned int ref_temp;
- int temp_prop[2];
- const char *tz_name;
- struct thermal_zone_device *tz;
-};
-
-struct volt_sel_table {
- int min;
- int max;
- int sel;
-};
-
/**
* @file mali_kbase_config_rk.c
* 对 platform_config_of_rk 的具体实现.
@@ -451,268 +429,20 @@ static void kbase_platform_rk_remove_sysfs_files(struct device *dev)
device_remove_file(dev, &dev_attr_utilisation);
}
-static int rockchip_get_efuse_value(struct device_node *np, char *porp_name,
- int *value)
-{
- struct nvmem_cell *cell;
- unsigned char *buf;
- size_t len;
-
- cell = of_nvmem_cell_get(np, porp_name);
- if (IS_ERR(cell))
- return PTR_ERR(cell);
-
- buf = (unsigned char *)nvmem_cell_read(cell, &len);
-
- nvmem_cell_put(cell);
-
- if (IS_ERR(buf))
- return PTR_ERR(buf);
-
- if (buf[0] == LEAKAGE_INVALID)
- return -EINVAL;
-
- *value = buf[0];
-
- kfree(buf);
-
- return 0;
-}
-
-static int rockchip_get_volt_sel_table(struct device_node *np, char *porp_name,
- struct volt_sel_table **table)
-{
- struct volt_sel_table *sel_table;
- const struct property *prop;
- int count, i;
-
- prop = of_find_property(np, porp_name, NULL);
- if (!prop)
- return -EINVAL;
-
- if (!prop->value)
- return -ENODATA;
-
- count = of_property_count_u32_elems(np, porp_name);
- if (count < 0)
- return -EINVAL;
-
- if (count % 3)
- return -EINVAL;
-
- sel_table = kzalloc(sizeof(*sel_table) * (count / 3 + 1), GFP_KERNEL);
- if (!sel_table)
- return -ENOMEM;
-
- for (i = 0; i < count / 3; i++) {
- of_property_read_u32_index(np, porp_name, 3 * i,
- &sel_table[i].min);
- of_property_read_u32_index(np, porp_name, 3 * i + 1,
- &sel_table[i].max);
- of_property_read_u32_index(np, porp_name, 3 * i + 2,
- &sel_table[i].sel);
- }
- sel_table[i].min = 0;
- sel_table[i].max = 0;
- sel_table[i].sel = LEAKAGE_TABLE_END;
-
- *table = sel_table;
-
- return 0;
-}
-
-static int rockchip_get_volt_sel(struct device_node *np, char *name,
- int value, int *sel)
-{
- struct volt_sel_table *table;
- int i, j = -1, ret;
-
- ret = rockchip_get_volt_sel_table(np, name, &table);
- if (ret)
- return -EINVAL;
-
- for (i = 0; table[i].sel != LEAKAGE_TABLE_END; i++) {
- if (value >= table[i].min)
- j = i;
- }
- if (j != -1)
- *sel = table[j].sel;
- else
- ret = -EINVAL;
-
- kfree(table);
-
- return ret;
-}
-
-static int rockchip_parse_pvtm_config(struct device_node *np,
- struct pvtm_config *pvtm)
-{
- if (!of_find_property(np, "rockchip,pvtm-voltage-sel", NULL))
- return -EINVAL;
- if (of_property_read_u32(np, "rockchip,pvtm-freq", &pvtm->freq))
- return -EINVAL;
- if (of_property_read_u32(np, "rockchip,pvtm-volt", &pvtm->volt))
- return -EINVAL;
- if (of_property_read_u32_array(np, "rockchip,pvtm-ch", pvtm->ch, 2))
- return -EINVAL;
- if (of_property_read_u32(np, "rockchip,pvtm-sample-time",
- &pvtm->sample_time))
- return -EINVAL;
- if (of_property_read_u32(np, "rockchip,pvtm-number", &pvtm->num))
- return -EINVAL;
- if (of_property_read_u32(np, "rockchip,pvtm-error", &pvtm->err))
- return -EINVAL;
- if (of_property_read_u32(np, "rockchip,pvtm-ref-temp", &pvtm->ref_temp))
- return -EINVAL;
- if (of_property_read_u32_array(np, "rockchip,pvtm-temp-prop",
- pvtm->temp_prop, 2))
- return -EINVAL;
- if (of_property_read_string(np, "rockchip,pvtm-thermal-zone",
- &pvtm->tz_name))
- return -EINVAL;
- pvtm->tz = thermal_zone_get_zone_by_name(pvtm->tz_name);
- if (IS_ERR(pvtm->tz))
- return -EINVAL;
- if (!pvtm->tz->ops->get_temp)
- return -EINVAL;
-
- return 0;
-}
-
-static int rockchip_get_pvtm_specific_value(struct device *dev,
- struct device_node *np,
- struct clk *clk,
- struct regulator *reg,
- int *target_value)
-{
- struct pvtm_config *pvtm;
- unsigned long old_freq;
- unsigned int old_volt;
- int cur_temp, diff_temp;
- int cur_value, total_value, avg_value, diff_value;
- int min_value, max_value;
- int ret = 0, i = 0, retry = 2;
-
- pvtm = kzalloc(sizeof(*pvtm), GFP_KERNEL);
- if (!pvtm)
- return -ENOMEM;
-
- ret = rockchip_parse_pvtm_config(np, pvtm);
- if (ret)
- goto pvtm_value_out;
-
- old_freq = clk_get_rate(clk);
- old_volt = regulator_get_voltage(reg);
-
- /*
- * Set pvtm_freq to the lowest frequency in dts,
- * so change frequency first.
- */
- ret = clk_set_rate(clk, pvtm->freq * 1000);
- if (ret) {
- dev_err(dev, "Failed to set pvtm freq\n");
- goto pvtm_value_out;
- }
-
- ret = regulator_set_voltage(reg, pvtm->volt, pvtm->volt);
- if (ret) {
- dev_err(dev, "Failed to set pvtm_volt\n");
- goto restore_clk;
- }
-
- /* The first few values may be fluctuant, if error is too big, retry*/
- while (retry--) {
- total_value = 0;
- min_value = INT_MAX;
- max_value = 0;
-
- for (i = 0; i < pvtm->num; i++) {
- cur_value = rockchip_get_pvtm_value(pvtm->ch[0],
- pvtm->ch[1],
- pvtm->sample_time);
- if (!cur_value)
- goto resetore_volt;
- if (cur_value < min_value)
- min_value = cur_value;
- if (cur_value > max_value)
- max_value = cur_value;
- total_value += cur_value;
- }
- if (max_value - min_value < pvtm->err)
- break;
- }
- avg_value = total_value / pvtm->num;
-
- /*
- * As pvtm is influenced by temperature, compute difference between
- * current temperature and reference temperature
- */
- pvtm->tz->ops->get_temp(pvtm->tz, &cur_temp);
- diff_temp = (cur_temp / 1000 - pvtm->ref_temp);
- diff_value = diff_temp *
- (diff_temp < 0 ? pvtm->temp_prop[0] : pvtm->temp_prop[1]);
- *target_value = avg_value + diff_value;
-
- dev_info(dev, "temp=%d, pvtm=%d (%d + %d)\n",
- cur_temp, *target_value, avg_value, diff_value);
-
-resetore_volt:
- regulator_set_voltage(reg, old_volt, old_volt);
-restore_clk:
- clk_set_rate(clk, old_freq);
-pvtm_value_out:
- kfree(pvtm);
-
- return ret;
-}
-
void kbase_platform_rk_set_opp_info(struct kbase_device *kbdev)
{
- struct device_node *np;
+#define MAX_PROP_NAME_LEN 3
char name[MAX_PROP_NAME_LEN];
- int pvmt_value, leakage;
- int lkg_volt_sel, pvtm_volt_sel, volt_sel = -1;
+ int lkg_volt_sel, pvtm_volt_sel, volt_sel;
int err = 0;
if (!kbdev)
return;
- if (IS_ERR_OR_NULL(kbdev->regulator))
- return;
- if (IS_ERR_OR_NULL(kbdev->clock))
- return;
-
- np = of_parse_phandle(kbdev->dev->of_node, "operating-points-v2", 0);
- if (!np) {
- dev_warn(kbdev->dev, "OPP-v2 not supported\n");
- return;
- }
-
- err = rockchip_get_efuse_value(np, "gpu_leakage", &leakage);
- if (!err) {
- dev_info(kbdev->dev, "leakage=%d\n", leakage);
- err = rockchip_get_volt_sel(np, "rockchip,leakage-voltage-sel",
- leakage, &lkg_volt_sel);
- if (!err) {
- dev_info(kbdev->dev, "leakage-sel=%d\n", lkg_volt_sel);
- volt_sel = lkg_volt_sel;
- }
- }
-
- err = rockchip_get_pvtm_specific_value(kbdev->dev, np, kbdev->clock,
- kbdev->regulator,
- &pvmt_value);
- if (!err) {
- err = rockchip_get_volt_sel(np, "rockchip,pvtm-voltage-sel",
- pvmt_value, &pvtm_volt_sel);
- if (!err) {
- dev_info(kbdev->dev, "pvtm-sel=%d\n", pvtm_volt_sel);
- if (volt_sel < 0 || volt_sel > pvtm_volt_sel)
- volt_sel = pvtm_volt_sel;
- }
- }
+ lkg_volt_sel = rockchip_of_get_lkg_volt_sel(kbdev->dev, "gpu_leakage");
+ pvtm_volt_sel = rockchip_of_get_pvtm_volt_sel(kbdev->dev, NULL, "mali");
+ volt_sel = max(lkg_volt_sel, pvtm_volt_sel);
if (volt_sel >= 0) {
snprintf(name, MAX_PROP_NAME_LEN, "L%d", volt_sel);
err = dev_pm_opp_set_prop_name(kbdev->dev, name);
diff --git a/drivers/soc/rockchip/Makefile b/drivers/soc/rockchip/Makefile
index 22e54844968a..074c65259676 100644
--- a/drivers/soc/rockchip/Makefile
+++ b/drivers/soc/rockchip/Makefile
@@ -12,3 +12,4 @@ obj-$(CONFIG_ROCKCHIP_SUSPEND_MODE) += rockchip_pm_config.o
obj-y += rk_vendor_storage.o
obj-y += rockchip-system-status.o
+obj-y += rockchip_opp_select.o
diff --git a/drivers/soc/rockchip/rockchip_opp_select.c b/drivers/soc/rockchip/rockchip_opp_select.c
new file mode 100644
index 000000000000..0f34a4b5f0a0
--- /dev/null
+++ b/drivers/soc/rockchip/rockchip_opp_select.c
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) 2017 Fuzhou Rockchip Electronics Co., Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <linux/clk.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/soc/rockchip/pvtm.h>
+#include <linux/thermal.h>
+#include <linux/pm_opp.h>
+#include <soc/rockchip/rockchip_opp_select.h>
+
+#include "../../clk/rockchip/clk.h"
+#include "../../base/power/opp/opp.h"
+
+#define LEAKAGE_TABLE_END ~1
+#define LEAKAGE_INVALID 0xff
+
+struct volt_sel_table {
+ int min;
+ int max;
+ int sel;
+};
+
+struct pvtm_config {
+ unsigned int freq;
+ unsigned int volt;
+ unsigned int ch[2];
+ unsigned int sample_time;
+ unsigned int num;
+ unsigned int err;
+ unsigned int ref_temp;
+ int temp_prop[2];
+ const char *tz_name;
+ struct thermal_zone_device *tz;
+};
+
+static int rockchip_get_efuse_value(struct device_node *np, char *porp_name,
+ int *value)
+{
+ struct nvmem_cell *cell;
+ unsigned char *buf;
+ size_t len;
+
+ cell = of_nvmem_cell_get(np, porp_name);
+ if (IS_ERR(cell))
+ return PTR_ERR(cell);
+
+ buf = (unsigned char *)nvmem_cell_read(cell, &len);
+
+ nvmem_cell_put(cell);
+
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
+
+ if (buf[0] == LEAKAGE_INVALID)
+ return -EINVAL;
+
+ *value = buf[0];
+
+ kfree(buf);
+
+ return 0;
+}
+
+static int rockchip_get_volt_sel_table(struct device_node *np, char *porp_name,
+ struct volt_sel_table **table)
+{
+ struct volt_sel_table *sel_table;
+ const struct property *prop;
+ int count, i;
+
+ prop = of_find_property(np, porp_name, NULL);
+ if (!prop)
+ return -EINVAL;
+
+ if (!prop->value)
+ return -ENODATA;
+
+ count = of_property_count_u32_elems(np, porp_name);
+ if (count < 0)
+ return -EINVAL;
+
+ if (count % 3)
+ return -EINVAL;
+
+ sel_table = kzalloc(sizeof(*sel_table) * (count / 3 + 1), GFP_KERNEL);
+ if (!sel_table)
+ return -ENOMEM;
+
+ for (i = 0; i < count / 3; i++) {
+ of_property_read_u32_index(np, porp_name, 3 * i,
+ &sel_table[i].min);
+ of_property_read_u32_index(np, porp_name, 3 * i + 1,
+ &sel_table[i].max);
+ of_property_read_u32_index(np, porp_name, 3 * i + 2,
+ &sel_table[i].sel);
+ }
+ sel_table[i].min = 0;
+ sel_table[i].max = 0;
+ sel_table[i].sel = LEAKAGE_TABLE_END;
+
+ *table = sel_table;
+
+ return 0;
+}
+
+static int rockchip_get_volt_sel(struct device_node *np, char *name,
+ int value, int *sel)
+{
+ struct volt_sel_table *table;
+ int i, j = -1, ret;
+
+ ret = rockchip_get_volt_sel_table(np, name, &table);
+ if (ret)
+ return -EINVAL;
+
+ for (i = 0; table[i].sel != LEAKAGE_TABLE_END; i++) {
+ if (value >= table[i].min)
+ j = i;
+ }
+ if (j != -1)
+ *sel = table[j].sel;
+ else
+ ret = -EINVAL;
+
+ kfree(table);
+
+ return ret;
+}
+
+static int rockchip_parse_pvtm_config(struct device_node *np,
+ struct pvtm_config *pvtm)
+{
+ if (!of_find_property(np, "rockchip,pvtm-voltage-sel", NULL))
+ return -EINVAL;
+ if (of_property_read_u32(np, "rockchip,pvtm-freq", &pvtm->freq))
+ return -EINVAL;
+ if (of_property_read_u32(np, "rockchip,pvtm-volt", &pvtm->volt))
+ return -EINVAL;
+ if (of_property_read_u32_array(np, "rockchip,pvtm-ch", pvtm->ch, 2))
+ return -EINVAL;
+ if (of_property_read_u32(np, "rockchip,pvtm-sample-time",
+ &pvtm->sample_time))
+ return -EINVAL;
+ if (of_property_read_u32(np, "rockchip,pvtm-number", &pvtm->num))
+ return -EINVAL;
+ if (of_property_read_u32(np, "rockchip,pvtm-error", &pvtm->err))
+ return -EINVAL;
+ if (of_property_read_u32(np, "rockchip,pvtm-ref-temp", &pvtm->ref_temp))
+ return -EINVAL;
+ if (of_property_read_u32_array(np, "rockchip,pvtm-temp-prop",
+ pvtm->temp_prop, 2))
+ return -EINVAL;
+ if (of_property_read_string(np, "rockchip,pvtm-thermal-zone",
+ &pvtm->tz_name))
+ return -EINVAL;
+ pvtm->tz = thermal_zone_get_zone_by_name(pvtm->tz_name);
+ if (IS_ERR(pvtm->tz))
+ return -EINVAL;
+ if (!pvtm->tz->ops->get_temp)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int rockchip_get_pvtm_specific_value(struct device *dev,
+ struct device_node *np,
+ struct clk *clk,
+ struct regulator *reg,
+ int *target_value)
+{
+ struct pvtm_config *pvtm;
+ unsigned long old_freq;
+ unsigned int old_volt;
+ int cur_temp, diff_temp;
+ int cur_value, total_value, avg_value, diff_value;
+ int min_value, max_value;
+ int ret = 0, i = 0, retry = 2;
+
+ pvtm = kzalloc(sizeof(*pvtm), GFP_KERNEL);
+ if (!pvtm)
+ return -ENOMEM;
+
+ ret = rockchip_parse_pvtm_config(np, pvtm);
+ if (ret)
+ goto pvtm_value_out;
+
+ old_freq = clk_get_rate(clk);
+ old_volt = regulator_get_voltage(reg);
+
+ /*
+ * Set pvtm_freq to the lowest frequency in dts,
+ * so change frequency first.
+ */
+ ret = clk_set_rate(clk, pvtm->freq * 1000);
+ if (ret) {
+ dev_err(dev, "Failed to set pvtm freq\n");
+ goto pvtm_value_out;
+ }
+
+ ret = regulator_set_voltage(reg, pvtm->volt, pvtm->volt);
+ if (ret) {
+ dev_err(dev, "Failed to set pvtm_volt\n");
+ goto restore_clk;
+ }
+
+ /* The first few values may be fluctuant, if error is too big, retry*/
+ while (retry--) {
+ total_value = 0;
+ min_value = INT_MAX;
+ max_value = 0;
+
+ for (i = 0; i < pvtm->num; i++) {
+ cur_value = rockchip_get_pvtm_value(pvtm->ch[0],
+ pvtm->ch[1],
+ pvtm->sample_time);
+ if (!cur_value)
+ goto resetore_volt;
+ if (cur_value < min_value)
+ min_value = cur_value;
+ if (cur_value > max_value)
+ max_value = cur_value;
+ total_value += cur_value;
+ }
+ if (max_value - min_value < pvtm->err)
+ break;
+ }
+ avg_value = total_value / pvtm->num;
+
+ /*
+ * As pvtm is influenced by temperature, compute difference between
+ * current temperature and reference temperature
+ */
+ pvtm->tz->ops->get_temp(pvtm->tz, &cur_temp);
+ diff_temp = (cur_temp / 1000 - pvtm->ref_temp);
+ diff_value = diff_temp *
+ (diff_temp < 0 ? pvtm->temp_prop[0] : pvtm->temp_prop[1]);
+ *target_value = avg_value + diff_value;
+
+ dev_info(dev, "temp=%d, pvtm=%d (%d + %d)\n",
+ cur_temp, *target_value, avg_value, diff_value);
+
+resetore_volt:
+ regulator_set_voltage(reg, old_volt, old_volt);
+restore_clk:
+ clk_set_rate(clk, old_freq);
+pvtm_value_out:
+ kfree(pvtm);
+
+ return ret;
+}
+
+int rockchip_of_get_lkg_scale_sel(struct device *dev, char *name)
+{
+ struct device_node *np;
+ int leakage, volt_sel;
+ int ret;
+
+ np = of_parse_phandle(dev->of_node, "operating-points-v2", 0);
+ if (!np) {
+ dev_warn(dev, "OPP-v2 not supported\n");
+ return -ENOENT;
+ }
+
+ ret = rockchip_get_efuse_value(np, name, &leakage);
+ if (!ret) {
+ dev_info(dev, "%s=%d\n", name, leakage);
+ ret = rockchip_get_volt_sel(np, "rockchip,leakage-scaling-sel",
+ leakage, &volt_sel);
+ if (!ret) {
+ dev_info(dev, "%s-scale-sel=%d\n", name, volt_sel);
+ return volt_sel;
+ }
+ } else {
+ dev_info(dev, "get %s fail\n", name);
+ ret = rockchip_get_volt_sel(np, "rockchip,leakage-scaling-sel",
+ 0, &volt_sel);
+ if (!ret) {
+ dev_info(dev, "%s-scale-sel=%d\n", name, volt_sel);
+ return volt_sel;
+ }
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(rockchip_of_get_lkg_scale_sel);
+
+int rockchip_of_get_lkg_volt_sel(struct device *dev, char *name)
+{
+ struct device_node *np;
+ int leakage, volt_sel;
+ int ret;
+
+ np = of_parse_phandle(dev->of_node, "operating-points-v2", 0);
+ if (!np) {
+ dev_warn(dev, "OPP-v2 not supported\n");
+ return -ENOENT;
+ }
+
+ ret = rockchip_get_efuse_value(np, name, &leakage);
+ if (!ret) {
+ dev_info(dev, "%s=%d\n", name, leakage);
+ ret = rockchip_get_volt_sel(np, "rockchip,leakage-voltage-sel",
+ leakage, &volt_sel);
+ if (!ret) {
+ dev_info(dev, "%s-volt-sel=%d\n", name, volt_sel);
+ return volt_sel;
+ }
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(rockchip_of_get_lkg_volt_sel);
+
+int rockchip_of_get_pvtm_volt_sel(struct device *dev,
+ char *clk_name,
+ char *reg_name)
+{
+ struct device_node *np;
+ struct regulator *reg;
+ struct clk *clk;
+ int pvtm, volt_sel;
+ int ret;
+
+ np = of_parse_phandle(dev->of_node, "operating-points-v2", 0);
+ if (!np) {
+ dev_warn(dev, "OPP-v2 not supported\n");
+ return -ENOENT;
+ }
+
+ clk = clk_get(dev, clk_name);
+ if (IS_ERR_OR_NULL(clk)) {
+ dev_err(dev, "Failed to get clk\n");
+ return PTR_ERR(clk);
+ }
+
+ reg = regulator_get_optional(dev, reg_name);
+ if (IS_ERR_OR_NULL(reg)) {
+ dev_err(dev, "Failed to get reg\n");
+ clk_put(clk);
+ return PTR_ERR(reg);
+ }
+
+ ret = rockchip_get_pvtm_specific_value(dev, np, clk, reg, &pvtm);
+ if (!ret)
+ ret = rockchip_get_volt_sel(np, "rockchip,pvtm-voltage-sel",
+ pvtm, &volt_sel);
+
+ regulator_put(reg);
+ clk_put(clk);
+
+ return ret ? ret : volt_sel;
+}
+EXPORT_SYMBOL(rockchip_of_get_pvtm_volt_sel);
+
+static int rockchip_of_get_irdrop(struct device_node *np, unsigned long rate)
+{
+ int irdrop, ret;
+
+ ret = rockchip_get_volt_sel(np, "rockchip,board-irdrop",
+ rate / 1000000, &irdrop);
+ return ret ? ret : irdrop;
+}
+
+int rockchip_adjust_opp_by_irdrop(struct device *dev)
+{
+ struct dev_pm_opp *opp, *safe_opp = NULL;
+ struct device_node *np;
+ unsigned long rate;
+ u32 max_volt = UINT_MAX;
+ int evb_irdrop = 0, board_irdrop, delta_irdrop;
+ int i, count, ret = 0;
+ bool reach_max_volt = false;
+
+ np = of_parse_phandle(dev->of_node, "operating-points-v2", 0);
+ if (!np) {
+ dev_warn(dev, "OPP-v2 not supported\n");
+ return -ENOENT;
+ }
+
+ of_property_read_u32_index(np, "rockchip,max-volt", 0, &max_volt);
+ of_property_read_u32_index(np, "rockchip,evb-irdrop", 0, &evb_irdrop);
+
+ count = dev_pm_opp_get_opp_count(dev);
+ if (count <= 0) {
+ ret = count ? count : -ENODATA;
+ goto out;
+ }
+
+ for (i = 0, rate = 0; i < count; i++, rate++) {
+ /* find next rate */
+ opp = dev_pm_opp_find_freq_ceil(dev, &rate);
+ if (IS_ERR(opp)) {
+ ret = PTR_ERR(opp);
+ goto out;
+ }
+ board_irdrop = rockchip_of_get_irdrop(np, opp->rate);
+ if (IS_ERR_VALUE(board_irdrop))
+ /* Assume it has the same IR-Drop as evb */
+ delta_irdrop = 0;
+ else
+ delta_irdrop = board_irdrop - evb_irdrop;
+ if ((opp->u_volt + delta_irdrop) <= max_volt) {
+ opp->u_volt += delta_irdrop;
+ opp->u_volt_min += delta_irdrop;
+ opp->u_volt_max += delta_irdrop;
+ if (!reach_max_volt)
+ safe_opp = opp;
+ if (opp->u_volt == max_volt)
+ reach_max_volt = true;
+ } else {
+ opp->u_volt = max_volt;
+ opp->u_volt_min = max_volt;
+ opp->u_volt_max = max_volt;
+ }
+ }
+
+ if (safe_opp && safe_opp != opp) {
+ struct clk *clk = of_clk_get_by_name(np, NULL);
+
+ if (!IS_ERR(clk)) {
+ rockchip_pll_clk_adaptive_rate(clk, safe_opp->rate);
+ clk_put(clk);
+ }
+ }
+out:
+ of_node_put(np);
+ return ret;
+}
+EXPORT_SYMBOL(rockchip_adjust_opp_by_irdrop);
diff --git a/include/dt-bindings/clock/rk3228-cru.h b/include/dt-bindings/clock/rk3228-cru.h
index 9b2aaa3110cc..2f22a7b1538d 100644
--- a/include/dt-bindings/clock/rk3228-cru.h
+++ b/include/dt-bindings/clock/rk3228-cru.h
@@ -73,6 +73,7 @@
#define SCLK_WIFI 141
#define SCLK_OTGPHY0 142
#define SCLK_OTGPHY1 143
+#define SCLK_DDRC 144
/* dclk gates */
#define DCLK_VOP 190
diff --git a/include/dt-bindings/dram/rockchip,rk322x.h b/include/dt-bindings/dram/rockchip,rk322x.h
new file mode 100644
index 000000000000..1ab3317d700e
--- /dev/null
+++ b/include/dt-bindings/dram/rockchip,rk322x.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _DT_BINDINGS_DRAM_ROCKCHIP_RK322X_H
+#define _DT_BINDINGS_DRAM_ROCKCHIP_RK322X_H
+
+#define DDR3_DS_34ohm (1 << 1)
+#define DDR3_DS_40ohm (0x0)
+
+#define LP2_DS_34ohm (0x1)
+#define LP2_DS_40ohm (0x2)
+#define LP2_DS_48ohm (0x3)
+#define LP2_DS_60ohm (0x4)
+#define LP2_DS_68_6ohm (0x5)/* optional */
+#define LP2_DS_80ohm (0x6)
+#define LP2_DS_120ohm (0x7)/* optional */
+
+#define LP3_DS_34ohm (0x1)
+#define LP3_DS_40ohm (0x2)
+#define LP3_DS_48ohm (0x3)
+#define LP3_DS_60ohm (0x4)
+#define LP3_DS_80ohm (0x6)
+#define LP3_DS_34D_40U (0x9)
+#define LP3_DS_40D_48U (0xa)
+#define LP3_DS_34D_48U (0xb)
+
+#define DDR3_ODT_DIS (0)
+#define DDR3_ODT_40ohm ((1 << 2) | (1 << 6))
+#define DDR3_ODT_60ohm (1 << 2)
+#define DDR3_ODT_120ohm (1 << 6)
+
+#define LP3_ODT_DIS (0)
+#define LP3_ODT_60ohm (1)
+#define LP3_ODT_120ohm (2)
+#define LP3_ODT_240ohm (3)
+
+#define PHY_DDR3_RON_RTT_DISABLE (0)
+#define PHY_DDR3_RON_RTT_451ohm (1)
+#define PHY_DDR3_RON_RTT_225ohm (2)
+#define PHY_DDR3_RON_RTT_150ohm (3)
+#define PHY_DDR3_RON_RTT_112ohm (4)
+#define PHY_DDR3_RON_RTT_90ohm (5)
+#define PHY_DDR3_RON_RTT_75ohm (6)
+#define PHY_DDR3_RON_RTT_64ohm (7)
+#define PHY_DDR3_RON_RTT_56ohm (16)
+#define PHY_DDR3_RON_RTT_50ohm (17)
+#define PHY_DDR3_RON_RTT_45ohm (18)
+#define PHY_DDR3_RON_RTT_41ohm (19)
+#define PHY_DDR3_RON_RTT_37ohm (20)
+#define PHY_DDR3_RON_RTT_34ohm (21)
+#define PHY_DDR3_RON_RTT_33ohm (22)
+#define PHY_DDR3_RON_RTT_30ohm (23)
+#define PHY_DDR3_RON_RTT_28ohm (24)
+#define PHY_DDR3_RON_RTT_26ohm (25)
+#define PHY_DDR3_RON_RTT_25ohm (26)
+#define PHY_DDR3_RON_RTT_23ohm (27)
+#define PHY_DDR3_RON_RTT_22ohm (28)
+#define PHY_DDR3_RON_RTT_21ohm (29)
+#define PHY_DDR3_RON_RTT_20ohm (30)
+#define PHY_DDR3_RON_RTT_19ohm (31)
+
+#define PHY_LP23_RON_RTT_DISABLE (0)
+#define PHY_LP23_RON_RTT_480ohm (1)
+#define PHY_LP23_RON_RTT_240ohm (2)
+#define PHY_LP23_RON_RTT_160ohm (3)
+#define PHY_LP23_RON_RTT_120ohm (4)
+#define PHY_LP23_RON_RTT_96ohm (5)
+#define PHY_LP23_RON_RTT_80ohm (6)
+#define PHY_LP23_RON_RTT_68ohm (7)
+#define PHY_LP23_RON_RTT_60ohm (16)
+#define PHY_LP23_RON_RTT_53ohm (17)
+#define PHY_LP23_RON_RTT_48ohm (18)
+#define PHY_LP23_RON_RTT_43ohm (19)
+#define PHY_LP23_RON_RTT_40ohm (20)
+#define PHY_LP23_RON_RTT_37ohm (21)
+#define PHY_LP23_RON_RTT_34ohm (22)
+#define PHY_LP23_RON_RTT_32ohm (23)
+#define PHY_LP23_RON_RTT_30ohm (24)
+#define PHY_LP23_RON_RTT_28ohm (25)
+#define PHY_LP23_RON_RTT_26ohm (26)
+#define PHY_LP23_RON_RTT_25ohm (27)
+#define PHY_LP23_RON_RTT_24ohm (28)
+#define PHY_LP23_RON_RTT_22ohm (29)
+#define PHY_LP23_RON_RTT_21ohm (30)
+#define PHY_LP23_RON_RTT_20ohm (31)
+
+#endif /* _DT_BINDINGS_DRAM_ROCKCHIP_RK322X_H */
diff --git a/include/soc/rockchip/rockchip_opp_select.h b/include/soc/rockchip/rockchip_opp_select.h
new file mode 100644
index 000000000000..b4317d030bd9
--- /dev/null
+++ b/include/soc/rockchip/rockchip_opp_select.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2017 Fuzhou Rockchip Electronics Co., Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#ifndef __SOC_ROCKCHIP_OPP_SELECT_H
+#define __SOC_ROCKCHIP_OPP_SELECT_H
+
+int rockchip_of_get_lkg_scale_sel(struct device *dev, char *name);
+int rockchip_of_get_lkg_volt_sel(struct device *dev, char *name);
+int rockchip_of_get_pvtm_volt_sel(struct device *dev,
+ char *clk_name,
+ char *reg_name);
+int rockchip_adjust_opp_by_irdrop(struct device *dev);
+
+#endif