1 // SPDX-License-Identifier: GPL-2.0-only
3 * DDR Self-Refresh Power Down (SRPD) support for Broadcom STB SoCs
7 #include <linux/init.h>
9 #include <linux/kernel.h>
10 #include <linux/module.h>
12 #include <linux/platform_device.h>
13 #include <linux/property.h>
15 #define REG_MEMC_CNTRLR_CONFIG 0x00
16 #define CNTRLR_CONFIG_LPDDR4_SHIFT 5
17 #define CNTRLR_CONFIG_MASK 0xf
18 #define REG_MEMC_SRPD_CFG_21 0x20
19 #define REG_MEMC_SRPD_CFG_20 0x34
20 #define REG_MEMC_SRPD_CFG_1x 0x3c
21 #define INACT_COUNT_SHIFT 0
22 #define INACT_COUNT_MASK 0xffff
23 #define SRPD_EN_SHIFT 16
25 struct brcmstb_memc_data
{
31 void __iomem
*ddr_ctrl
;
32 unsigned int timeout_cycles
;
37 static int brcmstb_memc_uses_lpddr4(struct brcmstb_memc
*memc
)
39 void __iomem
*config
= memc
->ddr_ctrl
+ REG_MEMC_CNTRLR_CONFIG
;
42 reg
= readl_relaxed(config
) & CNTRLR_CONFIG_MASK
;
44 return reg
== CNTRLR_CONFIG_LPDDR4_SHIFT
;
47 static int brcmstb_memc_srpd_config(struct brcmstb_memc
*memc
,
50 void __iomem
*cfg
= memc
->ddr_ctrl
+ memc
->srpd_offset
;
53 /* Max timeout supported in HW */
54 if (cycles
> INACT_COUNT_MASK
)
57 memc
->timeout_cycles
= cycles
;
59 val
= (cycles
<< INACT_COUNT_SHIFT
) & INACT_COUNT_MASK
;
61 val
|= BIT(SRPD_EN_SHIFT
);
63 writel_relaxed(val
, cfg
);
64 /* Ensure the write is committed to the controller */
65 (void)readl_relaxed(cfg
);
70 static ssize_t
frequency_show(struct device
*dev
,
71 struct device_attribute
*attr
, char *buf
)
73 struct brcmstb_memc
*memc
= dev_get_drvdata(dev
);
75 return sprintf(buf
, "%d\n", memc
->frequency
);
78 static ssize_t
srpd_show(struct device
*dev
,
79 struct device_attribute
*attr
, char *buf
)
81 struct brcmstb_memc
*memc
= dev_get_drvdata(dev
);
83 return sprintf(buf
, "%d\n", memc
->timeout_cycles
);
86 static ssize_t
srpd_store(struct device
*dev
, struct device_attribute
*attr
,
87 const char *buf
, size_t count
)
89 struct brcmstb_memc
*memc
= dev_get_drvdata(dev
);
94 * Cannot change the inactivity timeout on LPDDR4 chips because the
95 * dynamic tuning process will also get affected by the inactivity
96 * timeout, thus making it non functional.
98 if (brcmstb_memc_uses_lpddr4(memc
))
101 ret
= kstrtouint(buf
, 10, &val
);
105 ret
= brcmstb_memc_srpd_config(memc
, val
);
112 static DEVICE_ATTR_RO(frequency
);
113 static DEVICE_ATTR_RW(srpd
);
115 static struct attribute
*dev_attrs
[] = {
116 &dev_attr_frequency
.attr
,
121 static struct attribute_group dev_attr_group
= {
125 static int brcmstb_memc_probe(struct platform_device
*pdev
)
127 const struct brcmstb_memc_data
*memc_data
;
128 struct device
*dev
= &pdev
->dev
;
129 struct brcmstb_memc
*memc
;
132 memc
= devm_kzalloc(dev
, sizeof(*memc
), GFP_KERNEL
);
136 dev_set_drvdata(dev
, memc
);
138 memc_data
= device_get_match_data(dev
);
139 memc
->srpd_offset
= memc_data
->srpd_offset
;
141 memc
->ddr_ctrl
= devm_platform_ioremap_resource(pdev
, 0);
142 if (IS_ERR(memc
->ddr_ctrl
))
143 return PTR_ERR(memc
->ddr_ctrl
);
145 of_property_read_u32(pdev
->dev
.of_node
, "clock-frequency",
148 ret
= sysfs_create_group(&dev
->kobj
, &dev_attr_group
);
155 static void brcmstb_memc_remove(struct platform_device
*pdev
)
157 struct device
*dev
= &pdev
->dev
;
159 sysfs_remove_group(&dev
->kobj
, &dev_attr_group
);
162 enum brcmstb_memc_hwtype
{
168 static const struct brcmstb_memc_data brcmstb_memc_versions
[] = {
169 { .srpd_offset
= REG_MEMC_SRPD_CFG_21
},
170 { .srpd_offset
= REG_MEMC_SRPD_CFG_20
},
171 { .srpd_offset
= REG_MEMC_SRPD_CFG_1x
},
174 static const struct of_device_id brcmstb_memc_of_match
[] = {
176 .compatible
= "brcm,brcmstb-memc-ddr-rev-b.1.x",
177 .data
= &brcmstb_memc_versions
[BRCMSTB_MEMC_V1X
]
180 .compatible
= "brcm,brcmstb-memc-ddr-rev-b.2.0",
181 .data
= &brcmstb_memc_versions
[BRCMSTB_MEMC_V20
]
184 .compatible
= "brcm,brcmstb-memc-ddr-rev-b.2.1",
185 .data
= &brcmstb_memc_versions
[BRCMSTB_MEMC_V21
]
188 .compatible
= "brcm,brcmstb-memc-ddr-rev-b.2.2",
189 .data
= &brcmstb_memc_versions
[BRCMSTB_MEMC_V21
]
192 .compatible
= "brcm,brcmstb-memc-ddr-rev-b.2.3",
193 .data
= &brcmstb_memc_versions
[BRCMSTB_MEMC_V21
]
196 .compatible
= "brcm,brcmstb-memc-ddr-rev-b.2.5",
197 .data
= &brcmstb_memc_versions
[BRCMSTB_MEMC_V21
]
200 .compatible
= "brcm,brcmstb-memc-ddr-rev-b.2.6",
201 .data
= &brcmstb_memc_versions
[BRCMSTB_MEMC_V21
]
204 .compatible
= "brcm,brcmstb-memc-ddr-rev-b.2.7",
205 .data
= &brcmstb_memc_versions
[BRCMSTB_MEMC_V21
]
208 .compatible
= "brcm,brcmstb-memc-ddr-rev-b.2.8",
209 .data
= &brcmstb_memc_versions
[BRCMSTB_MEMC_V21
]
212 .compatible
= "brcm,brcmstb-memc-ddr-rev-b.3.0",
213 .data
= &brcmstb_memc_versions
[BRCMSTB_MEMC_V21
]
216 .compatible
= "brcm,brcmstb-memc-ddr-rev-b.3.1",
217 .data
= &brcmstb_memc_versions
[BRCMSTB_MEMC_V21
]
220 .compatible
= "brcm,brcmstb-memc-ddr-rev-c.1.0",
221 .data
= &brcmstb_memc_versions
[BRCMSTB_MEMC_V21
]
224 .compatible
= "brcm,brcmstb-memc-ddr-rev-c.1.1",
225 .data
= &brcmstb_memc_versions
[BRCMSTB_MEMC_V21
]
228 .compatible
= "brcm,brcmstb-memc-ddr-rev-c.1.2",
229 .data
= &brcmstb_memc_versions
[BRCMSTB_MEMC_V21
]
232 .compatible
= "brcm,brcmstb-memc-ddr-rev-c.1.3",
233 .data
= &brcmstb_memc_versions
[BRCMSTB_MEMC_V21
]
236 .compatible
= "brcm,brcmstb-memc-ddr-rev-c.1.4",
237 .data
= &brcmstb_memc_versions
[BRCMSTB_MEMC_V21
]
239 /* default to the original offset */
241 .compatible
= "brcm,brcmstb-memc-ddr",
242 .data
= &brcmstb_memc_versions
[BRCMSTB_MEMC_V1X
]
246 MODULE_DEVICE_TABLE(of
, brcmstb_memc_of_match
);
248 static int brcmstb_memc_suspend(struct device
*dev
)
250 struct brcmstb_memc
*memc
= dev_get_drvdata(dev
);
251 void __iomem
*cfg
= memc
->ddr_ctrl
+ memc
->srpd_offset
;
254 if (memc
->timeout_cycles
== 0)
258 * Disable SRPD prior to suspending the system since that can
259 * cause issues with other memory clients managed by the ARM
260 * trusted firmware to access memory.
262 val
= readl_relaxed(cfg
);
263 val
&= ~BIT(SRPD_EN_SHIFT
);
264 writel_relaxed(val
, cfg
);
265 /* Ensure the write is committed to the controller */
266 (void)readl_relaxed(cfg
);
271 static int brcmstb_memc_resume(struct device
*dev
)
273 struct brcmstb_memc
*memc
= dev_get_drvdata(dev
);
275 if (memc
->timeout_cycles
== 0)
278 return brcmstb_memc_srpd_config(memc
, memc
->timeout_cycles
);
281 static DEFINE_SIMPLE_DEV_PM_OPS(brcmstb_memc_pm_ops
, brcmstb_memc_suspend
,
282 brcmstb_memc_resume
);
284 static struct platform_driver brcmstb_memc_driver
= {
285 .probe
= brcmstb_memc_probe
,
286 .remove
= brcmstb_memc_remove
,
288 .name
= "brcmstb_memc",
289 .of_match_table
= brcmstb_memc_of_match
,
290 .pm
= pm_ptr(&brcmstb_memc_pm_ops
),
293 module_platform_driver(brcmstb_memc_driver
);
295 MODULE_LICENSE("GPL");
296 MODULE_AUTHOR("Broadcom");
297 MODULE_DESCRIPTION("DDR SRPD driver for Broadcom STB chips");