Skip to content

Commit 3da293d

Browse files
Nicolas FrattaroliAngeloGioacchino Del Regno
authored andcommitted
soc: mediatek: mtk-dvfsrc: Rework bandwidth calculations
The code, as it is, plays fast and loose with bandwidth units. It also doesn't specify its constraints in the actual maximum hardware value, but as some roundabout thing that then ends up multiplied into the actual hardware value constraint after some indirections. In part, this is due to the use of individual members for storing each limit, instead of making it possible to index them by type. Rework all of this by adding const array members indexed by the bandwidth type enum to the soc_data struct. This array expresses the actual hardware value limitations, not a factor thereof. Use the clamp function macro to clamp the values between the minimum and maximum constraints after all the calculations, which also means the code doesn't write nonsense to a hardware register when the math is wrong, as it'll constrain after all the calculations. Pass the type as the actual enum type as well, and not as an int. If there's some type checking that can be extracted from the function signature, then we may as well use it. Don't needlessly explicitly cast return values to the return type either; this is both unnecessary and makes it harder to spot type safety issues. Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com> Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
1 parent 39aa8c4 commit 3da293d

1 file changed

Lines changed: 67 additions & 40 deletions

File tree

drivers/soc/mediatek/mtk-dvfsrc.c

Lines changed: 67 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,6 @@ enum mtk_dvfsrc_bw_type {
6464
DVFSRC_BW_MAX,
6565
};
6666

67-
struct dvfsrc_bw_constraints {
68-
u16 max_dram_nom_bw;
69-
u16 max_dram_peak_bw;
70-
u16 max_dram_hrt_bw;
71-
};
72-
7367
struct dvfsrc_opp {
7468
u32 vcore_opp;
7569
u32 dram_opp;
@@ -98,7 +92,7 @@ struct dvfsrc_soc_data {
9892
const u8 *bw_units;
9993
const bool has_emi_ddr;
10094
const struct dvfsrc_opp_desc *opps_desc;
101-
u32 (*calc_dram_bw)(struct mtk_dvfsrc *dvfsrc, int type, u64 bw);
95+
u32 (*calc_dram_bw)(struct mtk_dvfsrc *dvfsrc, enum mtk_dvfsrc_bw_type type, u64 bw);
10296
u32 (*get_target_level)(struct mtk_dvfsrc *dvfsrc);
10397
u32 (*get_current_level)(struct mtk_dvfsrc *dvfsrc);
10498
u32 (*get_vcore_level)(struct mtk_dvfsrc *dvfsrc);
@@ -113,7 +107,22 @@ struct dvfsrc_soc_data {
113107
void (*set_vscp_level)(struct mtk_dvfsrc *dvfsrc, u32 level);
114108
int (*wait_for_opp_level)(struct mtk_dvfsrc *dvfsrc, u32 level);
115109
int (*wait_for_vcore_level)(struct mtk_dvfsrc *dvfsrc, u32 level);
116-
const struct dvfsrc_bw_constraints *bw_constraints;
110+
111+
/**
112+
* @bw_max_constraints - array of maximum bandwidth for this hardware
113+
*
114+
* indexed by &enum mtk_dvfsrc_bw_type, storing the maximum permissible
115+
* hardware value for each bandwidth type.
116+
*/
117+
const u32 *const bw_max_constraints;
118+
119+
/**
120+
* @bw_min_constraints - array of minimum bandwidth for this hardware
121+
*
122+
* indexed by &enum mtk_dvfsrc_bw_type, storing the minimum permissible
123+
* hardware value for each bandwidth type.
124+
*/
125+
const u32 *const bw_min_constraints;
117126
};
118127

119128
static u32 dvfsrc_readl(struct mtk_dvfsrc *dvfs, u32 offset)
@@ -383,59 +392,62 @@ static u32 dvfsrc_get_opp_count_v4(struct mtk_dvfsrc *dvfsrc)
383392
return FIELD_GET(DVFSRC_V4_BASIC_CTRL_OPP_COUNT, val) + 1;
384393
}
385394

386-
static u32 dvfsrc_calc_dram_bw_v1(struct mtk_dvfsrc *dvfsrc, int type, u64 bw)
395+
static u32
396+
dvfsrc_calc_dram_bw_v1(struct mtk_dvfsrc *dvfsrc, enum mtk_dvfsrc_bw_type type, u64 bw)
387397
{
388-
return (u32)div_u64(bw, 100 * 1000);
398+
return clamp_val(div_u64(bw, 100 * 1000), dvfsrc->dvd->bw_min_constraints[type],
399+
dvfsrc->dvd->bw_max_constraints[type]);
389400
}
390401

391-
static u32 dvfsrc_calc_dram_bw_v4(struct mtk_dvfsrc *dvfsrc, int type, u64 bw)
402+
/**
403+
* dvfsrc_calc_dram_bw_v4 - convert kbps to hardware register bandwidth value
404+
* @dvfsrc: pointer to the &struct mtk_dvfsrc of this driver instance
405+
* @type: one of %DVFSRC_BW_AVG, %DVFSRC_BW_PEAK, or %DVFSRC_BW_HRT
406+
* @bw: the bandwidth in kilobits per second
407+
*
408+
* Returns the hardware register value appropriate for expressing @bw, clamped
409+
* to hardware limits.
410+
*/
411+
static u32
412+
dvfsrc_calc_dram_bw_v4(struct mtk_dvfsrc *dvfsrc, enum mtk_dvfsrc_bw_type type, u64 bw)
392413
{
393414
u8 bw_unit = dvfsrc->dvd->bw_units[type];
394415
u64 bw_mbps;
416+
u32 bw_hw;
395417

396418
if (type < DVFSRC_BW_AVG || type >= DVFSRC_BW_MAX)
397419
return 0;
398420

399421
bw_mbps = div_u64(bw, 1000);
400-
return (u32)div_u64((bw_mbps + bw_unit - 1), bw_unit);
422+
bw_hw = div_u64((bw_mbps + bw_unit - 1), bw_unit);
423+
return clamp_val(bw_hw, dvfsrc->dvd->bw_min_constraints[type],
424+
dvfsrc->dvd->bw_max_constraints[type]);
401425
}
402426

403427
static void __dvfsrc_set_dram_bw_v1(struct mtk_dvfsrc *dvfsrc, u32 reg,
404-
int type, u16 max_bw, u16 min_bw, u64 bw)
428+
enum mtk_dvfsrc_bw_type type, u64 bw)
405429
{
406-
u32 new_bw = dvfsrc->dvd->calc_dram_bw(dvfsrc, type, bw);
407-
408-
/* If bw constraints (in mbps) are defined make sure to respect them */
409-
if (max_bw)
410-
new_bw = min(new_bw, max_bw);
411-
if (min_bw && new_bw > 0)
412-
new_bw = max(new_bw, min_bw);
430+
u32 bw_hw = dvfsrc->dvd->calc_dram_bw(dvfsrc, type, bw);
413431

414-
dvfsrc_writel(dvfsrc, reg, new_bw);
432+
dvfsrc_writel(dvfsrc, reg, bw_hw);
415433

416434
if (type == DVFSRC_BW_AVG && dvfsrc->dvd->has_emi_ddr)
417-
dvfsrc_writel(dvfsrc, DVFSRC_SW_EMI_BW, bw);
435+
dvfsrc_writel(dvfsrc, DVFSRC_SW_EMI_BW, bw_hw);
418436
}
419437

