Commit 4da90678 authored by Arnd Bergmann's avatar Arnd Bergmann

Merge tag 'memory-controller-drv-brcm-6.1' of...

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.orgSigned-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parents d551bdf3 a4be90ff
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: ...@@ -187,15 +187,8 @@ Required properties:
Sequencer DRAM parameters and control registers. Used for Self-Refresh Sequencer DRAM parameters and control registers. Used for Self-Refresh
Power-Down (SRPD), among other things. Power-Down (SRPD), among other things.
Required properties: See Documentation/devicetree/bindings/memory-controllers/brcm,brcmstb-memc-ddr.yaml for a
- compatible : should contain one of these full list of supported compatible strings and properties.
"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
Example: Example:
......
# 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 ...@@ -66,6 +66,15 @@ config BRCMSTB_DPFE
for the DRAM's temperature. Slower refresh rate means cooler RAM, for the DRAM's temperature. Slower refresh rate means cooler RAM,
higher refresh rate means hotter 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 config BT1_L2_CTL
bool "Baikal-T1 CM2 L2-RAM Cache Control Block" bool "Baikal-T1 CM2 L2-RAM Cache Control Block"
depends on MIPS_BAIKAL_T1 || COMPILE_TEST depends on MIPS_BAIKAL_T1 || COMPILE_TEST
......
...@@ -11,6 +11,7 @@ obj-$(CONFIG_ARM_PL172_MPMC) += pl172.o ...@@ -11,6 +11,7 @@ obj-$(CONFIG_ARM_PL172_MPMC) += pl172.o
obj-$(CONFIG_ATMEL_SDRAMC) += atmel-sdramc.o obj-$(CONFIG_ATMEL_SDRAMC) += atmel-sdramc.o
obj-$(CONFIG_ATMEL_EBI) += atmel-ebi.o obj-$(CONFIG_ATMEL_EBI) += atmel-ebi.o
obj-$(CONFIG_BRCMSTB_DPFE) += brcmstb_dpfe.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_BT1_L2_CTL) += bt1-l2-ctl.o
obj-$(CONFIG_TI_AEMIF) += ti-aemif.o obj-$(CONFIG_TI_AEMIF) += ti-aemif.o
obj-$(CONFIG_TI_EMIF) += emif.o obj-$(CONFIG_TI_EMIF) += emif.o
......
// 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");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment