Skip to content

Commit 75cf308

Browse files
author
AngeloGioacchino Del Regno
committed
soc: mediatek: mtk-dvfsrc: Add support for DVFSRCv4 and MT8196
Add support for the DVFSRC Version 4 by adding new functions for vcore/dram levels (in v4, called gears instead), and for readout of pre-programmed dvfsrc_opp entries, corresponding to each gear. In the probe function, for v4, the curr_opps is initialized from the get_hw_opps() function instead of platform data. In order to make use of the new DVFSRCv4 code, also add support for the MediaTek MT8196 SoC. Co-developed-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com> Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
1 parent 7cf9db2 commit 75cf308

1 file changed

Lines changed: 247 additions & 1 deletion

File tree

drivers/soc/mediatek/mtk-dvfsrc.c

Lines changed: 247 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,41 @@
1515
#include <linux/soc/mediatek/dvfsrc.h>
1616
#include <linux/soc/mediatek/mtk_sip_svc.h>
1717

18+
/* DVFSRC_BASIC_CONTROL */
19+
#define DVFSRC_V4_BASIC_CTRL_OPP_COUNT GENMASK(26, 20)
20+
1821
/* DVFSRC_LEVEL */
1922
#define DVFSRC_V1_LEVEL_TARGET_LEVEL GENMASK(15, 0)
2023
#define DVFSRC_TGT_LEVEL_IDLE 0x00
2124
#define DVFSRC_V1_LEVEL_CURRENT_LEVEL GENMASK(31, 16)
2225

26+
#define DVFSRC_V4_LEVEL_TARGET_LEVEL GENMASK(15, 8)
27+
#define DVFSRC_V4_LEVEL_TARGET_PRESENT BIT(16)
28+
2329
/* DVFSRC_SW_REQ, DVFSRC_SW_REQ2 */
2430
#define DVFSRC_V1_SW_REQ2_DRAM_LEVEL GENMASK(1, 0)
2531
#define DVFSRC_V1_SW_REQ2_VCORE_LEVEL GENMASK(3, 2)
2632

2733
#define DVFSRC_V2_SW_REQ_DRAM_LEVEL GENMASK(3, 0)
2834
#define DVFSRC_V2_SW_REQ_VCORE_LEVEL GENMASK(6, 4)
2935

36+
#define DVFSRC_V4_SW_REQ_EMI_LEVEL GENMASK(3, 0)
37+
#define DVFSRC_V4_SW_REQ_DRAM_LEVEL GENMASK(15, 12)
38+
3039
/* DVFSRC_VCORE */
3140
#define DVFSRC_V2_VCORE_REQ_VSCP_LEVEL GENMASK(14, 12)
3241

42+
/* DVFSRC_TARGET_GEAR */
43+
#define DVFSRC_V4_GEAR_TARGET_DRAM GENMASK(7, 0)
44+
#define DVFSRC_V4_GEAR_TARGET_VCORE GENMASK(15, 8)
45+
46+
/* DVFSRC_GEAR_INFO */
47+
#define DVFSRC_V4_GEAR_INFO_REG_WIDTH 0x4
48+
#define DVFSRC_V4_GEAR_INFO_REG_LEVELS 64
49+
#define DVFSRC_V4_GEAR_INFO_VCORE GENMASK(3, 0)
50+
#define DVFSRC_V4_GEAR_INFO_EMI GENMASK(7, 4)
51+
#define DVFSRC_V4_GEAR_INFO_DRAM GENMASK(15, 12)
52+
3353
#define DVFSRC_POLL_TIMEOUT_US 1000
3454
#define STARTUP_TIME_US 1
3555

