Skip to content

Commit d6fd599

Browse files
committed
Merge branches 'pm-em', 'pm-opp' and 'pm-devfreq'
Merge energy model management, OPP (operating performance points) and devfreq updates for 6.18-rc1: - Prevent CPU capacity updates after registering a perf domain from failing on a first CPU that is not present (Christian Loehle) - Add support for the cases in which frequency alone is not sufficient to uniquely identify an OPP (Krishna Chaitanya Chundru) - Use to_result() for OPP error handling in Rust (Onur Özkan) - Add support for LPDDR5 on Rockhip RK3588 SoC to rockchip-dfi devfreq driver (Nicolas Frattaroli) - Fix an issue where DDR cycle counts on RK3588/RK3528 with LPDDR4(X) are reported as half by adding a cycle multiplier to the DFI driver in rockchip-dfi devfreq-event driver (Nicolas Frattaroli) - Fix missing error pointer dereference check of regulator instance in the mtk-cci devfreq driver probe and remove a redundant condition from an if () statement in that driver (Dan Carpenter, Liao Yuanhong) * pm-em: PM: EM: Fix late boot with holes in CPU topology * pm-opp: OPP: Add support to find OPP for a set of keys rust: opp: use to_result for error handling * pm-devfreq: PM / devfreq: rockchip-dfi: add support for LPDDR5 PM / devfreq: rockchip-dfi: double count on RK3588 PM / devfreq: mtk-cci: avoid redundant conditions PM / devfreq: mtk-cci: Fix potential error pointer dereference in probe()
4 parents d3f8f8d + 1ebe8f7 + 8646f11 + 531453a commit d6fd599

8 files changed

Lines changed: 222 additions & 39 deletions

File tree

drivers/devfreq/event/rockchip-dfi.c

Lines changed: 72 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,18 @@
3434

3535
/* DDRMON_CTRL */
3636
#define DDRMON_CTRL 0x04
37+
#define DDRMON_CTRL_LPDDR5 BIT(6)
3738
#define DDRMON_CTRL_DDR4 BIT(5)
3839
#define DDRMON_CTRL_LPDDR4 BIT(4)
3940
#define DDRMON_CTRL_HARDWARE_EN BIT(3)
4041
#define DDRMON_CTRL_LPDDR23 BIT(2)
4142
#define DDRMON_CTRL_SOFTWARE_EN BIT(1)
4243
#define DDRMON_CTRL_TIMER_CNT_EN BIT(0)
43-
#define DDRMON_CTRL_DDR_TYPE_MASK (DDRMON_CTRL_DDR4 | \
44+
#define DDRMON_CTRL_DDR_TYPE_MASK (DDRMON_CTRL_LPDDR5 | \
45+
DDRMON_CTRL_DDR4 | \
4446
DDRMON_CTRL_LPDDR4 | \
4547
DDRMON_CTRL_LPDDR23)
48+
#define DDRMON_CTRL_LP5_BANK_MODE_MASK GENMASK(8, 7)
4649

4750
#define DDRMON_CH0_WR_NUM 0x20
4851
#define DDRMON_CH0_RD_NUM 0x24
@@ -116,12 +119,60 @@ struct rockchip_dfi {
116119
int buswidth[DMC_MAX_CHANNELS];
117120
int ddrmon_stride;
118121
bool ddrmon_ctrl_single;
122+
u32 lp5_bank_mode;
123+
bool lp5_ckr; /* true if in 4:1 command-to-data clock ratio mode */
124+
unsigned int count_multiplier; /* number of data clocks per count */
119125
};
120126

