diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2018-05-25 18:58:14 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2018-05-25 18:58:14 +0000 |
commit | 8c97d368fc30ce8bcb5e44e0af8f594edf1f1d55 (patch) | |
tree | 126a52e2303a9f6bc2ef842bcb413220663219b9 | |
parent | e1656ead165d4d90dbc07263c60f6231b23b3a52 (diff) | |
parent | 4db961ab5d9e2838fed5dd8bd839d478afb21c6a (diff) | |
download | rk-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.dtsi | 22 | ||||
-rw-r--r-- | arch/arm/boot/dts/rk322x-dram-default-timing.dtsi | 35 | ||||
-rw-r--r-- | arch/arm/boot/dts/rk322x.dtsi | 104 | ||||
-rw-r--r-- | drivers/clk/rockchip/clk-pll.c | 25 | ||||
-rw-r--r-- | drivers/clk/rockchip/clk-rk3228.c | 13 | ||||
-rw-r--r-- | drivers/clk/rockchip/clk.h | 1 | ||||
-rw-r--r-- | drivers/cpufreq/rockchip-cpufreq.c | 281 | ||||
-rw-r--r-- | drivers/devfreq/rockchip_dmc.c | 12 | ||||
-rwxr-xr-x | drivers/gpu/arm/mali400/mali/linux/mali_kernel_linux.c | 14 | ||||
-rw-r--r-- | drivers/gpu/arm/midgard/platform/rk/mali_kbase_config_rk.c | 282 | ||||
-rw-r--r-- | drivers/soc/rockchip/Makefile | 1 | ||||
-rw-r--r-- | drivers/soc/rockchip/rockchip_opp_select.c | 433 | ||||
-rw-r--r-- | include/dt-bindings/clock/rk3228-cru.h | 1 | ||||
-rw-r--r-- | include/dt-bindings/dram/rockchip,rk322x.h | 90 | ||||
-rw-r--r-- | include/soc/rockchip/rockchip_opp_select.h | 16 |
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 |