Memory controller drivers for v6.1 - Broadcom
Add support for the Broadcom STB memory controller (BRCMSTB_MEMC). -----BEGIN PGP SIGNATURE----- iQJEBAABCgAuFiEE3dJiKD0RGyM7briowTdm5oaLg9cFAmMbWlIQHGtyemtAa2Vy bmVsLm9yZwAKCRDBN2bmhouD17jnD/9npugLq9QcT3et9bd8nS1IoX01Jyt/1/2X z5m9ns3kiGOpcDY48XfISg5LA99F4A63LT/04OKzL0DqAnPXQBj2Kzzq7dad+t6L iL6p+M5eYmVZg25aEaTykQ3axGEn0vKxY4HogKefu/+jDyNsXrKBtDbO7MHSmAdK FP8+3qj7bGehAU/jb4CV6SQmtJeb70nqz/vlo5o/ZjMXnDgHH0ygKaueOhEgFRp1 uwoSZohDNOhmEylzq+k4akiU7KxmobIDNd+jUxiaJDph92cHMHzzlKpWC0adEmfl +zbjRqPLQRnxbv1+4haFpnM8+Tnsxb3er+U1Lr+4pxFmaQ3xObOy3XvdUpxsNVFI bYKtMYnqnuLKZ6ciImAd64YgMcClQAsle2Dk4neCyPBobIHG4Twg9g1yh6N9dBtC EJjzTx9AaBipztzL3/3bGcXDvcuTxy/warg/A5O4UFuEPnmIPT7dwkmYX4sev5dN 3hyMAEQewRUa+KUu4xCqlixg/+Rk1s+V4GRpoFwYtXOeo7n4BSKBiYiJzdtm7J83 4SC15DIIJosrGo4bzbNFzZ2P7yeiYjqyLYzPDKu3eafe7TsrJ6jn/7WBJ279N43+ wvwhTS8q9f9TwEnnjkQ9WOrygUedJ/x7unbolNfSgWaX73SS/FH4B0pvYwbq0w01 FXy6DrEglg== =4VeH -----END PGP SIGNATURE----- gpgsig -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmMfSjYACgkQmmx57+YA GNm52Q//UlafPau8mcmYVoLzfTI2S5+PhmPW2U+n0//PMAkZvYNpb7zN7/EKppQ0 DNh4PLIO8kJBei7wkYw8Ur/fOt417JQ3sRzTGM+sdtV+zqBXY2Rd5sb3o+NrBMT8 T1YnaTkFQwVOJtxcp9Qzjnywxcd6i42uwewQNZ+YdqKCWNoNmo8G5fzdApAIrK1N nAbAVagj5zgq6W8IoIivE0ww75vV/PmiH2PhDFde96yl6oM1C+bkTTOYJv2p+trT /XVYk5jSPqKUHANj1uUvNZ8wJ+3SaXgTLu+qyN8yeip/kFjBvSyxS9VsXoDGS8V5 JZbGBmm2X5GMN06PYoboD7fQ5bOmSwiewFWDvOBLWYnXUqi1i3/F+AZAFCwoHMsM sT0IhnnXUkP8SlCtUe7U35Hqw7AipQOogYWAGCCNLxAYTYOSyqJWuffr0nWwDMQo 4/NY177friEny5O5TNlmuSMeo0Dl7TxDwUNugHdLnQSYdMjmU5MwNcBSbMlqVd/e Qat+0GvTW/T2NUEI2erE/6flX3X8km3f6UqzwOy5ytYxPAcqQ3r5K4l5aZBpQzEI tqoVvT/9W/1ptazS7uOzNAlCGZHkkWjdCLEWHsC3RoGvV5BdoZ/P9WJTzpXnGNt3 xjsFmKLa0v+H1RwOvS0Bk/t6wOm00tduHQ4gWLOHJ693Qaa7GQ0= =RC6E -----END PGP SIGNATURE----- Merge tag 'memory-controller-drv-brcm-6.1' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl into arm/drivers Memory controller drivers for v6.1 - Broadcom Add support for the Broadcom STB memory controller (BRCMSTB_MEMC). * tag 'memory-controller-drv-brcm-6.1' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl: memory: brcmstb_memc: Add Broadcom STB memory controller driver Documentation: sysfs: Document Broadcom STB memc sysfs knobs dt-bindings: memory-controller: Document Broadcom STB MEMC Link: https://lore.kernel.org/r/20220909153037.824092-3-krzysztof.kozlowski@linaro.org Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
Коммит
4da90678a6
|
@ -0,0 +1,15 @@
|
|||
What: /sys/bus/platform/devices/*/srpd
|
||||
Date: July 2022
|
||||
KernelVersion: 5.21
|
||||
Contact: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Description:
|
||||
Self Refresh Power Down (SRPD) inactivity timeout counted in
|
||||
internal DDR controller clock cycles. Possible values range
|
||||
from 0 (disable inactivity timeout) to 65535 (0xffff).
|
||||
|
||||
What: /sys/bus/platform/devices/*/frequency
|
||||
Date: July 2022
|
||||
KernelVersion: 5.21
|
||||
Contact: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Description:
|
||||
DDR PHY frequency in Hz.
|
|
@ -187,15 +187,8 @@ Required properties:
|
|||
Sequencer DRAM parameters and control registers. Used for Self-Refresh
|
||||
Power-Down (SRPD), among other things.
|
||||
|
||||
Required properties:
|
||||
- compatible : should contain one of these
|
||||
"brcm,brcmstb-memc-ddr-rev-b.2.1"
|
||||
"brcm,brcmstb-memc-ddr-rev-b.2.2"
|
||||
"brcm,brcmstb-memc-ddr-rev-b.2.3"
|
||||
"brcm,brcmstb-memc-ddr-rev-b.3.0"
|
||||
"brcm,brcmstb-memc-ddr-rev-b.3.1"
|
||||
"brcm,brcmstb-memc-ddr"
|
||||
- reg : the MEMC DDR register range
|
||||
See Documentation/devicetree/bindings/memory-controllers/brcm,brcmstb-memc-ddr.yaml for a
|
||||
full list of supported compatible strings and properties.
|
||||
|
||||
Example:
|
||||
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/memory-controllers/brcm,brcmstb-memc-ddr.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Memory controller (MEMC) for Broadcom STB
|
||||
|
||||
maintainers:
|
||||
- Florian Fainelli <f.fainelli@gmail.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- brcm,brcmstb-memc-ddr-rev-b.1.x
|
||||
- brcm,brcmstb-memc-ddr-rev-b.2.0
|
||||
- brcm,brcmstb-memc-ddr-rev-b.2.1
|
||||
- brcm,brcmstb-memc-ddr-rev-b.2.2
|
||||
- brcm,brcmstb-memc-ddr-rev-b.2.3
|
||||
- brcm,brcmstb-memc-ddr-rev-b.2.5
|
||||
- brcm,brcmstb-memc-ddr-rev-b.2.6
|
||||
- brcm,brcmstb-memc-ddr-rev-b.2.7
|
||||
- brcm,brcmstb-memc-ddr-rev-b.2.8
|
||||
- brcm,brcmstb-memc-ddr-rev-b.3.0
|
||||
- brcm,brcmstb-memc-ddr-rev-b.3.1
|
||||
- brcm,brcmstb-memc-ddr-rev-c.1.0
|
||||
- brcm,brcmstb-memc-ddr-rev-c.1.1
|
||||
- brcm,brcmstb-memc-ddr-rev-c.1.2
|
||||
- brcm,brcmstb-memc-ddr-rev-c.1.3
|
||||
- brcm,brcmstb-memc-ddr-rev-c.1.4
|
||||
- const: brcm,brcmstb-memc-ddr
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clock-frequency:
|
||||
description: DDR PHY frequency in Hz
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
memory-controller@9902000 {
|
||||
compatible = "brcm,brcmstb-memc-ddr-rev-c.1.1", "brcm,brcmstb-memc-ddr";
|
||||
reg = <0x9902000 0x600>;
|
||||
clock-frequency = <2133000000>;
|
||||
};
|
|
@ -66,6 +66,15 @@ config BRCMSTB_DPFE
|
|||
for the DRAM's temperature. Slower refresh rate means cooler RAM,
|
||||
higher refresh rate means hotter RAM.
|
||||
|
||||
config BRCMSTB_MEMC
|
||||
tristate "Broadcom STB MEMC driver"
|
||||
default ARCH_BRCMSTB
|
||||
depends on ARCH_BRCMSTB || COMPILE_TEST
|
||||
help
|
||||
This driver provides a way to configure the Broadcom STB memory
|
||||
controller and specifically control the Self Refresh Power Down
|
||||
(SRPD) inactivity timeout.
|
||||
|
||||
config BT1_L2_CTL
|
||||
bool "Baikal-T1 CM2 L2-RAM Cache Control Block"
|
||||
depends on MIPS_BAIKAL_T1 || COMPILE_TEST
|
||||
|
|
|
@ -11,6 +11,7 @@ obj-$(CONFIG_ARM_PL172_MPMC) += pl172.o
|
|||
obj-$(CONFIG_ATMEL_SDRAMC) += atmel-sdramc.o
|
||||
obj-$(CONFIG_ATMEL_EBI) += atmel-ebi.o
|
||||
obj-$(CONFIG_BRCMSTB_DPFE) += brcmstb_dpfe.o
|
||||
obj-$(CONFIG_BRCMSTB_MEMC) += brcmstb_memc.o
|
||||
obj-$(CONFIG_BT1_L2_CTL) += bt1-l2-ctl.o
|
||||
obj-$(CONFIG_TI_AEMIF) += ti-aemif.o
|
||||
obj-$(CONFIG_TI_EMIF) += emif.o
|
||||
|
|
|
@ -0,0 +1,301 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* DDR Self-Refresh Power Down (SRPD) support for Broadcom STB SoCs
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define REG_MEMC_CNTRLR_CONFIG 0x00
|
||||
#define CNTRLR_CONFIG_LPDDR4_SHIFT 5
|
||||
#define CNTRLR_CONFIG_MASK 0xf
|
||||
#define REG_MEMC_SRPD_CFG_21 0x20
|
||||
#define REG_MEMC_SRPD_CFG_20 0x34
|
||||
#define REG_MEMC_SRPD_CFG_1x 0x3c
|
||||
#define INACT_COUNT_SHIFT 0
|
||||
#define INACT_COUNT_MASK 0xffff
|
||||
#define SRPD_EN_SHIFT 16
|
||||
|
||||
struct brcmstb_memc_data {
|
||||
u32 srpd_offset;
|
||||
};
|
||||
|
||||
struct brcmstb_memc {
|
||||
struct device *dev;
|
||||
void __iomem *ddr_ctrl;
|
||||
unsigned int timeout_cycles;
|
||||
u32 frequency;
|
||||
u32 srpd_offset;
|
||||
};
|
||||
|
||||
static int brcmstb_memc_uses_lpddr4(struct brcmstb_memc *memc)
|
||||
{
|
||||
void __iomem *config = memc->ddr_ctrl + REG_MEMC_CNTRLR_CONFIG;
|
||||
u32 reg;
|
||||
|
||||
reg = readl_relaxed(config) & CNTRLR_CONFIG_MASK;
|
||||
|
||||
return reg == CNTRLR_CONFIG_LPDDR4_SHIFT;
|
||||
}
|
||||
|
||||
static int brcmstb_memc_srpd_config(struct brcmstb_memc *memc,
|
||||
unsigned int cycles)
|
||||
{
|
||||
void __iomem *cfg = memc->ddr_ctrl + memc->srpd_offset;
|
||||
u32 val;
|
||||
|
||||
/* Max timeout supported in HW */
|
||||
if (cycles > INACT_COUNT_MASK)
|
||||
return -EINVAL;
|
||||
|
||||
memc->timeout_cycles = cycles;
|
||||
|
||||
val = (cycles << INACT_COUNT_SHIFT) & INACT_COUNT_MASK;
|
||||
if (cycles)
|
||||
val |= BIT(SRPD_EN_SHIFT);
|
||||
|
||||
writel_relaxed(val, cfg);
|
||||
/* Ensure the write is committed to the controller */
|
||||
(void)readl_relaxed(cfg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t frequency_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct brcmstb_memc *memc = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", memc->frequency);
|
||||
}
|
||||
|
||||
static ssize_t srpd_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct brcmstb_memc *memc = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", memc->timeout_cycles);
|
||||
}
|
||||
|
||||
static ssize_t srpd_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct brcmstb_memc *memc = dev_get_drvdata(dev);
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Cannot change the inactivity timeout on LPDDR4 chips because the
|
||||
* dynamic tuning process will also get affected by the inactivity
|
||||
* timeout, thus making it non functional.
|
||||
*/
|
||||
if (brcmstb_memc_uses_lpddr4(memc))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ret = kstrtouint(buf, 10, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = brcmstb_memc_srpd_config(memc, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(frequency);
|
||||
static DEVICE_ATTR_RW(srpd);
|
||||
|
||||
static struct attribute *dev_attrs[] = {
|
||||
&dev_attr_frequency.attr,
|
||||
&dev_attr_srpd.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group dev_attr_group = {
|
||||
.attrs = dev_attrs,
|
||||
};
|
||||
|
||||
static const struct of_device_id brcmstb_memc_of_match[];
|
||||
|
||||
static int brcmstb_memc_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct brcmstb_memc_data *memc_data;
|
||||
const struct of_device_id *of_id;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct brcmstb_memc *memc;
|
||||
int ret;
|
||||
|
||||
memc = devm_kzalloc(dev, sizeof(*memc), GFP_KERNEL);
|
||||
if (!memc)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_set_drvdata(dev, memc);
|
||||
|
||||
of_id = of_match_device(brcmstb_memc_of_match, dev);
|
||||
memc_data = of_id->data;
|
||||
memc->srpd_offset = memc_data->srpd_offset;
|
||||
|
||||
memc->ddr_ctrl = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(memc->ddr_ctrl))
|
||||
return PTR_ERR(memc->ddr_ctrl);
|
||||
|
||||
of_property_read_u32(pdev->dev.of_node, "clock-frequency",
|
||||
&memc->frequency);
|
||||
|
||||
ret = sysfs_create_group(&dev->kobj, &dev_attr_group);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int brcmstb_memc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
sysfs_remove_group(&dev->kobj, &dev_attr_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum brcmstb_memc_hwtype {
|
||||
BRCMSTB_MEMC_V21,
|
||||
BRCMSTB_MEMC_V20,
|
||||
BRCMSTB_MEMC_V1X,
|
||||
};
|
||||
|
||||
static const struct brcmstb_memc_data brcmstb_memc_versions[] = {
|
||||
{ .srpd_offset = REG_MEMC_SRPD_CFG_21 },
|
||||
{ .srpd_offset = REG_MEMC_SRPD_CFG_20 },
|
||||
{ .srpd_offset = REG_MEMC_SRPD_CFG_1x },
|
||||
};
|
||||
|
||||
static const struct of_device_id brcmstb_memc_of_match[] = {
|
||||
{
|
||||
.compatible = "brcm,brcmstb-memc-ddr-rev-b.1.x",
|
||||
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V1X]
|
||||
},
|
||||
{
|
||||
.compatible = "brcm,brcmstb-memc-ddr-rev-b.2.0",
|
||||
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V20]
|
||||
},
|
||||
{
|
||||
.compatible = "brcm,brcmstb-memc-ddr-rev-b.2.1",
|
||||
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21]
|
||||
},
|
||||
{
|
||||
.compatible = "brcm,brcmstb-memc-ddr-rev-b.2.2",
|
||||
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21]
|
||||
},
|
||||
{
|
||||
.compatible = "brcm,brcmstb-memc-ddr-rev-b.2.3",
|
||||
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21]
|
||||
},
|
||||
{
|
||||
.compatible = "brcm,brcmstb-memc-ddr-rev-b.2.5",
|
||||
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21]
|
||||
},
|
||||
{
|
||||
.compatible = "brcm,brcmstb-memc-ddr-rev-b.2.6",
|
||||
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21]
|
||||
},
|
||||
{
|
||||
.compatible = "brcm,brcmstb-memc-ddr-rev-b.2.7",
|
||||
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21]
|
||||
},
|
||||
{
|
||||
.compatible = "brcm,brcmstb-memc-ddr-rev-b.2.8",
|
||||
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21]
|
||||
},
|
||||
{
|
||||
.compatible = "brcm,brcmstb-memc-ddr-rev-b.3.0",
|
||||
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21]
|
||||
},
|
||||
{
|
||||
.compatible = "brcm,brcmstb-memc-ddr-rev-b.3.1",
|
||||
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21]
|
||||
},
|
||||
{
|
||||
.compatible = "brcm,brcmstb-memc-ddr-rev-c.1.0",
|
||||
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21]
|
||||
},
|
||||
{
|
||||
.compatible = "brcm,brcmstb-memc-ddr-rev-c.1.1",
|
||||
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21]
|
||||
},
|
||||
{
|
||||
.compatible = "brcm,brcmstb-memc-ddr-rev-c.1.2",
|
||||
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21]
|
||||
},
|
||||
{
|
||||
.compatible = "brcm,brcmstb-memc-ddr-rev-c.1.3",
|
||||
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21]
|
||||
},
|
||||
{
|
||||
.compatible = "brcm,brcmstb-memc-ddr-rev-c.1.4",
|
||||
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21]
|
||||
},
|
||||
/* default to the original offset */
|
||||
{
|
||||
.compatible = "brcm,brcmstb-memc-ddr",
|
||||
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V1X]
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static int brcmstb_memc_suspend(struct device *dev)
|
||||
{
|
||||
struct brcmstb_memc *memc = dev_get_drvdata(dev);
|
||||
void __iomem *cfg = memc->ddr_ctrl + memc->srpd_offset;
|
||||
u32 val;
|
||||
|
||||
if (memc->timeout_cycles == 0)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Disable SRPD prior to suspending the system since that can
|
||||
* cause issues with other memory clients managed by the ARM
|
||||
* trusted firmware to access memory.
|
||||
*/
|
||||
val = readl_relaxed(cfg);
|
||||
val &= ~BIT(SRPD_EN_SHIFT);
|
||||
writel_relaxed(val, cfg);
|
||||
/* Ensure the write is committed to the controller */
|
||||
(void)readl_relaxed(cfg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int brcmstb_memc_resume(struct device *dev)
|
||||
{
|
||||
struct brcmstb_memc *memc = dev_get_drvdata(dev);
|
||||
|
||||
if (memc->timeout_cycles == 0)
|
||||
return 0;
|
||||
|
||||
return brcmstb_memc_srpd_config(memc, memc->timeout_cycles);
|
||||
}
|
||||
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(brcmstb_memc_pm_ops, brcmstb_memc_suspend,
|
||||
brcmstb_memc_resume);
|
||||
|
||||
static struct platform_driver brcmstb_memc_driver = {
|
||||
.probe = brcmstb_memc_probe,
|
||||
.remove = brcmstb_memc_remove,
|
||||
.driver = {
|
||||
.name = "brcmstb_memc",
|
||||
.of_match_table = brcmstb_memc_of_match,
|
||||
.pm = pm_ptr(&brcmstb_memc_pm_ops),
|
||||
},
|
||||
};
|
||||
module_platform_driver(brcmstb_memc_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Broadcom");
|
||||
MODULE_DESCRIPTION("DDR SRPD driver for Broadcom STB chips");
|
Загрузка…
Ссылка в новой задаче