127+
static int rockchip_dfi_ddrtype_to_ctrl(struct rockchip_dfi *dfi, u32 *ctrl,
128+
u32 *mask)
129+
{
130+
u32 ddrmon_ver;
131+
132+
*mask = DDRMON_CTRL_DDR_TYPE_MASK;
133+
134+
switch (dfi->ddr_type) {
135+
case ROCKCHIP_DDRTYPE_LPDDR2:
136+
case ROCKCHIP_DDRTYPE_LPDDR3:
137+
*ctrl = DDRMON_CTRL_LPDDR23;
138+
break;
139+
case ROCKCHIP_DDRTYPE_LPDDR4:
140+
case ROCKCHIP_DDRTYPE_LPDDR4X:
141+
*ctrl = DDRMON_CTRL_LPDDR4;
142+
break;
143+
case ROCKCHIP_DDRTYPE_LPDDR5:
144+
ddrmon_ver = readl_relaxed(dfi->regs);
145+
if (ddrmon_ver < 0x40) {
146+
*ctrl = DDRMON_CTRL_LPDDR5 | dfi->lp5_bank_mode;
147+
*mask |= DDRMON_CTRL_LP5_BANK_MODE_MASK;
148+
break;
149+
}
150+
151+
/*
152+
* As it is unknown whether the unpleasant special case
153+
* behaviour used by the vendor kernel is needed for any
154+
* shipping hardware, ask users to report if they have
155+
* some of that hardware.
156+
*/
157+
dev_err(&dfi->edev->dev,
158+
"unsupported DDRMON version 0x%04X, please let linux-rockchip know!\n",
159+
ddrmon_ver);
160+
return -EOPNOTSUPP;
161+
default:
162+
dev_err(&dfi->edev->dev, "unsupported memory type 0x%X\n",
163+
dfi->ddr_type);
164+
return -EOPNOTSUPP;
165+
}
166+
167+
return 0;
168+
}
169+
121170
static int rockchip_dfi_enable(struct rockchip_dfi *dfi)
122171
{
123172
void __iomem *dfi_regs = dfi->regs;
124173
int i, ret = 0;
174+
u32 ctrl;
175+
u32 ctrl_mask;
125176

126177
mutex_lock(&dfi->mutex);
127178

@@ -135,8 +186,11 @@ static int rockchip_dfi_enable(struct rockchip_dfi *dfi)
135186
goto out;
136187
}
137188

189+
ret = rockchip_dfi_ddrtype_to_ctrl(dfi, &ctrl, &ctrl_mask);
190+
if (ret)
191+
goto out;
192+
138193
for (i = 0; i < dfi->max_channels; i++) {
139-
u32 ctrl = 0;
140194

141195
if (!(dfi->channel_mask & BIT(i)))
142196
continue;
@@ -146,21 +200,7 @@ static int rockchip_dfi_enable(struct rockchip_dfi *dfi)
146200
DDRMON_CTRL_SOFTWARE_EN | DDRMON_CTRL_HARDWARE_EN),
147201
dfi_regs + i * dfi->ddrmon_stride + DDRMON_CTRL);
148202

