soc: rockchip: pvtm: Update driver to use clk_bulk and reset array APIs

Change-Id: Ie6ab946fa95fd69607150bd5d48c78f0f58d387d
Signed-off-by: Finley Xiao <finley.xiao@rock-chips.com>
This commit is contained in:
Finley Xiao
2020-04-20 20:57:09 +08:00
committed by Tao Huang
parent 7204bbf8af
commit da913c30e2
7 changed files with 286 additions and 138 deletions

View File

@@ -19,14 +19,12 @@ Required properties:
- "rockchip,rk3399-pmu-pvtm" - for RK3399 SoCs.
- clocks: Must contain an entry for each entry in clock-names.
See ../../clocks/clock-bindings.txt for details.
- clock-names: Should be "clk", "pclk", "core_l", "core_b", "gpu", "ddr" and
"pmu".
- clock-names: Should be "clk", "pclk".
Optional properties:
- resets: Must contain an entry for each entry in reset-names.
See ../../reset/reset.txt for details.
- reset-names: Should be "clk", "pclk", "core_l", "core_b", "gpu", "ddr" and
"pmu".
- reset-names: Should be "rst", "rst-p".
Example:
@@ -41,11 +39,37 @@ grf: syscon@ff770000 {
pvtm: pvtm {
compatible = "rockchip,rk3399-pvtm";
clocks = <&cru SCLK_PVTM_CORE_L>, <&cru SCLK_PVTM_CORE_B>,
<&cru SCLK_PVTM_GPU>, <&cru SCLK_PVTM_DDR>;
clock-names = "core_l", "core_b", "gpu", "ddr";
resets = <&cru SRST_PVTM_CORE_L>, <&cru SRST_PVTM_CORE_B>,
<&cru SRST_PVTM_GPU>, <&cru SRST_PVTM_DDR>;
reset-names = "core_l", "core_b", "gpu", "ddr";
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
pvtm@0 {
reg = <0>;
clocks = <&cru SCLK_PVTM_CORE_L>;
clock-names = "clk";
resets = <&cru SRST_PVTM_CORE_L>;
reset-names = "rst";
};
pvtm@1 {
reg = <1>;
clocks = <&cru SCLK_PVTM_CORE_B>;
clock-names = "clk";
resets = <&cru SRST_PVTM_CORE_B>;
reset-names = "rst";
};
pvtm@2 {
reg = <2>;
clocks = <&cru SCLK_PVTM_DDR>;
clock-names = "clk";
resets = <&cru SRST_PVTM_DDR>;
reset-names = "rst";
};
pvtm@3 {
reg = <3>;
clocks = <&cru SCLK_PVTM_GPU>;
clock-names = "clk";
resets = <&cru SRST_PVTM_GPU>;
reset-names = "rst";
};
};
}

View File

@@ -1155,11 +1155,24 @@
pvtm: pvtm {
compatible = "rockchip,rk3288-pvtm";
clocks = <&cru SCLK_PVTM_CORE>, <&cru SCLK_PVTM_GPU>;
clock-names = "core", "gpu";
resets = <&cru SRST_CORE_PVTM>, <&cru SRST_GPU_PVTM>;
reset-names = "core", "gpu";
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
pvtm@0 {
reg = <0>;
clocks = <&cru SCLK_PVTM_CORE>;
clock-names = "clk";
resets = <&cru SRST_CORE_PVTM>;
reset-names = "rst";
};
pvtm@1 {
reg = <1>;
clocks = <&cru SCLK_PVTM_GPU>;
clock-names = "clk";
resets = <&cru SRST_GPU_PVTM>;
reset-names = "rst";
};
};
};

View File

@@ -469,9 +469,15 @@
pmu_pvtm: pmu-pvtm {
compatible = "rockchip,px30-pmu-pvtm";
clocks = <&pmucru SCLK_PVTM_PMU>;
clock-names = "pmu";
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
pvtm@1 {
reg = <1>;
clocks = <&pmucru SCLK_PVTM_PMU>;
clock-names = "clk";
};
};
};
@@ -690,9 +696,15 @@
pvtm: pvtm {
compatible = "rockchip,px30-pvtm";
clocks = <&cru SCLK_PVTM>;
clock-names = "core";
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
pvtm@0 {
reg = <0>;
clocks = <&cru SCLK_PVTM>;
clock-names = "clk";
};
};
};

