From 37f49e37ab4cb5d0bc4c60eb5c6d4dd57db767bb Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Fri, 10 May 2024 07:44:59 +0000
Subject: [PATCH] gmac get mac form eeprom
---
kernel/drivers/soc/rockchip/rockchip_opp_select.c | 327 +++++++++++++++++++++++++++++++++++++++++++++++++-----
1 files changed, 297 insertions(+), 30 deletions(-)
diff --git a/kernel/drivers/soc/rockchip/rockchip_opp_select.c b/kernel/drivers/soc/rockchip/rockchip_opp_select.c
index 82559da..6c496ad 100644
--- a/kernel/drivers/soc/rockchip/rockchip_opp_select.c
+++ b/kernel/drivers/soc/rockchip/rockchip_opp_select.c
@@ -12,6 +12,7 @@
#include <linux/nvmem-consumer.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
+#include <linux/rockchip/rockchip_sip.h>
#include <linux/slab.h>
#include <linux/soc/rockchip/pvtm.h>
#include <linux/thermal.h>
@@ -1004,15 +1005,15 @@
}
if (of_property_read_u32(np, "rockchip,pvtpll-len-min-rate", &min_rate))
- return;
+ goto out;
if (of_property_read_u32(np, "rockchip,pvtpll-len-max-rate", &max_rate))
- return;
+ goto out;
if (of_property_read_u32(np, "rockchip,pvtpll-len-margin", &margin))
- return;
+ goto out;
opp_table = dev_pm_opp_get_opp_table(info->dev);
if (!opp_table)
- return;
+ goto out;
old_rate = clk_get_rate(opp_table->clk);
opp_flag = OPP_ADD_LENGTH | ((margin & OPP_LENGTH_MASK) << OPP_LENGTH_SHIFT);
@@ -1033,8 +1034,97 @@
clk_set_rate(opp_table->clk, old_rate);
dev_pm_opp_put_opp_table(opp_table);
+out:
+ of_node_put(np);
}
EXPORT_SYMBOL(rockchip_pvtpll_add_length);
+
+void rockchip_init_pvtpll_table(struct rockchip_opp_info *info, int bin)
+{
+ struct device_node *np = NULL;
+ struct property *prop = NULL;
+ struct of_phandle_args clkspec = { 0 };
+ struct arm_smccc_res res;
+ char prop_name[NAME_MAX];
+ u32 *value;
+ int count;
+ int ret, i;
+
+ if (!info)
+ return;
+
+ np = of_parse_phandle(info->dev->of_node, "operating-points-v2", 0);
+ if (!np) {
+ dev_warn(info->dev, "OPP-v2 not supported\n");
+ return;
+ }
+
+ ret = of_parse_phandle_with_args(info->dev->of_node, "clocks",
+ "#clock-cells", 0, &clkspec);
+ if (ret)
+ goto out;
+ info->pvtpll_clk_id = clkspec.args[0];
+ of_node_put(clkspec.np);
+
+ res = sip_smc_get_pvtpll_info(PVTPLL_GET_INFO, info->pvtpll_clk_id);
+ if (res.a0)
+ goto out;
+ if (!res.a1)
+ info->pvtpll_low_temp = true;
+
+ if (bin > 0) {
+ snprintf(prop_name, sizeof(prop_name),
+ "rockchip,pvtpll-table-B%d", bin);
+ prop = of_find_property(np, prop_name, NULL);
+ }
+ if (!prop)
+ sprintf(prop_name, "rockchip,pvtpll-table");
+
+ prop = of_find_property(np, prop_name, NULL);
+ if (!prop)
+ goto out;
+
+ count = of_property_count_u32_elems(np, prop_name);
+ if (count < 0) {
+ dev_err(info->dev, "%s: Invalid %s property (%d)\n",
+ __func__, prop_name, count);
+ goto out;
+ } else if (count % 5) {
+ dev_err(info->dev, "Invalid count of %s\n", prop_name);
+ goto out;
+ }
+
+ value = kmalloc_array(count, sizeof(*value), GFP_KERNEL);
+ if (!value)
+ goto out;
+ ret = of_property_read_u32_array(np, prop_name, value, count);
+ if (ret) {
+ dev_err(info->dev, "%s: error parsing %s: %d\n",
+ __func__, prop_name, ret);
+ goto free_value;
+ }
+
+ for (i = 0; i < count; i += 5) {
+ res = sip_smc_pvtpll_config(PVTPLL_ADJUST_TABLE,
+ info->pvtpll_clk_id, value[i],
+ value[i + 1], value[i + 2],
+ value[i + 3], value[i + 4]);
+ if (res.a0) {
+ dev_err(info->dev,
+ "%s: error cfg clk_id=%u %u %u %u %u %u (%d)\n",
+ __func__, info->pvtpll_clk_id, value[i],
+ value[i + 1], value[i + 2], value[i + 3],
+ value[i + 4], (int)res.a0);
+ goto free_value;
+ }
+ }
+
+free_value:
+ kfree(value);
+out:
+ of_node_put(np);
+}
+EXPORT_SYMBOL(rockchip_init_pvtpll_table);
static int rockchip_get_pvtm_pvtpll(struct device *dev, struct device_node *np,
char *reg_name)
@@ -1165,12 +1255,13 @@
}
void rockchip_of_get_pvtm_sel(struct device *dev, struct device_node *np,
- char *reg_name, int process,
+ char *reg_name, int bin, int process,
int *volt_sel, int *scale_sel)
{
struct property *prop = NULL;
char name[NAME_MAX];
int pvtm, ret;
+ u32 hw = 0;
if (of_property_read_bool(np, "rockchip,pvtm-pvtpll"))
pvtm = rockchip_get_pvtm_pvtpll(dev, np, reg_name);
@@ -1185,6 +1276,17 @@
snprintf(name, sizeof(name),
"rockchip,p%d-pvtm-voltage-sel", process);
prop = of_find_property(np, name, NULL);
+ } else if (bin > 0) {
+ of_property_read_u32(np, "rockchip,pvtm-hw", &hw);
+ if (hw && (hw & BIT(bin))) {
+ sprintf(name, "rockchip,pvtm-voltage-sel-hw");
+ prop = of_find_property(np, name, NULL);
+ }
+ if (!prop) {
+ snprintf(name, sizeof(name),
+ "rockchip,pvtm-voltage-sel-B%d", bin);
+ prop = of_find_property(np, name, NULL);
+ }
}
if (!prop)
sprintf(name, "rockchip,pvtm-voltage-sel");
@@ -1195,6 +1297,7 @@
next:
if (!scale_sel)
return;
+ prop = NULL;
if (process >= 0) {
snprintf(name, sizeof(name),
"rockchip,p%d-pvtm-scaling-sel", process);
@@ -1294,6 +1397,46 @@
}
EXPORT_SYMBOL(rockchip_get_volt_rm_table);
+int rockchip_get_soc_info(struct device *dev, struct device_node *np, int *bin,
+ int *process)
+{
+ u8 value = 0;
+ int ret = 0;
+
+ if (*bin >= 0 || *process >= 0)
+ return 0;
+
+ if (of_property_match_string(np, "nvmem-cell-names",
+ "remark_spec_serial_number") >= 0)
+ rockchip_nvmem_cell_read_u8(np, "remark_spec_serial_number", &value);
+
+ if (!value && of_property_match_string(np, "nvmem-cell-names",
+ "specification_serial_number") >= 0) {
+ ret = rockchip_nvmem_cell_read_u8(np,
+ "specification_serial_number",
+ &value);
+ if (ret) {
+ dev_err(dev,
+ "Failed to get specification_serial_number\n");
+ return ret;
+ }
+ }
+
+ /* M */
+ if (value == 0xd)
+ *bin = 1;
+ /* J */
+ else if (value == 0xa)
+ *bin = 2;
+
+ if (*bin < 0)
+ *bin = 0;
+ dev_info(dev, "bin=%d\n", *bin);
+
+ return 0;
+}
+EXPORT_SYMBOL(rockchip_get_soc_info);
+
void rockchip_get_scale_volt_sel(struct device *dev, char *lkg_name,
char *reg_name, int bin, int process,
int *scale, int *volt_sel)
@@ -1311,7 +1454,7 @@
rockchip_of_get_lkg_sel(dev, np, lkg_name, process,
&lkg_volt_sel, &lkg_scale);
- rockchip_of_get_pvtm_sel(dev, np, reg_name, process,
+ rockchip_of_get_pvtm_sel(dev, np, reg_name, bin, process,
&pvtm_volt_sel, &pvtm_scale);
rockchip_of_get_bin_sel(dev, np, bin, &bin_scale);
rockchip_of_get_bin_volt_sel(dev, np, bin, &bin_volt_sel);
@@ -1348,6 +1491,42 @@
return dev_pm_opp_set_prop_name(dev, name);
}
EXPORT_SYMBOL(rockchip_set_opp_prop_name);
+
+struct opp_table *rockchip_set_opp_supported_hw(struct device *dev,
+ struct device_node *np,
+ int bin, int volt_sel)
+{
+ struct opp_table *opp_table;
+ u32 supported_hw[2];
+ u32 version = 0, speed = 0;
+
+ if (!of_property_read_bool(np, "rockchip,supported-hw"))
+ return NULL;
+
+ opp_table = dev_pm_opp_get_opp_table(dev);
+ if (!opp_table)
+ return NULL;
+ if (opp_table->supported_hw) {
+ dev_pm_opp_put_opp_table(opp_table);
+ return NULL;
+ }
+ dev_pm_opp_put_opp_table(opp_table);
+
+ if (bin >= 0)
+ version = bin;
+ if (volt_sel >= 0)
+ speed = volt_sel;
+
+ /* SoC Version */
+ supported_hw[0] = BIT(version);
+ /* Speed Grade */
+ supported_hw[1] = BIT(speed);
+
+ dev_info(dev, "soc version=%d, speed=%d\n", version, speed);
+
+ return dev_pm_opp_set_supported_hw(dev, supported_hw, 2);
+}
+EXPORT_SYMBOL(rockchip_set_opp_supported_hw);
static int rockchip_adjust_opp_by_irdrop(struct device *dev,
struct device_node *np,
@@ -1484,9 +1663,14 @@
if (opp->rate > opp_info.max_freq * 1000000)
continue;
- opp->supplies->u_volt += opp_info.volt * 1000;
- if (opp->supplies->u_volt > opp->supplies->u_volt_max)
- opp->supplies->u_volt = opp->supplies->u_volt_max;
+ opp->supplies[0].u_volt += opp_info.volt * 1000;
+ if (opp->supplies[0].u_volt > opp->supplies[0].u_volt_max)
+ opp->supplies[0].u_volt = opp->supplies[0].u_volt_max;
+ if (opp_table->regulator_count > 1) {
+ opp->supplies[1].u_volt += opp_info.volt * 1000;
+ if (opp->supplies[1].u_volt > opp->supplies[1].u_volt_max)
+ opp->supplies[1].u_volt = opp->supplies[1].u_volt_max;
+ }
}
mutex_unlock(&opp_table->lock);
@@ -1544,6 +1728,10 @@
rockchip_adjust_opp_by_irdrop(dev, np, &safe_rate, &max_rate);
dev_info(dev, "avs=%d\n", avs);
+
+ if (!safe_rate && !scale)
+ goto out_np;
+
clk = of_clk_get_by_name(np, NULL);
if (IS_ERR(clk)) {
if (!safe_rate)
@@ -1557,14 +1745,14 @@
if (safe_rate)
irdrop_scale = rockchip_pll_clk_rate_to_scale(clk, safe_rate);
- if (max_rate)
- opp_scale = rockchip_pll_clk_rate_to_scale(clk, max_rate);
target_scale = max(irdrop_scale, scale);
if (target_scale <= 0)
goto out_clk;
dev_dbg(dev, "target_scale=%d, irdrop_scale=%d, scale=%d\n",
target_scale, irdrop_scale, scale);
+ if (max_rate)
+ opp_scale = rockchip_pll_clk_rate_to_scale(clk, max_rate);
if (avs == AVS_SCALING_RATE) {
ret = rockchip_pll_clk_adaptive_scaling(clk, target_scale);
if (ret)
@@ -1749,13 +1937,78 @@
}
EXPORT_SYMBOL(rockchip_set_intermediate_rate);
+static int rockchip_get_opp_clk(struct device *dev, struct device_node *np,
+ struct rockchip_opp_info *info)
+{
+ struct clk_bulk_data *clks;
+ struct of_phandle_args clkspec;
+ int ret = 0, num_clks = 0, i;
+
+ if (of_find_property(np, "rockchip,opp-clocks", NULL)) {
+ num_clks = of_count_phandle_with_args(np, "rockchip,opp-clocks",
+ "#clock-cells");
+ if (num_clks <= 0)
+ return 0;
+ clks = devm_kcalloc(dev, num_clks, sizeof(*clks), GFP_KERNEL);
+ if (!clks)
+ return -ENOMEM;
+ for (i = 0; i < num_clks; i++) {
+ ret = of_parse_phandle_with_args(np,
+ "rockchip,opp-clocks",
+ "#clock-cells", i,
+ &clkspec);
+ if (ret < 0) {
+ dev_err(dev, "%s: failed to parse opp clk %d\n",
+ np->name, i);
+ goto error;
+ }
+ clks[i].clk = of_clk_get_from_provider(&clkspec);
+ of_node_put(clkspec.np);
+ if (IS_ERR(clks[i].clk)) {
+ ret = PTR_ERR(clks[i].clk);
+ clks[i].clk = NULL;
+ dev_err(dev, "%s: failed to get opp clk %d\n",
+ np->name, i);
+ goto error;
+ }
+ }
+ } else {
+ num_clks = of_clk_get_parent_count(np);
+ if (num_clks <= 0)
+ return 0;
+ clks = devm_kcalloc(dev, num_clks, sizeof(*clks), GFP_KERNEL);
+ if (!clks)
+ return -ENOMEM;
+ for (i = 0; i < num_clks; i++) {
+ clks[i].clk = of_clk_get(np, i);
+ if (IS_ERR(clks[i].clk)) {
+ ret = PTR_ERR(clks[i].clk);
+ clks[i].clk = NULL;
+ dev_err(dev, "%s: failed to get clk %d\n",
+ np->name, i);
+ goto error;
+ }
+ }
+ }
+ info->clks = clks;
+ info->num_clks = num_clks;
+
+ return 0;
+error:
+ while (--i >= 0)
+ clk_put(clks[i].clk);
+ devm_kfree(dev, clks);
+
+ return ret;
+}
+
int rockchip_init_opp_table(struct device *dev, struct rockchip_opp_info *info,
char *lkg_name, char *reg_name)
{
struct device_node *np;
int bin = -EINVAL, process = -EINVAL;
int scale = 0, volt_sel = -EINVAL;
- int ret = 0, num_clks = 0, i;
+ int ret = 0;
u32 freq;
/* Get OPP descriptor node */
@@ -1768,24 +2021,10 @@
goto next;
info->dev = dev;
- num_clks = of_clk_get_parent_count(np);
- if (num_clks > 0) {
- info->clks = devm_kcalloc(dev, num_clks, sizeof(*info->clks),
- GFP_KERNEL);
- if (!info->clks) {
- ret = -ENOMEM;
- goto out;
- }
- for (i = 0; i < num_clks; i++) {
- info->clks[i].clk = of_clk_get(np, i);
- if (IS_ERR(info->clks[i].clk)) {
- ret = PTR_ERR(info->clks[i].clk);
- dev_err(dev, "%s: failed to get clk %d\n",
- np->name, i);
- goto out;
- }
- }
- info->num_clks = num_clks;
+ ret = rockchip_get_opp_clk(dev, np, info);
+ if (ret)
+ goto out;
+ if (info->clks) {
ret = clk_bulk_prepare_enable(info->num_clks, info->clks);
if (ret) {
dev_err(dev, "failed to enable opp clks\n");
@@ -1810,11 +2049,14 @@
info->data->get_soc_info(dev, np, &bin, &process);
next:
+ rockchip_get_soc_info(dev, np, &bin, &process);
+ rockchip_init_pvtpll_table(info, bin);
rockchip_get_scale_volt_sel(dev, lkg_name, reg_name, bin, process,
&scale, &volt_sel);
if (info && info->data && info->data->set_soc_info)
info->data->set_soc_info(dev, np, bin, process, volt_sel);
rockchip_set_opp_prop_name(dev, process, volt_sel);
+ rockchip_set_opp_supported_hw(dev, np, bin, volt_sel);
ret = dev_pm_opp_of_add_table(dev);
if (ret) {
dev_err(dev, "Invalid operating-points in device tree.\n");
@@ -1834,6 +2076,31 @@
}
EXPORT_SYMBOL(rockchip_init_opp_table);
+void rockchip_uninit_opp_table(struct device *dev, struct rockchip_opp_info *info)
+{
+ struct opp_table *opp_table;
+
+ if (info) {
+ kfree(info->opp_table);
+ info->opp_table = NULL;
+ devm_kfree(dev, info->clks);
+ info->clks = NULL;
+ devm_kfree(dev, info->volt_rm_tbl);
+ info->volt_rm_tbl = NULL;
+ }
+
+ opp_table = dev_pm_opp_get_opp_table(dev);
+ if (IS_ERR(opp_table))
+ return;
+ dev_pm_opp_of_remove_table(dev);
+ if (opp_table->prop_name)
+ dev_pm_opp_put_prop_name(opp_table);
+ if (opp_table->supported_hw)
+ dev_pm_opp_put_supported_hw(opp_table);
+ dev_pm_opp_put_opp_table(opp_table);
+}
+EXPORT_SYMBOL(rockchip_uninit_opp_table);
+
MODULE_DESCRIPTION("ROCKCHIP OPP Select");
MODULE_AUTHOR("Finley Xiao <finley.xiao@rock-chips.com>, Liang Chen <cl@rock-chips.com>");
MODULE_LICENSE("GPL");
--
Gitblit v1.6.2