149-
/* set ddr type to dfi */
150-
switch (dfi->ddr_type) {
151-
case ROCKCHIP_DDRTYPE_LPDDR2:
152-
case ROCKCHIP_DDRTYPE_LPDDR3:
153-
ctrl = DDRMON_CTRL_LPDDR23;
154-
break;
155-
case ROCKCHIP_DDRTYPE_LPDDR4:
156-
case ROCKCHIP_DDRTYPE_LPDDR4X:
157-
ctrl = DDRMON_CTRL_LPDDR4;
158-
break;
159-
default:
160-
break;
161-
}
162-
163-
writel_relaxed(HIWORD_UPDATE(ctrl, DDRMON_CTRL_DDR_TYPE_MASK),
203+
writel_relaxed(HIWORD_UPDATE(ctrl, ctrl_mask),
164204
dfi_regs + i * dfi->ddrmon_stride + DDRMON_CTRL);
165205

166206
/* enable count, use software mode */
@@ -435,7 +475,7 @@ static u64 rockchip_ddr_perf_event_get_count(struct perf_event *event)
435475

436476
switch (event->attr.config) {
437477
case PERF_EVENT_CYCLES:
438-
count = total.c[0].clock_cycles;
478+
count = total.c[0].clock_cycles * dfi->count_multiplier;
439479
break;
440480
case PERF_EVENT_READ_BYTES:
441481
for (i = 0; i < dfi->max_channels; i++)
@@ -651,10 +691,14 @@ static int rockchip_ddr_perf_init(struct rockchip_dfi *dfi)
651691
break;
652692
case ROCKCHIP_DDRTYPE_LPDDR4:
653693
case ROCKCHIP_DDRTYPE_LPDDR4X:
694+
case ROCKCHIP_DDRTYPE_LPDDR5:
654695
dfi->burst_len = 16;
655696
break;
656697
}
657698

699+
if (!dfi->count_multiplier)
700+
dfi->count_multiplier = 1;
701+
658702
ret = perf_pmu_register(pmu, "rockchip_ddr", -1);
659703
if (ret)
660704
return ret;
@@ -726,7 +770,7 @@ static int rk3568_dfi_init(struct rockchip_dfi *dfi)
726770
static int rk3588_dfi_init(struct rockchip_dfi *dfi)
727771
{
728772
struct regmap *regmap_pmu = dfi->regmap_pmu;
729-
u32 reg2, reg3, reg4;
773+
u32 reg2, reg3, reg4, reg6;
730774

731775
regmap_read(regmap_pmu, RK3588_PMUGRF_OS_REG2, &reg2);
732776
regmap_read(regmap_pmu, RK3588_PMUGRF_OS_REG3, &reg3);
@@ -751,6 +795,15 @@ static int rk3588_dfi_init(struct rockchip_dfi *dfi)
751795
dfi->max_channels = 4;
752796

753797
dfi->ddrmon_stride = 0x4000;
798+
dfi->count_multiplier = 2;
799+
800+
if (dfi->ddr_type == ROCKCHIP_DDRTYPE_LPDDR5) {
801+
regmap_read(regmap_pmu, RK3588_PMUGRF_OS_REG6, &reg6);
802+
dfi->lp5_bank_mode = FIELD_GET(RK3588_PMUGRF_OS_REG6_LP5_BANK_MODE, reg6) << 7;
803+
dfi->lp5_ckr = FIELD_GET(RK3588_PMUGRF_OS_REG6_LP5_CKR, reg6);
804+
if (dfi->lp5_ckr)
805+
dfi->count_multiplier *= 2;
806+
}
754807

755808
return 0;
756809
};

drivers/devfreq/mtk-cci-devfreq.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ static int mtk_ccifreq_set_voltage(struct mtk_ccifreq_drv *drv, int new_voltage)
8686
soc_data->sram_max_volt);
8787
return ret;
8888
}
89-
} else if (pre_voltage > new_voltage) {
89+
} else {
9090
voltage = max(new_voltage,
9191
pre_vsram - soc_data->max_volt_shift);
9292
ret = regulator_set_voltage(drv->proc_reg, voltage,
@@ -386,7 +386,8 @@ static int mtk_ccifreq_probe(struct platform_device *pdev)
386386
out_free_resources:
387387
if (regulator_is_enabled(drv->proc_reg))
388388
regulator_disable(drv->proc_reg);
389-
if (drv->sram_reg && regulator_is_enabled(drv->sram_reg))
389+
if (!IS_ERR_OR_NULL(drv->sram_reg) &&
390+
regulator_is_enabled(drv->sram_reg))
390391
regulator_disable(drv->sram_reg);
391392

392393
return ret;

drivers/opp/core.c

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,16 @@ static unsigned long _read_bw(struct dev_pm_opp *opp, int index)
476476
return opp->bandwidth[index].peak;
477477
}
478478

479+
static unsigned long _read_opp_key(struct dev_pm_opp *opp, int index,
480+
struct dev_pm_opp_key *key)
481+
{
482+
key->bw = opp->bandwidth ? opp->bandwidth[index].peak : 0;
483+
key->freq = opp->rates[index];
484+
key->level = opp->level;
485+
486+
return true;
487+
}
488+
479489
/* Generic comparison helpers */
480490
static bool _compare_exact(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
481491
unsigned long opp_key, unsigned long key)
@@ -509,6 +519,22 @@ static bool _compare_floor(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
509519
return false;
510520
}
511521

522+
static bool _compare_opp_key_exact(struct dev_pm_opp **opp,
523+
struct dev_pm_opp *temp_opp, struct dev_pm_opp_key *opp_key,
524+
struct dev_pm_opp_key *key)
525+
{
526+
bool level_match = (key->level == OPP_LEVEL_UNSET || opp_key->level == key->level);
527+
bool freq_match = (key->freq == 0 || opp_key->freq == key->freq);
528+
bool bw_match = (key->bw == 0 || opp_key->bw == key->bw);
529+
530+
if (freq_match && level_match && bw_match) {
531+
*opp = temp_opp;
532+
return true;
533+
}
534+
535+
return false;
536+
}
537+
512538
/* Generic key finding helpers */
513539
static struct dev_pm_opp *_opp_table_find_key(struct opp_table *opp_table,
514540
unsigned long *key, int index, bool available,
@@ -541,6 +567,37 @@ static struct dev_pm_opp *_opp_table_find_key(struct opp_table *opp_table,
541567
return opp;
542568
}
543569

570+
static struct dev_pm_opp *_opp_table_find_opp_key(struct opp_table *opp_table,
571+
struct dev_pm_opp_key *key, bool available,
572+
unsigned long (*read)(struct dev_pm_opp *opp, int index,
573+
struct dev_pm_opp_key *key),
574+
bool (*compare)(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
575+
struct dev_pm_opp_key *opp_key, struct dev_pm_opp_key *key),
576+
bool (*assert)(struct opp_table *opp_table, unsigned int index))
577+
{
578+
struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
579+
struct dev_pm_opp_key temp_key;
580+
581+
/* Assert that the requirement is met */
582+
if (!assert(opp_table, 0))
583+
return ERR_PTR(-EINVAL);
584+
585+
guard(mutex)(&opp_table->lock);
586+
587+
list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
588+
if (temp_opp->available == available) {
589+
read(temp_opp, 0, &temp_key);
590+
if (compare(&opp, temp_opp, &temp_key, key)) {
591+
/* Increment the reference count of OPP */
592+
dev_pm_opp_get(opp);
593+
break;
594+
}
595+
}
596+
}
597+
598+
return opp;
599+
}
600+
544601
static struct dev_pm_opp *
545602
_find_key(struct device *dev, unsigned long *key, int index, bool available,
546603
unsigned long (*read)(struct dev_pm_opp *opp, int index),
@@ -632,6 +689,48 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
632689
}
633690
EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_exact);
634691

