diff --git a/patches-6.1/390-PM-devfreq-rockchip-dfi-Embed-desc-into-private-data.patch b/patches-6.1/390-PM-devfreq-rockchip-dfi-Embed-desc-into-private-data.patch new file mode 100644 index 0000000..cb3b814 --- /dev/null +++ b/patches-6.1/390-PM-devfreq-rockchip-dfi-Embed-desc-into-private-data.patch @@ -0,0 +1,43 @@ +From daaf4f20581337c3635e74b3ef63dff4ef5a497c Mon Sep 17 00:00:00 2001 +From: Sascha Hauer +Date: Wed, 24 May 2023 10:31:30 +0200 +Subject: [PATCH 390/414] PM / devfreq: rockchip-dfi: Embed desc into private + data struct + +No need for an extra allocation, just embed the struct +devfreq_event_desc into the private data struct. + +Signed-off-by: Sascha Hauer +Reviewed-by: Heiko Stuebner +Reviewed-by: Jonathan Cameron +--- + drivers/devfreq/event/rockchip-dfi.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +--- a/drivers/devfreq/event/rockchip-dfi.c ++++ b/drivers/devfreq/event/rockchip-dfi.c +@@ -49,7 +49,7 @@ struct dmc_usage { + */ + struct rockchip_dfi { + struct devfreq_event_dev *edev; +- struct devfreq_event_desc *desc; ++ struct devfreq_event_desc desc; + struct dmc_usage ch_usage[RK3399_DMC_NUM_CH]; + struct device *dev; + void __iomem *regs; +@@ -204,14 +204,10 @@ static int rockchip_dfi_probe(struct pla + + data->dev = dev; + +- desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL); +- if (!desc) +- return -ENOMEM; +- ++ desc = &data->desc; + desc->ops = &rockchip_dfi_ops; + desc->driver_data = data; + desc->name = np->name; +- data->desc = desc; + + data->edev = devm_devfreq_event_add_edev(&pdev->dev, desc); + if (IS_ERR(data->edev)) { diff --git a/patches-6.1/391-PM-devfreq-rockchip-dfi-use-consistent-name-for-priv.patch b/patches-6.1/391-PM-devfreq-rockchip-dfi-use-consistent-name-for-priv.patch new file mode 100644 index 0000000..46c6f07 --- /dev/null +++ b/patches-6.1/391-PM-devfreq-rockchip-dfi-use-consistent-name-for-priv.patch @@ -0,0 +1,182 @@ +From 6942ca2cdc0a11277b9329dc0cc4ebc26213a490 Mon Sep 17 00:00:00 2001 +From: Sascha Hauer +Date: Wed, 24 May 2023 10:31:31 +0200 +Subject: [PATCH 391/414] PM / devfreq: rockchip-dfi: use consistent name for + private data struct + +The variable name for the private data struct is 'info' in some +functions and 'data' in others. Both names do not give a clue what +type the variable has, so consistently use 'dfi'. + +Signed-off-by: Sascha Hauer +Reviewed-by: Heiko Stuebner +Reviewed-by: Jonathan Cameron +--- + drivers/devfreq/event/rockchip-dfi.c | 72 ++++++++++++++-------------- + 1 file changed, 36 insertions(+), 36 deletions(-) + +--- a/drivers/devfreq/event/rockchip-dfi.c ++++ b/drivers/devfreq/event/rockchip-dfi.c +@@ -59,13 +59,13 @@ struct rockchip_dfi { + + static void rockchip_dfi_start_hardware_counter(struct devfreq_event_dev *edev) + { +- struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); +- void __iomem *dfi_regs = info->regs; ++ struct rockchip_dfi *dfi = devfreq_event_get_drvdata(edev); ++ void __iomem *dfi_regs = dfi->regs; + u32 val; + u32 ddr_type; + + /* get ddr type */ +- regmap_read(info->regmap_pmu, RK3399_PMUGRF_OS_REG2, &val); ++ regmap_read(dfi->regmap_pmu, RK3399_PMUGRF_OS_REG2, &val); + ddr_type = (val >> RK3399_PMUGRF_DDRTYPE_SHIFT) & + RK3399_PMUGRF_DDRTYPE_MASK; + +@@ -84,28 +84,28 @@ static void rockchip_dfi_start_hardware_ + + static void rockchip_dfi_stop_hardware_counter(struct devfreq_event_dev *edev) + { +- struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); +- void __iomem *dfi_regs = info->regs; ++ struct rockchip_dfi *dfi = devfreq_event_get_drvdata(edev); ++ void __iomem *dfi_regs = dfi->regs; + + writel_relaxed(SOFTWARE_DIS, dfi_regs + DDRMON_CTRL); + } + + static int rockchip_dfi_get_busier_ch(struct devfreq_event_dev *edev) + { +- struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); ++ struct rockchip_dfi *dfi = devfreq_event_get_drvdata(edev); + u32 tmp, max = 0; + u32 i, busier_ch = 0; +- void __iomem *dfi_regs = info->regs; ++ void __iomem *dfi_regs = dfi->regs; + + rockchip_dfi_stop_hardware_counter(edev); + + /* Find out which channel is busier */ + for (i = 0; i < RK3399_DMC_NUM_CH; i++) { +- info->ch_usage[i].access = readl_relaxed(dfi_regs + ++ dfi->ch_usage[i].access = readl_relaxed(dfi_regs + + DDRMON_CH0_DFI_ACCESS_NUM + i * 20) * 4; +- info->ch_usage[i].total = readl_relaxed(dfi_regs + ++ dfi->ch_usage[i].total = readl_relaxed(dfi_regs + + DDRMON_CH0_COUNT_NUM + i * 20); +- tmp = info->ch_usage[i].access; ++ tmp = dfi->ch_usage[i].access; + if (tmp > max) { + busier_ch = i; + max = tmp; +@@ -118,20 +118,20 @@ static int rockchip_dfi_get_busier_ch(st + + static int rockchip_dfi_disable(struct devfreq_event_dev *edev) + { +- struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); ++ struct rockchip_dfi *dfi = devfreq_event_get_drvdata(edev); + + rockchip_dfi_stop_hardware_counter(edev); +- clk_disable_unprepare(info->clk); ++ clk_disable_unprepare(dfi->clk); + + return 0; + } + + static int rockchip_dfi_enable(struct devfreq_event_dev *edev) + { +- struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); ++ struct rockchip_dfi *dfi = devfreq_event_get_drvdata(edev); + int ret; + +- ret = clk_prepare_enable(info->clk); ++ ret = clk_prepare_enable(dfi->clk); + if (ret) { + dev_err(&edev->dev, "failed to enable dfi clk: %d\n", ret); + return ret; +@@ -149,13 +149,13 @@ static int rockchip_dfi_set_event(struct + static int rockchip_dfi_get_event(struct devfreq_event_dev *edev, + struct devfreq_event_data *edata) + { +- struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); ++ struct rockchip_dfi *dfi = devfreq_event_get_drvdata(edev); + int busier_ch; + + busier_ch = rockchip_dfi_get_busier_ch(edev); + +- edata->load_count = info->ch_usage[busier_ch].access; +- edata->total_count = info->ch_usage[busier_ch].total; ++ edata->load_count = dfi->ch_usage[busier_ch].access; ++ edata->total_count = dfi->ch_usage[busier_ch].total; + + return 0; + } +@@ -176,47 +176,47 @@ MODULE_DEVICE_TABLE(of, rockchip_dfi_id_ + static int rockchip_dfi_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; +- struct rockchip_dfi *data; ++ struct rockchip_dfi *dfi; + struct devfreq_event_desc *desc; + struct device_node *np = pdev->dev.of_node, *node; + +- data = devm_kzalloc(dev, sizeof(struct rockchip_dfi), GFP_KERNEL); +- if (!data) ++ dfi = devm_kzalloc(dev, sizeof(*dfi), GFP_KERNEL); ++ if (!dfi) + return -ENOMEM; + +- data->regs = devm_platform_ioremap_resource(pdev, 0); +- if (IS_ERR(data->regs)) +- return PTR_ERR(data->regs); +- +- data->clk = devm_clk_get(dev, "pclk_ddr_mon"); +- if (IS_ERR(data->clk)) +- return dev_err_probe(dev, PTR_ERR(data->clk), ++ dfi->regs = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(dfi->regs)) ++ return PTR_ERR(dfi->regs); ++ ++ dfi->clk = devm_clk_get(dev, "pclk_ddr_mon"); ++ if (IS_ERR(dfi->clk)) ++ return dev_err_probe(dev, PTR_ERR(dfi->clk), + "Cannot get the clk pclk_ddr_mon\n"); + + node = of_parse_phandle(np, "rockchip,pmu", 0); + if (!node) + return dev_err_probe(&pdev->dev, -ENODEV, "Can't find pmu_grf registers\n"); + +- data->regmap_pmu = syscon_node_to_regmap(node); ++ dfi->regmap_pmu = syscon_node_to_regmap(node); + of_node_put(node); +- if (IS_ERR(data->regmap_pmu)) +- return PTR_ERR(data->regmap_pmu); ++ if (IS_ERR(dfi->regmap_pmu)) ++ return PTR_ERR(dfi->regmap_pmu); + +- data->dev = dev; ++ dfi->dev = dev; + +- desc = &data->desc; ++ desc = &dfi->desc; + desc->ops = &rockchip_dfi_ops; +- desc->driver_data = data; ++ desc->driver_data = dfi; + desc->name = np->name; + +- data->edev = devm_devfreq_event_add_edev(&pdev->dev, desc); +- if (IS_ERR(data->edev)) { ++ dfi->edev = devm_devfreq_event_add_edev(&pdev->dev, desc); ++ if (IS_ERR(dfi->edev)) { + dev_err(&pdev->dev, + "failed to add devfreq-event device\n"); +- return PTR_ERR(data->edev); ++ return PTR_ERR(dfi->edev); + } + +- platform_set_drvdata(pdev, data); ++ platform_set_drvdata(pdev, dfi); + + return 0; + } diff --git a/patches-6.1/392-PM-devfreq-rockchip-dfi-Add-SoC-specific-init-functi.patch b/patches-6.1/392-PM-devfreq-rockchip-dfi-Add-SoC-specific-init-functi.patch new file mode 100644 index 0000000..7aeeab9 --- /dev/null +++ b/patches-6.1/392-PM-devfreq-rockchip-dfi-Add-SoC-specific-init-functi.patch @@ -0,0 +1,119 @@ +From 584df97ad3faf621edd820541b131d66a5cf5e83 Mon Sep 17 00:00:00 2001 +From: Sascha Hauer +Date: Wed, 24 May 2023 10:31:32 +0200 +Subject: [PATCH 392/414] PM / devfreq: rockchip-dfi: Add SoC specific init + function + +Move the RK3399 specifics to a SoC specific init function to make +the way free for supporting other SoCs later. + +Signed-off-by: Sascha Hauer +--- + drivers/devfreq/event/rockchip-dfi.c | 48 +++++++++++++++++++--------- + 1 file changed, 33 insertions(+), 15 deletions(-) + +--- a/drivers/devfreq/event/rockchip-dfi.c ++++ b/drivers/devfreq/event/rockchip-dfi.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + + #include + +@@ -55,27 +56,21 @@ struct rockchip_dfi { + void __iomem *regs; + struct regmap *regmap_pmu; + struct clk *clk; ++ u32 ddr_type; + }; + + static void rockchip_dfi_start_hardware_counter(struct devfreq_event_dev *edev) + { + struct rockchip_dfi *dfi = devfreq_event_get_drvdata(edev); + void __iomem *dfi_regs = dfi->regs; +- u32 val; +- u32 ddr_type; +- +- /* get ddr type */ +- regmap_read(dfi->regmap_pmu, RK3399_PMUGRF_OS_REG2, &val); +- ddr_type = (val >> RK3399_PMUGRF_DDRTYPE_SHIFT) & +- RK3399_PMUGRF_DDRTYPE_MASK; + + /* clear DDRMON_CTRL setting */ + writel_relaxed(CLR_DDRMON_CTRL, dfi_regs + DDRMON_CTRL); + + /* set ddr type to dfi */ +- if (ddr_type == RK3399_PMUGRF_DDRTYPE_LPDDR3) ++ if (dfi->ddr_type == RK3399_PMUGRF_DDRTYPE_LPDDR3) + writel_relaxed(LPDDR3_EN, dfi_regs + DDRMON_CTRL); +- else if (ddr_type == RK3399_PMUGRF_DDRTYPE_LPDDR4) ++ else if (dfi->ddr_type == RK3399_PMUGRF_DDRTYPE_LPDDR4) + writel_relaxed(LPDDR4_EN, dfi_regs + DDRMON_CTRL); + + /* enable count, use software mode */ +@@ -167,8 +162,26 @@ static const struct devfreq_event_ops ro + .set_event = rockchip_dfi_set_event, + }; + ++static int rk3399_dfi_init(struct rockchip_dfi *dfi) ++{ ++ struct regmap *regmap_pmu = dfi->regmap_pmu; ++ u32 val; ++ ++ dfi->clk = devm_clk_get(dfi->dev, "pclk_ddr_mon"); ++ if (IS_ERR(dfi->clk)) ++ return dev_err_probe(dfi->dev, PTR_ERR(dfi->clk), ++ "Cannot get the clk pclk_ddr_mon\n"); ++ ++ /* get ddr type */ ++ regmap_read(regmap_pmu, RK3399_PMUGRF_OS_REG2, &val); ++ dfi->ddr_type = (val >> RK3399_PMUGRF_DDRTYPE_SHIFT) & ++ RK3399_PMUGRF_DDRTYPE_MASK; ++ ++ return 0; ++}; ++ + static const struct of_device_id rockchip_dfi_id_match[] = { +- { .compatible = "rockchip,rk3399-dfi" }, ++ { .compatible = "rockchip,rk3399-dfi", .data = rk3399_dfi_init }, + { }, + }; + MODULE_DEVICE_TABLE(of, rockchip_dfi_id_match); +@@ -179,6 +192,12 @@ static int rockchip_dfi_probe(struct pla + struct rockchip_dfi *dfi; + struct devfreq_event_desc *desc; + struct device_node *np = pdev->dev.of_node, *node; ++ int (*soc_init)(struct rockchip_dfi *dfi); ++ int ret; ++ ++ soc_init = of_device_get_match_data(&pdev->dev); ++ if (!soc_init) ++ return -EINVAL; + + dfi = devm_kzalloc(dev, sizeof(*dfi), GFP_KERNEL); + if (!dfi) +@@ -188,11 +207,6 @@ static int rockchip_dfi_probe(struct pla + if (IS_ERR(dfi->regs)) + return PTR_ERR(dfi->regs); + +- dfi->clk = devm_clk_get(dev, "pclk_ddr_mon"); +- if (IS_ERR(dfi->clk)) +- return dev_err_probe(dev, PTR_ERR(dfi->clk), +- "Cannot get the clk pclk_ddr_mon\n"); +- + node = of_parse_phandle(np, "rockchip,pmu", 0); + if (!node) + return dev_err_probe(&pdev->dev, -ENODEV, "Can't find pmu_grf registers\n"); +@@ -209,6 +223,10 @@ static int rockchip_dfi_probe(struct pla + desc->driver_data = dfi; + desc->name = np->name; + ++ ret = soc_init(dfi); ++ if (ret) ++ return ret; ++ + dfi->edev = devm_devfreq_event_add_edev(&pdev->dev, desc); + if (IS_ERR(dfi->edev)) { + dev_err(&pdev->dev, diff --git a/patches-6.1/393-PM-devfreq-rockchip-dfi-dfi-store-raw-values-in-coun.patch b/patches-6.1/393-PM-devfreq-rockchip-dfi-dfi-store-raw-values-in-coun.patch new file mode 100644 index 0000000..a6a152e --- /dev/null +++ b/patches-6.1/393-PM-devfreq-rockchip-dfi-dfi-store-raw-values-in-coun.patch @@ -0,0 +1,36 @@ +From d019e53c06c97c9dba462ad5ea691579c4a38c8a Mon Sep 17 00:00:00 2001 +From: Sascha Hauer +Date: Wed, 24 May 2023 10:31:33 +0200 +Subject: [PATCH 393/414] PM / devfreq: rockchip-dfi: dfi store raw values in + counter struct + +When adding perf support to the DFI driver the perf part will +need the raw counter values, so move the fixed * 4 factor to +rockchip_dfi_get_event(). + +Signed-off-by: Sascha Hauer +Reviewed-by: Jonathan Cameron +--- + drivers/devfreq/event/rockchip-dfi.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/devfreq/event/rockchip-dfi.c ++++ b/drivers/devfreq/event/rockchip-dfi.c +@@ -97,7 +97,7 @@ static int rockchip_dfi_get_busier_ch(st + /* Find out which channel is busier */ + for (i = 0; i < RK3399_DMC_NUM_CH; i++) { + dfi->ch_usage[i].access = readl_relaxed(dfi_regs + +- DDRMON_CH0_DFI_ACCESS_NUM + i * 20) * 4; ++ DDRMON_CH0_DFI_ACCESS_NUM + i * 20); + dfi->ch_usage[i].total = readl_relaxed(dfi_regs + + DDRMON_CH0_COUNT_NUM + i * 20); + tmp = dfi->ch_usage[i].access; +@@ -149,7 +149,7 @@ static int rockchip_dfi_get_event(struct + + busier_ch = rockchip_dfi_get_busier_ch(edev); + +- edata->load_count = dfi->ch_usage[busier_ch].access; ++ edata->load_count = dfi->ch_usage[busier_ch].access * 4; + edata->total_count = dfi->ch_usage[busier_ch].total; + + return 0; diff --git a/patches-6.1/394-PM-devfreq-rockchip-dfi-Use-free-running-counter.patch b/patches-6.1/394-PM-devfreq-rockchip-dfi-Use-free-running-counter.patch new file mode 100644 index 0000000..c7a0b0f --- /dev/null +++ b/patches-6.1/394-PM-devfreq-rockchip-dfi-Use-free-running-counter.patch @@ -0,0 +1,122 @@ +From 28dc17d0ca6eab000fa477c7143fe5c65d2423e8 Mon Sep 17 00:00:00 2001 +From: Sascha Hauer +Date: Wed, 24 May 2023 10:31:34 +0200 +Subject: [PATCH 394/414] PM / devfreq: rockchip-dfi: Use free running counter + +The DDR_MON counters are free running counters. These are resetted to 0 +when starting them over like currently done when reading the current +counter values. + +Resetting the counters becomes a problem with perf support we want to +add later, because perf needs counters that are not modified elsewhere. + +This patch removes resetting the counters and keeps them running +instead. That means we no longer use the absolute counter values but +instead compare them with the counter values we read last time. Not +stopping the counters also has the impact that they are running while +we are reading them. We cannot read multiple timers atomically, so +the values do not exactly fit together. The effect should be negligible +though as the time between two measurements is some orders of magnitude +bigger than the time we need to read multiple registers. + +Signed-off-by: Sascha Hauer +--- + drivers/devfreq/event/rockchip-dfi.c | 52 ++++++++++++++++------------ + 1 file changed, 30 insertions(+), 22 deletions(-) + +--- a/drivers/devfreq/event/rockchip-dfi.c ++++ b/drivers/devfreq/event/rockchip-dfi.c +@@ -38,11 +38,15 @@ + #define DDRMON_CH1_COUNT_NUM 0x3c + #define DDRMON_CH1_DFI_ACCESS_NUM 0x40 + +-struct dmc_usage { ++struct dmc_count_channel { + u32 access; + u32 total; + }; + ++struct dmc_count { ++ struct dmc_count_channel c[RK3399_DMC_NUM_CH]; ++}; ++ + /* + * The dfi controller can monitor DDR load. It has an upper and lower threshold + * for the operating points. Whenever the usage leaves these bounds an event is +@@ -51,7 +55,7 @@ struct dmc_usage { + struct rockchip_dfi { + struct devfreq_event_dev *edev; + struct devfreq_event_desc desc; +- struct dmc_usage ch_usage[RK3399_DMC_NUM_CH]; ++ struct dmc_count last_event_count; + struct device *dev; + void __iomem *regs; + struct regmap *regmap_pmu; +@@ -85,30 +89,18 @@ static void rockchip_dfi_stop_hardware_c + writel_relaxed(SOFTWARE_DIS, dfi_regs + DDRMON_CTRL); + } + +-static int rockchip_dfi_get_busier_ch(struct devfreq_event_dev *edev) ++static void rockchip_dfi_read_counters(struct devfreq_event_dev *edev, struct dmc_count *count) + { + struct rockchip_dfi *dfi = devfreq_event_get_drvdata(edev); +- u32 tmp, max = 0; +- u32 i, busier_ch = 0; ++ u32 i; + void __iomem *dfi_regs = dfi->regs; + +- rockchip_dfi_stop_hardware_counter(edev); +- +- /* Find out which channel is busier */ + for (i = 0; i < RK3399_DMC_NUM_CH; i++) { +- dfi->ch_usage[i].access = readl_relaxed(dfi_regs + ++ count->c[i].access = readl_relaxed(dfi_regs + + DDRMON_CH0_DFI_ACCESS_NUM + i * 20); +- dfi->ch_usage[i].total = readl_relaxed(dfi_regs + ++ count->c[i].total = readl_relaxed(dfi_regs + + DDRMON_CH0_COUNT_NUM + i * 20); +- tmp = dfi->ch_usage[i].access; +- if (tmp > max) { +- busier_ch = i; +- max = tmp; +- } + } +- rockchip_dfi_start_hardware_counter(edev); +- +- return busier_ch; + } + + static int rockchip_dfi_disable(struct devfreq_event_dev *edev) +@@ -145,12 +137,28 @@ static int rockchip_dfi_get_event(struct + struct devfreq_event_data *edata) + { + struct rockchip_dfi *dfi = devfreq_event_get_drvdata(edev); +- int busier_ch; ++ struct dmc_count count; ++ struct dmc_count *last = &dfi->last_event_count; ++ u32 access = 0, total = 0; ++ int i; ++ ++ rockchip_dfi_read_counters(edev, &count); ++ ++ /* We can only report one channel, so find the busiest one */ ++ for (i = 0; i < RK3399_DMC_NUM_CH; i++) { ++ u32 a = count.c[i].access - last->c[i].access; ++ u32 t = count.c[i].total - last->c[i].total; ++ ++ if (a > access) { ++ access = a; ++ total = t; ++ } ++ } + +- busier_ch = rockchip_dfi_get_busier_ch(edev); ++ edata->load_count = access * 4; ++ edata->total_count = total; + +- edata->load_count = dfi->ch_usage[busier_ch].access * 4; +- edata->total_count = dfi->ch_usage[busier_ch].total; ++ dfi->last_event_count = count; + + return 0; + } diff --git a/patches-6.1/395-PM-devfreq-rockchip-dfi-introduce-channel-mask.patch b/patches-6.1/395-PM-devfreq-rockchip-dfi-introduce-channel-mask.patch new file mode 100644 index 0000000..d4a10d8 --- /dev/null +++ b/patches-6.1/395-PM-devfreq-rockchip-dfi-introduce-channel-mask.patch @@ -0,0 +1,84 @@ +From b08008c9f4396787040a48561b908c8acc82c349 Mon Sep 17 00:00:00 2001 +From: Sascha Hauer +Date: Wed, 24 May 2023 10:31:35 +0200 +Subject: [PATCH 395/414] PM / devfreq: rockchip-dfi: introduce channel mask + +Different Rockchip SoC variants have a different number of channels. +Introduce a channel mask to make the number of channels configurable +from SoC initialization code. + +Signed-off-by: Sascha Hauer +--- + drivers/devfreq/event/rockchip-dfi.c | 23 +++++++++++++++++------ + 1 file changed, 17 insertions(+), 6 deletions(-) + +--- a/drivers/devfreq/event/rockchip-dfi.c ++++ b/drivers/devfreq/event/rockchip-dfi.c +@@ -18,10 +18,11 @@ + #include + #include + #include ++#include + + #include + +-#define RK3399_DMC_NUM_CH 2 ++#define DMC_MAX_CHANNELS 2 + + /* DDRMON_CTRL */ + #define DDRMON_CTRL 0x04 +@@ -44,7 +45,7 @@ struct dmc_count_channel { + }; + + struct dmc_count { +- struct dmc_count_channel c[RK3399_DMC_NUM_CH]; ++ struct dmc_count_channel c[DMC_MAX_CHANNELS]; + }; + + /* +@@ -61,6 +62,7 @@ struct rockchip_dfi { + struct regmap *regmap_pmu; + struct clk *clk; + u32 ddr_type; ++ unsigned int channel_mask; + }; + + static void rockchip_dfi_start_hardware_counter(struct devfreq_event_dev *edev) +@@ -95,7 +97,9 @@ static void rockchip_dfi_read_counters(s + u32 i; + void __iomem *dfi_regs = dfi->regs; + +- for (i = 0; i < RK3399_DMC_NUM_CH; i++) { ++ for (i = 0; i < DMC_MAX_CHANNELS; i++) { ++ if (!(dfi->channel_mask & BIT(i))) ++ continue; + count->c[i].access = readl_relaxed(dfi_regs + + DDRMON_CH0_DFI_ACCESS_NUM + i * 20); + count->c[i].total = readl_relaxed(dfi_regs + +@@ -145,9 +149,14 @@ static int rockchip_dfi_get_event(struct + rockchip_dfi_read_counters(edev, &count); + + /* We can only report one channel, so find the busiest one */ +- for (i = 0; i < RK3399_DMC_NUM_CH; i++) { +- u32 a = count.c[i].access - last->c[i].access; +- u32 t = count.c[i].total - last->c[i].total; ++ for (i = 0; i < DMC_MAX_CHANNELS; i++) { ++ u32 a, t; ++ ++ if (!(dfi->channel_mask & BIT(i))) ++ continue; ++ ++ a = count.c[i].access - last->c[i].access; ++ t = count.c[i].total - last->c[i].total; + + if (a > access) { + access = a; +@@ -185,6 +194,8 @@ static int rk3399_dfi_init(struct rockch + dfi->ddr_type = (val >> RK3399_PMUGRF_DDRTYPE_SHIFT) & + RK3399_PMUGRF_DDRTYPE_MASK; + ++ dfi->channel_mask = GENMASK(1, 0); ++ + return 0; + }; + diff --git a/patches-6.1/396-PM-devfreq-rk3399_dmc-dfi-generalize-DDRTYPE-defines.patch b/patches-6.1/396-PM-devfreq-rk3399_dmc-dfi-generalize-DDRTYPE-defines.patch new file mode 100644 index 0000000..48b2984 --- /dev/null +++ b/patches-6.1/396-PM-devfreq-rk3399_dmc-dfi-generalize-DDRTYPE-defines.patch @@ -0,0 +1,124 @@ +From 71dd420de9dd4ed9e1830a97d7d05b9d241b71fe Mon Sep 17 00:00:00 2001 +From: Sascha Hauer +Date: Wed, 24 May 2023 10:31:36 +0200 +Subject: [PATCH 396/414] PM / devfreq: rk3399_dmc,dfi: generalize DDRTYPE + defines + +The DDRTYPE defines are named to be RK3399 specific, but they can be +used for other Rockchip SoCs as well, so replace the RK3399_PMUGRF_ +prefix with ROCKCHIP_. They are defined in a SoC specific header +file, so when generalizing the prefix also move the new defines to +a SoC agnostic header file. While at it use GENMASK to define the +DDRTYPE bitfield and give it a name including the full register name. + +Signed-off-by: Sascha Hauer +--- + drivers/devfreq/event/rockchip-dfi.c | 9 +++++---- + drivers/devfreq/rk3399_dmc.c | 10 +++++----- + include/soc/rockchip/rk3399_grf.h | 7 +------ + include/soc/rockchip/rockchip_grf.h | 17 +++++++++++++++++ + 4 files changed, 28 insertions(+), 15 deletions(-) + create mode 100644 include/soc/rockchip/rockchip_grf.h + +--- a/drivers/devfreq/event/rockchip-dfi.c ++++ b/drivers/devfreq/event/rockchip-dfi.c +@@ -18,8 +18,10 @@ + #include + #include + #include ++#include + #include + ++#include + #include + + #define DMC_MAX_CHANNELS 2 +@@ -74,9 +76,9 @@ static void rockchip_dfi_start_hardware_ + writel_relaxed(CLR_DDRMON_CTRL, dfi_regs + DDRMON_CTRL); + + /* set ddr type to dfi */ +- if (dfi->ddr_type == RK3399_PMUGRF_DDRTYPE_LPDDR3) ++ if (dfi->ddr_type == ROCKCHIP_DDRTYPE_LPDDR3) + writel_relaxed(LPDDR3_EN, dfi_regs + DDRMON_CTRL); +- else if (dfi->ddr_type == RK3399_PMUGRF_DDRTYPE_LPDDR4) ++ else if (dfi->ddr_type == ROCKCHIP_DDRTYPE_LPDDR4) + writel_relaxed(LPDDR4_EN, dfi_regs + DDRMON_CTRL); + + /* enable count, use software mode */ +@@ -191,8 +193,7 @@ static int rk3399_dfi_init(struct rockch + + /* get ddr type */ + regmap_read(regmap_pmu, RK3399_PMUGRF_OS_REG2, &val); +- dfi->ddr_type = (val >> RK3399_PMUGRF_DDRTYPE_SHIFT) & +- RK3399_PMUGRF_DDRTYPE_MASK; ++ dfi->ddr_type = FIELD_GET(RK3399_PMUGRF_OS_REG2_DDRTYPE, val); + + dfi->channel_mask = GENMASK(1, 0); + +--- a/drivers/devfreq/rk3399_dmc.c ++++ b/drivers/devfreq/rk3399_dmc.c +@@ -22,6 +22,7 @@ + #include + + #include ++#include + #include + #include + +@@ -381,17 +382,16 @@ static int rk3399_dmcfreq_probe(struct p + } + + regmap_read(data->regmap_pmu, RK3399_PMUGRF_OS_REG2, &val); +- ddr_type = (val >> RK3399_PMUGRF_DDRTYPE_SHIFT) & +- RK3399_PMUGRF_DDRTYPE_MASK; ++ ddr_type = FIELD_GET(RK3399_PMUGRF_OS_REG2_DDRTYPE, val); + + switch (ddr_type) { +- case RK3399_PMUGRF_DDRTYPE_DDR3: ++ case ROCKCHIP_DDRTYPE_DDR3: + data->odt_dis_freq = data->ddr3_odt_dis_freq; + break; +- case RK3399_PMUGRF_DDRTYPE_LPDDR3: ++ case ROCKCHIP_DDRTYPE_LPDDR3: + data->odt_dis_freq = data->lpddr3_odt_dis_freq; + break; +- case RK3399_PMUGRF_DDRTYPE_LPDDR4: ++ case ROCKCHIP_DDRTYPE_LPDDR4: + data->odt_dis_freq = data->lpddr4_odt_dis_freq; + break; + default: +--- a/include/soc/rockchip/rk3399_grf.h ++++ b/include/soc/rockchip/rk3399_grf.h +@@ -11,11 +11,6 @@ + + /* PMU GRF Registers */ + #define RK3399_PMUGRF_OS_REG2 0x308 +-#define RK3399_PMUGRF_DDRTYPE_SHIFT 13 +-#define RK3399_PMUGRF_DDRTYPE_MASK 7 +-#define RK3399_PMUGRF_DDRTYPE_DDR3 3 +-#define RK3399_PMUGRF_DDRTYPE_LPDDR2 5 +-#define RK3399_PMUGRF_DDRTYPE_LPDDR3 6 +-#define RK3399_PMUGRF_DDRTYPE_LPDDR4 7 ++#define RK3399_PMUGRF_OS_REG2_DDRTYPE GENMASK(15, 13) + + #endif +--- /dev/null ++++ b/include/soc/rockchip/rockchip_grf.h +@@ -0,0 +1,17 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Rockchip General Register Files definitions ++ */ ++ ++#ifndef __SOC_ROCKCHIP_GRF_H ++#define __SOC_ROCKCHIP_GRF_H ++ ++/* Rockchip DDRTYPE defines */ ++enum { ++ ROCKCHIP_DDRTYPE_DDR3 = 3, ++ ROCKCHIP_DDRTYPE_LPDDR2 = 5, ++ ROCKCHIP_DDRTYPE_LPDDR3 = 6, ++ ROCKCHIP_DDRTYPE_LPDDR4 = 7, ++}; ++ ++#endif /* __SOC_ROCKCHIP_GRF_H */ diff --git a/patches-6.1/397-PM-devfreq-rockchip-dfi-Clean-up-DDR-type-register-d.patch b/patches-6.1/397-PM-devfreq-rockchip-dfi-Clean-up-DDR-type-register-d.patch new file mode 100644 index 0000000..a277d0f --- /dev/null +++ b/patches-6.1/397-PM-devfreq-rockchip-dfi-Clean-up-DDR-type-register-d.patch @@ -0,0 +1,85 @@ +From 3787ec8983d7210be174eb0bc758029002c448e5 Mon Sep 17 00:00:00 2001 +From: Sascha Hauer +Date: Wed, 24 May 2023 10:31:37 +0200 +Subject: [PATCH 397/414] PM / devfreq: rockchip-dfi: Clean up DDR type + register defines + +Use the HIWORD_UPDATE() define known from other rockchip drivers to +make the defines look less odd to the readers who've seen other +rockchip drivers. + +The HIWORD registers have their functional bits in the lower 16 bits +whereas the upper 16 bits contain a mask. Only the functional bits that +have the corresponding mask bit set are modified during a write. Although +the register writes look different, the end result should be the same, +at least there's no functional change intended with this patch. + +Signed-off-by: Sascha Hauer +--- + drivers/devfreq/event/rockchip-dfi.c | 33 ++++++++++++++++++---------- + 1 file changed, 21 insertions(+), 12 deletions(-) + +--- a/drivers/devfreq/event/rockchip-dfi.c ++++ b/drivers/devfreq/event/rockchip-dfi.c +@@ -26,15 +26,19 @@ + + #define DMC_MAX_CHANNELS 2 + ++#define HIWORD_UPDATE(val, mask) ((val) | (mask) << 16) ++ + /* DDRMON_CTRL */ + #define DDRMON_CTRL 0x04 +-#define CLR_DDRMON_CTRL (0x1f0000 << 0) +-#define LPDDR4_EN (0x10001 << 4) +-#define HARDWARE_EN (0x10001 << 3) +-#define LPDDR3_EN (0x10001 << 2) +-#define SOFTWARE_EN (0x10001 << 1) +-#define SOFTWARE_DIS (0x10000 << 1) +-#define TIME_CNT_EN (0x10001 << 0) ++#define DDRMON_CTRL_DDR4 BIT(5) ++#define DDRMON_CTRL_LPDDR4 BIT(4) ++#define DDRMON_CTRL_HARDWARE_EN BIT(3) ++#define DDRMON_CTRL_LPDDR23 BIT(2) ++#define DDRMON_CTRL_SOFTWARE_EN BIT(1) ++#define DDRMON_CTRL_TIMER_CNT_EN BIT(0) ++#define DDRMON_CTRL_DDR_TYPE_MASK (DDRMON_CTRL_DDR4 | \ ++ DDRMON_CTRL_LPDDR4 | \ ++ DDRMON_CTRL_LPDDR23) + + #define DDRMON_CH0_COUNT_NUM 0x28 + #define DDRMON_CH0_DFI_ACCESS_NUM 0x2c +@@ -73,16 +77,20 @@ static void rockchip_dfi_start_hardware_ + void __iomem *dfi_regs = dfi->regs; + + /* clear DDRMON_CTRL setting */ +- writel_relaxed(CLR_DDRMON_CTRL, dfi_regs + DDRMON_CTRL); ++ writel_relaxed(HIWORD_UPDATE(0, DDRMON_CTRL_TIMER_CNT_EN | DDRMON_CTRL_SOFTWARE_EN | ++ DDRMON_CTRL_HARDWARE_EN), dfi_regs + DDRMON_CTRL); + + /* set ddr type to dfi */ + if (dfi->ddr_type == ROCKCHIP_DDRTYPE_LPDDR3) +- writel_relaxed(LPDDR3_EN, dfi_regs + DDRMON_CTRL); ++ writel_relaxed(HIWORD_UPDATE(DDRMON_CTRL_LPDDR23, DDRMON_CTRL_DDR_TYPE_MASK), ++ dfi_regs + DDRMON_CTRL); + else if (dfi->ddr_type == ROCKCHIP_DDRTYPE_LPDDR4) +- writel_relaxed(LPDDR4_EN, dfi_regs + DDRMON_CTRL); ++ writel_relaxed(HIWORD_UPDATE(DDRMON_CTRL_LPDDR4, DDRMON_CTRL_DDR_TYPE_MASK), ++ dfi_regs + DDRMON_CTRL); + + /* enable count, use software mode */ +- writel_relaxed(SOFTWARE_EN, dfi_regs + DDRMON_CTRL); ++ writel_relaxed(HIWORD_UPDATE(DDRMON_CTRL_SOFTWARE_EN, DDRMON_CTRL_SOFTWARE_EN), ++ dfi_regs + DDRMON_CTRL); + } + + static void rockchip_dfi_stop_hardware_counter(struct devfreq_event_dev *edev) +@@ -90,7 +98,8 @@ static void rockchip_dfi_stop_hardware_c + struct rockchip_dfi *dfi = devfreq_event_get_drvdata(edev); + void __iomem *dfi_regs = dfi->regs; + +- writel_relaxed(SOFTWARE_DIS, dfi_regs + DDRMON_CTRL); ++ writel_relaxed(HIWORD_UPDATE(0, DDRMON_CTRL_SOFTWARE_EN), ++ dfi_regs + DDRMON_CTRL); + } + + static void rockchip_dfi_read_counters(struct devfreq_event_dev *edev, struct dmc_count *count) diff --git a/patches-6.1/398-PM-devfreq-rockchip-dfi-Add-RK3568-support.patch b/patches-6.1/398-PM-devfreq-rockchip-dfi-Add-RK3568-support.patch new file mode 100644 index 0000000..f106348 --- /dev/null +++ b/patches-6.1/398-PM-devfreq-rockchip-dfi-Add-RK3568-support.patch @@ -0,0 +1,71 @@ +From 871f38fefb7142038faa50292215d8e19e8366ca Mon Sep 17 00:00:00 2001 +From: Sascha Hauer +Date: Wed, 24 May 2023 10:31:38 +0200 +Subject: [PATCH 398/414] PM / devfreq: rockchip-dfi: Add RK3568 support + +This adds RK3568 support to the DFI driver. Only iniitialization +differs from the currently supported RK3399. + +Signed-off-by: Sascha Hauer +--- + drivers/devfreq/event/rockchip-dfi.c | 21 +++++++++++++++++++++ + include/soc/rockchip/rk3568_grf.h | 12 ++++++++++++ + 2 files changed, 33 insertions(+) + create mode 100644 include/soc/rockchip/rk3568_grf.h + +--- a/drivers/devfreq/event/rockchip-dfi.c ++++ b/drivers/devfreq/event/rockchip-dfi.c +@@ -23,6 +23,7 @@ + + #include + #include ++#include + + #define DMC_MAX_CHANNELS 2 + +@@ -209,10 +210,30 @@ static int rk3399_dfi_init(struct rockch + return 0; + }; + ++static int rk3568_dfi_init(struct rockchip_dfi *dfi) ++{ ++ struct regmap *regmap_pmu = dfi->regmap_pmu; ++ u32 reg2, reg3; ++ ++ regmap_read(regmap_pmu, RK3568_PMUGRF_OS_REG2, ®2); ++ regmap_read(regmap_pmu, RK3568_PMUGRF_OS_REG3, ®3); ++ ++ dfi->ddr_type = FIELD_GET(RK3568_PMUGRF_OS_REG2_DRAMTYPE_INFO, reg2); ++ ++ if (FIELD_GET(RK3568_PMUGRF_OS_REG3_SYSREG_VERSION, reg3) >= 0x3) ++ dfi->ddr_type |= FIELD_GET(RK3568_PMUGRF_OS_REG3_DRAMTYPE_INFO_V3, reg3) << 3; ++ ++ dfi->channel_mask = 1; ++ ++ return 0; ++}; ++ + static const struct of_device_id rockchip_dfi_id_match[] = { + { .compatible = "rockchip,rk3399-dfi", .data = rk3399_dfi_init }, ++ { .compatible = "rockchip,rk3568-dfi", .data = rk3568_dfi_init }, + { }, + }; ++ + MODULE_DEVICE_TABLE(of, rockchip_dfi_id_match); + + static int rockchip_dfi_probe(struct platform_device *pdev) +--- /dev/null ++++ b/include/soc/rockchip/rk3568_grf.h +@@ -0,0 +1,12 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++#ifndef __SOC_RK3568_GRF_H ++#define __SOC_RK3568_GRF_H ++ ++#define RK3568_PMUGRF_OS_REG2 0x208 ++#define RK3568_PMUGRF_OS_REG2_DRAMTYPE_INFO GENMASK(15, 13) ++ ++#define RK3568_PMUGRF_OS_REG3 0x20c ++#define RK3568_PMUGRF_OS_REG3_DRAMTYPE_INFO_V3 GENMASK(13, 12) ++#define RK3568_PMUGRF_OS_REG3_SYSREG_VERSION GENMASK(31, 28) ++ ++#endif /* __SOC_RK3568_GRF_H */ diff --git a/patches-6.1/399-PM-devfreq-rockchip-dfi-Handle-LPDDR2-correctly.patch b/patches-6.1/399-PM-devfreq-rockchip-dfi-Handle-LPDDR2-correctly.patch new file mode 100644 index 0000000..7c5e6c0 --- /dev/null +++ b/patches-6.1/399-PM-devfreq-rockchip-dfi-Handle-LPDDR2-correctly.patch @@ -0,0 +1,40 @@ +From e0606b7dac4764ef7d7cd07dbb127913a01cf0bb Mon Sep 17 00:00:00 2001 +From: Sascha Hauer +Date: Wed, 24 May 2023 10:31:39 +0200 +Subject: [PATCH 399/414] PM / devfreq: rockchip-dfi: Handle LPDDR2 correctly + +According to the downstream driver the DDRMON_CTRL_LPDDR23 bit must be +set for both LPDDR2 and LPDDR3. Add the missing LPDDR2 case and while +at it turn the if/else if/else into switch/case which makes it easier +to read. + +Signed-off-by: Sascha Hauer +Reviewed-by: Jonathan Cameron +--- + drivers/devfreq/event/rockchip-dfi.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +--- a/drivers/devfreq/event/rockchip-dfi.c ++++ b/drivers/devfreq/event/rockchip-dfi.c +@@ -82,12 +82,19 @@ static void rockchip_dfi_start_hardware_ + DDRMON_CTRL_HARDWARE_EN), dfi_regs + DDRMON_CTRL); + + /* set ddr type to dfi */ +- if (dfi->ddr_type == ROCKCHIP_DDRTYPE_LPDDR3) ++ switch (dfi->ddr_type) { ++ case ROCKCHIP_DDRTYPE_LPDDR2: ++ case ROCKCHIP_DDRTYPE_LPDDR3: + writel_relaxed(HIWORD_UPDATE(DDRMON_CTRL_LPDDR23, DDRMON_CTRL_DDR_TYPE_MASK), + dfi_regs + DDRMON_CTRL); +- else if (dfi->ddr_type == ROCKCHIP_DDRTYPE_LPDDR4) ++ break; ++ case ROCKCHIP_DDRTYPE_LPDDR4: + writel_relaxed(HIWORD_UPDATE(DDRMON_CTRL_LPDDR4, DDRMON_CTRL_DDR_TYPE_MASK), + dfi_regs + DDRMON_CTRL); ++ break; ++ default: ++ break; ++ } + + /* enable count, use software mode */ + writel_relaxed(HIWORD_UPDATE(DDRMON_CTRL_SOFTWARE_EN, DDRMON_CTRL_SOFTWARE_EN), diff --git a/patches-6.1/400-PM-devfreq-rockchip-dfi-Handle-LPDDR4X.patch b/patches-6.1/400-PM-devfreq-rockchip-dfi-Handle-LPDDR4X.patch new file mode 100644 index 0000000..76fa429 --- /dev/null +++ b/patches-6.1/400-PM-devfreq-rockchip-dfi-Handle-LPDDR4X.patch @@ -0,0 +1,35 @@ +From 192bbf5cd0c46e1abf02c629e2ea28739b039465 Mon Sep 17 00:00:00 2001 +From: Sascha Hauer +Date: Wed, 24 May 2023 10:31:40 +0200 +Subject: [PATCH 400/414] PM / devfreq: rockchip-dfi: Handle LPDDR4X + +In the DFI driver LPDDR4X can be handled in the same way as LPDDR4. Add +the missing case. + +Signed-off-by: Sascha Hauer +Reviewed-by: Jonathan Cameron +--- + drivers/devfreq/event/rockchip-dfi.c | 1 + + include/soc/rockchip/rockchip_grf.h | 1 + + 2 files changed, 2 insertions(+) + +--- a/drivers/devfreq/event/rockchip-dfi.c ++++ b/drivers/devfreq/event/rockchip-dfi.c +@@ -89,6 +89,7 @@ static void rockchip_dfi_start_hardware_ + dfi_regs + DDRMON_CTRL); + break; + case ROCKCHIP_DDRTYPE_LPDDR4: ++ case ROCKCHIP_DDRTYPE_LPDDR4X: + writel_relaxed(HIWORD_UPDATE(DDRMON_CTRL_LPDDR4, DDRMON_CTRL_DDR_TYPE_MASK), + dfi_regs + DDRMON_CTRL); + break; +--- a/include/soc/rockchip/rockchip_grf.h ++++ b/include/soc/rockchip/rockchip_grf.h +@@ -12,6 +12,7 @@ enum { + ROCKCHIP_DDRTYPE_LPDDR2 = 5, + ROCKCHIP_DDRTYPE_LPDDR3 = 6, + ROCKCHIP_DDRTYPE_LPDDR4 = 7, ++ ROCKCHIP_DDRTYPE_LPDDR4X = 8, + }; + + #endif /* __SOC_ROCKCHIP_GRF_H */ diff --git a/patches-6.1/401-PM-devfreq-rockchip-dfi-Pass-private-data-struct-to-.patch b/patches-6.1/401-PM-devfreq-rockchip-dfi-Pass-private-data-struct-to-.patch new file mode 100644 index 0000000..cd879c5 --- /dev/null +++ b/patches-6.1/401-PM-devfreq-rockchip-dfi-Pass-private-data-struct-to-.patch @@ -0,0 +1,77 @@ +From b9b81d118d52e5e673b0fdecaf93adbde0beebd8 Mon Sep 17 00:00:00 2001 +From: Sascha Hauer +Date: Wed, 24 May 2023 10:31:41 +0200 +Subject: [PATCH 401/414] PM / devfreq: rockchip-dfi: Pass private data struct + to internal functions + +The internal functions do not need the struct devfreq_event_dev *, +so pass them the struct rockchip_dfi *. This is a preparation for +adding perf support later which doesn't have a struct devfreq_event_dev *. + +Signed-off-by: Sascha Hauer +Reviewed-by: Jonathan Cameron +--- + drivers/devfreq/event/rockchip-dfi.c | 15 ++++++--------- + 1 file changed, 6 insertions(+), 9 deletions(-) + +--- a/drivers/devfreq/event/rockchip-dfi.c ++++ b/drivers/devfreq/event/rockchip-dfi.c +@@ -72,9 +72,8 @@ struct rockchip_dfi { + unsigned int channel_mask; + }; + +-static void rockchip_dfi_start_hardware_counter(struct devfreq_event_dev *edev) ++static void rockchip_dfi_start_hardware_counter(struct rockchip_dfi *dfi) + { +- struct rockchip_dfi *dfi = devfreq_event_get_drvdata(edev); + void __iomem *dfi_regs = dfi->regs; + + /* clear DDRMON_CTRL setting */ +@@ -102,18 +101,16 @@ static void rockchip_dfi_start_hardware_ + dfi_regs + DDRMON_CTRL); + } + +-static void rockchip_dfi_stop_hardware_counter(struct devfreq_event_dev *edev) ++static void rockchip_dfi_stop_hardware_counter(struct rockchip_dfi *dfi) + { +- struct rockchip_dfi *dfi = devfreq_event_get_drvdata(edev); + void __iomem *dfi_regs = dfi->regs; + + writel_relaxed(HIWORD_UPDATE(0, DDRMON_CTRL_SOFTWARE_EN), + dfi_regs + DDRMON_CTRL); + } + +-static void rockchip_dfi_read_counters(struct devfreq_event_dev *edev, struct dmc_count *count) ++static void rockchip_dfi_read_counters(struct rockchip_dfi *dfi, struct dmc_count *count) + { +- struct rockchip_dfi *dfi = devfreq_event_get_drvdata(edev); + u32 i; + void __iomem *dfi_regs = dfi->regs; + +@@ -131,7 +128,7 @@ static int rockchip_dfi_disable(struct d + { + struct rockchip_dfi *dfi = devfreq_event_get_drvdata(edev); + +- rockchip_dfi_stop_hardware_counter(edev); ++ rockchip_dfi_stop_hardware_counter(dfi); + clk_disable_unprepare(dfi->clk); + + return 0; +@@ -148,7 +145,7 @@ static int rockchip_dfi_enable(struct de + return ret; + } + +- rockchip_dfi_start_hardware_counter(edev); ++ rockchip_dfi_start_hardware_counter(dfi); + return 0; + } + +@@ -166,7 +163,7 @@ static int rockchip_dfi_get_event(struct + u32 access = 0, total = 0; + int i; + +- rockchip_dfi_read_counters(edev, &count); ++ rockchip_dfi_read_counters(dfi, &count); + + /* We can only report one channel, so find the busiest one */ + for (i = 0; i < DMC_MAX_CHANNELS; i++) { diff --git a/patches-6.1/402-PM-devfreq-rockchip-dfi-Prepare-for-multiple-users.patch b/patches-6.1/402-PM-devfreq-rockchip-dfi-Prepare-for-multiple-users.patch new file mode 100644 index 0000000..ee58888 --- /dev/null +++ b/patches-6.1/402-PM-devfreq-rockchip-dfi-Prepare-for-multiple-users.patch @@ -0,0 +1,135 @@ +From 520ab63511920ec641657f8cc6838cc8645b1f08 Mon Sep 17 00:00:00 2001 +From: Sascha Hauer +Date: Wed, 24 May 2023 10:31:42 +0200 +Subject: [PATCH 402/414] PM / devfreq: rockchip-dfi: Prepare for multiple + users + +When adding perf support later the DFI must be enabled when +either of devfreq-event or perf is active. Prepare for that +by adding a usage counter for the DFI. Also move enabling +and disabling of the clock away from the devfreq-event specific +functions to which the perf specific part won't have access. + +Signed-off-by: Sascha Hauer +Reviewed-by: Jonathan Cameron +--- + drivers/devfreq/event/rockchip-dfi.c | 57 +++++++++++++++++++--------- + 1 file changed, 40 insertions(+), 17 deletions(-) + +--- a/drivers/devfreq/event/rockchip-dfi.c ++++ b/drivers/devfreq/event/rockchip-dfi.c +@@ -68,13 +68,28 @@ struct rockchip_dfi { + void __iomem *regs; + struct regmap *regmap_pmu; + struct clk *clk; ++ int usecount; ++ struct mutex mutex; + u32 ddr_type; + unsigned int channel_mask; + }; + +-static void rockchip_dfi_start_hardware_counter(struct rockchip_dfi *dfi) ++static int rockchip_dfi_enable(struct rockchip_dfi *dfi) + { + void __iomem *dfi_regs = dfi->regs; ++ int ret = 0; ++ ++ mutex_lock(&dfi->mutex); ++ ++ dfi->usecount++; ++ if (dfi->usecount > 1) ++ goto out; ++ ++ ret = clk_prepare_enable(dfi->clk); ++ if (ret) { ++ dev_err(&dfi->edev->dev, "failed to enable dfi clk: %d\n", ret); ++ goto out; ++ } + + /* clear DDRMON_CTRL setting */ + writel_relaxed(HIWORD_UPDATE(0, DDRMON_CTRL_TIMER_CNT_EN | DDRMON_CTRL_SOFTWARE_EN | +@@ -99,14 +114,30 @@ static void rockchip_dfi_start_hardware_ + /* enable count, use software mode */ + writel_relaxed(HIWORD_UPDATE(DDRMON_CTRL_SOFTWARE_EN, DDRMON_CTRL_SOFTWARE_EN), + dfi_regs + DDRMON_CTRL); ++out: ++ mutex_unlock(&dfi->mutex); ++ ++ return ret; + } + +-static void rockchip_dfi_stop_hardware_counter(struct rockchip_dfi *dfi) ++static void rockchip_dfi_disable(struct rockchip_dfi *dfi) + { + void __iomem *dfi_regs = dfi->regs; + ++ mutex_lock(&dfi->mutex); ++ ++ dfi->usecount--; ++ ++ WARN_ON_ONCE(dfi->usecount < 0); ++ ++ if (dfi->usecount > 0) ++ goto out; ++ + writel_relaxed(HIWORD_UPDATE(0, DDRMON_CTRL_SOFTWARE_EN), + dfi_regs + DDRMON_CTRL); ++ clk_disable_unprepare(dfi->clk); ++out: ++ mutex_unlock(&dfi->mutex); + } + + static void rockchip_dfi_read_counters(struct rockchip_dfi *dfi, struct dmc_count *count) +@@ -124,29 +155,20 @@ static void rockchip_dfi_read_counters(s + } + } + +-static int rockchip_dfi_disable(struct devfreq_event_dev *edev) ++static int rockchip_dfi_event_disable(struct devfreq_event_dev *edev) + { + struct rockchip_dfi *dfi = devfreq_event_get_drvdata(edev); + +- rockchip_dfi_stop_hardware_counter(dfi); +- clk_disable_unprepare(dfi->clk); ++ rockchip_dfi_disable(dfi); + + return 0; + } + +-static int rockchip_dfi_enable(struct devfreq_event_dev *edev) ++static int rockchip_dfi_event_enable(struct devfreq_event_dev *edev) + { + struct rockchip_dfi *dfi = devfreq_event_get_drvdata(edev); +- int ret; + +- ret = clk_prepare_enable(dfi->clk); +- if (ret) { +- dev_err(&edev->dev, "failed to enable dfi clk: %d\n", ret); +- return ret; +- } +- +- rockchip_dfi_start_hardware_counter(dfi); +- return 0; ++ return rockchip_dfi_enable(dfi); + } + + static int rockchip_dfi_set_event(struct devfreq_event_dev *edev) +@@ -190,8 +212,8 @@ static int rockchip_dfi_get_event(struct + } + + static const struct devfreq_event_ops rockchip_dfi_ops = { +- .disable = rockchip_dfi_disable, +- .enable = rockchip_dfi_enable, ++ .disable = rockchip_dfi_event_disable, ++ .enable = rockchip_dfi_event_enable, + .get_event = rockchip_dfi_get_event, + .set_event = rockchip_dfi_set_event, + }; +@@ -272,6 +294,7 @@ static int rockchip_dfi_probe(struct pla + return PTR_ERR(dfi->regmap_pmu); + + dfi->dev = dev; ++ mutex_init(&dfi->mutex); + + desc = &dfi->desc; + desc->ops = &rockchip_dfi_ops; diff --git a/patches-6.1/403-PM-devfreq-rockchip-dfi-give-variable-a-better-name.patch b/patches-6.1/403-PM-devfreq-rockchip-dfi-give-variable-a-better-name.patch new file mode 100644 index 0000000..73d23d1 --- /dev/null +++ b/patches-6.1/403-PM-devfreq-rockchip-dfi-give-variable-a-better-name.patch @@ -0,0 +1,78 @@ +From 86d650a48df6685ab1d5133a119e3c8cd2d620be Mon Sep 17 00:00:00 2001 +From: Sascha Hauer +Date: Wed, 24 May 2023 10:31:43 +0200 +Subject: [PATCH 403/414] PM / devfreq: rockchip-dfi: give variable a better + name + +struct dmc_count_channel::total counts the clock cycles of the DDR +controller. Rename it accordingly to give the reader a better idea +what this is about. While at it, at some documentation to struct +dmc_count_channel. + +Signed-off-by: Sascha Hauer +--- + drivers/devfreq/event/rockchip-dfi.c | 19 ++++++++++++------- + 1 file changed, 12 insertions(+), 7 deletions(-) + +--- a/drivers/devfreq/event/rockchip-dfi.c ++++ b/drivers/devfreq/event/rockchip-dfi.c +@@ -46,9 +46,14 @@ + #define DDRMON_CH1_COUNT_NUM 0x3c + #define DDRMON_CH1_DFI_ACCESS_NUM 0x40 + ++/** ++ * struct dmc_count_channel - structure to hold counter values from the DDR controller ++ * @access: Number of read and write accesses ++ * @clock_cycles: DDR clock cycles ++ */ + struct dmc_count_channel { + u32 access; +- u32 total; ++ u32 clock_cycles; + }; + + struct dmc_count { +@@ -150,7 +155,7 @@ static void rockchip_dfi_read_counters(s + continue; + count->c[i].access = readl_relaxed(dfi_regs + + DDRMON_CH0_DFI_ACCESS_NUM + i * 20); +- count->c[i].total = readl_relaxed(dfi_regs + ++ count->c[i].clock_cycles = readl_relaxed(dfi_regs + + DDRMON_CH0_COUNT_NUM + i * 20); + } + } +@@ -182,29 +187,29 @@ static int rockchip_dfi_get_event(struct + struct rockchip_dfi *dfi = devfreq_event_get_drvdata(edev); + struct dmc_count count; + struct dmc_count *last = &dfi->last_event_count; +- u32 access = 0, total = 0; ++ u32 access = 0, clock_cycles = 0; + int i; + + rockchip_dfi_read_counters(dfi, &count); + + /* We can only report one channel, so find the busiest one */ + for (i = 0; i < DMC_MAX_CHANNELS; i++) { +- u32 a, t; ++ u32 a, c; + + if (!(dfi->channel_mask & BIT(i))) + continue; + + a = count.c[i].access - last->c[i].access; +- t = count.c[i].total - last->c[i].total; ++ c = count.c[i].clock_cycles - last->c[i].clock_cycles; + + if (a > access) { + access = a; +- total = t; ++ clock_cycles = c; + } + } + + edata->load_count = access * 4; +- edata->total_count = total; ++ edata->total_count = clock_cycles; + + dfi->last_event_count = count; + diff --git a/patches-6.1/404-PM-devfreq-rockchip-dfi-Add-perf-support.patch b/patches-6.1/404-PM-devfreq-rockchip-dfi-Add-perf-support.patch new file mode 100644 index 0000000..23fc900 --- /dev/null +++ b/patches-6.1/404-PM-devfreq-rockchip-dfi-Add-perf-support.patch @@ -0,0 +1,593 @@ +From 6c88de2b2d35f01b4f6fb7bcbce3f5c928292133 Mon Sep 17 00:00:00 2001 +From: Sascha Hauer +Date: Wed, 24 May 2023 10:31:44 +0200 +Subject: [PATCH 404/414] PM / devfreq: rockchip-dfi: Add perf support + +The DFI is a unit which is suitable for measuring DDR utilization, but +so far it could only be used as an event driver for the DDR frequency +scaling driver. This adds perf support to the DFI driver. + +Usage with the 'perf' tool can look like: + +perf stat -a -e rockchip_ddr/cycles/,\ + rockchip_ddr/read-bytes/,\ + rockchip_ddr/write-bytes/,\ + rockchip_ddr/bytes/ sleep 1 + + Performance counter stats for 'system wide': + + 1582524826 rockchip_ddr/cycles/ + 1802.25 MB rockchip_ddr/read-bytes/ + 1793.72 MB rockchip_ddr/write-bytes/ + 3595.90 MB rockchip_ddr/bytes/ + + 1.014369709 seconds time elapsed + +perf support has been tested on a RK3568 and a RK3399, the latter with +dual channel DDR. + +Signed-off-by: Sascha Hauer +--- + drivers/devfreq/event/rockchip-dfi.c | 439 ++++++++++++++++++++++++++- + include/soc/rockchip/rk3399_grf.h | 2 + + include/soc/rockchip/rk3568_grf.h | 1 + + 3 files changed, 437 insertions(+), 5 deletions(-) + +--- a/drivers/devfreq/event/rockchip-dfi.c ++++ b/drivers/devfreq/event/rockchip-dfi.c +@@ -16,10 +16,12 @@ + #include + #include + #include ++#include + #include + #include + #include + #include ++#include + + #include + #include +@@ -41,19 +43,39 @@ + DDRMON_CTRL_LPDDR4 | \ + DDRMON_CTRL_LPDDR23) + ++#define DDRMON_CH0_WR_NUM 0x20 ++#define DDRMON_CH0_RD_NUM 0x24 + #define DDRMON_CH0_COUNT_NUM 0x28 + #define DDRMON_CH0_DFI_ACCESS_NUM 0x2c + #define DDRMON_CH1_COUNT_NUM 0x3c + #define DDRMON_CH1_DFI_ACCESS_NUM 0x40 + ++#define PERF_EVENT_CYCLES 0x0 ++#define PERF_EVENT_READ_BYTES 0x1 ++#define PERF_EVENT_WRITE_BYTES 0x2 ++#define PERF_EVENT_READ_BYTES0 0x3 ++#define PERF_EVENT_WRITE_BYTES0 0x4 ++#define PERF_EVENT_READ_BYTES1 0x5 ++#define PERF_EVENT_WRITE_BYTES1 0x6 ++#define PERF_EVENT_READ_BYTES2 0x7 ++#define PERF_EVENT_WRITE_BYTES2 0x8 ++#define PERF_EVENT_READ_BYTES3 0x9 ++#define PERF_EVENT_WRITE_BYTES3 0xa ++#define PERF_EVENT_BYTES 0xb ++#define PERF_ACCESS_TYPE_MAX 0xc ++ + /** + * struct dmc_count_channel - structure to hold counter values from the DDR controller + * @access: Number of read and write accesses + * @clock_cycles: DDR clock cycles ++ * @read_access: number of read accesses ++ * @write_acccess: number of write accesses + */ + struct dmc_count_channel { +- u32 access; +- u32 clock_cycles; ++ u64 access; ++ u64 clock_cycles; ++ u64 read_access; ++ u64 write_access; + }; + + struct dmc_count { +@@ -69,6 +91,11 @@ struct rockchip_dfi { + struct devfreq_event_dev *edev; + struct devfreq_event_desc desc; + struct dmc_count last_event_count; ++ ++ struct dmc_count last_perf_count; ++ struct dmc_count total_count; ++ seqlock_t count_seqlock; /* protects last_perf_count and total_count */ ++ + struct device *dev; + void __iomem *regs; + struct regmap *regmap_pmu; +@@ -77,6 +104,14 @@ struct rockchip_dfi { + struct mutex mutex; + u32 ddr_type; + unsigned int channel_mask; ++ enum cpuhp_state cpuhp_state; ++ struct hlist_node node; ++ struct pmu pmu; ++ struct hrtimer timer; ++ unsigned int cpu; ++ int active_events; ++ int burst_len; ++ int buswidth[DMC_MAX_CHANNELS]; + }; + + static int rockchip_dfi_enable(struct rockchip_dfi *dfi) +@@ -145,7 +180,7 @@ out: + mutex_unlock(&dfi->mutex); + } + +-static void rockchip_dfi_read_counters(struct rockchip_dfi *dfi, struct dmc_count *count) ++static void rockchip_dfi_read_counters(struct rockchip_dfi *dfi, struct dmc_count *c) + { + u32 i; + void __iomem *dfi_regs = dfi->regs; +@@ -153,13 +188,36 @@ static void rockchip_dfi_read_counters(s + for (i = 0; i < DMC_MAX_CHANNELS; i++) { + if (!(dfi->channel_mask & BIT(i))) + continue; +- count->c[i].access = readl_relaxed(dfi_regs + ++ c->c[i].read_access = readl_relaxed(dfi_regs + ++ DDRMON_CH0_RD_NUM + i * 20); ++ c->c[i].write_access = readl_relaxed(dfi_regs + ++ DDRMON_CH0_WR_NUM + i * 20); ++ c->c[i].access = readl_relaxed(dfi_regs + + DDRMON_CH0_DFI_ACCESS_NUM + i * 20); +- count->c[i].clock_cycles = readl_relaxed(dfi_regs + ++ c->c[i].clock_cycles = readl_relaxed(dfi_regs + + DDRMON_CH0_COUNT_NUM + i * 20); + } + } + ++static void rockchip_ddr_perf_counters_add(struct rockchip_dfi *dfi, ++ const struct dmc_count *now, ++ struct dmc_count *res) ++{ ++ const struct dmc_count *last = &dfi->last_perf_count; ++ int i; ++ ++ for (i = 0; i < DMC_MAX_CHANNELS; i++) { ++ res->c[i].read_access = dfi->total_count.c[i].read_access + ++ (u32)(now->c[i].read_access - last->c[i].read_access); ++ res->c[i].write_access = dfi->total_count.c[i].write_access + ++ (u32)(now->c[i].write_access - last->c[i].write_access); ++ res->c[i].access = dfi->total_count.c[i].access + ++ (u32)(now->c[i].access - last->c[i].access); ++ res->c[i].clock_cycles = dfi->total_count.c[i].clock_cycles + ++ (u32)(now->c[i].clock_cycles - last->c[i].clock_cycles); ++ } ++} ++ + static int rockchip_dfi_event_disable(struct devfreq_event_dev *edev) + { + struct rockchip_dfi *dfi = devfreq_event_get_drvdata(edev); +@@ -223,6 +281,367 @@ static const struct devfreq_event_ops ro + .set_event = rockchip_dfi_set_event, + }; + ++#ifdef CONFIG_PERF_EVENTS ++ ++static ssize_t ddr_perf_cpumask_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct pmu *pmu = dev_get_drvdata(dev); ++ struct rockchip_dfi *dfi = container_of(pmu, struct rockchip_dfi, pmu); ++ ++ return cpumap_print_to_pagebuf(true, buf, cpumask_of(dfi->cpu)); ++} ++ ++static struct device_attribute ddr_perf_cpumask_attr = ++ __ATTR(cpumask, 0444, ddr_perf_cpumask_show, NULL); ++ ++static struct attribute *ddr_perf_cpumask_attrs[] = { ++ &ddr_perf_cpumask_attr.attr, ++ NULL, ++}; ++ ++static const struct attribute_group ddr_perf_cpumask_attr_group = { ++ .attrs = ddr_perf_cpumask_attrs, ++}; ++ ++PMU_EVENT_ATTR_STRING(cycles, ddr_pmu_cycles, "event="__stringify(PERF_EVENT_CYCLES)) ++ ++#define DFI_PMU_EVENT_ATTR(_name, _var, _str) \ ++ PMU_EVENT_ATTR_STRING(_name, _var, _str); \ ++ PMU_EVENT_ATTR_STRING(_name.unit, _var##_unit, "MB"); \ ++ PMU_EVENT_ATTR_STRING(_name.scale, _var##_scale, "9.536743164e-07") ++ ++DFI_PMU_EVENT_ATTR(read-bytes0, ddr_pmu_read_bytes0, "event="__stringify(PERF_EVENT_READ_BYTES0)); ++DFI_PMU_EVENT_ATTR(write-bytes0, ddr_pmu_write_bytes0, "event="__stringify(PERF_EVENT_WRITE_BYTES0)); ++ ++DFI_PMU_EVENT_ATTR(read-bytes1, ddr_pmu_read_bytes1, "event="__stringify(PERF_EVENT_READ_BYTES1)); ++DFI_PMU_EVENT_ATTR(write-bytes1, ddr_pmu_write_bytes1, "event="__stringify(PERF_EVENT_WRITE_BYTES1)); ++ ++DFI_PMU_EVENT_ATTR(read-bytes2, ddr_pmu_read_bytes2, "event="__stringify(PERF_EVENT_READ_BYTES2)); ++DFI_PMU_EVENT_ATTR(write-bytes2, ddr_pmu_write_bytes2, "event="__stringify(PERF_EVENT_WRITE_BYTES2)); ++ ++DFI_PMU_EVENT_ATTR(read-bytes3, ddr_pmu_read_bytes3, "event="__stringify(PERF_EVENT_READ_BYTES3)); ++DFI_PMU_EVENT_ATTR(write-bytes3, ddr_pmu_write_bytes3, "event="__stringify(PERF_EVENT_WRITE_BYTES3)); ++ ++DFI_PMU_EVENT_ATTR(read-bytes, ddr_pmu_read_bytes, "event="__stringify(PERF_EVENT_READ_BYTES)); ++DFI_PMU_EVENT_ATTR(write-bytes, ddr_pmu_write_bytes, "event="__stringify(PERF_EVENT_WRITE_BYTES)); ++ ++DFI_PMU_EVENT_ATTR(bytes, ddr_pmu_bytes, "event="__stringify(PERF_EVENT_BYTES)); ++ ++#define DFI_ATTR_MB(_name) \ ++ &_name.attr.attr, \ ++ &_name##_unit.attr.attr, \ ++ &_name##_scale.attr.attr ++ ++static struct attribute *ddr_perf_events_attrs[] = { ++ &ddr_pmu_cycles.attr.attr, ++ DFI_ATTR_MB(ddr_pmu_read_bytes), ++ DFI_ATTR_MB(ddr_pmu_write_bytes), ++ DFI_ATTR_MB(ddr_pmu_read_bytes0), ++ DFI_ATTR_MB(ddr_pmu_write_bytes0), ++ DFI_ATTR_MB(ddr_pmu_read_bytes1), ++ DFI_ATTR_MB(ddr_pmu_write_bytes1), ++ DFI_ATTR_MB(ddr_pmu_read_bytes2), ++ DFI_ATTR_MB(ddr_pmu_write_bytes2), ++ DFI_ATTR_MB(ddr_pmu_read_bytes3), ++ DFI_ATTR_MB(ddr_pmu_write_bytes3), ++ DFI_ATTR_MB(ddr_pmu_bytes), ++ NULL, ++}; ++ ++static const struct attribute_group ddr_perf_events_attr_group = { ++ .name = "events", ++ .attrs = ddr_perf_events_attrs, ++}; ++ ++PMU_FORMAT_ATTR(event, "config:0-7"); ++ ++static struct attribute *ddr_perf_format_attrs[] = { ++ &format_attr_event.attr, ++ NULL, ++}; ++ ++static const struct attribute_group ddr_perf_format_attr_group = { ++ .name = "format", ++ .attrs = ddr_perf_format_attrs, ++}; ++ ++static const struct attribute_group *attr_groups[] = { ++ &ddr_perf_events_attr_group, ++ &ddr_perf_cpumask_attr_group, ++ &ddr_perf_format_attr_group, ++ NULL, ++}; ++ ++static int rockchip_ddr_perf_event_init(struct perf_event *event) ++{ ++ struct rockchip_dfi *dfi = container_of(event->pmu, struct rockchip_dfi, pmu); ++ ++ if (event->attr.type != event->pmu->type) ++ return -ENOENT; ++ ++ if (event->attach_state & PERF_ATTACH_TASK) ++ return -EINVAL; ++ ++ if (event->cpu < 0) { ++ dev_warn(dfi->dev, "Can't provide per-task data!\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static u64 rockchip_ddr_perf_event_get_count(struct perf_event *event) ++{ ++ struct rockchip_dfi *dfi = container_of(event->pmu, struct rockchip_dfi, pmu); ++ int blen = dfi->burst_len; ++ struct dmc_count total, now; ++ unsigned int seq; ++ u64 c = 0; ++ int i; ++ ++ rockchip_dfi_read_counters(dfi, &now); ++ ++ do { ++ seq = read_seqbegin(&dfi->count_seqlock); ++ ++ rockchip_ddr_perf_counters_add(dfi, &now, &total); ++ ++ } while (read_seqretry(&dfi->count_seqlock, seq)); ++ ++ switch (event->attr.config) { ++ case PERF_EVENT_CYCLES: ++ c = total.c[0].clock_cycles; ++ break; ++ case PERF_EVENT_READ_BYTES: ++ for (i = 0; i < DMC_MAX_CHANNELS; i++) ++ c += total.c[i].read_access * blen * dfi->buswidth[i]; ++ break; ++ case PERF_EVENT_WRITE_BYTES: ++ for (i = 0; i < DMC_MAX_CHANNELS; i++) ++ c += total.c[i].write_access * blen * dfi->buswidth[i]; ++ break; ++ case PERF_EVENT_READ_BYTES0: ++ c = total.c[0].read_access * blen * dfi->buswidth[0]; ++ break; ++ case PERF_EVENT_WRITE_BYTES0: ++ c = total.c[0].write_access * blen * dfi->buswidth[0]; ++ break; ++ case PERF_EVENT_READ_BYTES1: ++ c = total.c[1].read_access * blen * dfi->buswidth[1]; ++ break; ++ case PERF_EVENT_WRITE_BYTES1: ++ c = total.c[1].write_access * blen * dfi->buswidth[1]; ++ break; ++ case PERF_EVENT_READ_BYTES2: ++ c = total.c[2].read_access * blen * dfi->buswidth[2]; ++ break; ++ case PERF_EVENT_WRITE_BYTES2: ++ c = total.c[2].write_access * blen * dfi->buswidth[2]; ++ break; ++ case PERF_EVENT_READ_BYTES3: ++ c = total.c[3].read_access * blen * dfi->buswidth[3]; ++ break; ++ case PERF_EVENT_WRITE_BYTES3: ++ c = total.c[3].write_access * blen * dfi->buswidth[3]; ++ break; ++ case PERF_EVENT_BYTES: ++ for (i = 0; i < DMC_MAX_CHANNELS; i++) ++ c += total.c[i].access * blen * dfi->buswidth[i]; ++ break; ++ } ++ ++ return c; ++} ++ ++static void rockchip_ddr_perf_event_update(struct perf_event *event) ++{ ++ u64 now; ++ s64 prev; ++ ++ if (event->attr.config >= PERF_ACCESS_TYPE_MAX) ++ return; ++ ++ now = rockchip_ddr_perf_event_get_count(event); ++ prev = local64_xchg(&event->hw.prev_count, now); ++ local64_add(now - prev, &event->count); ++} ++ ++static void rockchip_ddr_perf_event_start(struct perf_event *event, int flags) ++{ ++ u64 now = rockchip_ddr_perf_event_get_count(event); ++ ++ local64_set(&event->hw.prev_count, now); ++} ++ ++static int rockchip_ddr_perf_event_add(struct perf_event *event, int flags) ++{ ++ struct rockchip_dfi *dfi = container_of(event->pmu, struct rockchip_dfi, pmu); ++ ++ dfi->active_events++; ++ ++ if (dfi->active_events == 1) ++ hrtimer_start(&dfi->timer, ns_to_ktime(NSEC_PER_SEC), HRTIMER_MODE_REL); ++ ++ if (flags & PERF_EF_START) ++ rockchip_ddr_perf_event_start(event, flags); ++ ++ return 0; ++} ++ ++static void rockchip_ddr_perf_event_stop(struct perf_event *event, int flags) ++{ ++ rockchip_ddr_perf_event_update(event); ++} ++ ++static void rockchip_ddr_perf_event_del(struct perf_event *event, int flags) ++{ ++ struct rockchip_dfi *dfi = container_of(event->pmu, struct rockchip_dfi, pmu); ++ ++ rockchip_ddr_perf_event_stop(event, PERF_EF_UPDATE); ++ ++ dfi->active_events--; ++ ++ if (dfi->active_events == 0) ++ hrtimer_cancel(&dfi->timer); ++} ++ ++static enum hrtimer_restart rockchip_dfi_timer(struct hrtimer *timer) ++{ ++ struct rockchip_dfi *dfi = container_of(timer, struct rockchip_dfi, timer); ++ struct dmc_count now, total; ++ ++ rockchip_dfi_read_counters(dfi, &now); ++ ++ write_seqlock(&dfi->count_seqlock); ++ ++ rockchip_ddr_perf_counters_add(dfi, &now, &total); ++ dfi->total_count = total; ++ dfi->last_perf_count = now; ++ ++ write_sequnlock(&dfi->count_seqlock); ++ ++ hrtimer_forward_now(&dfi->timer, ns_to_ktime(NSEC_PER_SEC)); ++ ++ return HRTIMER_RESTART; ++}; ++ ++static int ddr_perf_offline_cpu(unsigned int cpu, struct hlist_node *node) ++{ ++ struct rockchip_dfi *dfi = hlist_entry_safe(node, struct rockchip_dfi, node); ++ int target; ++ ++ if (cpu != dfi->cpu) ++ return 0; ++ ++ target = cpumask_any_but(cpu_online_mask, cpu); ++ if (target >= nr_cpu_ids) ++ return 0; ++ ++ perf_pmu_migrate_context(&dfi->pmu, cpu, target); ++ dfi->cpu = target; ++ ++ return 0; ++} ++ ++static void rockchip_ddr_cpuhp_remove_state(void *data) ++{ ++ struct rockchip_dfi *dfi = data; ++ ++ cpuhp_remove_multi_state(dfi->cpuhp_state); ++ ++ rockchip_dfi_disable(dfi); ++} ++ ++static void rockchip_ddr_cpuhp_remove_instance(void *data) ++{ ++ struct rockchip_dfi *dfi = data; ++ ++ cpuhp_state_remove_instance_nocalls(dfi->cpuhp_state, &dfi->node); ++} ++ ++static void rockchip_ddr_perf_remove(void *data) ++{ ++ struct rockchip_dfi *dfi = data; ++ ++ perf_pmu_unregister(&dfi->pmu); ++} ++ ++static int rockchip_ddr_perf_init(struct rockchip_dfi *dfi) ++{ ++ struct pmu *pmu = &dfi->pmu; ++ int ret; ++ ++ seqlock_init(&dfi->count_seqlock); ++ ++ pmu->module = THIS_MODULE; ++ pmu->capabilities = PERF_PMU_CAP_NO_EXCLUDE; ++ pmu->task_ctx_nr = perf_invalid_context; ++ pmu->attr_groups = attr_groups; ++ pmu->event_init = rockchip_ddr_perf_event_init; ++ pmu->add = rockchip_ddr_perf_event_add; ++ pmu->del = rockchip_ddr_perf_event_del; ++ pmu->start = rockchip_ddr_perf_event_start; ++ pmu->stop = rockchip_ddr_perf_event_stop; ++ pmu->read = rockchip_ddr_perf_event_update; ++ ++ dfi->cpu = raw_smp_processor_id(); ++ ++ ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, ++ "rockchip_ddr_perf_pmu", ++ NULL, ++ ddr_perf_offline_cpu); ++ ++ if (ret < 0) { ++ dev_err(dfi->dev, "cpuhp_setup_state_multi failed: %d\n", ret); ++ return ret; ++ } ++ ++ dfi->cpuhp_state = ret; ++ ++ rockchip_dfi_enable(dfi); ++ ++ ret = devm_add_action_or_reset(dfi->dev, rockchip_ddr_cpuhp_remove_state, dfi); ++ if (ret) ++ return ret; ++ ++ ret = cpuhp_state_add_instance_nocalls(dfi->cpuhp_state, &dfi->node); ++ if (ret) { ++ dev_err(dfi->dev, "Error %d registering hotplug\n", ret); ++ return ret; ++ } ++ ++ ret = devm_add_action_or_reset(dfi->dev, rockchip_ddr_cpuhp_remove_instance, dfi); ++ if (ret) ++ return ret; ++ ++ hrtimer_init(&dfi->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ++ dfi->timer.function = rockchip_dfi_timer; ++ ++ switch (dfi->ddr_type) { ++ case ROCKCHIP_DDRTYPE_LPDDR2: ++ case ROCKCHIP_DDRTYPE_LPDDR3: ++ dfi->burst_len = 8; ++ break; ++ case ROCKCHIP_DDRTYPE_LPDDR4: ++ case ROCKCHIP_DDRTYPE_LPDDR4X: ++ dfi->burst_len = 16; ++ break; ++ } ++ ++ ret = perf_pmu_register(pmu, "rockchip_ddr", -1); ++ if (ret) ++ return ret; ++ ++ return devm_add_action_or_reset(dfi->dev, rockchip_ddr_perf_remove, dfi); ++} ++#else ++static int rockchip_ddr_perf_init(struct rockchip_dfi *dfi) ++{ ++ return 0; ++} ++#endif ++ + static int rk3399_dfi_init(struct rockchip_dfi *dfi) + { + struct regmap *regmap_pmu = dfi->regmap_pmu; +@@ -239,6 +658,9 @@ static int rk3399_dfi_init(struct rockch + + dfi->channel_mask = GENMASK(1, 0); + ++ dfi->buswidth[0] = FIELD_GET(RK3399_PMUGRF_OS_REG2_BW_CH0, val) == 0 ? 4 : 2; ++ dfi->buswidth[1] = FIELD_GET(RK3399_PMUGRF_OS_REG2_BW_CH1, val) == 0 ? 4 : 2; ++ + return 0; + }; + +@@ -255,6 +677,8 @@ static int rk3568_dfi_init(struct rockch + if (FIELD_GET(RK3568_PMUGRF_OS_REG3_SYSREG_VERSION, reg3) >= 0x3) + dfi->ddr_type |= FIELD_GET(RK3568_PMUGRF_OS_REG3_DRAMTYPE_INFO_V3, reg3) << 3; + ++ dfi->buswidth[0] = FIELD_GET(RK3568_PMUGRF_OS_REG2_BW_CH0, reg2) == 0 ? 4 : 2; ++ + dfi->channel_mask = 1; + + return 0; +@@ -317,6 +741,10 @@ static int rockchip_dfi_probe(struct pla + return PTR_ERR(dfi->edev); + } + ++ ret = rockchip_ddr_perf_init(dfi); ++ if (ret) ++ return ret; ++ + platform_set_drvdata(pdev, dfi); + + return 0; +@@ -327,6 +755,7 @@ static struct platform_driver rockchip_d + .driver = { + .name = "rockchip-dfi", + .of_match_table = rockchip_dfi_id_match, ++ .suppress_bind_attrs = true, + }, + }; + module_platform_driver(rockchip_dfi_driver); +--- a/include/soc/rockchip/rk3399_grf.h ++++ b/include/soc/rockchip/rk3399_grf.h +@@ -12,5 +12,7 @@ + /* PMU GRF Registers */ + #define RK3399_PMUGRF_OS_REG2 0x308 + #define RK3399_PMUGRF_OS_REG2_DDRTYPE GENMASK(15, 13) ++#define RK3399_PMUGRF_OS_REG2_BW_CH0 GENMASK(3, 2) ++#define RK3399_PMUGRF_OS_REG2_BW_CH1 GENMASK(19, 18) + + #endif +--- a/include/soc/rockchip/rk3568_grf.h ++++ b/include/soc/rockchip/rk3568_grf.h +@@ -4,6 +4,7 @@ + + #define RK3568_PMUGRF_OS_REG2 0x208 + #define RK3568_PMUGRF_OS_REG2_DRAMTYPE_INFO GENMASK(15, 13) ++#define RK3568_PMUGRF_OS_REG2_BW_CH0 GENMASK(3, 2) + + #define RK3568_PMUGRF_OS_REG3 0x20c + #define RK3568_PMUGRF_OS_REG3_DRAMTYPE_INFO_V3 GENMASK(13, 12) diff --git a/patches-6.1/405-PM-devfreq-rockchip-dfi-make-register-stride-SoC-spe.patch b/patches-6.1/405-PM-devfreq-rockchip-dfi-make-register-stride-SoC-spe.patch new file mode 100644 index 0000000..a9b5155 --- /dev/null +++ b/patches-6.1/405-PM-devfreq-rockchip-dfi-make-register-stride-SoC-spe.patch @@ -0,0 +1,56 @@ +From 1067b1854ad723a3cd57f76924fb3c7ddea6f22e Mon Sep 17 00:00:00 2001 +From: Sascha Hauer +Date: Wed, 24 May 2023 10:31:45 +0200 +Subject: [PATCH 405/414] PM / devfreq: rockchip-dfi: make register stride SoC + specific + +The currently supported RK3399 has a stride of 20 between the channel +specific registers. Upcoming RK3588 has a different stride, so put +the stride into driver data to make it configurable. +While at it convert decimal 20 to hex 0x14 for consistency with RK3588 +which has a register stride 0x4000 and we want to write that in hex +as well. + +Signed-off-by: Sascha Hauer +Reviewed-by: Jonathan Cameron +--- + drivers/devfreq/event/rockchip-dfi.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +--- a/drivers/devfreq/event/rockchip-dfi.c ++++ b/drivers/devfreq/event/rockchip-dfi.c +@@ -112,6 +112,7 @@ struct rockchip_dfi { + int active_events; + int burst_len; + int buswidth[DMC_MAX_CHANNELS]; ++ int ddrmon_stride; + }; + + static int rockchip_dfi_enable(struct rockchip_dfi *dfi) +@@ -189,13 +190,13 @@ static void rockchip_dfi_read_counters(s + if (!(dfi->channel_mask & BIT(i))) + continue; + c->c[i].read_access = readl_relaxed(dfi_regs + +- DDRMON_CH0_RD_NUM + i * 20); ++ DDRMON_CH0_RD_NUM + i * dfi->ddrmon_stride); + c->c[i].write_access = readl_relaxed(dfi_regs + +- DDRMON_CH0_WR_NUM + i * 20); ++ DDRMON_CH0_WR_NUM + i * dfi->ddrmon_stride); + c->c[i].access = readl_relaxed(dfi_regs + +- DDRMON_CH0_DFI_ACCESS_NUM + i * 20); ++ DDRMON_CH0_DFI_ACCESS_NUM + i * dfi->ddrmon_stride); + c->c[i].clock_cycles = readl_relaxed(dfi_regs + +- DDRMON_CH0_COUNT_NUM + i * 20); ++ DDRMON_CH0_COUNT_NUM + i * dfi->ddrmon_stride); + } + } + +@@ -661,6 +662,8 @@ static int rk3399_dfi_init(struct rockch + dfi->buswidth[0] = FIELD_GET(RK3399_PMUGRF_OS_REG2_BW_CH0, val) == 0 ? 4 : 2; + dfi->buswidth[1] = FIELD_GET(RK3399_PMUGRF_OS_REG2_BW_CH1, val) == 0 ? 4 : 2; + ++ dfi->ddrmon_stride = 0x14; ++ + return 0; + }; + diff --git a/patches-6.1/406-PM-devfreq-rockchip-dfi-account-for-multiple-DDRMON_.patch b/patches-6.1/406-PM-devfreq-rockchip-dfi-account-for-multiple-DDRMON_.patch new file mode 100644 index 0000000..19128ce --- /dev/null +++ b/patches-6.1/406-PM-devfreq-rockchip-dfi-account-for-multiple-DDRMON_.patch @@ -0,0 +1,137 @@ +From 69dbc52aef08f566494ae5da340dc708c3f3e362 Mon Sep 17 00:00:00 2001 +From: Sascha Hauer +Date: Wed, 24 May 2023 10:31:46 +0200 +Subject: [PATCH 406/414] PM / devfreq: rockchip-dfi: account for multiple + DDRMON_CTRL registers + +The currently supported RK3399 has a set of registers per channel, but +it has only a single DDRMON_CTRL register. With upcoming RK3588 this +will be different, the RK3588 has a DDRMON_CTRL register per channel. + +Instead of expecting a single DDRMON_CTRL register, loop over the +channels and write the channel specific DDRMON_CTRL register. Break +out early out of the loop when there is only a single DDRMON_CTRL +register like on the RK3399. + +Signed-off-by: Sascha Hauer +Reviewed-by: Jonathan Cameron +--- + drivers/devfreq/event/rockchip-dfi.c | 72 ++++++++++++++++++---------- + 1 file changed, 48 insertions(+), 24 deletions(-) + +--- a/drivers/devfreq/event/rockchip-dfi.c ++++ b/drivers/devfreq/event/rockchip-dfi.c +@@ -113,12 +113,13 @@ struct rockchip_dfi { + int burst_len; + int buswidth[DMC_MAX_CHANNELS]; + int ddrmon_stride; ++ bool ddrmon_ctrl_single; + }; + + static int rockchip_dfi_enable(struct rockchip_dfi *dfi) + { + void __iomem *dfi_regs = dfi->regs; +- int ret = 0; ++ int i, ret = 0; + + mutex_lock(&dfi->mutex); + +@@ -132,29 +133,41 @@ static int rockchip_dfi_enable(struct ro + goto out; + } + +- /* clear DDRMON_CTRL setting */ +- writel_relaxed(HIWORD_UPDATE(0, DDRMON_CTRL_TIMER_CNT_EN | DDRMON_CTRL_SOFTWARE_EN | +- DDRMON_CTRL_HARDWARE_EN), dfi_regs + DDRMON_CTRL); ++ for (i = 0; i < DMC_MAX_CHANNELS; i++) { ++ u32 ctrl = 0; + +- /* set ddr type to dfi */ +- switch (dfi->ddr_type) { +- case ROCKCHIP_DDRTYPE_LPDDR2: +- case ROCKCHIP_DDRTYPE_LPDDR3: +- writel_relaxed(HIWORD_UPDATE(DDRMON_CTRL_LPDDR23, DDRMON_CTRL_DDR_TYPE_MASK), +- dfi_regs + DDRMON_CTRL); +- break; +- case ROCKCHIP_DDRTYPE_LPDDR4: +- case ROCKCHIP_DDRTYPE_LPDDR4X: +- writel_relaxed(HIWORD_UPDATE(DDRMON_CTRL_LPDDR4, DDRMON_CTRL_DDR_TYPE_MASK), +- dfi_regs + DDRMON_CTRL); +- break; +- default: +- break; +- } ++ if (!(dfi->channel_mask & BIT(i))) ++ continue; + +- /* enable count, use software mode */ +- writel_relaxed(HIWORD_UPDATE(DDRMON_CTRL_SOFTWARE_EN, DDRMON_CTRL_SOFTWARE_EN), +- dfi_regs + DDRMON_CTRL); ++ /* clear DDRMON_CTRL setting */ ++ writel_relaxed(HIWORD_UPDATE(0, DDRMON_CTRL_TIMER_CNT_EN | ++ DDRMON_CTRL_SOFTWARE_EN | DDRMON_CTRL_HARDWARE_EN), ++ dfi_regs + i * dfi->ddrmon_stride + DDRMON_CTRL); ++ ++ /* set ddr type to dfi */ ++ switch (dfi->ddr_type) { ++ case ROCKCHIP_DDRTYPE_LPDDR2: ++ case ROCKCHIP_DDRTYPE_LPDDR3: ++ ctrl = DDRMON_CTRL_LPDDR23; ++ break; ++ case ROCKCHIP_DDRTYPE_LPDDR4: ++ case ROCKCHIP_DDRTYPE_LPDDR4X: ++ ctrl = DDRMON_CTRL_LPDDR4; ++ break; ++ default: ++ break; ++ } ++ ++ writel_relaxed(HIWORD_UPDATE(ctrl, DDRMON_CTRL_DDR_TYPE_MASK), ++ dfi_regs + i * dfi->ddrmon_stride + DDRMON_CTRL); ++ ++ /* enable count, use software mode */ ++ writel_relaxed(HIWORD_UPDATE(DDRMON_CTRL_SOFTWARE_EN, DDRMON_CTRL_SOFTWARE_EN), ++ dfi_regs + i * dfi->ddrmon_stride + DDRMON_CTRL); ++ ++ if (dfi->ddrmon_ctrl_single) ++ break; ++ } + out: + mutex_unlock(&dfi->mutex); + +@@ -164,6 +177,7 @@ out: + static void rockchip_dfi_disable(struct rockchip_dfi *dfi) + { + void __iomem *dfi_regs = dfi->regs; ++ int i; + + mutex_lock(&dfi->mutex); + +@@ -174,8 +188,17 @@ static void rockchip_dfi_disable(struct + if (dfi->usecount > 0) + goto out; + +- writel_relaxed(HIWORD_UPDATE(0, DDRMON_CTRL_SOFTWARE_EN), +- dfi_regs + DDRMON_CTRL); ++ for (i = 0; i < DMC_MAX_CHANNELS; i++) { ++ if (!(dfi->channel_mask & BIT(i))) ++ continue; ++ ++ writel_relaxed(HIWORD_UPDATE(0, DDRMON_CTRL_SOFTWARE_EN), ++ dfi_regs + i * dfi->ddrmon_stride + DDRMON_CTRL); ++ ++ if (dfi->ddrmon_ctrl_single) ++ break; ++ } ++ + clk_disable_unprepare(dfi->clk); + out: + mutex_unlock(&dfi->mutex); +@@ -663,6 +686,7 @@ static int rk3399_dfi_init(struct rockch + dfi->buswidth[1] = FIELD_GET(RK3399_PMUGRF_OS_REG2_BW_CH1, val) == 0 ? 4 : 2; + + dfi->ddrmon_stride = 0x14; ++ dfi->ddrmon_ctrl_single = true; + + return 0; + }; diff --git a/patches-6.1/411-arm64-dts-rockchip-rk3399-Enable-DFI.patch b/patches-6.1/411-arm64-dts-rockchip-rk3399-Enable-DFI.patch new file mode 100644 index 0000000..bf31f80 --- /dev/null +++ b/patches-6.1/411-arm64-dts-rockchip-rk3399-Enable-DFI.patch @@ -0,0 +1,24 @@ +From 6bda3afaebc2e69491f09e469dd5d72b94547a09 Mon Sep 17 00:00:00 2001 +From: Sascha Hauer +Date: Wed, 24 May 2023 10:31:51 +0200 +Subject: [PATCH 411/414] arm64: dts: rockchip: rk3399: Enable DFI + +the DFI unit can provide useful data for measuring DDR utilization +and works without any configuration from the board, so enable it in the +dtsi file directly. + +Signed-off-by: Sascha Hauer +--- + arch/arm64/boot/dts/rockchip/rk3399.dtsi | 1 - + 1 file changed, 1 deletion(-) + +--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +@@ -1331,7 +1331,6 @@ + interrupts = ; + clocks = <&cru PCLK_DDR_MON>; + clock-names = "pclk_ddr_mon"; +- status = "disabled"; + }; + + vpu: video-codec@ff650000 { diff --git a/patches-6.1/412-arm64-dts-rockchip-rk356x-Add-DFI.patch b/patches-6.1/412-arm64-dts-rockchip-rk356x-Add-DFI.patch new file mode 100644 index 0000000..ce9dceb --- /dev/null +++ b/patches-6.1/412-arm64-dts-rockchip-rk356x-Add-DFI.patch @@ -0,0 +1,29 @@ +From 512c554e882c8e326bffb5d8ac1d5f22d5b85012 Mon Sep 17 00:00:00 2001 +From: Sascha Hauer +Date: Wed, 24 May 2023 10:31:52 +0200 +Subject: [PATCH 412/414] arm64: dts: rockchip: rk356x: Add DFI + +The DFI unit can be used to measure DRAM utilization using perf. Add the +node to the device tree. + +Signed-off-by: Sascha Hauer +--- + arch/arm64/boot/dts/rockchip/rk356x.dtsi | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/arch/arm64/boot/dts/rockchip/rk356x.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk356x.dtsi +@@ -959,6 +959,13 @@ + reg = <0x0 0xfe1a8100 0x0 0x20>; + }; + ++ dfi: dfi@fe230000 { ++ compatible = "rockchip,rk3568-dfi"; ++ reg = <0x00 0xfe230000 0x00 0x400>; ++ interrupts = ; ++ rockchip,pmu = <&pmugrf>; ++ }; ++ + pcie2x1: pcie@fe260000 { + compatible = "rockchip,rk3568-pcie"; + reg = <0x3 0xc0000000 0x0 0x00400000>, diff --git a/patches-6.1/805-PM-devfreq-rockchip-dfi-add-more-soc-support.patch b/patches-6.1/805-PM-devfreq-rockchip-dfi-add-more-soc-support.patch deleted file mode 100644 index 0bde4e1..0000000 --- a/patches-6.1/805-PM-devfreq-rockchip-dfi-add-more-soc-support.patch +++ /dev/null @@ -1,662 +0,0 @@ -From 4db93c6dad0c71750b86163df2fdb21c35f00d9a Mon Sep 17 00:00:00 2001 -From: hmz007 -Date: Tue, 19 Nov 2019 12:49:48 +0800 -Subject: [PATCH] PM / devfreq: rockchip-dfi: add more soc support - -Signed-off-by: hmz007 ---- - drivers/devfreq/event/rockchip-dfi.c | 554 ++++++++++++++++++++++++--- - 1 file changed, 505 insertions(+), 49 deletions(-) - ---- a/drivers/devfreq/event/rockchip-dfi.c -+++ b/drivers/devfreq/event/rockchip-dfi.c -@@ -18,25 +18,66 @@ - #include - #include - --#include -- --#define RK3399_DMC_NUM_CH 2 -+#define PX30_PMUGRF_OS_REG2 0x208 - -+#define RK3128_GRF_SOC_CON0 0x140 -+#define RK3128_GRF_OS_REG1 0x1cc -+#define RK3128_GRF_DFI_WRNUM 0x220 -+#define RK3128_GRF_DFI_RDNUM 0x224 -+#define RK3128_GRF_DFI_TIMERVAL 0x22c -+#define RK3128_DDR_MONITOR_EN ((1 << (16 + 6)) + (1 << 6)) -+#define RK3128_DDR_MONITOR_DISB ((1 << (16 + 6)) + (0 << 6)) -+ -+#define RK3288_PMU_SYS_REG2 0x9c -+#define RK3288_GRF_SOC_CON4 0x254 -+#define RK3288_GRF_SOC_STATUS(n) (0x280 + (n) * 4) -+#define RK3288_DFI_EN (0x30003 << 14) -+#define RK3288_DFI_DIS (0x30000 << 14) -+#define RK3288_LPDDR_SEL (0x10001 << 13) -+#define RK3288_DDR3_SEL (0x10000 << 13) -+ -+#define RK3328_GRF_OS_REG2 0x5d0 -+ -+#define RK3368_GRF_DDRC0_CON0 0x600 -+#define RK3368_GRF_SOC_STATUS5 0x494 -+#define RK3368_GRF_SOC_STATUS6 0x498 -+#define RK3368_GRF_SOC_STATUS8 0x4a0 -+#define RK3368_GRF_SOC_STATUS9 0x4a4 -+#define RK3368_GRF_SOC_STATUS10 0x4a8 -+#define RK3368_DFI_EN (0x30003 << 5) -+#define RK3368_DFI_DIS (0x30000 << 5) -+ -+#define MAX_DMC_NUM_CH 2 -+#define READ_DRAMTYPE_INFO(n) (((n) >> 13) & 0x7) -+#define READ_CH_INFO(n) (((n) >> 28) & 0x3) - /* DDRMON_CTRL */ --#define DDRMON_CTRL 0x04 --#define CLR_DDRMON_CTRL (0x1f0000 << 0) --#define LPDDR4_EN (0x10001 << 4) --#define HARDWARE_EN (0x10001 << 3) --#define LPDDR3_EN (0x10001 << 2) --#define SOFTWARE_EN (0x10001 << 1) --#define SOFTWARE_DIS (0x10000 << 1) --#define TIME_CNT_EN (0x10001 << 0) -+#define DDRMON_CTRL 0x04 -+#define CLR_DDRMON_CTRL (0x3f0000 << 0) -+#define DDR4_EN (0x10001 << 5) -+#define LPDDR4_EN (0x10001 << 4) -+#define HARDWARE_EN (0x10001 << 3) -+#define LPDDR2_3_EN (0x10001 << 2) -+#define SOFTWARE_EN (0x10001 << 1) -+#define SOFTWARE_DIS (0x10000 << 1) -+#define TIME_CNT_EN (0x10001 << 0) - - #define DDRMON_CH0_COUNT_NUM 0x28 - #define DDRMON_CH0_DFI_ACCESS_NUM 0x2c - #define DDRMON_CH1_COUNT_NUM 0x3c - #define DDRMON_CH1_DFI_ACCESS_NUM 0x40 - -+/* pmu grf */ -+#define PMUGRF_OS_REG2 0x308 -+ -+enum { -+ DDR4 = 0, -+ DDR3 = 3, -+ LPDDR2 = 5, -+ LPDDR3 = 6, -+ LPDDR4 = 7, -+ UNUSED = 0xFF -+}; -+ - struct dmc_usage { - u32 access; - u32 total; -@@ -50,33 +91,261 @@ struct dmc_usage { - struct rockchip_dfi { - struct devfreq_event_dev *edev; - struct devfreq_event_desc *desc; -- struct dmc_usage ch_usage[RK3399_DMC_NUM_CH]; -+ struct dmc_usage ch_usage[MAX_DMC_NUM_CH]; - struct device *dev; - void __iomem *regs; - struct regmap *regmap_pmu; -+ struct regmap *regmap_grf; -+ struct regmap *regmap_pmugrf; - struct clk *clk; -+ u32 dram_type; -+ /* -+ * available mask, 1: available, 0: not available -+ * each bit represent a channel -+ */ -+ u32 ch_msk; -+}; -+ -+static void rk3128_dfi_start_hardware_counter(struct devfreq_event_dev *edev) -+{ -+ struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); -+ -+ regmap_write(info->regmap_grf, -+ RK3128_GRF_SOC_CON0, -+ RK3128_DDR_MONITOR_EN); -+} -+ -+static void rk3128_dfi_stop_hardware_counter(struct devfreq_event_dev *edev) -+{ -+ struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); -+ -+ regmap_write(info->regmap_grf, -+ RK3128_GRF_SOC_CON0, -+ RK3128_DDR_MONITOR_DISB); -+} -+ -+static int rk3128_dfi_disable(struct devfreq_event_dev *edev) -+{ -+ rk3128_dfi_stop_hardware_counter(edev); -+ -+ return 0; -+} -+ -+static int rk3128_dfi_enable(struct devfreq_event_dev *edev) -+{ -+ rk3128_dfi_start_hardware_counter(edev); -+ -+ return 0; -+} -+ -+static int rk3128_dfi_set_event(struct devfreq_event_dev *edev) -+{ -+ return 0; -+} -+ -+static int rk3128_dfi_get_event(struct devfreq_event_dev *edev, -+ struct devfreq_event_data *edata) -+{ -+ struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); -+ unsigned long flags; -+ u32 dfi_wr, dfi_rd, dfi_timer; -+ -+ local_irq_save(flags); -+ -+ rk3128_dfi_stop_hardware_counter(edev); -+ -+ regmap_read(info->regmap_grf, RK3128_GRF_DFI_WRNUM, &dfi_wr); -+ regmap_read(info->regmap_grf, RK3128_GRF_DFI_RDNUM, &dfi_rd); -+ regmap_read(info->regmap_grf, RK3128_GRF_DFI_TIMERVAL, &dfi_timer); -+ -+ edata->load_count = (dfi_wr + dfi_rd) * 4; -+ edata->total_count = dfi_timer; -+ -+ rk3128_dfi_start_hardware_counter(edev); -+ -+ local_irq_restore(flags); -+ -+ return 0; -+} -+ -+static const struct devfreq_event_ops rk3128_dfi_ops = { -+ .disable = rk3128_dfi_disable, -+ .enable = rk3128_dfi_enable, -+ .get_event = rk3128_dfi_get_event, -+ .set_event = rk3128_dfi_set_event, -+}; -+ -+static void rk3288_dfi_start_hardware_counter(struct devfreq_event_dev *edev) -+{ -+ struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); -+ -+ regmap_write(info->regmap_grf, RK3288_GRF_SOC_CON4, RK3288_DFI_EN); -+} -+ -+static void rk3288_dfi_stop_hardware_counter(struct devfreq_event_dev *edev) -+{ -+ struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); -+ -+ regmap_write(info->regmap_grf, RK3288_GRF_SOC_CON4, RK3288_DFI_DIS); -+} -+ -+static int rk3288_dfi_disable(struct devfreq_event_dev *edev) -+{ -+ rk3288_dfi_stop_hardware_counter(edev); -+ -+ return 0; -+} -+ -+static int rk3288_dfi_enable(struct devfreq_event_dev *edev) -+{ -+ rk3288_dfi_start_hardware_counter(edev); -+ -+ return 0; -+} -+ -+static int rk3288_dfi_set_event(struct devfreq_event_dev *edev) -+{ -+ return 0; -+} -+ -+static int rk3288_dfi_get_busier_ch(struct devfreq_event_dev *edev) -+{ -+ struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); -+ u32 tmp, max = 0; -+ u32 i, busier_ch = 0; -+ u32 rd_count, wr_count, total_count; -+ -+ rk3288_dfi_stop_hardware_counter(edev); -+ -+ /* Find out which channel is busier */ -+ for (i = 0; i < MAX_DMC_NUM_CH; i++) { -+ if (!(info->ch_msk & BIT(i))) -+ continue; -+ regmap_read(info->regmap_grf, -+ RK3288_GRF_SOC_STATUS(11 + i * 4), &wr_count); -+ regmap_read(info->regmap_grf, -+ RK3288_GRF_SOC_STATUS(12 + i * 4), &rd_count); -+ regmap_read(info->regmap_grf, -+ RK3288_GRF_SOC_STATUS(14 + i * 4), &total_count); -+ info->ch_usage[i].access = (wr_count + rd_count) * 4; -+ info->ch_usage[i].total = total_count; -+ tmp = info->ch_usage[i].access; -+ if (tmp > max) { -+ busier_ch = i; -+ max = tmp; -+ } -+ } -+ rk3288_dfi_start_hardware_counter(edev); -+ -+ return busier_ch; -+} -+ -+static int rk3288_dfi_get_event(struct devfreq_event_dev *edev, -+ struct devfreq_event_data *edata) -+{ -+ struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); -+ int busier_ch; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ busier_ch = rk3288_dfi_get_busier_ch(edev); -+ local_irq_restore(flags); -+ -+ edata->load_count = info->ch_usage[busier_ch].access; -+ edata->total_count = info->ch_usage[busier_ch].total; -+ -+ return 0; -+} -+ -+static const struct devfreq_event_ops rk3288_dfi_ops = { -+ .disable = rk3288_dfi_disable, -+ .enable = rk3288_dfi_enable, -+ .get_event = rk3288_dfi_get_event, -+ .set_event = rk3288_dfi_set_event, -+}; -+ -+static void rk3368_dfi_start_hardware_counter(struct devfreq_event_dev *edev) -+{ -+ struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); -+ -+ regmap_write(info->regmap_grf, RK3368_GRF_DDRC0_CON0, RK3368_DFI_EN); -+} -+ -+static void rk3368_dfi_stop_hardware_counter(struct devfreq_event_dev *edev) -+{ -+ struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); -+ -+ regmap_write(info->regmap_grf, RK3368_GRF_DDRC0_CON0, RK3368_DFI_DIS); -+} -+ -+static int rk3368_dfi_disable(struct devfreq_event_dev *edev) -+{ -+ rk3368_dfi_stop_hardware_counter(edev); -+ -+ return 0; -+} -+ -+static int rk3368_dfi_enable(struct devfreq_event_dev *edev) -+{ -+ rk3368_dfi_start_hardware_counter(edev); -+ -+ return 0; -+} -+ -+static int rk3368_dfi_set_event(struct devfreq_event_dev *edev) -+{ -+ return 0; -+} -+ -+static int rk3368_dfi_get_event(struct devfreq_event_dev *edev, -+ struct devfreq_event_data *edata) -+{ -+ struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); -+ unsigned long flags; -+ u32 dfi0_wr, dfi0_rd, dfi1_wr, dfi1_rd, dfi_timer; -+ -+ local_irq_save(flags); -+ -+ rk3368_dfi_stop_hardware_counter(edev); -+ -+ regmap_read(info->regmap_grf, RK3368_GRF_SOC_STATUS5, &dfi0_wr); -+ regmap_read(info->regmap_grf, RK3368_GRF_SOC_STATUS6, &dfi0_rd); -+ regmap_read(info->regmap_grf, RK3368_GRF_SOC_STATUS9, &dfi1_wr); -+ regmap_read(info->regmap_grf, RK3368_GRF_SOC_STATUS10, &dfi1_rd); -+ regmap_read(info->regmap_grf, RK3368_GRF_SOC_STATUS8, &dfi_timer); -+ -+ edata->load_count = (dfi0_wr + dfi0_rd + dfi1_wr + dfi1_rd) * 2; -+ edata->total_count = dfi_timer; -+ -+ rk3368_dfi_start_hardware_counter(edev); -+ -+ local_irq_restore(flags); -+ -+ return 0; -+} -+ -+static const struct devfreq_event_ops rk3368_dfi_ops = { -+ .disable = rk3368_dfi_disable, -+ .enable = rk3368_dfi_enable, -+ .get_event = rk3368_dfi_get_event, -+ .set_event = rk3368_dfi_set_event, - }; - - static void rockchip_dfi_start_hardware_counter(struct devfreq_event_dev *edev) - { - struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); - void __iomem *dfi_regs = info->regs; -- u32 val; -- u32 ddr_type; -- -- /* get ddr type */ -- regmap_read(info->regmap_pmu, RK3399_PMUGRF_OS_REG2, &val); -- ddr_type = (val >> RK3399_PMUGRF_DDRTYPE_SHIFT) & -- RK3399_PMUGRF_DDRTYPE_MASK; - - /* clear DDRMON_CTRL setting */ - writel_relaxed(CLR_DDRMON_CTRL, dfi_regs + DDRMON_CTRL); - - /* set ddr type to dfi */ -- if (ddr_type == RK3399_PMUGRF_DDRTYPE_LPDDR3) -- writel_relaxed(LPDDR3_EN, dfi_regs + DDRMON_CTRL); -- else if (ddr_type == RK3399_PMUGRF_DDRTYPE_LPDDR4) -+ if (info->dram_type == LPDDR3 || info->dram_type == LPDDR2) -+ writel_relaxed(LPDDR2_3_EN, dfi_regs + DDRMON_CTRL); -+ else if (info->dram_type == LPDDR4) - writel_relaxed(LPDDR4_EN, dfi_regs + DDRMON_CTRL); -+ else if (info->dram_type == DDR4) -+ writel_relaxed(DDR4_EN, dfi_regs + DDRMON_CTRL); - - /* enable count, use software mode */ - writel_relaxed(SOFTWARE_EN, dfi_regs + DDRMON_CTRL); -@@ -100,12 +369,22 @@ static int rockchip_dfi_get_busier_ch(st - rockchip_dfi_stop_hardware_counter(edev); - - /* Find out which channel is busier */ -- for (i = 0; i < RK3399_DMC_NUM_CH; i++) { -- info->ch_usage[i].access = readl_relaxed(dfi_regs + -- DDRMON_CH0_DFI_ACCESS_NUM + i * 20) * 4; -+ for (i = 0; i < MAX_DMC_NUM_CH; i++) { -+ if (!(info->ch_msk & BIT(i))) -+ continue; -+ - info->ch_usage[i].total = readl_relaxed(dfi_regs + - DDRMON_CH0_COUNT_NUM + i * 20); -- tmp = info->ch_usage[i].access; -+ -+ /* LPDDR4 BL = 16,other DDR type BL = 8 */ -+ tmp = readl_relaxed(dfi_regs + -+ DDRMON_CH0_DFI_ACCESS_NUM + i * 20); -+ if (info->dram_type == LPDDR4) -+ tmp *= 8; -+ else -+ tmp *= 4; -+ info->ch_usage[i].access = tmp; -+ - if (tmp > max) { - busier_ch = i; - max = tmp; -@@ -121,7 +400,8 @@ static int rockchip_dfi_disable(struct d - struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); - - rockchip_dfi_stop_hardware_counter(edev); -- clk_disable_unprepare(info->clk); -+ if (info->clk) -+ clk_disable_unprepare(info->clk); - - return 0; - } -@@ -131,10 +411,13 @@ static int rockchip_dfi_enable(struct de - struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); - int ret; - -- ret = clk_prepare_enable(info->clk); -- if (ret) { -- dev_err(&edev->dev, "failed to enable dfi clk: %d\n", ret); -- return ret; -+ if (info->clk) { -+ ret = clk_prepare_enable(info->clk); -+ if (ret) { -+ dev_err(&edev->dev, "failed to enable dfi clk: %d\n", -+ ret); -+ return ret; -+ } - } - - rockchip_dfi_start_hardware_counter(edev); -@@ -151,8 +434,11 @@ static int rockchip_dfi_get_event(struct - { - struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); - int busier_ch; -+ unsigned long flags; - -+ local_irq_save(flags); - busier_ch = rockchip_dfi_get_busier_ch(edev); -+ local_irq_restore(flags); - - edata->load_count = info->ch_usage[busier_ch].access; - edata->total_count = info->ch_usage[busier_ch].total; -@@ -167,22 +453,116 @@ static const struct devfreq_event_ops ro - .set_event = rockchip_dfi_set_event, - }; - --static const struct of_device_id rockchip_dfi_id_match[] = { -- { .compatible = "rockchip,rk3399-dfi" }, -- { }, --}; --MODULE_DEVICE_TABLE(of, rockchip_dfi_id_match); -+static __init int px30_dfi_init(struct platform_device *pdev, -+ struct rockchip_dfi *data, -+ struct devfreq_event_desc *desc) -+{ -+ struct device_node *np = pdev->dev.of_node, *node; -+ struct resource *res; -+ u32 val; - --static int rockchip_dfi_probe(struct platform_device *pdev) -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ data->regs = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(data->regs)) -+ return PTR_ERR(data->regs); -+ -+ node = of_parse_phandle(np, "rockchip,pmugrf", 0); -+ if (node) { -+ data->regmap_pmugrf = syscon_node_to_regmap(node); -+ if (IS_ERR(data->regmap_pmugrf)) -+ return PTR_ERR(data->regmap_pmugrf); -+ } -+ -+ regmap_read(data->regmap_pmugrf, PX30_PMUGRF_OS_REG2, &val); -+ data->dram_type = READ_DRAMTYPE_INFO(val); -+ data->ch_msk = 1; -+ data->clk = NULL; -+ -+ desc->ops = &rockchip_dfi_ops; -+ -+ return 0; -+} -+ -+static __init int rk3128_dfi_init(struct platform_device *pdev, -+ struct rockchip_dfi *data, -+ struct devfreq_event_desc *desc) - { -- struct device *dev = &pdev->dev; -- struct rockchip_dfi *data; -- struct devfreq_event_desc *desc; - struct device_node *np = pdev->dev.of_node, *node; - -- data = devm_kzalloc(dev, sizeof(struct rockchip_dfi), GFP_KERNEL); -- if (!data) -- return -ENOMEM; -+ node = of_parse_phandle(np, "rockchip,grf", 0); -+ if (node) { -+ data->regmap_grf = syscon_node_to_regmap(node); -+ if (IS_ERR(data->regmap_grf)) -+ return PTR_ERR(data->regmap_grf); -+ } -+ -+ desc->ops = &rk3128_dfi_ops; -+ -+ return 0; -+} -+ -+static __init int rk3288_dfi_init(struct platform_device *pdev, -+ struct rockchip_dfi *data, -+ struct devfreq_event_desc *desc) -+{ -+ struct device_node *np = pdev->dev.of_node, *node; -+ u32 val; -+ -+ node = of_parse_phandle(np, "rockchip,pmu", 0); -+ if (node) { -+ data->regmap_pmu = syscon_node_to_regmap(node); -+ if (IS_ERR(data->regmap_pmu)) -+ return PTR_ERR(data->regmap_pmu); -+ } -+ -+ node = of_parse_phandle(np, "rockchip,grf", 0); -+ if (node) { -+ data->regmap_grf = syscon_node_to_regmap(node); -+ if (IS_ERR(data->regmap_grf)) -+ return PTR_ERR(data->regmap_grf); -+ } -+ -+ regmap_read(data->regmap_pmu, RK3288_PMU_SYS_REG2, &val); -+ data->dram_type = READ_DRAMTYPE_INFO(val); -+ data->ch_msk = READ_CH_INFO(val); -+ -+ if (data->dram_type == DDR3) -+ regmap_write(data->regmap_grf, RK3288_GRF_SOC_CON4, -+ RK3288_DDR3_SEL); -+ else -+ regmap_write(data->regmap_grf, RK3288_GRF_SOC_CON4, -+ RK3288_LPDDR_SEL); -+ -+ desc->ops = &rk3288_dfi_ops; -+ -+ return 0; -+} -+ -+static __init int rk3368_dfi_init(struct platform_device *pdev, -+ struct rockchip_dfi *data, -+ struct devfreq_event_desc *desc) -+{ -+ struct device *dev = &pdev->dev; -+ -+ if (!dev->parent || !dev->parent->of_node) -+ return -EINVAL; -+ -+ data->regmap_grf = syscon_node_to_regmap(dev->parent->of_node); -+ if (IS_ERR(data->regmap_grf)) -+ return PTR_ERR(data->regmap_grf); -+ -+ desc->ops = &rk3368_dfi_ops; -+ -+ return 0; -+} -+ -+static __init int rockchip_dfi_init(struct platform_device *pdev, -+ struct rockchip_dfi *data, -+ struct devfreq_event_desc *desc) -+{ -+ struct device *dev = &pdev->dev; -+ struct device_node *np = pdev->dev.of_node, *node; -+ u32 val; - - data->regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(data->regs)) -@@ -201,21 +581,97 @@ static int rockchip_dfi_probe(struct pla - if (IS_ERR(data->regmap_pmu)) - return PTR_ERR(data->regmap_pmu); - } -- data->dev = dev; -+ -+ regmap_read(data->regmap_pmu, PMUGRF_OS_REG2, &val); -+ data->dram_type = READ_DRAMTYPE_INFO(val); -+ data->ch_msk = READ_CH_INFO(val); -+ -+ desc->ops = &rockchip_dfi_ops; -+ -+ return 0; -+} -+ -+static __init int rk3328_dfi_init(struct platform_device *pdev, -+ struct rockchip_dfi *data, -+ struct devfreq_event_desc *desc) -+{ -+ struct device_node *np = pdev->dev.of_node, *node; -+ struct resource *res; -+ u32 val; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ data->regs = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(data->regs)) -+ return PTR_ERR(data->regs); -+ -+ node = of_parse_phandle(np, "rockchip,grf", 0); -+ if (node) { -+ data->regmap_grf = syscon_node_to_regmap(node); -+ if (IS_ERR(data->regmap_grf)) -+ return PTR_ERR(data->regmap_grf); -+ } -+ -+ regmap_read(data->regmap_grf, RK3328_GRF_OS_REG2, &val); -+ data->dram_type = READ_DRAMTYPE_INFO(val); -+ data->ch_msk = 1; -+ data->clk = NULL; -+ -+ desc->ops = &rockchip_dfi_ops; -+ -+ return 0; -+} -+ -+static const struct of_device_id rockchip_dfi_id_match[] = { -+ { .compatible = "rockchip,px30-dfi", .data = px30_dfi_init }, -+ { .compatible = "rockchip,rk1808-dfi", .data = px30_dfi_init }, -+ { .compatible = "rockchip,rk3128-dfi", .data = rk3128_dfi_init }, -+ { .compatible = "rockchip,rk3288-dfi", .data = rk3288_dfi_init }, -+ { .compatible = "rockchip,rk3328-dfi", .data = rk3328_dfi_init }, -+ { .compatible = "rockchip,rk3368-dfi", .data = rk3368_dfi_init }, -+ { .compatible = "rockchip,rk3399-dfi", .data = rockchip_dfi_init }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(of, rockchip_dfi_id_match); -+ -+static int rockchip_dfi_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct rockchip_dfi *data; -+ struct devfreq_event_desc *desc; -+ struct device_node *np = pdev->dev.of_node; -+ const struct of_device_id *match; -+ int (*init)(struct platform_device *pdev, struct rockchip_dfi *data, -+ struct devfreq_event_desc *desc); -+ -+ data = devm_kzalloc(dev, sizeof(struct rockchip_dfi), GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; - - desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL); - if (!desc) - return -ENOMEM; - -- desc->ops = &rockchip_dfi_ops; -+ match = of_match_node(rockchip_dfi_id_match, pdev->dev.of_node); -+ if (match) { -+ init = match->data; -+ if (init) { -+ if (init(pdev, data, desc)) -+ return -EINVAL; -+ } else { -+ return 0; -+ } -+ } else { -+ return 0; -+ } -+ - desc->driver_data = data; - desc->name = np->name; - data->desc = desc; -+ data->dev = dev; - -- data->edev = devm_devfreq_event_add_edev(&pdev->dev, desc); -+ data->edev = devm_devfreq_event_add_edev(dev, desc); - if (IS_ERR(data->edev)) { -- dev_err(&pdev->dev, -- "failed to add devfreq-event device\n"); -+ dev_err(dev, "failed to add devfreq-event device\n"); - return PTR_ERR(data->edev); - } -