@@ -52,6 +72,7 @@ struct dvfsrc_bw_constraints {
5272
struct dvfsrc_opp {
5373
u32 vcore_opp;
5474
u32 dram_opp;
75+
u32 emi_opp;
5576
};
5677

5778
struct dvfsrc_opp_desc {
@@ -72,13 +93,16 @@ struct mtk_dvfsrc {
7293

7394
struct dvfsrc_soc_data {
7495
const int *regs;
96+
const u8 *bw_units;
7597
const bool has_emi_ddr;
7698
const struct dvfsrc_opp_desc *opps_desc;
7799
u32 (*calc_dram_bw)(struct mtk_dvfsrc *dvfsrc, int type, u64 bw);
78100
u32 (*get_target_level)(struct mtk_dvfsrc *dvfsrc);
79101
u32 (*get_current_level)(struct mtk_dvfsrc *dvfsrc);
80102
u32 (*get_vcore_level)(struct mtk_dvfsrc *dvfsrc);
81103
u32 (*get_vscp_level)(struct mtk_dvfsrc *dvfsrc);
104+
u32 (*get_opp_count)(struct mtk_dvfsrc *dvfsrc);
105+
int (*get_hw_opps)(struct mtk_dvfsrc *dvfsrc);
82106
void (*set_dram_bw)(struct mtk_dvfsrc *dvfsrc, u64 bw);
83107
void (*set_dram_peak_bw)(struct mtk_dvfsrc *dvfsrc, u64 bw);
84108
void (*set_dram_hrt_bw)(struct mtk_dvfsrc *dvfsrc, u64 bw);
@@ -101,6 +125,7 @@ static void dvfsrc_writel(struct mtk_dvfsrc *dvfs, u32 offset, u32 val)
101125
}
102126

103127
enum dvfsrc_regs {
128+
DVFSRC_BASIC_CONTROL,
104129
DVFSRC_SW_REQ,
105130
DVFSRC_SW_REQ2,
106131
DVFSRC_LEVEL,
@@ -110,6 +135,9 @@ enum dvfsrc_regs {
110135
DVFSRC_SW_HRT_BW,
111136
DVFSRC_SW_EMI_BW,
112137
DVFSRC_VCORE,
138+
DVFSRC_TARGET_GEAR,
139+
DVFSRC_GEAR_INFO_L,
140+
DVFSRC_GEAR_INFO_H,
113141
DVFSRC_REGS_MAX,
114142
};
115143

@@ -130,13 +158,43 @@ static const int dvfsrc_mt8195_regs[] = {
130158
[DVFSRC_TARGET_LEVEL] = 0xd48,
131159
};
132160

161+
static const int dvfsrc_mt8196_regs[] = {
162+
[DVFSRC_BASIC_CONTROL] = 0x0,
163+
[DVFSRC_SW_REQ] = 0x18,
164+
[DVFSRC_VCORE] = 0x80,
165+
[DVFSRC_GEAR_INFO_L] = 0xfc,
166+
[DVFSRC_SW_BW] = 0x1e8,
167+
[DVFSRC_SW_PEAK_BW] = 0x1f4,
168+
[DVFSRC_SW_HRT_BW] = 0x20c,
169+
[DVFSRC_LEVEL] = 0x5f0,
170+
[DVFSRC_TARGET_LEVEL] = 0x5f0,
171+
[DVFSRC_SW_REQ2] = 0x604,
172+
[DVFSRC_SW_EMI_BW] = 0x60c,
173+
[DVFSRC_TARGET_GEAR] = 0x6ac,
174+
[DVFSRC_GEAR_INFO_H] = 0x6b0,
175+
};
176+
133177
static const struct dvfsrc_opp *dvfsrc_get_current_opp(struct mtk_dvfsrc *dvfsrc)
134178
{
135179
u32 level = dvfsrc->dvd->get_current_level(dvfsrc);
136180

137181
return &dvfsrc->curr_opps->opps[level];
138182
}
139183

184+
static u32 dvfsrc_get_current_target_vcore_gear(struct mtk_dvfsrc *dvfsrc)
185+
{
186+
u32 val = dvfsrc_readl(dvfsrc, DVFSRC_TARGET_GEAR);
187+
188+
return FIELD_GET(DVFSRC_V4_GEAR_TARGET_VCORE, val);
189+
}
190+
191+
static u32 dvfsrc_get_current_target_dram_gear(struct mtk_dvfsrc *dvfsrc)
192+
{
193+
u32 val = dvfsrc_readl(dvfsrc, DVFSRC_TARGET_GEAR);
194+
195+
return FIELD_GET(DVFSRC_V4_GEAR_TARGET_DRAM, val);
196+
}
197+
140198
static bool dvfsrc_is_idle(struct mtk_dvfsrc *dvfsrc)
141199
{
142200
if (!dvfsrc->dvd->get_target_level)
@@ -193,6 +251,24 @@ static int dvfsrc_wait_for_opp_level_v2(struct mtk_dvfsrc *dvfsrc, u32 level)
193251
return 0;
194252
}
195253

254+
static int dvfsrc_wait_for_vcore_level_v4(struct mtk_dvfsrc *dvfsrc, u32 level)
255+
{
256+
u32 val;
257+
258+
return readx_poll_timeout_atomic(dvfsrc_get_current_target_vcore_gear,
259+
dvfsrc, val, val >= level,
260+
STARTUP_TIME_US, DVFSRC_POLL_TIMEOUT_US);
261+
}
262+
263+
static int dvfsrc_wait_for_opp_level_v4(struct mtk_dvfsrc *dvfsrc, u32 level)
264+
{
265+
u32 val;
266+
267+
return readx_poll_timeout_atomic(dvfsrc_get_current_target_dram_gear,
268+
dvfsrc, val, val >= level,
269+
STARTUP_TIME_US, DVFSRC_POLL_TIMEOUT_US);
270+
}
271+
196272
static u32 dvfsrc_get_target_level_v1(struct mtk_dvfsrc *dvfsrc)
197273
{
198274
u32 val = dvfsrc_readl(dvfsrc, DVFSRC_LEVEL);
@@ -226,6 +302,27 @@ static u32 dvfsrc_get_current_level_v2(struct mtk_dvfsrc *dvfsrc)
226302
return 0;
227303
}
228304

305+
static u32 dvfsrc_get_target_level_v4(struct mtk_dvfsrc *dvfsrc)
306+
{
307+
u32 val = dvfsrc_readl(dvfsrc, DVFSRC_TARGET_LEVEL);
308+
309+
if (val & DVFSRC_V4_LEVEL_TARGET_PRESENT)
310+
return FIELD_GET(DVFSRC_V4_LEVEL_TARGET_LEVEL, val) + 1;
311+
return 0;
312+
}
313+
314+
static u32 dvfsrc_get_current_level_v4(struct mtk_dvfsrc *dvfsrc)
315+
{
316+
u32 level = dvfsrc_readl(dvfsrc, DVFSRC_LEVEL) + 1;
317+
318+
/* Valid levels */
319+
if (level < dvfsrc->curr_opps->num_opp)
320+
return dvfsrc->curr_opps->num_opp - level;
321+
322+
/* Zero for level 0 or invalid level */
323+
return 0;
324+
}
325+
229326
static u32 dvfsrc_get_vcore_level_v1(struct mtk_dvfsrc *dvfsrc)
230327
{
231328
u32 val = dvfsrc_readl(dvfsrc, DVFSRC_SW_REQ2);
@@ -277,11 +374,30 @@ static void dvfsrc_set_vscp_level_v2(struct mtk_dvfsrc *dvfsrc, u32 level)
277374
dvfsrc_writel(dvfsrc, DVFSRC_VCORE, val);
278375
}
279376

377+
static u32 dvfsrc_get_opp_count_v4(struct mtk_dvfsrc *dvfsrc)
378+
{
379+
u32 val = dvfsrc_readl(dvfsrc, DVFSRC_BASIC_CONTROL);
380+
381+
return FIELD_GET(DVFSRC_V4_BASIC_CTRL_OPP_COUNT, val) + 1;
382+
}
383+
280384
static u32 dvfsrc_calc_dram_bw_v1(struct mtk_dvfsrc *dvfsrc, int type, u64 bw)
281385
{
282386
return (u32)div_u64(bw, 100 * 1000);
283387
}
284388

389+
static u32 dvfsrc_calc_dram_bw_v4(struct mtk_dvfsrc *dvfsrc, int type, u64 bw)
390+
{
391+
u8 bw_unit = dvfsrc->dvd->bw_units[type];
392+
u64 bw_mbps;
393+
394+
if (type < DVFSRC_BW_AVG || type >= DVFSRC_BW_MAX)
395+
return 0;
396+
397+
bw_mbps = div_u64(bw, 1000);
398+
return (u32)div_u64((bw_mbps + bw_unit - 1), bw_unit);
399+
}
400+
285401
static void __dvfsrc_set_dram_bw_v1(struct mtk_dvfsrc *dvfsrc, u32 reg,
286402
int type, u16 max_bw, u16 min_bw, u64 bw)
287403
{
@@ -333,6 +449,100 @@ static void dvfsrc_set_opp_level_v1(struct mtk_dvfsrc *dvfsrc, u32 level)
333449
dvfsrc_writel(dvfsrc, DVFSRC_SW_REQ, val);
334450
}
335451

452+
static u32 dvfsrc_get_opp_gear(struct mtk_dvfsrc *dvfsrc, u8 level)
453+
{
454+
u32 reg_ofst, val;
455+
u8 idx;
456+
457+
/* Calculate register offset and index for requested gear */
458+
if (level < DVFSRC_V4_GEAR_INFO_REG_LEVELS) {
459+
reg_ofst = dvfsrc->dvd->regs[DVFSRC_GEAR_INFO_L];
460+
idx = level;
461+
} else {
462+
reg_ofst = dvfsrc->dvd->regs[DVFSRC_GEAR_INFO_H];
463+
idx = level - DVFSRC_V4_GEAR_INFO_REG_LEVELS;
464+
}
465+
reg_ofst += DVFSRC_V4_GEAR_INFO_REG_WIDTH * (level / 2);
466+
467+
/* Read the corresponding gear register */
468+
val = readl(dvfsrc->regs + reg_ofst);
469+
470+
/* Each register contains two sets of data, 16 bits per gear */
471+
val >>= 16 * (idx % 2);
472+
473+
return val;
474+
}
475+
476+
static int dvfsrc_get_hw_opps_v4(struct mtk_dvfsrc *dvfsrc)
477+
{
478+
struct dvfsrc_opp *dvfsrc_opps;
479+
struct dvfsrc_opp_desc *desc;
480+
u32 num_opps, gear_info;
481+
u8 num_vcore, num_dram;
482+
u8 num_emi;
483+
int i;
484+
485+
num_opps = dvfsrc_get_opp_count_v4(dvfsrc);
486+
if (num_opps == 0) {
487+
dev_err(dvfsrc->dev, "No OPPs programmed in DVFSRC MCU.\n");
488+
return -EINVAL;
489+
}
490+
491+
/*
492+
* The first 16 bits set in the gear info table says how many OPPs
493+
* and how many vcore, dram and emi table entries are available.
494+
*/
495+
gear_info = dvfsrc_readl(dvfsrc, DVFSRC_GEAR_INFO_L);
496+
if (gear_info == 0) {
497+
dev_err(dvfsrc->dev, "No gear info in DVFSRC MCU.\n");
498+
return -EINVAL;
499+
}
500+
501+
num_vcore = FIELD_GET(DVFSRC_V4_GEAR_INFO_VCORE, gear_info) + 1;
502+
num_dram = FIELD_GET(DVFSRC_V4_GEAR_INFO_DRAM, gear_info) + 1;
503+
num_emi = FIELD_GET(DVFSRC_V4_GEAR_INFO_EMI, gear_info) + 1;
504+
dev_info(dvfsrc->dev,
505+
"Discovered %u gears and %u vcore, %u dram, %u emi table entries.\n",
506+
num_opps, num_vcore, num_dram, num_emi);
507+
508+
/* Allocate everything now as anything else after that cannot fail */
509+
desc = devm_kzalloc(dvfsrc->dev, sizeof(*desc), GFP_KERNEL);
510+
if (!desc)
511+
return -ENOMEM;
512+
513+
dvfsrc_opps = devm_kcalloc(dvfsrc->dev, num_opps + 1,
514+
sizeof(*dvfsrc_opps), GFP_KERNEL);
515+
if (!dvfsrc_opps)
516+
return -ENOMEM;
517+
518+
/* Read the OPP table gear indices */
519+
for (i = 0; i <= num_opps; i++) {
520+
gear_info = dvfsrc_get_opp_gear(dvfsrc, num_opps - i);
521+
dvfsrc_opps[i].vcore_opp = FIELD_GET(DVFSRC_V4_GEAR_INFO_VCORE, gear_info);
522+
dvfsrc_opps[i].dram_opp = FIELD_GET(DVFSRC_V4_GEAR_INFO_DRAM, gear_info);
523+
dvfsrc_opps[i].emi_opp = FIELD_GET(DVFSRC_V4_GEAR_INFO_EMI, gear_info);
524+
};
525+
desc->num_opp = num_opps + 1;
526+
desc->opps = dvfsrc_opps;
527+
528+
/* Assign to main structure now that everything is done! */
529+
dvfsrc->curr_opps = desc;
530+
531+
return 0;
532+
}
533+
534+
static void dvfsrc_set_dram_level_v4(struct mtk_dvfsrc *dvfsrc, u32 level)
535+
{
536+
u32 val = dvfsrc_readl(dvfsrc, DVFSRC_SW_REQ);
537+
538+
val &= ~DVFSRC_V4_SW_REQ_DRAM_LEVEL;
539+
val |= FIELD_PREP(DVFSRC_V4_SW_REQ_DRAM_LEVEL, level);
540+
541+
dev_dbg(dvfsrc->dev, "%s level=%u\n", __func__, level);
542+
543+
dvfsrc_writel(dvfsrc, DVFSRC_SW_REQ, val);
544+
}
545+
336546
int mtk_dvfsrc_send_request(const struct device *dev, u32 cmd, u64 data)
337547
{
338548
struct mtk_dvfsrc *dvfsrc = dev_get_drvdata(dev);
@@ -448,7 +658,14 @@ static int mtk_dvfsrc_probe(struct platform_device *pdev)
448658
dvfsrc->dram_type = ares.a1;
449659
dev_dbg(&pdev->dev, "DRAM Type: %d\n", dvfsrc->dram_type);
450660

451-
dvfsrc->curr_opps = &dvfsrc->dvd->opps_desc[dvfsrc->dram_type];
661+
/* Newer versions of the DVFSRC MCU have pre-programmed gear tables */
662+
if (dvfsrc->dvd->get_hw_opps) {
663+
ret = dvfsrc->dvd->get_hw_opps(dvfsrc);
664+
if (ret)
665+
return ret;
666+
} else {
667+
dvfsrc->curr_opps = &dvfsrc->dvd->opps_desc[dvfsrc->dram_type];
668+
}
452669
platform_set_drvdata(pdev, dvfsrc);
453670

454671
ret = devm_of_platform_populate(&pdev->dev);
@@ -576,10 +793,39 @@ static const struct dvfsrc_soc_data mt8195_data = {
576793
.bw_constraints = &dvfsrc_bw_constr_v2,
577794
};
578795

796+
static const u8 mt8196_bw_units[] = {
797+
[DVFSRC_BW_AVG] = 64,
798+
[DVFSRC_BW_PEAK] = 64,
799+
[DVFSRC_BW_HRT] = 30,
800+
};
801+
802+
static const struct dvfsrc_soc_data mt8196_data = {
803+
.regs = dvfsrc_mt8196_regs,
804+
.bw_units = mt8196_bw_units,
805+
.has_emi_ddr = true,
806+
.get_target_level = dvfsrc_get_target_level_v4,
807+
.get_current_level = dvfsrc_get_current_level_v4,
808+
.get_vcore_level = dvfsrc_get_vcore_level_v2,
809+
.get_vscp_level = dvfsrc_get_vscp_level_v2,
810+
.get_opp_count = dvfsrc_get_opp_count_v4,
811+
.get_hw_opps = dvfsrc_get_hw_opps_v4,
812+
.calc_dram_bw = dvfsrc_calc_dram_bw_v4,
813+
.set_dram_bw = dvfsrc_set_dram_bw_v1,
814+
.set_dram_peak_bw = dvfsrc_set_dram_peak_bw_v1,
815+
.set_dram_hrt_bw = dvfsrc_set_dram_hrt_bw_v1,
816+
.set_opp_level = dvfsrc_set_dram_level_v4,
817+
.set_vcore_level = dvfsrc_set_vcore_level_v2,
818+
.set_vscp_level = dvfsrc_set_vscp_level_v2,
819+
.wait_for_opp_level = dvfsrc_wait_for_opp_level_v4,
820+
.wait_for_vcore_level = dvfsrc_wait_for_vcore_level_v4,
821+
.bw_constraints = &dvfsrc_bw_constr_v1,
822+
};
823+
579824
static const struct of_device_id mtk_dvfsrc_of_match[] = {
580825
{ .compatible = "mediatek,mt6893-dvfsrc", .data = &mt6893_data },
581826
{ .compatible = "mediatek,mt8183-dvfsrc", .data = &mt8183_data },
582827
{ .compatible = "mediatek,mt8195-dvfsrc", .data = &mt8195_data },
828+
{ .compatible = "mediatek,mt8196-dvfsrc", .data = &mt8196_data },
583829
{ /* sentinel */ }
584830
};
585831

0 commit comments

Comments
 (0)