692+
/**
693+
* dev_pm_opp_find_key_exact() - Search for an OPP with exact key set
694+
* @dev: Device for which the OPP is being searched
695+
* @key: OPP key set to match
696+
* @available: true/false - match for available OPP
697+
*
698+
* Search for an exact match of the key set in the OPP table.
699+
*
700+
* Return: A matching opp on success, else ERR_PTR in case of error.
701+
* Possible error values:
702+
* EINVAL: for bad pointers
703+
* ERANGE: no match found for search
704+
* ENODEV: if device not found in list of registered devices
705+
*
706+
* Note: 'available' is a modifier for the search. If 'available' == true,
707+
* then the match is for exact matching key and is available in the stored
708+
* OPP table. If false, the match is for exact key which is not available.
709+
*
710+
* This provides a mechanism to enable an OPP which is not available currently
711+
* or the opposite as well.
712+
*
713+
* The callers are required to call dev_pm_opp_put() for the returned OPP after
714+
* use.
715+
*/
716+
struct dev_pm_opp *dev_pm_opp_find_key_exact(struct device *dev,
717+
struct dev_pm_opp_key *key,
718+
bool available)
719+
{
720+
struct opp_table *opp_table __free(put_opp_table) = _find_opp_table(dev);
721+
722+
if (IS_ERR(opp_table)) {
723+
dev_err(dev, "%s: OPP table not found (%ld)\n", __func__,
724+
PTR_ERR(opp_table));
725+
return ERR_CAST(opp_table);
726+
}
727+
728+
return _opp_table_find_opp_key(opp_table, key, available,
729+
_read_opp_key, _compare_opp_key_exact,
730+
assert_single_clk);
731+
}
732+
EXPORT_SYMBOL_GPL(dev_pm_opp_find_key_exact);
733+
635734
/**
636735
* dev_pm_opp_find_freq_exact_indexed() - Search for an exact freq for the
637736
* clock corresponding to the index

include/linux/pm_opp.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,25 @@ struct dev_pm_opp_data {
9898
unsigned long u_volt;
9999
};
100100

101+
/**
102+
* struct dev_pm_opp_key - Key used to identify OPP entries
103+
* @freq: Frequency in Hz. Use 0 if frequency is not to be matched.
104+
* @level: Performance level associated with the OPP entry.
105+
* Use OPP_LEVEL_UNSET if level is not to be matched.
106+
* @bw: Bandwidth associated with the OPP entry.
107+
* Use 0 if bandwidth is not to be matched.
108+
*
109+
* This structure is used to uniquely identify an OPP entry based on
110+
* frequency, performance level, and bandwidth. Each field can be
111+
* selectively ignored during matching by setting it to its respective
112+
* NOP value.
113+
*/
114+
struct dev_pm_opp_key {
115+
unsigned long freq;
116+
unsigned int level;
117+
u32 bw;
118+
};
119+
101120
#if defined(CONFIG_PM_OPP)
102121

