DVFSRC_BW_MAX,
};
-struct dvfsrc_bw_constraints {
- u16 max_dram_nom_bw;
- u16 max_dram_peak_bw;
- u16 max_dram_hrt_bw;
-};
-
struct dvfsrc_opp {
u32 vcore_opp;
u32 dram_opp;
const u8 *bw_units;
const bool has_emi_ddr;
const struct dvfsrc_opp_desc *opps_desc;
- u32 (*calc_dram_bw)(struct mtk_dvfsrc *dvfsrc, int type, u64 bw);
+ u32 (*calc_dram_bw)(struct mtk_dvfsrc *dvfsrc, enum mtk_dvfsrc_bw_type type, u64 bw);
u32 (*get_target_level)(struct mtk_dvfsrc *dvfsrc);
u32 (*get_current_level)(struct mtk_dvfsrc *dvfsrc);
u32 (*get_vcore_level)(struct mtk_dvfsrc *dvfsrc);
void (*set_vscp_level)(struct mtk_dvfsrc *dvfsrc, u32 level);
int (*wait_for_opp_level)(struct mtk_dvfsrc *dvfsrc, u32 level);
int (*wait_for_vcore_level)(struct mtk_dvfsrc *dvfsrc, u32 level);
- const struct dvfsrc_bw_constraints *bw_constraints;
+
+ /**
+ * @bw_max_constraints - array of maximum bandwidth for this hardware
+ *
+ * indexed by &enum mtk_dvfsrc_bw_type, storing the maximum permissible
+ * hardware value for each bandwidth type.
+ */
+ const u32 *const bw_max_constraints;
+
+ /**
+ * @bw_min_constraints - array of minimum bandwidth for this hardware
+ *
+ * indexed by &enum mtk_dvfsrc_bw_type, storing the minimum permissible
+ * hardware value for each bandwidth type.
+ */
+ const u32 *const bw_min_constraints;
};
static u32 dvfsrc_readl(struct mtk_dvfsrc *dvfs, u32 offset)
return FIELD_GET(DVFSRC_V4_BASIC_CTRL_OPP_COUNT, val) + 1;
}
-static u32 dvfsrc_calc_dram_bw_v1(struct mtk_dvfsrc *dvfsrc, int type, u64 bw)
+static u32
+dvfsrc_calc_dram_bw_v1(struct mtk_dvfsrc *dvfsrc, enum mtk_dvfsrc_bw_type type, u64 bw)
{
- return (u32)div_u64(bw, 100 * 1000);
+ return clamp_val(div_u64(bw, 100 * 1000), dvfsrc->dvd->bw_min_constraints[type],
+ dvfsrc->dvd->bw_max_constraints[type]);
}
-static u32 dvfsrc_calc_dram_bw_v4(struct mtk_dvfsrc *dvfsrc, int type, u64 bw)
+/**
+ * dvfsrc_calc_dram_bw_v4 - convert kbps to hardware register bandwidth value
+ * @dvfsrc: pointer to the &struct mtk_dvfsrc of this driver instance
+ * @type: one of %DVFSRC_BW_AVG, %DVFSRC_BW_PEAK, or %DVFSRC_BW_HRT
+ * @bw: the bandwidth in kilobits per second
+ *
+ * Returns the hardware register value appropriate for expressing @bw, clamped
+ * to hardware limits.
+ */
+static u32
+dvfsrc_calc_dram_bw_v4(struct mtk_dvfsrc *dvfsrc, enum mtk_dvfsrc_bw_type type, u64 bw)
{
u8 bw_unit = dvfsrc->dvd->bw_units[type];
u64 bw_mbps;
+ u32 bw_hw;
if (type < DVFSRC_BW_AVG || type >= DVFSRC_BW_MAX)
return 0;
bw_mbps = div_u64(bw, 1000);
- return (u32)div_u64((bw_mbps + bw_unit - 1), bw_unit);
+ bw_hw = div_u64((bw_mbps + bw_unit - 1), bw_unit);
+ return clamp_val(bw_hw, dvfsrc->dvd->bw_min_constraints[type],
+ dvfsrc->dvd->bw_max_constraints[type]);
}
static void __dvfsrc_set_dram_bw_v1(struct mtk_dvfsrc *dvfsrc, u32 reg,
- int type, u16 max_bw, u16 min_bw, u64 bw)
+ enum mtk_dvfsrc_bw_type type, u64 bw)
{
- u32 new_bw = dvfsrc->dvd->calc_dram_bw(dvfsrc, type, bw);
-
- /* If bw constraints (in mbps) are defined make sure to respect them */
- if (max_bw)
- new_bw = min(new_bw, max_bw);
- if (min_bw && new_bw > 0)
- new_bw = max(new_bw, min_bw);
+ u32 bw_hw = dvfsrc->dvd->calc_dram_bw(dvfsrc, type, bw);
- dvfsrc_writel(dvfsrc, reg, new_bw);
+ dvfsrc_writel(dvfsrc, reg, bw_hw);
if (type == DVFSRC_BW_AVG && dvfsrc->dvd->has_emi_ddr)
- dvfsrc_writel(dvfsrc, DVFSRC_SW_EMI_BW, bw);
+ dvfsrc_writel(dvfsrc, DVFSRC_SW_EMI_BW, bw_hw);
}
static void dvfsrc_set_dram_bw_v1(struct mtk_dvfsrc *dvfsrc, u64 bw)
{
- u64 max_bw = dvfsrc->dvd->bw_constraints->max_dram_nom_bw;
-
- __dvfsrc_set_dram_bw_v1(dvfsrc, DVFSRC_SW_BW, DVFSRC_BW_AVG, max_bw, 0, bw);
+ __dvfsrc_set_dram_bw_v1(dvfsrc, DVFSRC_SW_BW, DVFSRC_BW_AVG, bw);
};
static void dvfsrc_set_dram_peak_bw_v1(struct mtk_dvfsrc *dvfsrc, u64 bw)
{
- u64 max_bw = dvfsrc->dvd->bw_constraints->max_dram_peak_bw;
-
- __dvfsrc_set_dram_bw_v1(dvfsrc, DVFSRC_SW_PEAK_BW, DVFSRC_BW_PEAK, max_bw, 0, bw);
+ __dvfsrc_set_dram_bw_v1(dvfsrc, DVFSRC_SW_PEAK_BW, DVFSRC_BW_PEAK, bw);
}
static void dvfsrc_set_dram_hrt_bw_v1(struct mtk_dvfsrc *dvfsrc, u64 bw)
{
- u64 max_bw = dvfsrc->dvd->bw_constraints->max_dram_hrt_bw;
-
- __dvfsrc_set_dram_bw_v1(dvfsrc, DVFSRC_SW_HRT_BW, DVFSRC_BW_HRT, max_bw, 0, bw);
+ __dvfsrc_set_dram_bw_v1(dvfsrc, DVFSRC_SW_HRT_BW, DVFSRC_BW_HRT, bw);
}
static void dvfsrc_set_opp_level_v1(struct mtk_dvfsrc *dvfsrc, u32 level)
return 0;
}
-static const struct dvfsrc_bw_constraints dvfsrc_bw_constr_v1 = { 0, 0, 0 };
-static const struct dvfsrc_bw_constraints dvfsrc_bw_constr_v2 = {
- .max_dram_nom_bw = 255,
- .max_dram_peak_bw = 255,
- .max_dram_hrt_bw = 1023,
+static const u32 dvfsrc_bw_min_constr_none[DVFSRC_BW_MAX] = {
+ [DVFSRC_BW_AVG] = 0,
+ [DVFSRC_BW_PEAK] = 0,
+ [DVFSRC_BW_HRT] = 0,
+};
+
+static const u32 dvfsrc_bw_max_constr_v1[DVFSRC_BW_MAX] = {
+ [DVFSRC_BW_AVG] = U32_MAX,
+ [DVFSRC_BW_PEAK] = U32_MAX,
+ [DVFSRC_BW_HRT] = U32_MAX,
+};
+
+static const u32 dvfsrc_bw_max_constr_v2[DVFSRC_BW_MAX] = {
+ [DVFSRC_BW_AVG] = 65535,
+ [DVFSRC_BW_PEAK] = 65535,
+ [DVFSRC_BW_HRT] = 1023,
};
static const struct dvfsrc_opp dvfsrc_opp_mt6893_lp4[] = {
.set_vscp_level = dvfsrc_set_vscp_level_v2,
.wait_for_opp_level = dvfsrc_wait_for_opp_level_v2,
.wait_for_vcore_level = dvfsrc_wait_for_vcore_level_v1,
- .bw_constraints = &dvfsrc_bw_constr_v2,
+ .bw_max_constraints = dvfsrc_bw_max_constr_v2,
+ .bw_min_constraints = dvfsrc_bw_min_constr_none,
};
static const struct dvfsrc_opp dvfsrc_opp_mt8183_lp4[] = {
.set_vcore_level = dvfsrc_set_vcore_level_v1,
.wait_for_opp_level = dvfsrc_wait_for_opp_level_v1,
.wait_for_vcore_level = dvfsrc_wait_for_vcore_level_v1,
- .bw_constraints = &dvfsrc_bw_constr_v1,
+ .bw_max_constraints = dvfsrc_bw_max_constr_v1,
+ .bw_min_constraints = dvfsrc_bw_min_constr_none,
};
static const struct dvfsrc_opp dvfsrc_opp_mt8195_lp4[] = {
.set_vscp_level = dvfsrc_set_vscp_level_v2,
.wait_for_opp_level = dvfsrc_wait_for_opp_level_v2,
.wait_for_vcore_level = dvfsrc_wait_for_vcore_level_v1,
- .bw_constraints = &dvfsrc_bw_constr_v2,
+ .bw_max_constraints = dvfsrc_bw_max_constr_v2,
+ .bw_min_constraints = dvfsrc_bw_min_constr_none,
};
static const u8 mt8196_bw_units[] = {
.set_vscp_level = dvfsrc_set_vscp_level_v2,
.wait_for_opp_level = dvfsrc_wait_for_opp_level_v4,
.wait_for_vcore_level = dvfsrc_wait_for_vcore_level_v4,
- .bw_constraints = &dvfsrc_bw_constr_v1,
+ .bw_max_constraints = dvfsrc_bw_max_constr_v2,
+ .bw_min_constraints = dvfsrc_bw_min_constr_none,
};
static const struct of_device_id mtk_dvfsrc_of_match[] = {