Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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/

authored by

Nicolas Frattaroli and committed by
Chanwoo Choi
eddb5ba9 f89c7fb8

+73 -20
+66 -18
drivers/devfreq/event/rockchip-dfi.c
··· 34 34 35 35 /* DDRMON_CTRL */ 36 36 #define DDRMON_CTRL 0x04 37 + #define DDRMON_CTRL_LPDDR5 BIT(6) 37 38 #define DDRMON_CTRL_DDR4 BIT(5) 38 39 #define DDRMON_CTRL_LPDDR4 BIT(4) 39 40 #define DDRMON_CTRL_HARDWARE_EN BIT(3) 40 41 #define DDRMON_CTRL_LPDDR23 BIT(2) 41 42 #define DDRMON_CTRL_SOFTWARE_EN BIT(1) 42 43 #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 | \ 44 46 DDRMON_CTRL_LPDDR4 | \ 45 47 DDRMON_CTRL_LPDDR23) 48 + #define DDRMON_CTRL_LP5_BANK_MODE_MASK GENMASK(8, 7) 46 49 47 50 #define DDRMON_CH0_WR_NUM 0x20 48 51 #define DDRMON_CH0_RD_NUM 0x24 ··· 119 116 int buswidth[DMC_MAX_CHANNELS]; 120 117 int ddrmon_stride; 121 118 bool ddrmon_ctrl_single; 119 + u32 lp5_bank_mode; 120 + bool lp5_ckr; /* true if in 4:1 command-to-data clock ratio mode */ 122 121 unsigned int count_multiplier; /* number of data clocks per count */ 123 122 }; 123 + 124 + static int rockchip_dfi_ddrtype_to_ctrl(struct rockchip_dfi *dfi, u32 *ctrl, 125 + u32 *mask) 126 + { 127 + u32 ddrmon_ver; 128 + 129 + *mask = DDRMON_CTRL_DDR_TYPE_MASK; 130 + 131 + switch (dfi->ddr_type) { 132 + case ROCKCHIP_DDRTYPE_LPDDR2: 133 + case ROCKCHIP_DDRTYPE_LPDDR3: 134 + *ctrl = DDRMON_CTRL_LPDDR23; 135 + break; 136 + case ROCKCHIP_DDRTYPE_LPDDR4: 137 + case ROCKCHIP_DDRTYPE_LPDDR4X: 138 + *ctrl = DDRMON_CTRL_LPDDR4; 139 + break; 140 + case ROCKCHIP_DDRTYPE_LPDDR5: 141 + ddrmon_ver = readl_relaxed(dfi->regs); 142 + if (ddrmon_ver < 0x40) { 143 + *ctrl = DDRMON_CTRL_LPDDR5 | dfi->lp5_bank_mode; 144 + *mask |= DDRMON_CTRL_LP5_BANK_MODE_MASK; 145 + break; 146 + } 147 + 148 + /* 149 + * As it is unknown whether the unpleasant special case 150 + * behaviour used by the vendor kernel is needed for any 151 + * shipping hardware, ask users to report if they have 152 + * some of that hardware. 153 + */ 154 + dev_err(&dfi->edev->dev, 155 + "unsupported DDRMON version 0x%04X, please let linux-rockchip know!\n", 156 + ddrmon_ver); 157 + return -EOPNOTSUPP; 158 + default: 159 + dev_err(&dfi->edev->dev, "unsupported memory type 0x%X\n", 160 + dfi->ddr_type); 161 + return -EOPNOTSUPP; 162 + } 163 + 164 + return 0; 165 + } 124 166 125 167 static int rockchip_dfi_enable(struct rockchip_dfi *dfi) 126 168 { 127 169 void __iomem *dfi_regs = dfi->regs; 128 170 int i, ret = 0; 171 + u32 ctrl; 172 + u32 ctrl_mask; 129 173 130 174 mutex_lock(&dfi->mutex); 131 175 ··· 186 136 goto out; 187 137 } 188 138 139 + ret = rockchip_dfi_ddrtype_to_ctrl(dfi, &ctrl, &ctrl_mask); 140 + if (ret) 141 + goto out; 142 + 189 143 for (i = 0; i < dfi->max_channels; i++) { 190 - u32 ctrl = 0; 191 144 192 145 if (!(dfi->channel_mask & BIT(i))) 193 146 continue; ··· 200 147 DDRMON_CTRL_SOFTWARE_EN | DDRMON_CTRL_HARDWARE_EN), 201 148 dfi_regs + i * dfi->ddrmon_stride + DDRMON_CTRL); 202 149 203 - /* set ddr type to dfi */ 204 - switch (dfi->ddr_type) { 205 - case ROCKCHIP_DDRTYPE_LPDDR2: 206 - case ROCKCHIP_DDRTYPE_LPDDR3: 207 - ctrl = DDRMON_CTRL_LPDDR23; 208 - break; 209 - case ROCKCHIP_DDRTYPE_LPDDR4: 210 - case ROCKCHIP_DDRTYPE_LPDDR4X: 211 - ctrl = DDRMON_CTRL_LPDDR4; 212 - break; 213 - default: 214 - break; 215 - } 216 - 217 - writel_relaxed(HIWORD_UPDATE(ctrl, DDRMON_CTRL_DDR_TYPE_MASK), 150 + writel_relaxed(HIWORD_UPDATE(ctrl, ctrl_mask), 218 151 dfi_regs + i * dfi->ddrmon_stride + DDRMON_CTRL); 219 152 220 153 /* enable count, use software mode */ ··· 691 652 break; 692 653 case ROCKCHIP_DDRTYPE_LPDDR4: 693 654 case ROCKCHIP_DDRTYPE_LPDDR4X: 655 + case ROCKCHIP_DDRTYPE_LPDDR5: 694 656 dfi->burst_len = 16; 695 657 break; 696 658 } ··· 770 730 static int rk3588_dfi_init(struct rockchip_dfi *dfi) 771 731 { 772 732 struct regmap *regmap_pmu = dfi->regmap_pmu; 773 - u32 reg2, reg3, reg4; 733 + u32 reg2, reg3, reg4, reg6; 774 734 775 735 regmap_read(regmap_pmu, RK3588_PMUGRF_OS_REG2, &reg2); 776 736 regmap_read(regmap_pmu, RK3588_PMUGRF_OS_REG3, &reg3); ··· 796 756 797 757 dfi->ddrmon_stride = 0x4000; 798 758 dfi->count_multiplier = 2; 759 + 760 + if (dfi->ddr_type == ROCKCHIP_DDRTYPE_LPDDR5) { 761 + regmap_read(regmap_pmu, RK3588_PMUGRF_OS_REG6, &reg6); 762 + dfi->lp5_bank_mode = FIELD_GET(RK3588_PMUGRF_OS_REG6_LP5_BANK_MODE, reg6) << 7; 763 + dfi->lp5_ckr = FIELD_GET(RK3588_PMUGRF_OS_REG6_LP5_CKR, reg6); 764 + if (dfi->lp5_ckr) 765 + dfi->count_multiplier *= 2; 766 + } 799 767 800 768 return 0; 801 769 };
+6 -2
include/soc/rockchip/rk3588_grf.h
··· 12 12 #define RK3588_PMUGRF_OS_REG3_DRAMTYPE_INFO_V3 GENMASK(13, 12) 13 13 #define RK3588_PMUGRF_OS_REG3_SYSREG_VERSION GENMASK(31, 28) 14 14 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) 17 21 18 22 #endif /* __SOC_RK3588_GRF_H */
+1
include/soc/rockchip/rockchip_grf.h
··· 13 13 ROCKCHIP_DDRTYPE_LPDDR3 = 6, 14 14 ROCKCHIP_DDRTYPE_LPDDR4 = 7, 15 15 ROCKCHIP_DDRTYPE_LPDDR4X = 8, 16 + ROCKCHIP_DDRTYPE_LPDDR5 = 9, 16 17 }; 17 18 18 19 #endif /* __SOC_ROCKCHIP_GRF_H */