103122
struct opp_table *dev_pm_opp_get_opp_table(struct device *dev);
@@ -131,6 +150,10 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
131150
unsigned long freq,
132151
bool available);
133152

153+
struct dev_pm_opp *dev_pm_opp_find_key_exact(struct device *dev,
154+
struct dev_pm_opp_key *key,
155+
bool available);
156+
134157
struct dev_pm_opp *
135158
dev_pm_opp_find_freq_exact_indexed(struct device *dev, unsigned long freq,
136159
u32 index, bool available);
@@ -289,6 +312,13 @@ static inline struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
289312
return ERR_PTR(-EOPNOTSUPP);
290313
}
291314

315+
static inline struct dev_pm_opp *dev_pm_opp_find_key_exact(struct device *dev,
316+
struct dev_pm_opp_key *key,
317+
bool available)
318+
{
319+
return ERR_PTR(-EOPNOTSUPP);
320+
}
321+
292322
static inline struct dev_pm_opp *
293323
dev_pm_opp_find_freq_exact_indexed(struct device *dev, unsigned long freq,
294324
u32 index, bool available)

include/soc/rockchip/rk3588_grf.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@
1212
#define RK3588_PMUGRF_OS_REG3_DRAMTYPE_INFO_V3 GENMASK(13, 12)
1313
#define RK3588_PMUGRF_OS_REG3_SYSREG_VERSION GENMASK(31, 28)
1414

15-
#define RK3588_PMUGRF_OS_REG4 0x210
16-
#define RK3588_PMUGRF_OS_REG5 0x214
15+
#define RK3588_PMUGRF_OS_REG4 0x210
16+
#define RK3588_PMUGRF_OS_REG5 0x214
17+
#define RK3588_PMUGRF_OS_REG6 0x218
18+
#define RK3588_PMUGRF_OS_REG6_LP5_BANK_MODE GENMASK(2, 1)
19+
/* Whether the LPDDR5 is in 2:1 (= 0) or 4:1 (= 1) CKR a.k.a. DQS mode */
20+
#define RK3588_PMUGRF_OS_REG6_LP5_CKR BIT(0)
1721

1822
#endif /* __SOC_RK3588_GRF_H */

include/soc/rockchip/rockchip_grf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ enum {
1313
ROCKCHIP_DDRTYPE_LPDDR3 = 6,
1414
ROCKCHIP_DDRTYPE_LPDDR4 = 7,
1515
ROCKCHIP_DDRTYPE_LPDDR4X = 8,
16+
ROCKCHIP_DDRTYPE_LPDDR5 = 9,
1617
};
1718

1819
#endif /* __SOC_ROCKCHIP_GRF_H */

0 commit comments

Comments
 (0)