View File

@@ -391,9 +391,15 @@
npu_pvtm: npu-pvtm {
compatible = "rockchip,rk1808-npu-pvtm";
clocks = <&cru SCLK_PVTM_NPU>;
clock-names = "npu";
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
pvtm@2 {
reg = <2>;
clocks = <&cru SCLK_PVTM_NPU>;
clock-names = "clk";
}
};
rgb: rgb {
@@ -465,9 +471,15 @@
pmu_pvtm: pmu-pvtm {
compatible = "rockchip,rk1808-pmu-pvtm";
clocks = <&cru SCLK_PVTM_PMU>;
clock-names = "pmu";
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
pvtm@1 {
reg = <1>;
clocks = <&cru SCLK_PVTM_PMU>;
clock-names = "clk";
};
};
reboot-mode {
@@ -496,9 +508,15 @@
pvtm: pvtm {
compatible = "rockchip,rk1808-pvtm";
clocks = <&cru SCLK_PVTM_CORE>;
clock-names = "core";
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
pvtm@0 {
reg = <0>;
clocks = <&cru SCLK_PVTM_CORE>;
clock-names = "clk";
};
};
};

View File

@@ -373,8 +373,14 @@
pmu_pvtm: pmu-pvtm {
compatible = "rockchip,rk3308-pmu-pvtm";
clocks = <&cru SCLK_PVTM_PMU>;
clock-names = "pmu";
#address-cells = <1>;
#size-cells = <0>;
pvtm@1 {
reg = <1>;
clocks = <&cru SCLK_PVTM_PMU>;
clock-names = "clk";
};
};
reboot-mode {
@@ -403,8 +409,14 @@
pvtm: pvtm {
compatible = "rockchip,rk3308-pvtm";
clocks = <&cru SCLK_PVTM_CORE>;
clock-names = "core";
#address-cells = <1>;
#size-cells = <0>;
pvtm@0 {
reg = <0>;
clocks = <&cru SCLK_PVTM_CORE>;
clock-names = "clk";
};
};
};

View File

@@ -1172,11 +1172,17 @@
pmu_pvtm: pmu-pvtm {
compatible = "rockchip,rk3399-pmu-pvtm";
clocks = <&pmucru SCLK_PVTM_PMU>;
clock-names = "pmu";
resets = <&cru SRST_PVTM>;
reset-names = "pmu";
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
pvtm@4 {
reg = <4>;
clocks = <&pmucru SCLK_PVTM_PMU>;
clock-names = "clk";
resets = <&cru SRST_PVTM>;
reset-names = "rst";
};
};
};
@@ -1616,17 +1622,38 @@
pvtm: pvtm {
compatible = "rockchip,rk3399-pvtm";
clocks = <&cru SCLK_PVTM_CORE_L>,
<&cru SCLK_PVTM_CORE_B>,
<&cru SCLK_PVTM_GPU>,
<&cru SCLK_PVTM_DDR>;
clock-names = "core_l", "core_b", "gpu", "ddr";
resets = <&cru SRST_PVTM_CORE_L>,
<&cru SRST_PVTM_CORE_B>,
<&cru SRST_PVTM_GPU>,
<&cru SRST_PVTM_DDR>;
reset-names = "core_l", "core_b", "gpu", "ddr";
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
pvtm@0 {
reg = <0>;
clocks = <&cru SCLK_PVTM_CORE_L>;
clock-names = "clk";
resets = <&cru SRST_PVTM_CORE_L>;
reset-names = "rst";
};
pvtm@1 {
reg = <1>;
clocks = <&cru SCLK_PVTM_CORE_B>;
clock-names = "clk";
resets = <&cru SRST_PVTM_CORE_B>;
reset-names = "rst";
};
pvtm@2 {
reg = <2>;
clocks = <&cru SCLK_PVTM_DDR>;
clock-names = "clk";
resets = <&cru SRST_PVTM_DDR>;
reset-names = "rst";
};
pvtm@3 {
reg = <3>;
clocks = <&cru SCLK_PVTM_GPU>;
clock-names = "clk";
resets = <&cru SRST_PVTM_GPU>;
reset-names = "rst";
};
};
};