420438
static void dvfsrc_set_dram_bw_v1(struct mtk_dvfsrc *dvfsrc, u64 bw)
421439
{
422-
u64 max_bw = dvfsrc->dvd->bw_constraints->max_dram_nom_bw;
423-
424-
__dvfsrc_set_dram_bw_v1(dvfsrc, DVFSRC_SW_BW, DVFSRC_BW_AVG, max_bw, 0, bw);
440+
__dvfsrc_set_dram_bw_v1(dvfsrc, DVFSRC_SW_BW, DVFSRC_BW_AVG, bw);
425441
};
426442

427443
static void dvfsrc_set_dram_peak_bw_v1(struct mtk_dvfsrc *dvfsrc, u64 bw)
428444
{
429-
u64 max_bw = dvfsrc->dvd->bw_constraints->max_dram_peak_bw;
430-
431-
__dvfsrc_set_dram_bw_v1(dvfsrc, DVFSRC_SW_PEAK_BW, DVFSRC_BW_PEAK, max_bw, 0, bw);
445+
__dvfsrc_set_dram_bw_v1(dvfsrc, DVFSRC_SW_PEAK_BW, DVFSRC_BW_PEAK, bw);
432446
}
433447

434448
static void dvfsrc_set_dram_hrt_bw_v1(struct mtk_dvfsrc *dvfsrc, u64 bw)
435449
{
436-
u64 max_bw = dvfsrc->dvd->bw_constraints->max_dram_hrt_bw;
437-
438-
__dvfsrc_set_dram_bw_v1(dvfsrc, DVFSRC_SW_HRT_BW, DVFSRC_BW_HRT, max_bw, 0, bw);
450+
__dvfsrc_set_dram_bw_v1(dvfsrc, DVFSRC_SW_HRT_BW, DVFSRC_BW_HRT, bw);
439451
}
440452

