Skip to content

Commit eddb5ba

Browse files
Nicolas Frattarolichanwoochoi
authored andcommitted
PM / devfreq: rockchip-dfi: add support for LPDDR5
The Rockchip RK3588 SoC can also support LPDDR5 memory. This type of memory needs some special case handling in the rockchip-dfi driver. Add support for it in rockchip-dfi, as well as the needed GRF register definitions. This has been tested as returning both the right cycle count and bandwidth on a LPDDR5 board where the CKR bit is 1. I couldn't test whether the values are correct on a system where CKR is 0, as I'm not savvy enough with the Rockchip tooling to know whether this can be set in the DDR init blob. Downstream has some special case handling for a hardware version where not just the control bits differ, but also the register. Since I don't know whether that hardware version is in any production silicon, it's left unimplemented for now, with an error message urging users to report if they have such a system. There is a slight change of behaviour for non-LPDDR5 systems: instead of writing 0 as the control flags to the control register and pretending everything is alright if the memory type is unknown, we now explicitly return an error. Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com> Reviewed-by: Sascha Hauer <s.hauer@pengutronix.de> Acked-by: Heiko Stuebner <heiko@sntech.de> Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com> Link: https://patchwork.kernel.org/project/linux-pm/patch/20250530-rk3588-dfi-improvements-v1-2-6e077c243a95@collabora.com/
1 parent f89c7fb commit eddb5ba

3 files changed

Lines changed: 73 additions & 20 deletions

File tree

drivers/devfreq/event/rockchip-dfi.c

Lines changed: 66 additions & 18 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,13 +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 */
119124
unsigned int count_multiplier; /* number of data clocks per count */
120125
};
121126

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+
122170
static int rockchip_dfi_enable(struct rockchip_dfi *dfi)
123171
{
124172
void __iomem *dfi_regs = dfi->regs;
125173
int i, ret = 0;
174+
u32 ctrl;
175+
u32 ctrl_mask;
126176

127177
mutex_lock(&dfi->mutex);
128178

@@ -136,8 +186,11 @@ static int rockchip_dfi_enable(struct rockchip_dfi *dfi)
136186
goto out;
137187
}
138188

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

142195
if (!(dfi->channel_mask & BIT(i)))
143196
continue;
@@ -147,21 +200,7 @@ static int rockchip_dfi_enable(struct rockchip_dfi *dfi)
147200
DDRMON_CTRL_SOFTWARE_EN | DDRMON_CTRL_HARDWARE_EN),
148201
dfi_regs + i * dfi->ddrmon_stride + DDRMON_CTRL);
149202

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

167206
/* enable count, use software mode */
@@ -652,6 +691,7 @@ static int rockchip_ddr_perf_init(struct rockchip_dfi *dfi)
652691
break;
653692
case ROCKCHIP_DDRTYPE_LPDDR4:
654693
case ROCKCHIP_DDRTYPE_LPDDR4X:
694+
case ROCKCHIP_DDRTYPE_LPDDR5:
655695
dfi->burst_len = 16;
656696
break;
657697
}
@@ -730,7 +770,7 @@ static int rk3568_dfi_init(struct rockchip_dfi *dfi)
730770
static int rk3588_dfi_init(struct rockchip_dfi *dfi)
731771
{
732772
struct regmap *regmap_pmu = dfi->regmap_pmu;
733-
u32 reg2, reg3, reg4;
773+
u32 reg2, reg3, reg4, reg6;
734774

735775
regmap_read(regmap_pmu, RK3588_PMUGRF_OS_REG2, &reg2);
736776
regmap_read(regmap_pmu, RK3588_PMUGRF_OS_REG3, &reg3);
@@ -757,6 +797,14 @@ static int rk3588_dfi_init(struct rockchip_dfi *dfi)
757797
dfi->ddrmon_stride = 0x4000;
758798
dfi->count_multiplier = 2;
759799

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+
}
807+
760808
return 0;
761809
};
762810

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)