View File

@@ -14,6 +14,7 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_clk.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
@@ -22,30 +23,12 @@
#include <linux/soc/rockchip/pvtm.h>
#include <linux/thermal.h>
#define PX30_PVTM_CORE 0
#define PX30_PVTM_PMU 1
#define RK1808_PVTM_CORE 0
#define RK1808_PVTM_PMU 1
#define RK1808_PVTM_NPU 2
#define RK3288_PVTM_CORE 0
#define RK3288_PVTM_GPU 1
#define RK3399_PVTM_CORE_L 0
#define RK3399_PVTM_CORE_B 1
#define RK3399_PVTM_DDR 2
#define RK3399_PVTM_GPU 3
#define RK3399_PVTM_PMU 4
#define PVTM_START_EN 0x1
#define wr_mask_bit(v, off, mask) ((v) << (off) | (mask) << (16 + off))
#define PVTM(_ch, _name, _num_sub, _start, _en, _cal, _done, _freq) \
{ \
.ch = _ch, \
.clk_name = _name, \
.name = _name, \
.num_sub = _num_sub, \
.bit_start = _start, \
.bit_en = _en, \
@@ -60,7 +43,7 @@ struct rockchip_pvtm_channel {
u32 reg_cal;
u32 reg_freq;
unsigned char ch;
unsigned char *clk_name;
unsigned char *name;
unsigned int num_sub;
unsigned int bit_start;
unsigned int bit_en;
@@ -83,7 +66,8 @@ struct rockchip_pvtm {
struct list_head node;
struct device *dev;
struct regmap *grf;
struct clk *clk;
int num_clks;
struct clk_bulk_data *clks;
struct reset_control *rst;
const struct rockchip_pvtm_channel *channel;
struct thermal_zone_device *tz;
@@ -155,10 +139,10 @@ static int __init pvtm_debug_init(void)
}
list_for_each_entry(pvtm, &pvtm_list, node) {
dentry = debugfs_create_dir(pvtm->channel->clk_name, rootdir);
dentry = debugfs_create_dir(pvtm->channel->name, rootdir);
if (!dentry) {
dev_err(pvtm->dev, "failed to creat pvtm %s debug dir\n",
pvtm->channel->clk_name);
pvtm->channel->name);
return -ENOMEM;
}
@@ -166,7 +150,7 @@ static int __init pvtm_debug_init(void)
(void *)pvtm, &pvtm_value_fops);
if (!d) {
dev_err(pvtm->dev, "failed to pvtm %s value node\n",
pvtm->channel->clk_name);
pvtm->channel->name);
return -ENOMEM;
}
}
@@ -269,12 +253,12 @@ static void rk3399_pvtm_set_ring_sel(struct rockchip_pvtm *pvtm,
{
unsigned int ch = pvtm->channel->ch;
if (ch == RK3399_PVTM_CORE_B) {
if (ch == 1) {
regmap_write(pvtm->grf, pvtm->con + 0x14,
wr_mask_bit(sub_ch >> 0x3, 0, 0x1));
sub_ch &= 0x3;
}
if (ch != RK3399_PVTM_PMU)
if (ch != 4)
regmap_write(pvtm->grf, pvtm->con,
wr_mask_bit(sub_ch, (ch * 0x4 + 0x2), 0x3));
}
@@ -284,28 +268,24 @@ static u32 rockchip_pvtm_get_value(struct rockchip_pvtm *pvtm,
unsigned int time_us)
{
const struct rockchip_pvtm_channel *channel = pvtm->channel;
unsigned int ch = pvtm->channel->ch;
unsigned int clk_cnt, check_cnt = 100;
u32 sta, val = 0;
int ret;
ret = clk_prepare_enable(pvtm->clk);
ret = clk_bulk_prepare_enable(pvtm->num_clks, pvtm->clks);
if (ret < 0) {
dev_err(pvtm->dev, "failed to enable %d\n", ch);
dev_err(pvtm->dev, "failed to prepare/enable pvtm clks\n");
return 0;
}
if (pvtm->rst) {
ret = rockchip_pvtm_reset(pvtm);
if (ret) {
clk_disable_unprepare(pvtm->clk);
return 0;
}
ret = rockchip_pvtm_reset(pvtm);
if (ret) {
dev_err(pvtm->dev, "failed to reset pvtm\n");
goto disable_clks;
}
/* if last status is enabled, stop calculating cycles first*/
regmap_read(pvtm->grf, pvtm->con, &sta);
if (sta & PVTM_START_EN)
if (sta & BIT(channel->bit_en))
regmap_write(pvtm->grf, pvtm->con,
wr_mask_bit(0, channel->bit_start, 0x1));
@@ -345,13 +325,14 @@ static u32 rockchip_pvtm_get_value(struct rockchip_pvtm *pvtm,
regmap_write(pvtm->grf, pvtm->con,
wr_mask_bit(0, channel->bit_en, 0x1));
clk_disable_unprepare(pvtm->clk);
disable_clks:
clk_bulk_disable_unprepare(pvtm->num_clks, pvtm->clks);
return val;
}
static const struct rockchip_pvtm_channel px30_pvtm_channels[] = {
PVTM(PX30_PVTM_CORE, "core", 3, 0, 1, 0x4, 0, 0x4),
PVTM(0, "core", 3, 0, 1, 0x4, 0, 0x4),
};
static const struct rockchip_pvtm_info px30_pvtm = {
@@ -364,7 +345,7 @@ static const struct rockchip_pvtm_info px30_pvtm = {
};
static const struct rockchip_pvtm_channel px30_pmupvtm_channels[] = {
PVTM(PX30_PVTM_PMU, "pmu", 1, 0, 1, 0x4, 0, 0x4),
PVTM(1, "pmu", 1, 0, 1, 0x4, 0, 0x4),
};
static const struct rockchip_pvtm_info px30_pmupvtm = {
@@ -376,7 +357,7 @@ static const struct rockchip_pvtm_info px30_pmupvtm = {
};
static const struct rockchip_pvtm_channel rk1808_pvtm_channels[] = {
PVTM(RK1808_PVTM_CORE, "core", 5, 0, 1, 0x4, 0, 0x4),
PVTM(0, "core", 5, 0, 1, 0x4, 0, 0x4),
};
static const struct rockchip_pvtm_info rk1808_pvtm = {
@@ -389,7 +370,7 @@ static const struct rockchip_pvtm_info rk1808_pvtm = {
};
static const struct rockchip_pvtm_channel rk1808_pmupvtm_channels[] = {
PVTM(RK1808_PVTM_PMU, "pmu", 1, 0, 1, 0x4, 0, 0x4),
PVTM(1, "pmu", 1, 0, 1, 0x4, 0, 0x4),
};
static const struct rockchip_pvtm_info rk1808_pmupvtm = {
@@ -401,7 +382,7 @@ static const struct rockchip_pvtm_info rk1808_pmupvtm = {
};
static const struct rockchip_pvtm_channel rk1808_npupvtm_channels[] = {
PVTM(RK1808_PVTM_NPU, "npu", 5, 0, 1, 0x4, 0, 0x4),
PVTM(2, "npu", 5, 0, 1, 0x4, 0, 0x4),
};
static const struct rockchip_pvtm_info rk1808_npupvtm = {
@@ -414,8 +395,8 @@ static const struct rockchip_pvtm_info rk1808_npupvtm = {
};
static const struct rockchip_pvtm_channel rk3288_pvtm_channels[] = {
PVTM(RK3288_PVTM_CORE, "core", 1, 0, 1, 0x4, 1, 0x4),
PVTM(RK3288_PVTM_GPU, "gpu", 1, 8, 9, 0x8, 0, 0x8),
PVTM(0, "core", 1, 0, 1, 0x4, 1, 0x4),
PVTM(1, "gpu", 1, 8, 9, 0x8, 0, 0x8),
};
static const struct rockchip_pvtm_info rk3288_pvtm = {
@@ -435,10 +416,10 @@ static const struct rockchip_pvtm_info rk3308_pmupvtm = {
};
static const struct rockchip_pvtm_channel rk3399_pvtm_channels[] = {
PVTM(RK3399_PVTM_CORE_L, "core_l", 4, 0, 1, 0x4, 0, 0x4),
PVTM(RK3399_PVTM_CORE_B, "core_b", 6, 4, 5, 0x8, 1, 0x8),
PVTM(RK3399_PVTM_DDR, "ddr", 4, 8, 9, 0xc, 3, 0x10),
PVTM(RK3399_PVTM_GPU, "gpu", 4, 12, 13, 0x10, 2, 0xc),
PVTM(0, "core_l", 4, 0, 1, 0x4, 0, 0x4),
PVTM(1, "core_b", 6, 4, 5, 0x8, 1, 0x8),
PVTM(2, "ddr", 4, 8, 9, 0xc, 3, 0x10),
PVTM(3, "gpu", 4, 12, 13, 0x10, 2, 0xc),
};
static const struct rockchip_pvtm_info rk3399_pvtm = {
@@ -451,7 +432,7 @@ static const struct rockchip_pvtm_info rk3399_pvtm = {
};
static const struct rockchip_pvtm_channel rk3399_pmupvtm_channels[] = {
PVTM(RK3399_PVTM_PMU, "pmu", 1, 0, 1, 0x4, 0, 0x4),
PVTM(4, "pmu", 1, 0, 1, 0x4, 0, 0x4),
};
static const struct rockchip_pvtm_info rk3399_pmupvtm = {
@@ -507,17 +488,109 @@ static const struct of_device_id rockchip_pvtm_match[] = {
};
MODULE_DEVICE_TABLE(of, rockchip_pvtm_match);
static int rockchip_pvtm_get_ch_index(const struct rockchip_pvtm_info *info,
u32 ch, u32 *index)
{
int i;
for (i = 0; i < info->num_channels; i++) {
if (ch == info->channels[i].ch) {
*index = i;
return 0;
}
}
return -EINVAL;
}
static struct rockchip_pvtm *
rockchip_pvtm_init(struct device *dev, struct device_node *node,
const struct rockchip_pvtm_info *info,
struct regmap *grf)
{
struct rockchip_pvtm *pvtm;
const char *tz_name;
u32 ch, index, i;
if (of_property_read_u32(node, "reg", &ch)) {
dev_err(dev, "%s: failed to retrieve pvtm ch\n", node->name);
return NULL;
}
if (rockchip_pvtm_get_ch_index(info, ch, &index)) {
dev_err(dev, "%s: invalid pvtm ch %d\n", node->name, ch);
return NULL;
}
pvtm = devm_kzalloc(dev, sizeof(*pvtm), GFP_KERNEL);
if (!pvtm)
return NULL;
pvtm->dev = dev;
pvtm->grf = grf;
pvtm->con = info->con;
pvtm->sta = info->sta;
pvtm->get_value = info->get_value;
pvtm->channel = &info->channels[index];
if (info->set_ring_sel)
pvtm->set_ring_sel = info->set_ring_sel;
if (!of_property_read_string(node, "thermal-zone", &tz_name)) {
pvtm->tz = thermal_zone_get_zone_by_name(tz_name);
if (IS_ERR(pvtm->tz)) {
dev_err(pvtm->dev, "failed to retrieve pvtm_tz\n");
pvtm->tz = NULL;
}
}
pvtm->num_clks = of_clk_get_parent_count(node);
if (pvtm->num_clks <= 0) {
dev_err(dev, "%s: does not have clocks\n", node->name);
return NULL;
}
pvtm->clks = devm_kcalloc(dev, pvtm->num_clks, sizeof(*pvtm->clks),
GFP_KERNEL);
if (!pvtm->clks)
return NULL;
for (i = 0; i < pvtm->num_clks; i++) {
pvtm->clks[i].clk = of_clk_get(node, i);
if (IS_ERR(pvtm->clks[i].clk)) {
dev_err(dev, "%s: failed to get clk at index %d\n",
node->name, i);
return NULL;
}
}
pvtm->rst = devm_reset_control_array_get_optional_exclusive(dev);
if (IS_ERR(pvtm->rst))
dev_dbg(dev, "%s: failed to get reset\n", node->name);
return pvtm;
}
static void rockchip_del_pvtm(const struct rockchip_pvtm_info *info)
{
struct rockchip_pvtm *pvtm, *tmp;
int i;
if (list_empty(&pvtm_list))
return;
for (i = 0; i < info->num_channels; i++) {
list_for_each_entry_safe(pvtm, tmp, &pvtm_list, node) {
if (pvtm->channel->ch == info->channels[i].ch)
list_del(&pvtm->node);
}
}
}
static int rockchip_pvtm_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = pdev->dev.of_node;
struct device_node *node;
const struct of_device_id *match;
const struct rockchip_pvtm_info *info;
struct rockchip_pvtm *pvtm;
struct regmap *grf;
struct thermal_zone_device *pvtm_tz = NULL;
const char *tz_name;
int i;
match = of_match_device(dev->driver->of_match_table, dev);
if (!match || !match->data) {
@@ -525,58 +598,27 @@ static int rockchip_pvtm_probe(struct platform_device *pdev)
return -EINVAL;
}
info = match->data;
if (!dev->parent || !dev->parent->of_node)
return -EINVAL;
grf = syscon_node_to_regmap(dev->parent->of_node);
if (IS_ERR(grf))
return PTR_ERR(grf);
pvtm = devm_kzalloc(dev, sizeof(*pvtm) * info->num_channels,
GFP_KERNEL);
if (!pvtm)
return -ENOMEM;
if (!of_property_read_string(np, "thermal-zone", &tz_name)) {
pvtm_tz = thermal_zone_get_zone_by_name(tz_name);
if (IS_ERR(pvtm_tz)) {
dev_err(dev, "debug failed to get pvtm_tz\n");
pvtm_tz = NULL;
for_each_available_child_of_node(np, node) {
pvtm = rockchip_pvtm_init(dev, node, match->data, grf);
if (!pvtm) {
dev_err(dev, "failed to handle node %s\n", node->name);
goto error;
}
}
for (i = 0; i < info->num_channels; i++) {
pvtm[i].dev = &pdev->dev;
pvtm[i].grf = grf;
pvtm[i].con = info->con;
pvtm[i].sta = info->sta;
pvtm[i].get_value = info->get_value;
pvtm[i].channel = &info->channels[i];
pvtm[i].tz = pvtm_tz;
if (info->set_ring_sel)
pvtm[i].set_ring_sel = info->set_ring_sel;
pvtm[i].clk = devm_clk_get(dev, info->channels[i].clk_name);
if (IS_ERR_OR_NULL(pvtm[i].clk)) {
dev_err(dev, "failed to get clk %d %s\n", i,
info->channels[i].clk_name);
return PTR_ERR(pvtm[i].clk);
}
pvtm[i].rst =
devm_reset_control_get(dev, info->channels[i].clk_name);
if (IS_ERR_OR_NULL(pvtm[i].rst)) {
dev_info(dev, "failed to get rst %d %s\n", i,
info->channels[i].clk_name);
pvtm[i].rst = NULL;
}
list_add(&pvtm[i].node, &pvtm_list);
list_add(&pvtm->node, &pvtm_list);
}
return 0;
error:
rockchip_del_pvtm(match->data);
return -EINVAL;
}
static struct platform_driver rockchip_pvtm_driver = {