441453
static void dvfsrc_set_opp_level_v1(struct mtk_dvfsrc *dvfsrc, u32 level)
@@ -688,11 +700,22 @@ static int mtk_dvfsrc_probe(struct platform_device *pdev)
688700
return 0;
689701
}
690702

691-
static const struct dvfsrc_bw_constraints dvfsrc_bw_constr_v1 = { 0, 0, 0 };
692-
static const struct dvfsrc_bw_constraints dvfsrc_bw_constr_v2 = {
693-
.max_dram_nom_bw = 255,
694-
.max_dram_peak_bw = 255,
695-
.max_dram_hrt_bw = 1023,
703+
static const u32 dvfsrc_bw_min_constr_none[DVFSRC_BW_MAX] = {
704+
[DVFSRC_BW_AVG] = 0,
705+
[DVFSRC_BW_PEAK] = 0,
706+
[DVFSRC_BW_HRT] = 0,
707+
};
708+
709+
static const u32 dvfsrc_bw_max_constr_v1[DVFSRC_BW_MAX] = {
710+
[DVFSRC_BW_AVG] = U32_MAX,
711+
[DVFSRC_BW_PEAK] = U32_MAX,
712+
[DVFSRC_BW_HRT] = U32_MAX,
713+
};
714+
715+
static const u32 dvfsrc_bw_max_constr_v2[DVFSRC_BW_MAX] = {
716+
[DVFSRC_BW_AVG] = 65535,
717+
[DVFSRC_BW_PEAK] = 65535,
718+
[DVFSRC_BW_HRT] = 1023,
696719
};
697720

698721
static const struct dvfsrc_opp dvfsrc_opp_mt6893_lp4[] = {
@@ -725,7 +748,8 @@ static const struct dvfsrc_soc_data mt6893_data = {
725748
.set_vscp_level = dvfsrc_set_vscp_level_v2,
726749
.wait_for_opp_level = dvfsrc_wait_for_opp_level_v2,
727750
.wait_for_vcore_level = dvfsrc_wait_for_vcore_level_v1,
728-
.bw_constraints = &dvfsrc_bw_constr_v2,
751+
.bw_max_constraints = dvfsrc_bw_max_constr_v2,
752+
.bw_min_constraints = dvfsrc_bw_min_constr_none,
729753
};
730754

731755
static const struct dvfsrc_opp dvfsrc_opp_mt8183_lp4[] = {
@@ -763,7 +787,8 @@ static const struct dvfsrc_soc_data mt8183_data = {
763787
.set_vcore_level = dvfsrc_set_vcore_level_v1,
764788
.wait_for_opp_level = dvfsrc_wait_for_opp_level_v1,
765789
.wait_for_vcore_level = dvfsrc_wait_for_vcore_level_v1,
766-
.bw_constraints = &dvfsrc_bw_constr_v1,
790+
.bw_max_constraints = dvfsrc_bw_max_constr_v1,
791+
.bw_min_constraints = dvfsrc_bw_min_constr_none,
767792
};
768793

769794
static const struct dvfsrc_opp dvfsrc_opp_mt8195_lp4[] = {
@@ -797,7 +822,8 @@ static const struct dvfsrc_soc_data mt8195_data = {
797822
.set_vscp_level = dvfsrc_set_vscp_level_v2,
798823
.wait_for_opp_level = dvfsrc_wait_for_opp_level_v2,
799824
.wait_for_vcore_level = dvfsrc_wait_for_vcore_level_v1,
800-
.bw_constraints = &dvfsrc_bw_constr_v2,
825+
.bw_max_constraints = dvfsrc_bw_max_constr_v2,
826+
.bw_min_constraints = dvfsrc_bw_min_constr_none,
801827
};
802828

803829
static const u8 mt8196_bw_units[] = {
@@ -825,7 +851,8 @@ static const struct dvfsrc_soc_data mt8196_data = {
825851
.set_vscp_level = dvfsrc_set_vscp_level_v2,
826852
.wait_for_opp_level = dvfsrc_wait_for_opp_level_v4,
827853
.wait_for_vcore_level = dvfsrc_wait_for_vcore_level_v4,
828-
.bw_constraints = &dvfsrc_bw_constr_v1,
854+
.bw_max_constraints = dvfsrc_bw_max_constr_v2,
855+
.bw_min_constraints = dvfsrc_bw_min_constr_none,
829856
};
830857

831858
static const struct of_device_id mtk_dvfsrc_of_match[] = {

0 commit comments

Comments
 (0)