summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/bus/brcmstb_gisb.c100
-rw-r--r--drivers/cpufreq/scmi-cpufreq.c6
-rw-r--r--drivers/dma/ti/k3-udma-glue.c2
-rw-r--r--drivers/firmware/Kconfig2
-rw-r--r--drivers/firmware/Makefile2
-rw-r--r--drivers/firmware/arm_scmi/Makefile6
-rw-r--r--drivers/firmware/arm_scmi/bus.c6
-rw-r--r--drivers/firmware/arm_scmi/clock.c9
-rw-r--r--drivers/firmware/arm_scmi/common.h26
-rw-r--r--drivers/firmware/arm_scmi/driver.c31
-rw-r--r--drivers/firmware/arm_scmi/mailbox.c4
-rw-r--r--drivers/firmware/arm_scmi/notify.c2
-rw-r--r--drivers/firmware/arm_scmi/perf.c9
-rw-r--r--drivers/firmware/arm_scmi/power.c9
-rw-r--r--drivers/firmware/arm_scmi/reset.c9
-rw-r--r--drivers/firmware/arm_scmi/sensors.c9
-rw-r--r--drivers/firmware/arm_scmi/smc.c2
-rw-r--r--drivers/firmware/arm_scmi/system.c131
-rw-r--r--drivers/firmware/imx/scu-pd.c4
-rw-r--r--drivers/firmware/smccc/smccc.c2
-rw-r--r--drivers/firmware/tegra/bpmp.c3
-rw-r--r--drivers/firmware/ti_sci.c6
-rw-r--r--drivers/gpu/drm/mediatek/mtk_drm_crtc.c2
-rw-r--r--drivers/mailbox/tegra-hsp.c9
-rw-r--r--drivers/memory/Kconfig52
-rw-r--r--drivers/memory/Makefile2
-rw-r--r--drivers/memory/brcmstb_dpfe.c46
-rw-r--r--drivers/memory/emif.c55
-rw-r--r--drivers/memory/fsl-corenet-cf.c6
-rw-r--r--drivers/memory/mtk-smi.c23
-rw-r--r--drivers/memory/omap-gpmc.c272
-rw-r--r--drivers/memory/renesas-rpc-if.c4
-rw-r--r--drivers/memory/samsung/exynos5422-dmc.c108
-rw-r--r--drivers/memory/tegra/tegra124-emc.c14
-rw-r--r--drivers/memory/tegra/tegra124.c1
-rw-r--r--drivers/memory/tegra/tegra186-emc.c10
-rw-r--r--drivers/memory/tegra/tegra210-emc-cc-r21021.c3
-rw-r--r--drivers/memory/tegra/tegra210.c2
-rw-r--r--drivers/reset/Kconfig5
-rw-r--r--drivers/reset/core.c3
-rw-r--r--drivers/reset/reset-imx7.c13
-rw-r--r--drivers/reset/reset-zynqmp.c50
-rw-r--r--drivers/reset/sti/reset-syscfg.c7
-rw-r--r--drivers/soc/amlogic/meson-ee-pwrc.c30
-rw-r--r--drivers/soc/amlogic/meson-gx-pwrc-vpu.c4
-rw-r--r--drivers/soc/bcm/Kconfig10
-rw-r--r--drivers/soc/bcm/Makefile1
-rw-r--r--drivers/soc/bcm/bcm63xx/Kconfig12
-rw-r--r--drivers/soc/bcm/bcm63xx/Makefile2
-rw-r--r--drivers/soc/bcm/bcm63xx/bcm63xx-power.c378
-rw-r--r--drivers/soc/bcm/brcmstb/biuctrl.c105
-rw-r--r--drivers/soc/fsl/dpio/qbman-portal.c2
-rw-r--r--drivers/soc/fsl/qbman/bman.c2
-rw-r--r--drivers/soc/fsl/qbman/qman_test_api.c2
-rw-r--r--drivers/soc/fsl/qe/ucc.c2
-rw-r--r--drivers/soc/imx/gpcv2.c15
-rw-r--r--drivers/soc/mediatek/mtk-cmdq-helper.c113
-rw-r--r--drivers/soc/mediatek/mtk-infracfg.c4
-rw-r--r--drivers/soc/qcom/apr.c2
-rw-r--r--drivers/soc/qcom/llcc-qcom.c7
-rw-r--r--drivers/soc/qcom/rpmh-internal.h4
-rw-r--r--drivers/soc/qcom/rpmh-rsc.c115
-rw-r--r--drivers/soc/qcom/socinfo.c5
-rw-r--r--drivers/soc/renesas/Kconfig354
-rw-r--r--drivers/soc/renesas/Makefile1
-rw-r--r--drivers/soc/renesas/r8a779a0-sysc.c448
-rw-r--r--drivers/soc/renesas/rcar-rst.c6
-rw-r--r--drivers/soc/renesas/renesas-soc.c8
-rw-r--r--drivers/soc/sunxi/sunxi_sram.c2
-rw-r--r--drivers/soc/tegra/fuse/fuse-tegra.c8
-rw-r--r--drivers/soc/tegra/fuse/fuse-tegra30.c30
-rw-r--r--drivers/soc/tegra/fuse/fuse.h10
-rw-r--r--drivers/soc/tegra/fuse/tegra-apbmisc.c26
-rw-r--r--drivers/soc/tegra/pmc.c146
-rw-r--r--drivers/soc/ti/Kconfig11
-rw-r--r--drivers/soc/ti/Makefile1
-rw-r--r--drivers/soc/ti/k3-ringacc.c33
-rw-r--r--drivers/soc/ti/k3-socinfo.c1
-rw-r--r--drivers/soc/ti/knav_dma.c16
-rw-r--r--drivers/soc/ti/knav_qmss_queue.c14
-rw-r--r--drivers/soc/ti/pruss.c354
-rw-r--r--drivers/soc/ti/ti_sci_pm_domains.c251
-rw-r--r--drivers/tee/optee/core.c7
-rw-r--r--drivers/tee/optee/optee_msg.h21
-rw-r--r--drivers/tee/optee/optee_private.h1
-rw-r--r--drivers/tee/optee/optee_smc.h3
-rw-r--r--drivers/tee/optee/rpc.c95
-rw-r--r--drivers/tee/tee_core.c89
-rw-r--r--drivers/tee/tee_shm.c32
89 files changed, 2969 insertions, 881 deletions
diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c
index ec1004c858b8..7355fa2cb439 100644
--- a/drivers/bus/brcmstb_gisb.c
+++ b/drivers/bus/brcmstb_gisb.c
@@ -30,8 +30,22 @@
#define ARB_ERR_CAP_STATUS_WRITE (1 << 1)
#define ARB_ERR_CAP_STATUS_VALID (1 << 0)
+#define ARB_BP_CAP_CLEAR (1 << 0)
+#define ARB_BP_CAP_STATUS_PROT_SHIFT 14
+#define ARB_BP_CAP_STATUS_TYPE (1 << 13)
+#define ARB_BP_CAP_STATUS_RSP_SHIFT 10
+#define ARB_BP_CAP_STATUS_MASK GENMASK(1, 0)
+#define ARB_BP_CAP_STATUS_BS_SHIFT 2
+#define ARB_BP_CAP_STATUS_WRITE (1 << 1)
+#define ARB_BP_CAP_STATUS_VALID (1 << 0)
+
enum {
ARB_TIMER,
+ ARB_BP_CAP_CLR,
+ ARB_BP_CAP_HI_ADDR,
+ ARB_BP_CAP_ADDR,
+ ARB_BP_CAP_STATUS,
+ ARB_BP_CAP_MASTER,
ARB_ERR_CAP_CLR,
ARB_ERR_CAP_HI_ADDR,
ARB_ERR_CAP_ADDR,
@@ -41,6 +55,11 @@ enum {
static const int gisb_offsets_bcm7038[] = {
[ARB_TIMER] = 0x00c,
+ [ARB_BP_CAP_CLR] = 0x014,
+ [ARB_BP_CAP_HI_ADDR] = -1,
+ [ARB_BP_CAP_ADDR] = 0x0b8,
+ [ARB_BP_CAP_STATUS] = 0x0c0,
+ [ARB_BP_CAP_MASTER] = -1,
[ARB_ERR_CAP_CLR] = 0x0c4,
[ARB_ERR_CAP_HI_ADDR] = -1,
[ARB_ERR_CAP_ADDR] = 0x0c8,
@@ -50,6 +69,11 @@ static const int gisb_offsets_bcm7038[] = {
static const int gisb_offsets_bcm7278[] = {
[ARB_TIMER] = 0x008,
+ [ARB_BP_CAP_CLR] = 0x01c,
+ [ARB_BP_CAP_HI_ADDR] = -1,
+ [ARB_BP_CAP_ADDR] = 0x220,
+ [ARB_BP_CAP_STATUS] = 0x230,
+ [ARB_BP_CAP_MASTER] = 0x234,
[ARB_ERR_CAP_CLR] = 0x7f8,
[ARB_ERR_CAP_HI_ADDR] = -1,
[ARB_ERR_CAP_ADDR] = 0x7e0,
@@ -59,6 +83,11 @@ static const int gisb_offsets_bcm7278[] = {
static const int gisb_offsets_bcm7400[] = {
[ARB_TIMER] = 0x00c,
+ [ARB_BP_CAP_CLR] = 0x014,
+ [ARB_BP_CAP_HI_ADDR] = -1,
+ [ARB_BP_CAP_ADDR] = 0x0b8,
+ [ARB_BP_CAP_STATUS] = 0x0c0,
+ [ARB_BP_CAP_MASTER] = 0x0c4,
[ARB_ERR_CAP_CLR] = 0x0c8,
[ARB_ERR_CAP_HI_ADDR] = -1,
[ARB_ERR_CAP_ADDR] = 0x0cc,
@@ -68,6 +97,11 @@ static const int gisb_offsets_bcm7400[] = {
static const int gisb_offsets_bcm7435[] = {
[ARB_TIMER] = 0x00c,
+ [ARB_BP_CAP_CLR] = 0x014,
+ [ARB_BP_CAP_HI_ADDR] = -1,
+ [ARB_BP_CAP_ADDR] = 0x158,
+ [ARB_BP_CAP_STATUS] = 0x160,
+ [ARB_BP_CAP_MASTER] = 0x164,
[ARB_ERR_CAP_CLR] = 0x168,
[ARB_ERR_CAP_HI_ADDR] = -1,
[ARB_ERR_CAP_ADDR] = 0x16c,
@@ -77,6 +111,11 @@ static const int gisb_offsets_bcm7435[] = {
static const int gisb_offsets_bcm7445[] = {
[ARB_TIMER] = 0x008,
+ [ARB_BP_CAP_CLR] = 0x010,
+ [ARB_BP_CAP_HI_ADDR] = -1,
+ [ARB_BP_CAP_ADDR] = 0x1d8,
+ [ARB_BP_CAP_STATUS] = 0x1e0,
+ [ARB_BP_CAP_MASTER] = 0x1e4,
[ARB_ERR_CAP_CLR] = 0x7e4,
[ARB_ERR_CAP_HI_ADDR] = 0x7e8,
[ARB_ERR_CAP_ADDR] = 0x7ec,
@@ -125,6 +164,16 @@ static u64 gisb_read_address(struct brcmstb_gisb_arb_device *gdev)
return value;
}
+static u64 gisb_read_bp_address(struct brcmstb_gisb_arb_device *gdev)
+{
+ u64 value;
+
+ value = gisb_read(gdev, ARB_BP_CAP_ADDR);
+ value |= (u64)gisb_read(gdev, ARB_BP_CAP_HI_ADDR) << 32;
+
+ return value;
+}
+
static void gisb_write(struct brcmstb_gisb_arb_device *gdev, u32 val, int reg)
{
int offset = gdev->gisb_offsets[reg];
@@ -210,8 +259,8 @@ static int brcmstb_gisb_arb_decode_addr(struct brcmstb_gisb_arb_device *gdev,
m_name = m_fmt;
}
- pr_crit("%s: %s at 0x%llx [%c %s], core: %s\n",
- __func__, reason, arb_addr,
+ pr_crit("GISB: %s at 0x%llx [%c %s], core: %s\n",
+ reason, arb_addr,
cap_status & ARB_ERR_CAP_STATUS_WRITE ? 'W' : 'R',
cap_status & ARB_ERR_CAP_STATUS_TIMEOUT ? "timeout" : "",
m_name);
@@ -259,6 +308,41 @@ static irqreturn_t brcmstb_gisb_tea_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static irqreturn_t brcmstb_gisb_bp_handler(int irq, void *dev_id)
+{
+ struct brcmstb_gisb_arb_device *gdev = dev_id;
+ const char *m_name;
+ u32 bp_status;
+ u64 arb_addr;
+ u32 master;
+ char m_fmt[11];
+
+ bp_status = gisb_read(gdev, ARB_BP_CAP_STATUS);
+
+ /* Invalid captured address, bail out */
+ if (!(bp_status & ARB_BP_CAP_STATUS_VALID))
+ return IRQ_HANDLED;
+
+ /* Read the address and master */
+ arb_addr = gisb_read_bp_address(gdev);
+ master = gisb_read(gdev, ARB_BP_CAP_MASTER);
+
+ m_name = brcmstb_gisb_master_to_str(gdev, master);
+ if (!m_name) {
+ snprintf(m_fmt, sizeof(m_fmt), "0x%08x", master);
+ m_name = m_fmt;
+ }
+
+ pr_crit("GISB: breakpoint at 0x%llx [%c], core: %s\n",
+ arb_addr, bp_status & ARB_BP_CAP_STATUS_WRITE ? 'W' : 'R',
+ m_name);
+
+ /* clear the GISB error */
+ gisb_write(gdev, ARB_ERR_CAP_CLEAR, ARB_ERR_CAP_CLR);
+
+ return IRQ_HANDLED;
+}
+
/*
* Dump out gisb errors on die or panic.
*/
@@ -317,13 +401,14 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev)
struct brcmstb_gisb_arb_device *gdev;
const struct of_device_id *of_id;
struct resource *r;
- int err, timeout_irq, tea_irq;
+ int err, timeout_irq, tea_irq, bp_irq;
unsigned int num_masters, j = 0;
int i, first, last;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
timeout_irq = platform_get_irq(pdev, 0);
tea_irq = platform_get_irq(pdev, 1);
+ bp_irq = platform_get_irq(pdev, 2);
gdev = devm_kzalloc(&pdev->dev, sizeof(*gdev), GFP_KERNEL);
if (!gdev)
@@ -356,6 +441,15 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev)
if (err < 0)
return err;
+ /* Interrupt is optional */
+ if (bp_irq > 0) {
+ err = devm_request_irq(&pdev->dev, bp_irq,
+ brcmstb_gisb_bp_handler, 0, pdev->name,
+ gdev);
+ if (err < 0)
+ return err;
+ }
+
/* If we do not have a valid mask, assume all masters are enabled */
if (of_property_read_u32(dn, "brcm,gisb-arb-master-mask",
&gdev->valid_mask))
diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c
index 6dd1311660b5..e855e8612a67 100644
--- a/drivers/cpufreq/scmi-cpufreq.c
+++ b/drivers/cpufreq/scmi-cpufreq.c
@@ -29,7 +29,7 @@ static const struct scmi_handle *handle;
static unsigned int scmi_cpufreq_get_rate(unsigned int cpu)
{
struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu);
- struct scmi_perf_ops *perf_ops = handle->perf_ops;
+ const struct scmi_perf_ops *perf_ops = handle->perf_ops;
struct scmi_data *priv = policy->driver_data;
unsigned long rate;
int ret;
@@ -49,7 +49,7 @@ static int
scmi_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index)
{
struct scmi_data *priv = policy->driver_data;
- struct scmi_perf_ops *perf_ops = handle->perf_ops;
+ const struct scmi_perf_ops *perf_ops = handle->perf_ops;
u64 freq = policy->freq_table[index].frequency;
return perf_ops->freq_set(handle, priv->domain_id, freq * 1000, false);
@@ -59,7 +59,7 @@ static unsigned int scmi_cpufreq_fast_switch(struct cpufreq_policy *policy,
unsigned int target_freq)
{
struct scmi_data *priv = policy->driver_data;
- struct scmi_perf_ops *perf_ops = handle->perf_ops;
+ const struct scmi_perf_ops *perf_ops = handle->perf_ops;
if (!perf_ops->freq_set(handle, priv->domain_id,
target_freq * 1000, true))
diff --git a/drivers/dma/ti/k3-udma-glue.c b/drivers/dma/ti/k3-udma-glue.c
index 42c8ad10d75e..a367584f0d7b 100644
--- a/drivers/dma/ti/k3-udma-glue.c
+++ b/drivers/dma/ti/k3-udma-glue.c
@@ -573,8 +573,8 @@ static int k3_udma_glue_cfg_rx_flow(struct k3_udma_glue_rx_channel *rx_chn,
/* request and cfg rings */
ret = k3_ringacc_request_rings_pair(rx_chn->common.ringacc,
- flow_cfg->ring_rxq_id,
flow_cfg->ring_rxfdq0_id,
+ flow_cfg->ring_rxq_id,
&flow->ringrxfdq,
&flow->ringrx);
if (ret) {
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index d78dd3c82e9d..3315e3c21586 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -7,7 +7,7 @@
menu "Firmware Drivers"
config ARM_SCMI_PROTOCOL
- bool "ARM System Control and Management Interface (SCMI) Message Protocol"
+ tristate "ARM System Control and Management Interface (SCMI) Message Protocol"
depends on ARM || ARM64 || COMPILE_TEST
depends on MAILBOX
help
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 99510be9f5ed..5e013b6a3692 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -22,7 +22,7 @@ obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o
obj-$(CONFIG_TRUSTED_FOUNDATIONS) += trusted_foundations.o
obj-$(CONFIG_TURRIS_MOX_RWTM) += turris-mox-rwtm.o
-obj-$(CONFIG_ARM_SCMI_PROTOCOL) += arm_scmi/
+obj-y += arm_scmi/
obj-y += broadcom/
obj-y += meson/
obj-$(CONFIG_GOOGLE_FIRMWARE) += google/
diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile
index 6f9cbc4aef22..bc0d54f8e861 100644
--- a/drivers/firmware/arm_scmi/Makefile
+++ b/drivers/firmware/arm_scmi/Makefile
@@ -1,9 +1,11 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-y = scmi-bus.o scmi-driver.o scmi-protocols.o scmi-transport.o
scmi-bus-y = bus.o
scmi-driver-y = driver.o notify.o
scmi-transport-y = shmem.o
scmi-transport-$(CONFIG_MAILBOX) += mailbox.o
scmi-transport-$(CONFIG_HAVE_ARM_SMCCC_DISCOVERY) += smc.o
-scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o
+scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o system.o
+scmi-module-objs := $(scmi-bus-y) $(scmi-driver-y) $(scmi-protocols-y) \
+ $(scmi-transport-y)
+obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-module.o
obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o
diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bus.c
index db55c43a2cbd..1377ec76a45d 100644
--- a/drivers/firmware/arm_scmi/bus.c
+++ b/drivers/firmware/arm_scmi/bus.c
@@ -230,7 +230,7 @@ static void scmi_devices_unregister(void)
bus_for_each_dev(&scmi_bus_type, NULL, NULL, __scmi_devices_unregister);
}
-static int __init scmi_bus_init(void)
+int __init scmi_bus_init(void)
{
int retval;
@@ -240,12 +240,10 @@ static int __init scmi_bus_init(void)
return retval;
}
-subsys_initcall(scmi_bus_init);
-static void __exit scmi_bus_exit(void)
+void __exit scmi_bus_exit(void)
{
scmi_devices_unregister();
bus_unregister(&scmi_bus_type);
ida_destroy(&scmi_bus_id);
}
-module_exit(scmi_bus_exit);
diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c
index 75e39882746e..c1cfe3ee3d55 100644
--- a/drivers/firmware/arm_scmi/clock.c
+++ b/drivers/firmware/arm_scmi/clock.c
@@ -318,7 +318,7 @@ scmi_clock_info_get(const struct scmi_handle *handle, u32 clk_id)
return clk;
}
-static struct scmi_clk_ops clk_ops = {
+static const struct scmi_clk_ops clk_ops = {
.count_get = scmi_clock_count_get,
.info_get = scmi_clock_info_get,
.rate_get = scmi_clock_rate_get,
@@ -364,9 +364,4 @@ static int scmi_clock_protocol_init(struct scmi_handle *handle)
return 0;
}
-static int __init scmi_clock_init(void)
-{
- return scmi_protocol_register(SCMI_PROTOCOL_CLOCK,
- &scmi_clock_protocol_init);
-}
-subsys_initcall(scmi_clock_init);
+DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_CLOCK, clock)
diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h
index c113e578cc6c..37fb583f1bf5 100644
--- a/drivers/firmware/arm_scmi/common.h
+++ b/drivers/firmware/arm_scmi/common.h
@@ -156,6 +156,30 @@ void scmi_setup_protocol_implemented(const struct scmi_handle *handle,
int scmi_base_protocol_init(struct scmi_handle *h);
+int __init scmi_bus_init(void);
+void __exit scmi_bus_exit(void);
+
+#define DECLARE_SCMI_REGISTER_UNREGISTER(func) \
+ int __init scmi_##func##_register(void); \
+ void __exit scmi_##func##_unregister(void)
+DECLARE_SCMI_REGISTER_UNREGISTER(clock);
+DECLARE_SCMI_REGISTER_UNREGISTER(perf);
+DECLARE_SCMI_REGISTER_UNREGISTER(power);
+DECLARE_SCMI_REGISTER_UNREGISTER(reset);
+DECLARE_SCMI_REGISTER_UNREGISTER(sensors);
+DECLARE_SCMI_REGISTER_UNREGISTER(system);
+
+#define DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(id, name) \
+int __init scmi_##name##_register(void) \
+{ \
+ return scmi_protocol_register((id), &scmi_##name##_protocol_init); \
+} \
+\
+void __exit scmi_##name##_unregister(void) \
+{ \
+ scmi_protocol_unregister((id)); \
+}
+
/* SCMI Transport */
/**
* struct scmi_chan_info - Structure representing a SCMI channel information
@@ -210,7 +234,7 @@ struct scmi_transport_ops {
* @max_msg_size: Maximum size of data per message that can be handled.
*/
struct scmi_desc {
- struct scmi_transport_ops *ops;
+ const struct scmi_transport_ops *ops;
int max_rx_timeout_ms;
int max_msg;
int max_msg_size;
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index 03ec74242c14..c5dea87edf8f 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -730,6 +730,7 @@ struct scmi_prot_devnames {
static struct scmi_prot_devnames devnames[] = {
{ SCMI_PROTOCOL_POWER, { "genpd" },},
+ { SCMI_PROTOCOL_SYSTEM, { "syspower" },},
{ SCMI_PROTOCOL_PERF, { "cpufreq" },},
{ SCMI_PROTOCOL_CLOCK, { "clocks" },},
{ SCMI_PROTOCOL_SENSOR, { "hwmon" },},
@@ -928,7 +929,35 @@ static struct platform_driver scmi_driver = {
.remove = scmi_remove,
};
-module_platform_driver(scmi_driver);
+static int __init scmi_driver_init(void)
+{
+ scmi_bus_init();
+
+ scmi_clock_register();
+ scmi_perf_register();
+ scmi_power_register();
+ scmi_reset_register();
+ scmi_sensors_register();
+ scmi_system_register();
+
+ return platform_driver_register(&scmi_driver);
+}
+subsys_initcall(scmi_driver_init);
+
+static void __exit scmi_driver_exit(void)
+{
+ scmi_bus_exit();
+
+ scmi_clock_unregister();
+ scmi_perf_unregister();
+ scmi_power_unregister();
+ scmi_reset_unregister();
+ scmi_sensors_unregister();
+ scmi_system_unregister();
+
+ platform_driver_unregister(&scmi_driver);
+}
+module_exit(scmi_driver_exit);
MODULE_ALIAS("platform: arm-scmi");
MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
diff --git a/drivers/firmware/arm_scmi/mailbox.c b/drivers/firmware/arm_scmi/mailbox.c
index 6998dc86b5ce..4626404be541 100644
--- a/drivers/firmware/arm_scmi/mailbox.c
+++ b/drivers/firmware/arm_scmi/mailbox.c
@@ -110,7 +110,7 @@ static int mailbox_chan_free(int id, void *p, void *data)
struct scmi_chan_info *cinfo = p;
struct scmi_mailbox *smbox = cinfo->transport_info;
- if (!IS_ERR(smbox->chan)) {
+ if (smbox && !IS_ERR(smbox->chan)) {
mbox_free_channel(smbox->chan);
cinfo->transport_info = NULL;
smbox->chan = NULL;
@@ -181,7 +181,7 @@ mailbox_poll_done(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer)
return shmem_poll_done(smbox->shmem, xfer);
}
-static struct scmi_transport_ops scmi_mailbox_ops = {
+static const struct scmi_transport_ops scmi_mailbox_ops = {
.chan_available = mailbox_chan_available,
.chan_setup = mailbox_chan_setup,
.chan_free = mailbox_chan_free,
diff --git a/drivers/firmware/arm_scmi/notify.c b/drivers/firmware/arm_scmi/notify.c
index 4731daaacd19..2754f9d01636 100644
--- a/drivers/firmware/arm_scmi/notify.c
+++ b/drivers/firmware/arm_scmi/notify.c
@@ -1421,7 +1421,7 @@ static void scmi_protocols_late_init(struct work_struct *work)
* notify_ops are attached to the handle so that can be accessed
* directly from an scmi_driver to register its own notifiers.
*/
-static struct scmi_notify_ops notify_ops = {
+static const struct scmi_notify_ops notify_ops = {
.register_event_notifier = scmi_register_notifier,
.unregister_event_notifier = scmi_unregister_notifier,
};
diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c
index 3e1e87012c95..ed475b40bd08 100644
--- a/drivers/firmware/arm_scmi/perf.c
+++ b/drivers/firmware/arm_scmi/perf.c
@@ -748,7 +748,7 @@ static bool scmi_fast_switch_possible(const struct scmi_handle *handle,
return dom->fc_info && dom->fc_info->level_set_addr;
}
-static struct scmi_perf_ops perf_ops = {
+static const struct scmi_perf_ops perf_ops = {
.limits_set = scmi_perf_limits_set,
.limits_get = scmi_perf_limits_get,
.level_set = scmi_perf_level_set,
@@ -890,9 +890,4 @@ static int scmi_perf_protocol_init(struct scmi_handle *handle)
return 0;
}
-static int __init scmi_perf_init(void)
-{
- return scmi_protocol_register(SCMI_PROTOCOL_PERF,
- &scmi_perf_protocol_init);
-}
-subsys_initcall(scmi_perf_init);
+DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_PERF, perf)
diff --git a/drivers/firmware/arm_scmi/power.c b/drivers/firmware/arm_scmi/power.c
index 46f213644c49..1f37258e9bee 100644
--- a/drivers/firmware/arm_scmi/power.c
+++ b/drivers/firmware/arm_scmi/power.c
@@ -184,7 +184,7 @@ static char *scmi_power_name_get(const struct scmi_handle *handle, u32 domain)
return dom->name;
}
-static struct scmi_power_ops power_ops = {
+static const struct scmi_power_ops power_ops = {
.num_domains_get = scmi_power_num_domains_get,
.name_get = scmi_power_name_get,
.state_set = scmi_power_state_set,
@@ -301,9 +301,4 @@ static int scmi_power_protocol_init(struct scmi_handle *handle)
return 0;
}
-static int __init scmi_power_init(void)
-{
- return scmi_protocol_register(SCMI_PROTOCOL_POWER,
- &scmi_power_protocol_init);
-}
-subsys_initcall(scmi_power_init);
+DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_POWER, power)
diff --git a/drivers/firmware/arm_scmi/reset.c b/drivers/firmware/arm_scmi/reset.c
index 3691bafca057..f063cfe17e02 100644
--- a/drivers/firmware/arm_scmi/reset.c
+++ b/drivers/firmware/arm_scmi/reset.c
@@ -194,7 +194,7 @@ scmi_reset_domain_deassert(const struct scmi_handle *handle, u32 domain)
return scmi_domain_reset(handle, domain, 0, ARCH_COLD_RESET);
}
-static struct scmi_reset_ops reset_ops = {
+static const struct scmi_reset_ops reset_ops = {
.num_domains_get = scmi_reset_num_domains_get,
.name_get = scmi_reset_name_get,
.latency_get = scmi_reset_latency_get,
@@ -313,9 +313,4 @@ static int scmi_reset_protocol_init(struct scmi_handle *handle)
return 0;
}
-static int __init scmi_reset_init(void)
-{
- return scmi_protocol_register(SCMI_PROTOCOL_RESET,
- &scmi_reset_protocol_init);
-}
-subsys_initcall(scmi_reset_init);
+DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_RESET, reset)
diff --git a/drivers/firmware/arm_scmi/sensors.c b/drivers/firmware/arm_scmi/sensors.c
index 1af0ad362e82..9703cf6356a0 100644
--- a/drivers/firmware/arm_scmi/sensors.c
+++ b/drivers/firmware/arm_scmi/sensors.c
@@ -275,7 +275,7 @@ static int scmi_sensor_count_get(const struct scmi_handle *handle)
return si->num_sensors;
}
-static struct scmi_sensor_ops sensor_ops = {
+static const struct scmi_sensor_ops sensor_ops = {
.count_get = scmi_sensor_count_get,
.info_get = scmi_sensor_info_get,
.trip_point_config = scmi_sensor_trip_point_config,
@@ -365,9 +365,4 @@ static int scmi_sensors_protocol_init(struct scmi_handle *handle)
return 0;
}
-static int __init scmi_sensors_init(void)
-{
- return scmi_protocol_register(SCMI_PROTOCOL_SENSOR,
- &scmi_sensors_protocol_init);
-}
-subsys_initcall(scmi_sensors_init);
+DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_SENSOR, sensors)
diff --git a/drivers/firmware/arm_scmi/smc.c b/drivers/firmware/arm_scmi/smc.c
index a1537d123e38..1a03c3ec0230 100644
--- a/drivers/firmware/arm_scmi/smc.c
+++ b/drivers/firmware/arm_scmi/smc.c
@@ -137,7 +137,7 @@ smc_poll_done(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer)
return shmem_poll_done(scmi_info->shmem, xfer);
}
-static struct scmi_transport_ops scmi_smc_ops = {
+static const struct scmi_transport_ops scmi_smc_ops = {
.chan_available = smc_chan_available,
.chan_setup = smc_chan_setup,
.chan_free = smc_chan_free,
diff --git a/drivers/firmware/arm_scmi/system.c b/drivers/firmware/arm_scmi/system.c
new file mode 100644
index 000000000000..283e12d5f24b
--- /dev/null
+++ b/drivers/firmware/arm_scmi/system.c
@@ -0,0 +1,131 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * System Control and Management Interface (SCMI) System Power Protocol
+ *
+ * Copyright (C) 2020 ARM Ltd.
+ */
+
+#define pr_fmt(fmt) "SCMI Notifications SYSTEM - " fmt
+
+#include <linux/scmi_protocol.h>
+
+#include "common.h"
+#include "notify.h"
+
+#define SCMI_SYSTEM_NUM_SOURCES 1
+
+enum scmi_system_protocol_cmd {
+ SYSTEM_POWER_STATE_NOTIFY = 0x5,
+};
+
+struct scmi_system_power_state_notify {
+ __le32 notify_enable;
+};
+
+struct scmi_system_power_state_notifier_payld {
+ __le32 agent_id;
+ __le32 flags;
+ __le32 system_state;
+};
+
+struct scmi_system_info {
+ u32 version;
+};
+
+static int scmi_system_request_notify(const struct scmi_handle *handle,
+ bool enable)
+{
+ int ret;
+ struct scmi_xfer *t;
+ struct scmi_system_power_state_notify *notify;
+
+ ret = scmi_xfer_get_init(handle, SYSTEM_POWER_STATE_NOTIFY,
+ SCMI_PROTOCOL_SYSTEM, sizeof(*notify), 0, &t);
+ if (ret)
+ return ret;
+
+ notify = t->tx.buf;
+ notify->notify_enable = enable ? cpu_to_le32(BIT(0)) : 0;
+
+ ret = scmi_do_xfer(handle, t);
+
+ scmi_xfer_put(handle, t);
+ return ret;
+}
+
+static int scmi_system_set_notify_enabled(const struct scmi_handle *handle,
+ u8 evt_id, u32 src_id, bool enable)
+{
+ int ret;
+
+ ret = scmi_system_request_notify(handle, enable);
+ if (ret)
+ pr_debug("FAIL_ENABLE - evt[%X] - ret:%d\n", evt_id, ret);
+
+ return ret;
+}
+
+static void *scmi_system_fill_custom_report(const struct scmi_handle *handle,
+ u8 evt_id, ktime_t timestamp,
+ const void *payld, size_t payld_sz,
+ void *report, u32 *src_id)
+{
+ const struct scmi_system_power_state_notifier_payld *p = payld;
+ struct scmi_system_power_state_notifier_report *r = report;
+
+ if (evt_id != SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER ||
+ sizeof(*p) != payld_sz)
+ return NULL;
+
+ r->timestamp = timestamp;
+ r->agent_id = le32_to_cpu(p->agent_id);
+ r->flags = le32_to_cpu(p->flags);
+ r->system_state = le32_to_cpu(p->system_state);
+ *src_id = 0;
+
+ return r;
+}
+
+static const struct scmi_event system_events[] = {
+ {
+ .id = SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER,
+ .max_payld_sz =
+ sizeof(struct scmi_system_power_state_notifier_payld),
+ .max_report_sz =
+ sizeof(struct scmi_system_power_state_notifier_report),
+ },
+};
+
+static const struct scmi_event_ops system_event_ops = {
+ .set_notify_enabled = scmi_system_set_notify_enabled,
+ .fill_custom_report = scmi_system_fill_custom_report,
+};
+
+static int scmi_system_protocol_init(struct scmi_handle *handle)
+{
+ u32 version;
+ struct scmi_system_info *pinfo;
+
+ scmi_version_get(handle, SCMI_PROTOCOL_SYSTEM, &version);
+
+ dev_dbg(handle->dev, "System Power Version %d.%d\n",
+ PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
+
+ pinfo = devm_kzalloc(handle->dev, sizeof(*pinfo), GFP_KERNEL);
+ if (!pinfo)
+ return -ENOMEM;
+
+ scmi_register_protocol_events(handle,
+ SCMI_PROTOCOL_SYSTEM, SCMI_PROTO_QUEUE_SZ,
+ &system_event_ops,
+ system_events,
+ ARRAY_SIZE(system_events),
+ SCMI_SYSTEM_NUM_SOURCES);
+
+ pinfo->version = version;
+ handle->system_priv = pinfo;
+
+ return 0;
+}
+
+DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_SYSTEM, system)
diff --git a/drivers/firmware/imx/scu-pd.c b/drivers/firmware/imx/scu-pd.c
index af3d6d9ead28..946eea292b52 100644
--- a/drivers/firmware/imx/scu-pd.c
+++ b/drivers/firmware/imx/scu-pd.c
@@ -46,6 +46,7 @@
#include <dt-bindings/firmware/imx/rsrc.h>
#include <linux/firmware/imx/sci.h>
+#include <linux/firmware/imx/svc/rm.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -256,6 +257,9 @@ imx_scu_add_pm_domain(struct device *dev, int idx,
struct imx_sc_pm_domain *sc_pd;
int ret;
+ if (!imx_sc_rm_is_resource_owned(pm_ipc_handle, pd_ranges->rsrc + idx))
+ return NULL;
+
sc_pd = devm_kzalloc(dev, sizeof(*sc_pd), GFP_KERNEL);
if (!sc_pd)
return ERR_PTR(-ENOMEM);
diff --git a/drivers/firmware/smccc/smccc.c b/drivers/firmware/smccc/smccc.c
index 4e80921ee212..00c88b809c0c 100644
--- a/drivers/firmware/smccc/smccc.c
+++ b/drivers/firmware/smccc/smccc.c
@@ -24,8 +24,10 @@ enum arm_smccc_conduit arm_smccc_1_1_get_conduit(void)
return smccc_conduit;
}
+EXPORT_SYMBOL_GPL(arm_smccc_1_1_get_conduit);
u32 arm_smccc_get_version(void)
{
return smccc_version;
}
+EXPORT_SYMBOL_GPL(arm_smccc_get_version);
diff --git a/drivers/firmware/tegra/bpmp.c b/drivers/firmware/tegra/bpmp.c
index 4d93d8925e14..0742a90cb844 100644
--- a/drivers/firmware/tegra/bpmp.c
+++ b/drivers/firmware/tegra/bpmp.c
@@ -856,7 +856,8 @@ static const struct tegra_bpmp_soc tegra210_soc = {
static const struct of_device_id tegra_bpmp_match[] = {
#if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) || \
- IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC)
+ IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \
+ IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC)
{ .compatible = "nvidia,tegra186-bpmp", .data = &tegra186_soc },
#endif
#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)
diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index 722af9ee53d6..896f53ec7857 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -1106,7 +1106,8 @@ static int ti_sci_cmd_get_clock(const struct ti_sci_handle *handle, u32 dev_id,
static int ti_sci_cmd_idle_clock(const struct ti_sci_handle *handle,
u32 dev_id, u32 clk_id)
{
- return ti_sci_set_clock_state(handle, dev_id, clk_id, 0,
+ return ti_sci_set_clock_state(handle, dev_id, clk_id,
+ MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE,
MSG_CLOCK_SW_STATE_UNREQ);
}
@@ -1125,7 +1126,8 @@ static int ti_sci_cmd_idle_clock(const struct ti_sci_handle *handle,
static int ti_sci_cmd_put_clock(const struct ti_sci_handle *handle,
u32 dev_id, u32 clk_id)
{
- return ti_sci_set_clock_state(handle, dev_id, clk_id, 0,
+ return ti_sci_set_clock_state(handle, dev_id, clk_id,
+ MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE,
MSG_CLOCK_SW_STATE_AUTO);
}
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index 4d29568be3f5..ac038572164d 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -481,7 +481,7 @@ static void mtk_drm_crtc_hw_config(struct mtk_drm_crtc *mtk_crtc)
mbox_flush(mtk_crtc->cmdq_client->chan, 2000);
cmdq_handle = cmdq_pkt_create(mtk_crtc->cmdq_client, PAGE_SIZE);
cmdq_pkt_clear_event(cmdq_handle, mtk_crtc->cmdq_event);
- cmdq_pkt_wfe(cmdq_handle, mtk_crtc->cmdq_event);
+ cmdq_pkt_wfe(cmdq_handle, mtk_crtc->cmdq_event, false);
mtk_crtc_ddp_config(crtc, cmdq_handle);
cmdq_pkt_finalize(cmdq_handle);
cmdq_pkt_flush_async(cmdq_handle, ddp_cmdq_cb, cmdq_handle);
diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c
index 834b35dc3b13..e07091d71986 100644
--- a/drivers/mailbox/tegra-hsp.c
+++ b/drivers/mailbox/tegra-hsp.c
@@ -13,6 +13,8 @@
#include <linux/pm.h>
#include <linux/slab.h>
+#include <soc/tegra/fuse.h>
+
#include <dt-bindings/mailbox/tegra186-hsp.h>
#include "mailbox.h"
@@ -322,7 +324,12 @@ static int tegra_hsp_doorbell_startup(struct mbox_chan *chan)
if (!ccplex)
return -ENODEV;
- if (!tegra_hsp_doorbell_can_ring(db))
+ /*
+ * On simulation platforms the BPMP hasn't had a chance yet to mark
+ * the doorbell as ringable by the CCPLEX, so we want to skip extra
+ * checks here.
+ */
+ if (tegra_is_silicon() && !tegra_hsp_doorbell_can_ring(db))
return -ENODEV;
spin_lock_irqsave(&hsp->lock, flags);
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index 2c79e95dd486..00e013b14703 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -32,8 +32,9 @@ config ARM_PL172_MPMC
config ATMEL_SDRAMC
bool "Atmel (Multi-port DDR-)SDRAM Controller"
- default y
- depends on ARCH_AT91 && OF
+ default y if ARCH_AT91
+ depends on ARCH_AT91 || COMPILE_TEST
+ depends on OF
help
This driver is for Atmel SDRAM Controller or Atmel Multi-port
DDR-SDRAM Controller available on Atmel AT91SAM9 and SAMA5 SoCs.
@@ -42,8 +43,9 @@ config ATMEL_SDRAMC
config ATMEL_EBI
bool "Atmel EBI driver"
- default y
- depends on ARCH_AT91 && OF
+ default y if ARCH_AT91
+ depends on ARCH_AT91 || COMPILE_TEST
+ depends on OF
select MFD_SYSCON
select MFD_ATMEL_SMC
help
@@ -52,6 +54,18 @@ config ATMEL_EBI
tree is used. This bus supports NANDs, external ethernet controller,
SRAMs, ATA devices, etc.
+config BRCMSTB_DPFE
+ bool "Broadcom STB DPFE driver" if COMPILE_TEST
+ default y if ARCH_BRCMSTB
+ depends on ARCH_BRCMSTB || COMPILE_TEST
+ help
+ This driver provides access to the DPFE interface of Broadcom
+ STB SoCs. The firmware running on the DCPU inside the DDR PHY can
+ provide current information about the system's RAM, for instance
+ the DRAM refresh rate. This can be used as an indirect indicator
+ for the DRAM's temperature. Slower refresh rate means cooler RAM,
+ higher refresh rate means hotter RAM.
+
config BT1_L2_CTL
bool "Baikal-T1 CM2 L2-RAM Cache Control Block"
depends on MIPS_BAIKAL_T1 || COMPILE_TEST
@@ -65,7 +79,8 @@ config BT1_L2_CTL
config TI_AEMIF
tristate "Texas Instruments AEMIF driver"
- depends on (ARCH_DAVINCI || ARCH_KEYSTONE) && OF
+ depends on ARCH_DAVINCI || ARCH_KEYSTONE || COMPILE_TEST
+ depends on OF
help
This driver is for the AEMIF module available in Texas Instruments
SoCs. AEMIF stands for Asynchronous External Memory Interface and
@@ -76,7 +91,7 @@ config TI_AEMIF
config TI_EMIF
tristate "Texas Instruments EMIF driver"
- depends on ARCH_OMAP2PLUS
+ depends on ARCH_OMAP2PLUS || COMPILE_TEST
select DDR
help
This driver is for the EMIF module available in Texas Instruments
@@ -88,7 +103,8 @@ config TI_EMIF
temperature changes
config OMAP_GPMC
- bool
+ bool "Texas Instruments OMAP SoC GPMC driver" if COMPILE_TEST
+ depends on OF_ADDRESS
select GPIOLIB
help
This driver is for the General Purpose Memory Controller (GPMC)
@@ -112,7 +128,8 @@ config OMAP_GPMC_DEBUG
config TI_EMIF_SRAM
tristate "Texas Instruments EMIF SRAM driver"
- depends on (SOC_AM33XX || SOC_AM43XX) && SRAM
+ depends on SOC_AM33XX || SOC_AM43XX || (ARM && COMPILE_TEST)
+ depends on SRAM
help
This driver is for the EMIF module available on Texas Instruments
AM33XX and AM43XX SoCs and is required for PM. Certain parts of
@@ -122,8 +139,9 @@ config TI_EMIF_SRAM
config MVEBU_DEVBUS
bool "Marvell EBU Device Bus Controller"
- default y
- depends on PLAT_ORION && OF
+ default y if PLAT_ORION
+ depends on PLAT_ORION || COMPILE_TEST
+ depends on OF
help
This driver is for the Device Bus controller available in some
Marvell EBU SoCs such as Discovery (mv78xx0), Orion (88f5xxx) and
@@ -132,7 +150,7 @@ config MVEBU_DEVBUS
config FSL_CORENET_CF
tristate "Freescale CoreNet Error Reporting"
- depends on FSL_SOC_BOOKE
+ depends on FSL_SOC_BOOKE || COMPILE_TEST
help
Say Y for reporting of errors from the Freescale CoreNet
Coherency Fabric. Errors reported include accesses to
@@ -141,7 +159,7 @@ config FSL_CORENET_CF
represents a coherency violation.
config FSL_IFC
- bool
+ bool "Freescale IFC driver" if COMPILE_TEST
depends on FSL_SOC || ARCH_LAYERSCAPE || SOC_LS1021A || COMPILE_TEST
depends on HAS_IOMEM
@@ -155,7 +173,7 @@ config JZ4780_NEMC
memory devices such as NAND and SRAM.
config MTK_SMI
- bool
+ bool "Mediatek SoC Memory Controller driver" if COMPILE_TEST
depends on ARCH_MEDIATEK || COMPILE_TEST
help
This driver is for the Memory Controller module in MediaTek SoCs,
@@ -164,7 +182,7 @@ config MTK_SMI
config DA8XX_DDRCTL
bool "Texas Instruments da8xx DDR2/mDDR driver"
- depends on ARCH_DAVINCI_DA8XX
+ depends on ARCH_DAVINCI_DA8XX || COMPILE_TEST
help
This driver is for the DDR2/mDDR Memory Controller present on
Texas Instruments da8xx SoCs. It's used to tweak various memory
@@ -172,16 +190,16 @@ config DA8XX_DDRCTL
config PL353_SMC
tristate "ARM PL35X Static Memory Controller(SMC) driver"
- default y
+ default y if ARM
depends on ARM
- depends on ARM_AMBA
+ depends on ARM_AMBA || COMPILE_TEST
help
This driver is for the ARM PL351/PL353 Static Memory
Controller(SMC) module.
config RENESAS_RPCIF
tristate "Renesas RPC-IF driver"
- depends on ARCH_RENESAS
+ depends on ARCH_RENESAS || COMPILE_TEST
select REGMAP_MMIO
help
This supports Renesas R-Car Gen3 RPC-IF which provides either SPI
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
index b4533ffff2bc..e71cf7b99641 100644
--- a/drivers/memory/Makefile
+++ b/drivers/memory/Makefile
@@ -10,7 +10,7 @@ endif
obj-$(CONFIG_ARM_PL172_MPMC) += pl172.o
obj-$(CONFIG_ATMEL_SDRAMC) += atmel-sdramc.o
obj-$(CONFIG_ATMEL_EBI) += atmel-ebi.o
-obj-$(CONFIG_ARCH_BRCMSTB) += brcmstb_dpfe.o
+obj-$(CONFIG_BRCMSTB_DPFE) += brcmstb_dpfe.o
obj-$(CONFIG_BT1_L2_CTL) += bt1-l2-ctl.o
obj-$(CONFIG_TI_AEMIF) += ti-aemif.o
obj-$(CONFIG_TI_EMIF) += emif.o
diff --git a/drivers/memory/brcmstb_dpfe.c b/drivers/memory/brcmstb_dpfe.c
index 60e8633b1175..f43ba69fbb3e 100644
--- a/drivers/memory/brcmstb_dpfe.c
+++ b/drivers/memory/brcmstb_dpfe.c
@@ -188,11 +188,6 @@ struct brcmstb_dpfe_priv {
struct mutex lock;
};
-static const char * const error_text[] = {
- "Success", "Header code incorrect", "Unknown command or argument",
- "Incorrect checksum", "Malformed command", "Timed out",
-};
-
/*
* Forward declaration of our sysfs attribute functions, so we can declare the
* attribute data structures early.
@@ -307,6 +302,20 @@ static const struct dpfe_api dpfe_api_v3 = {
},
};
+static const char *get_error_text(unsigned int i)
+{
+ static const char * const error_text[] = {
+ "Success", "Header code incorrect",
+ "Unknown command or argument", "Incorrect checksum",
+ "Malformed command", "Timed out", "Unknown error",
+ };
+
+ if (unlikely(i >= ARRAY_SIZE(error_text)))
+ i = ARRAY_SIZE(error_text) - 1;
+
+ return error_text[i];
+}
+
static bool is_dcpu_enabled(struct brcmstb_dpfe_priv *priv)
{
u32 val;
@@ -445,7 +454,7 @@ static int __send_command(struct brcmstb_dpfe_priv *priv, unsigned int cmd,
}
if (resp != 0) {
mutex_unlock(&priv->lock);
- return -ETIMEDOUT;
+ return -ffs(DCPU_RET_ERR_TIMEDOUT);
}
/* Compute checksum over the message */
@@ -647,8 +656,10 @@ static int brcmstb_dpfe_download_firmware(struct brcmstb_dpfe_priv *priv)
return (ret == -ENOENT) ? -EPROBE_DEFER : ret;
ret = __verify_firmware(&init, fw);
- if (ret)
- return -EFAULT;
+ if (ret) {
+ ret = -EFAULT;
+ goto release_fw;
+ }
__disable_dcpu(priv);
@@ -667,18 +678,20 @@ static int brcmstb_dpfe_download_firmware(struct brcmstb_dpfe_priv *priv)
ret = __write_firmware(priv->dmem, dmem, dmem_size, is_big_endian);
if (ret)
- return ret;
+ goto release_fw;
ret = __write_firmware(priv->imem, imem, imem_size, is_big_endian);
if (ret)
- return ret;
+ goto release_fw;
ret = __verify_fw_checksum(&init, priv, header, init.chksum);
if (ret)
- return ret;
+ goto release_fw;
__enable_dcpu(priv);
- return 0;
+release_fw:
+ release_firmware(fw);
+ return ret;
}
static ssize_t generic_show(unsigned int command, u32 response[],
@@ -691,7 +704,7 @@ static ssize_t generic_show(unsigned int command, u32 response[],
ret = __send_command(priv, command, response);
if (ret < 0)
- return sprintf(buf, "ERROR: %s\n", error_text[-ret]);
+ return sprintf(buf, "ERROR: %s\n", get_error_text(-ret));
return 0;
}
@@ -888,11 +901,8 @@ static int brcmstb_dpfe_probe(struct platform_device *pdev)
}
ret = brcmstb_dpfe_download_firmware(priv);
- if (ret) {
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "Couldn't download firmware -- %d\n", ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "Couldn't download firmware\n");
ret = sysfs_create_groups(&pdev->dev.kobj, priv->dpfe_api->sysfs_attrs);
if (!ret)
diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c
index bb6a71d26798..ddb1879f07d3 100644
--- a/drivers/memory/emif.c
+++ b/drivers/memory/emif.c
@@ -131,16 +131,7 @@ static int emif_regdump_show(struct seq_file *s, void *unused)
return 0;
}
-static int emif_regdump_open(struct inode *inode, struct file *file)
-{
- return single_open(file, emif_regdump_show, inode->i_private);
-}
-
-static const struct file_operations emif_regdump_fops = {
- .open = emif_regdump_open,
- .read = seq_read,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(emif_regdump);
static int emif_mr4_show(struct seq_file *s, void *unused)
{
@@ -150,48 +141,16 @@ static int emif_mr4_show(struct seq_file *s, void *unused)
return 0;
}
-static int emif_mr4_open(struct inode *inode, struct file *file)
-{
- return single_open(file, emif_mr4_show, inode->i_private);
-}
-
-static const struct file_operations emif_mr4_fops = {
- .open = emif_mr4_open,
- .read = seq_read,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(emif_mr4);
static int __init_or_module emif_debugfs_init(struct emif_data *emif)
{
- struct dentry *dentry;
- int ret;
-
- dentry = debugfs_create_dir(dev_name(emif->dev), NULL);
- if (!dentry) {
- ret = -ENOMEM;
- goto err0;
- }
- emif->debugfs_root = dentry;
-
- dentry = debugfs_create_file("regcache_dump", S_IRUGO,
- emif->debugfs_root, emif, &emif_regdump_fops);
- if (!dentry) {
- ret = -ENOMEM;
- goto err1;
- }
-
- dentry = debugfs_create_file("mr4", S_IRUGO,
- emif->debugfs_root, emif, &emif_mr4_fops);
- if (!dentry) {
- ret = -ENOMEM;
- goto err1;
- }
-
+ emif->debugfs_root = debugfs_create_dir(dev_name(emif->dev), NULL);
+ debugfs_create_file("regcache_dump", S_IRUGO, emif->debugfs_root, emif,
+ &emif_regdump_fops);
+ debugfs_create_file("mr4", S_IRUGO, emif->debugfs_root, emif,
+ &emif_mr4_fops);
return 0;
-err1:
- debugfs_remove_recursive(emif->debugfs_root);
-err0:
- return ret;
}
static void __exit emif_debugfs_exit(struct emif_data *emif)
diff --git a/drivers/memory/fsl-corenet-cf.c b/drivers/memory/fsl-corenet-cf.c
index 0b0ed72016da..0309bd5a1800 100644
--- a/drivers/memory/fsl-corenet-cf.c
+++ b/drivers/memory/fsl-corenet-cf.c
@@ -211,10 +211,8 @@ static int ccf_probe(struct platform_device *pdev)
dev_set_drvdata(&pdev->dev, ccf);
irq = platform_get_irq(pdev, 0);
- if (!irq) {
- dev_err(&pdev->dev, "%s: no irq\n", __func__);
- return -ENXIO;
- }
+ if (irq < 0)
+ return irq;
ret = devm_request_irq(&pdev->dev, irq, ccf_irq, 0, pdev->name, ccf);
if (ret) {
diff --git a/drivers/memory/mtk-smi.c b/drivers/memory/mtk-smi.c
index c21262502581..691e4c344cf8 100644
--- a/drivers/memory/mtk-smi.c
+++ b/drivers/memory/mtk-smi.c
@@ -19,6 +19,9 @@
/* mt8173 */
#define SMI_LARB_MMU_EN 0xf00
+/* mt8167 */
+#define MT8167_SMI_LARB_MMU_EN 0xfc0
+
/* mt2701 */
#define REG_SMI_SECUR_CON_BASE 0x5c0
@@ -179,6 +182,13 @@ static void mtk_smi_larb_config_port_mt8173(struct device *dev)
writel(*larb->mmu, larb->base + SMI_LARB_MMU_EN);
}
+static void mtk_smi_larb_config_port_mt8167(struct device *dev)
+{
+ struct mtk_smi_larb *larb = dev_get_drvdata(dev);
+
+ writel(*larb->mmu, larb->base + MT8167_SMI_LARB_MMU_EN);
+}
+
static void mtk_smi_larb_config_port_gen1(struct device *dev)
{
struct mtk_smi_larb *larb = dev_get_drvdata(dev);
@@ -226,6 +236,11 @@ static const struct mtk_smi_larb_gen mtk_smi_larb_mt8173 = {
.config_port = mtk_smi_larb_config_port_mt8173,
};
+static const struct mtk_smi_larb_gen mtk_smi_larb_mt8167 = {
+ /* mt8167 do not need the port in larb */
+ .config_port = mtk_smi_larb_config_port_mt8167,
+};
+
static const struct mtk_smi_larb_gen mtk_smi_larb_mt2701 = {
.port_in_larb = {
LARB0_PORT_OFFSET, LARB1_PORT_OFFSET,
@@ -255,6 +270,10 @@ static const struct mtk_smi_larb_gen mtk_smi_larb_mt8183 = {
static const struct of_device_id mtk_smi_larb_of_ids[] = {
{
+ .compatible = "mediatek,mt8167-smi-larb",
+ .data = &mtk_smi_larb_mt8167
+ },
+ {
.compatible = "mediatek,mt8173-smi-larb",
.data = &mtk_smi_larb_mt8173
},
@@ -419,6 +438,10 @@ static const struct of_device_id mtk_smi_common_of_ids[] = {
.data = &mtk_smi_common_gen2,
},
{
+ .compatible = "mediatek,mt8167-smi-common",
+ .data = &mtk_smi_common_gen2,
+ },
+ {
.compatible = "mediatek,mt2701-smi-common",
.data = &mtk_smi_common_gen1,
},
diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index ca0097664b12..cfa730cfd145 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -33,8 +33,6 @@
#include <linux/platform_data/mtd-nand-omap2.h>
-#include <asm/mach-types.h>
-
#define DEVICE_NAME "omap-gpmc"
/* GPMC register offsets */
@@ -245,7 +243,6 @@ static DEFINE_SPINLOCK(gpmc_mem_lock);
/* Define chip-selects as reserved by default until probe completes */
static unsigned int gpmc_cs_num = GPMC_CS_NUM;
static unsigned int gpmc_nr_waitpins;
-static resource_size_t phys_base, mem_size;
static unsigned int gpmc_capability;
static void __iomem *gpmc_base;
@@ -634,14 +631,6 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit, int max
return 0;
}
-#define GPMC_SET_ONE_CD_MAX(reg, st, end, max, field, cd) \
- if (set_gpmc_timing_reg(cs, (reg), (st), (end), (max), \
- t->field, (cd), #field) < 0) \
- return -1
-
-#define GPMC_SET_ONE(reg, st, end, field) \
- GPMC_SET_ONE_CD_MAX(reg, st, end, 0, field, GPMC_CD_FCLK)
-
/**
* gpmc_calc_waitmonitoring_divider - calculate proper GPMCFCLKDIVIDER based on WAITMONITORINGTIME
* WAITMONITORINGTIME will be _at least_ as long as desired, i.e.
@@ -700,12 +689,12 @@ int gpmc_calc_divider(unsigned int sync_clk)
int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t,
const struct gpmc_settings *s)
{
- int div;
+ int div, ret;
u32 l;
div = gpmc_calc_divider(t->sync_clk);
if (div < 0)
- return div;
+ return -EINVAL;
/*
* See if we need to change the divider for waitmonitoringtime.
@@ -729,57 +718,114 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t,
__func__,
t->wait_monitoring
);
- return -1;
+ return -ENXIO;
}
}
- GPMC_SET_ONE(GPMC_CS_CONFIG2, 0, 3, cs_on);
- GPMC_SET_ONE(GPMC_CS_CONFIG2, 8, 12, cs_rd_off);
- GPMC_SET_ONE(GPMC_CS_CONFIG2, 16, 20, cs_wr_off);
+ ret = 0;
+ ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG2, 0, 3, 0, t->cs_on,
+ GPMC_CD_FCLK, "cs_on");
+ ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG2, 8, 12, 0, t->cs_rd_off,
+ GPMC_CD_FCLK, "cs_rd_off");
+ ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG2, 16, 20, 0, t->cs_wr_off,
+ GPMC_CD_FCLK, "cs_wr_off");
+ if (ret)
+ return -ENXIO;
+
+ ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG3, 0, 3, 0, t->adv_on,
+ GPMC_CD_FCLK, "adv_on");
+ ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG3, 8, 12, 0, t->adv_rd_off,
+ GPMC_CD_FCLK, "adv_rd_off");
+ ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG3, 16, 20, 0, t->adv_wr_off,
+ GPMC_CD_FCLK, "adv_wr_off");
+ if (ret)
+ return -ENXIO;
- GPMC_SET_ONE(GPMC_CS_CONFIG3, 0, 3, adv_on);
- GPMC_SET_ONE(GPMC_CS_CONFIG3, 8, 12, adv_rd_off);
- GPMC_SET_ONE(GPMC_CS_CONFIG3, 16, 20, adv_wr_off);
if (gpmc_capability & GPMC_HAS_MUX_AAD) {
- GPMC_SET_ONE(GPMC_CS_CONFIG3, 4, 6, adv_aad_mux_on);
- GPMC_SET_ONE(GPMC_CS_CONFIG3, 24, 26, adv_aad_mux_rd_off);
- GPMC_SET_ONE(GPMC_CS_CONFIG3, 28, 30, adv_aad_mux_wr_off);
+ ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG3, 4, 6, 0,
+ t->adv_aad_mux_on, GPMC_CD_FCLK,
+ "adv_aad_mux_on");
+ ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG3, 24, 26, 0,
+ t->adv_aad_mux_rd_off, GPMC_CD_FCLK,
+ "adv_aad_mux_rd_off");
+ ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG3, 28, 30, 0,
+ t->adv_aad_mux_wr_off, GPMC_CD_FCLK,
+ "adv_aad_mux_wr_off");
+ if (ret)
+ return -ENXIO;
}
- GPMC_SET_ONE(GPMC_CS_CONFIG4, 0, 3, oe_on);
- GPMC_SET_ONE(GPMC_CS_CONFIG4, 8, 12, oe_off);
+ ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG4, 0, 3, 0, t->oe_on,
+ GPMC_CD_FCLK, "oe_on");
+ ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG4, 8, 12, 0, t->oe_off,
+ GPMC_CD_FCLK, "oe_off");
if (gpmc_capability & GPMC_HAS_MUX_AAD) {
- GPMC_SET_ONE(GPMC_CS_CONFIG4, 4, 6, oe_aad_mux_on);
- GPMC_SET_ONE(GPMC_CS_CONFIG4, 13, 15, oe_aad_mux_off);
+ ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG4, 4, 6, 0,
+ t->oe_aad_mux_on, GPMC_CD_FCLK,
+ "oe_aad_mux_on");
+ ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG4, 13, 15, 0,
+ t->oe_aad_mux_off, GPMC_CD_FCLK,
+ "oe_aad_mux_off");
+ }
+ ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG4, 16, 19, 0, t->we_on,
+ GPMC_CD_FCLK, "we_on");
+ ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG4, 24, 28, 0, t->we_off,
+ GPMC_CD_FCLK, "we_off");
+ if (ret)
+ return -ENXIO;
+
+ ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG5, 0, 4, 0, t->rd_cycle,
+ GPMC_CD_FCLK, "rd_cycle");
+ ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG5, 8, 12, 0, t->wr_cycle,
+ GPMC_CD_FCLK, "wr_cycle");
+ ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG5, 16, 20, 0, t->access,
+ GPMC_CD_FCLK, "access");
+ ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG5, 24, 27, 0,
+ t->page_burst_access, GPMC_CD_FCLK,
+ "page_burst_access");
+ if (ret)
+ return -ENXIO;
+
+ ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG6, 0, 3, 0,
+ t->bus_turnaround, GPMC_CD_FCLK,
+ "bus_turnaround");
+ ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG6, 8, 11, 0,
+ t->cycle2cycle_delay, GPMC_CD_FCLK,
+ "cycle2cycle_delay");
+ if (ret)
+ return -ENXIO;
+
+ if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS) {
+ ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG6, 16, 19, 0,
+ t->wr_data_mux_bus, GPMC_CD_FCLK,
+ "wr_data_mux_bus");
+ if (ret)
+ return -ENXIO;
+ }
+ if (gpmc_capability & GPMC_HAS_WR_ACCESS) {
+ ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG6, 24, 28, 0,
+ t->wr_access, GPMC_CD_FCLK,
+ "wr_access");
+ if (ret)
+ return -ENXIO;
}
- GPMC_SET_ONE(GPMC_CS_CONFIG4, 16, 19, we_on);
- GPMC_SET_ONE(GPMC_CS_CONFIG4, 24, 28, we_off);
-
- GPMC_SET_ONE(GPMC_CS_CONFIG5, 0, 4, rd_cycle);
- GPMC_SET_ONE(GPMC_CS_CONFIG5, 8, 12, wr_cycle);
- GPMC_SET_ONE(GPMC_CS_CONFIG5, 16, 20, access);
-
- GPMC_SET_ONE(GPMC_CS_CONFIG5, 24, 27, page_burst_access);
-
- GPMC_SET_ONE(GPMC_CS_CONFIG6, 0, 3, bus_turnaround);
- GPMC_SET_ONE(GPMC_CS_CONFIG6, 8, 11, cycle2cycle_delay);
-
- if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
- GPMC_SET_ONE(GPMC_CS_CONFIG6, 16, 19, wr_data_mux_bus);
- if (gpmc_capability & GPMC_HAS_WR_ACCESS)
- GPMC_SET_ONE(GPMC_CS_CONFIG6, 24, 28, wr_access);
l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
l &= ~0x03;
l |= (div - 1);
gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l);
- GPMC_SET_ONE_CD_MAX(GPMC_CS_CONFIG1, 18, 19,
- GPMC_CONFIG1_WAITMONITORINGTIME_MAX,
- wait_monitoring, GPMC_CD_CLK);
- GPMC_SET_ONE_CD_MAX(GPMC_CS_CONFIG1, 25, 26,
- GPMC_CONFIG1_CLKACTIVATIONTIME_MAX,
- clk_activation, GPMC_CD_FCLK);
+ ret = 0;
+ ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG1, 18, 19,
+ GPMC_CONFIG1_WAITMONITORINGTIME_MAX,
+ t->wait_monitoring, GPMC_CD_CLK,
+ "wait_monitoring");
+ ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG1, 25, 26,
+ GPMC_CONFIG1_CLKACTIVATIONTIME_MAX,
+ t->clk_activation, GPMC_CD_FCLK,
+ "clk_activation");
+ if (ret)
+ return -ENXIO;
#ifdef CONFIG_OMAP_GPMC_DEBUG
pr_info("GPMC CS%d CLK period is %lu ns (div %d)\n",
@@ -870,20 +916,6 @@ static bool gpmc_cs_reserved(int cs)
return gpmc->flags & GPMC_CS_RESERVED;
}
-static void gpmc_cs_set_name(int cs, const char *name)
-{
- struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
-
- gpmc->name = name;
-}
-
-static const char *gpmc_cs_get_name(int cs)
-{
- struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
-
- return gpmc->name;
-}
-
static unsigned long gpmc_mem_align(unsigned long size)
{
int order;
@@ -929,56 +961,13 @@ static int gpmc_cs_delete_mem(int cs)
return r;
}
-/**
- * gpmc_cs_remap - remaps a chip-select physical base address
- * @cs: chip-select to remap
- * @base: physical base address to re-map chip-select to
- *
- * Re-maps a chip-select to a new physical base address specified by
- * "base". Returns 0 on success and appropriate negative error code
- * on failure.
- */
-static int gpmc_cs_remap(int cs, u32 base)
-{
- int ret;
- u32 old_base, size;
-
- if (cs > gpmc_cs_num) {
- pr_err("%s: requested chip-select is disabled\n", __func__);
- return -ENODEV;
- }
-
- /*
- * Make sure we ignore any device offsets from the GPMC partition
- * allocated for the chip select and that the new base confirms
- * to the GPMC 16MB minimum granularity.
- */
- base &= ~(SZ_16M - 1);
-
- gpmc_cs_get_memconf(cs, &old_base, &size);
- if (base == old_base)
- return 0;
-
- ret = gpmc_cs_delete_mem(cs);
- if (ret < 0)
- return ret;
-
- ret = gpmc_cs_insert_mem(cs, base, size);
- if (ret < 0)
- return ret;
-
- ret = gpmc_cs_set_memconf(cs, base, size);
-
- return ret;
-}
-
int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
{
struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
struct resource *res = &gpmc->mem;
int r = -1;
- if (cs > gpmc_cs_num) {
+ if (cs >= gpmc_cs_num) {
pr_err("%s: requested chip-select is disabled\n", __func__);
return -ENODEV;
}
@@ -1025,8 +1014,7 @@ void gpmc_cs_free(int cs)
spin_lock(&gpmc_mem_lock);
if (cs >= gpmc_cs_num || cs < 0 || !gpmc_cs_reserved(cs)) {
- printk(KERN_ERR "Trying to free non-reserved GPMC CS%d\n", cs);
- BUG();
+ WARN(1, "Trying to free non-reserved GPMC CS%d\n", cs);
spin_unlock(&gpmc_mem_lock);
return;
}
@@ -1896,6 +1884,63 @@ static const struct of_device_id gpmc_dt_ids[] = {
{ }
};
+static void gpmc_cs_set_name(int cs, const char *name)
+{
+ struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
+
+ gpmc->name = name;
+}
+
+static const char *gpmc_cs_get_name(int cs)
+{
+ struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
+
+ return gpmc->name;
+}
+
+/**
+ * gpmc_cs_remap - remaps a chip-select physical base address
+ * @cs: chip-select to remap
+ * @base: physical base address to re-map chip-select to
+ *
+ * Re-maps a chip-select to a new physical base address specified by
+ * "base". Returns 0 on success and appropriate negative error code
+ * on failure.
+ */
+static int gpmc_cs_remap(int cs, u32 base)
+{
+ int ret;
+ u32 old_base, size;
+
+ if (cs >= gpmc_cs_num) {
+ pr_err("%s: requested chip-select is disabled\n", __func__);
+ return -ENODEV;
+ }
+
+ /*
+ * Make sure we ignore any device offsets from the GPMC partition
+ * allocated for the chip select and that the new base confirms
+ * to the GPMC 16MB minimum granularity.
+ */
+ base &= ~(SZ_16M - 1);
+
+ gpmc_cs_get_memconf(cs, &old_base, &size);
+ if (base == old_base)
+ return 0;
+
+ ret = gpmc_cs_delete_mem(cs);
+ if (ret < 0)
+ return ret;
+
+ ret = gpmc_cs_insert_mem(cs, base, size);
+ if (ret < 0)
+ return ret;
+
+ ret = gpmc_cs_set_memconf(cs, base, size);
+
+ return ret;
+}
+
/**
* gpmc_read_settings_dt - read gpmc settings from device-tree
* @np: pointer to device-tree node for a gpmc child device
@@ -2265,6 +2310,10 @@ static void gpmc_probe_dt_children(struct platform_device *pdev)
}
}
#else
+void gpmc_read_settings_dt(struct device_node *np, struct gpmc_settings *p)
+{
+ memset(p, 0, sizeof(*p));
+}
static int gpmc_probe_dt(struct platform_device *pdev)
{
return 0;
@@ -2347,12 +2396,9 @@ static int gpmc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, gpmc);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL)
+ if (!res)
return -ENOENT;
- phys_base = res->start;
- mem_size = resource_size(res);
-
gpmc_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(gpmc_base))
return PTR_ERR(gpmc_base);
diff --git a/drivers/memory/renesas-rpc-if.c b/drivers/memory/renesas-rpc-if.c
index 88f51ec8f1d1..f2a33a1af836 100644
--- a/drivers/memory/renesas-rpc-if.c
+++ b/drivers/memory/renesas-rpc-if.c
@@ -199,10 +199,8 @@ int rpcif_sw_init(struct rpcif *rpc, struct device *dev)
rpc->dirmap = NULL;
rpc->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
- if (IS_ERR(rpc->rstc))
- return PTR_ERR(rpc->rstc);
- return 0;
+ return PTR_ERR_OR_ZERO(rpc->rstc);
}
EXPORT_SYMBOL(rpcif_sw_init);
diff --git a/drivers/memory/samsung/exynos5422-dmc.c b/drivers/memory/samsung/exynos5422-dmc.c
index 714d1f6f077c..c5ee4121a4d2 100644
--- a/drivers/memory/samsung/exynos5422-dmc.c
+++ b/drivers/memory/samsung/exynos5422-dmc.c
@@ -98,6 +98,8 @@ MODULE_PARM_DESC(irqmode, "Enable IRQ mode (0=off [default], 1=on)");
/**
* struct dmc_opp_table - Operating level desciption
+ * @freq_hz: target frequency in Hz
+ * @volt_uv: target voltage in uV
*
* Covers frequency and voltage settings of the DMC operating mode.
*/
@@ -108,6 +110,41 @@ struct dmc_opp_table {
/**
* struct exynos5_dmc - main structure describing DMC device
+ * @dev: DMC device
+ * @df: devfreq device structure returned by devfreq framework
+ * @gov_data: configuration of devfreq governor
+ * @base_drexi0: DREX0 registers mapping
+ * @base_drexi1: DREX1 registers mapping
+ * @clk_regmap: regmap for clock controller registers
+ * @lock: protects curr_rate and frequency/voltage setting section
+ * @curr_rate: current frequency
+ * @curr_volt: current voltage
+ * @opp: OPP table
+ * @opp_count: number of 'opp' elements
+ * @timings_arr_size: number of 'timings' elements
+ * @timing_row: values for timing row register, for each OPP
+ * @timing_data: values for timing data register, for each OPP
+ * @timing_power: balues for timing power register, for each OPP
+ * @timings: DDR memory timings, from device tree
+ * @min_tck: DDR memory minimum timing values, from device tree
+ * @bypass_timing_row: value for timing row register for bypass timings
+ * @bypass_timing_data: value for timing data register for bypass timings
+ * @bypass_timing_power: value for timing power register for bypass
+ * timings
+ * @vdd_mif: Memory interface regulator
+ * @fout_spll: clock: SPLL
+ * @fout_bpll: clock: BPLL
+ * @mout_spll: clock: mux SPLL
+ * @mout_bpll: clock: mux BPLL
+ * @mout_mclk_cdrex: clock: mux mclk_cdrex
+ * @mout_mx_mspll_ccore: clock: mux mx_mspll_ccore
+ * @counter: devfreq events
+ * @num_counters: number of 'counter' elements
+ * @last_overflow_ts: time (in ns) of last overflow of each DREX
+ * @load: utilization in percents
+ * @total: total time between devfreq events
+ * @in_irq_mode: whether running in interrupt mode (true)
+ * or polling (false)
*
* The main structure for the Dynamic Memory Controller which covers clocks,
* memory regions, HW information, parameters and current operating mode.
@@ -119,12 +156,11 @@ struct exynos5_dmc {
void __iomem *base_drexi0;
void __iomem *base_drexi1;
struct regmap *clk_regmap;
+ /* Protects curr_rate and frequency/voltage setting section */
struct mutex lock;
unsigned long curr_rate;
unsigned long curr_volt;
- unsigned long bypass_rate;
struct dmc_opp_table *opp;
- struct dmc_opp_table opp_bypass;
int opp_count;
u32 timings_arr_size;
u32 *timing_row;
@@ -142,8 +178,6 @@ struct exynos5_dmc {
struct clk *mout_bpll;
struct clk *mout_mclk_cdrex;
struct clk *mout_mx_mspll_ccore;
- struct clk *mx_mspll_ccore_phy;
- struct clk *mout_mx_mspll_ccore_phy;
struct devfreq_event_dev **counter;
int num_counters;
u64 last_overflow_ts[2];
@@ -169,7 +203,7 @@ struct timing_reg {
unsigned int val;
};
-static const struct timing_reg timing_row[] = {
+static const struct timing_reg timing_row_reg_fields[] = {
TIMING_FIELD("tRFC", 24, 31),
TIMING_FIELD("tRRD", 20, 23),
TIMING_FIELD("tRP", 16, 19),
@@ -178,7 +212,7 @@ static const struct timing_reg timing_row[] = {
TIMING_FIELD("tRAS", 0, 5),
};
-static const struct timing_reg timing_data[] = {
+static const struct timing_reg timing_data_reg_fields[] = {
TIMING_FIELD("tWTR", 28, 31),
TIMING_FIELD("tWR", 24, 27),
TIMING_FIELD("tRTP", 20, 23),
@@ -189,7 +223,7 @@ static const struct timing_reg timing_data[] = {
TIMING_FIELD("RL", 0, 3),
};
-static const struct timing_reg timing_power[] = {
+static const struct timing_reg timing_power_reg_fields[] = {
TIMING_FIELD("tFAW", 26, 31),
TIMING_FIELD("tXSR", 16, 25),
TIMING_FIELD("tXP", 8, 15),
@@ -197,8 +231,9 @@ static const struct timing_reg timing_power[] = {
TIMING_FIELD("tMRD", 0, 3),
};
-#define TIMING_COUNT (ARRAY_SIZE(timing_row) + ARRAY_SIZE(timing_data) + \
- ARRAY_SIZE(timing_power))
+#define TIMING_COUNT (ARRAY_SIZE(timing_row_reg_fields) + \
+ ARRAY_SIZE(timing_data_reg_fields) + \
+ ARRAY_SIZE(timing_power_reg_fields))
static int exynos5_counters_set_event(struct exynos5_dmc *dmc)
{
@@ -346,7 +381,6 @@ err_opp:
/**
* exynos5_set_bypass_dram_timings() - Low-level changes of the DRAM timings
* @dmc: device for which the new settings is going to be applied
- * @param: DRAM parameters which passes timing data
*
* Low-level function for changing timings for DRAM memory clocking from
* 'bypass' clock source (fixed frequency @400MHz).
@@ -453,9 +487,6 @@ static int exynos5_dmc_align_bypass_voltage(struct exynos5_dmc *dmc,
unsigned long target_volt)
{
int ret = 0;
- unsigned long bypass_volt = dmc->opp_bypass.volt_uv;
-
- target_volt = max(bypass_volt, target_volt);
if (dmc->curr_volt >= target_volt)
return 0;
@@ -617,6 +648,7 @@ disable_clocks:
* requested
* @target_volt: returned voltage which corresponds to the returned
* frequency
+ * @flags: devfreq flags provided for this frequency change request
*
* Function gets requested frequency and checks OPP framework for needed
* frequency and voltage. It populates the values 'target_rate' and
@@ -908,7 +940,10 @@ static int exynos5_dmc_get_status(struct device *dev,
int ret;
if (dmc->in_irq_mode) {
+ mutex_lock(&dmc->lock);
stat->current_frequency = dmc->curr_rate;
+ mutex_unlock(&dmc->lock);
+
stat->busy_time = dmc->load;
stat->total_time = dmc->total;
} else {
@@ -950,7 +985,7 @@ static int exynos5_dmc_get_cur_freq(struct device *dev, unsigned long *freq)
return 0;
}
-/**
+/*
* exynos5_dmc_df_profile - Devfreq governor's profile structure
*
* It provides to the devfreq framework needed functions and polling period.
@@ -993,7 +1028,9 @@ exynos5_dmc_align_init_freq(struct exynos5_dmc *dmc,
/**
* create_timings_aligned() - Create register values and align with standard
* @dmc: device for which the frequency is going to be set
- * @idx: speed bin in the OPP table
+ * @reg_timing_row: array to fill with values for timing row register
+ * @reg_timing_data: array to fill with values for timing data register
+ * @reg_timing_power: array to fill with values for timing power register
* @clk_period_ps: the period of the clock, known as tCK
*
* The function calculates timings and creates a register value ready for
@@ -1018,117 +1055,117 @@ static int create_timings_aligned(struct exynos5_dmc *dmc, u32 *reg_timing_row,
val = dmc->timings->tRFC / clk_period_ps;
val += dmc->timings->tRFC % clk_period_ps ? 1 : 0;
val = max(val, dmc->min_tck->tRFC);
- reg = &timing_row[0];
+ reg = &timing_row_reg_fields[0];
*reg_timing_row |= TIMING_VAL2REG(reg, val);
val = dmc->timings->tRRD / clk_period_ps;
val += dmc->timings->tRRD % clk_period_ps ? 1 : 0;
val = max(val, dmc->min_tck->tRRD);
- reg = &timing_row[1];
+ reg = &timing_row_reg_fields[1];
*reg_timing_row |= TIMING_VAL2REG(reg, val);
val = dmc->timings->tRPab / clk_period_ps;
val += dmc->timings->tRPab % clk_period_ps ? 1 : 0;
val = max(val, dmc->min_tck->tRPab);
- reg = &timing_row[2];
+ reg = &timing_row_reg_fields[2];
*reg_timing_row |= TIMING_VAL2REG(reg, val);
val = dmc->timings->tRCD / clk_period_ps;
val += dmc->timings->tRCD % clk_period_ps ? 1 : 0;
val = max(val, dmc->min_tck->tRCD);
- reg = &timing_row[3];
+ reg = &timing_row_reg_fields[3];
*reg_timing_row |= TIMING_VAL2REG(reg, val);
val = dmc->timings->tRC / clk_period_ps;
val += dmc->timings->tRC % clk_period_ps ? 1 : 0;
val = max(val, dmc->min_tck->tRC);
- reg = &timing_row[4];
+ reg = &timing_row_reg_fields[4];
*reg_timing_row |= TIMING_VAL2REG(reg, val);
val = dmc->timings->tRAS / clk_period_ps;
val += dmc->timings->tRAS % clk_period_ps ? 1 : 0;
val = max(val, dmc->min_tck->tRAS);
- reg = &timing_row[5];
+ reg = &timing_row_reg_fields[5];
*reg_timing_row |= TIMING_VAL2REG(reg, val);
/* data related timings */
val = dmc->timings->tWTR / clk_period_ps;
val += dmc->timings->tWTR % clk_period_ps ? 1 : 0;
val = max(val, dmc->min_tck->tWTR);
- reg = &timing_data[0];
+ reg = &timing_data_reg_fields[0];
*reg_timing_data |= TIMING_VAL2REG(reg, val);
val = dmc->timings->tWR / clk_period_ps;
val += dmc->timings->tWR % clk_period_ps ? 1 : 0;
val = max(val, dmc->min_tck->tWR);
- reg = &timing_data[1];
+ reg = &timing_data_reg_fields[1];
*reg_timing_data |= TIMING_VAL2REG(reg, val);
val = dmc->timings->tRTP / clk_period_ps;
val += dmc->timings->tRTP % clk_period_ps ? 1 : 0;
val = max(val, dmc->min_tck->tRTP);
- reg = &timing_data[2];
+ reg = &timing_data_reg_fields[2];
*reg_timing_data |= TIMING_VAL2REG(reg, val);
val = dmc->timings->tW2W_C2C / clk_period_ps;
val += dmc->timings->tW2W_C2C % clk_period_ps ? 1 : 0;
val = max(val, dmc->min_tck->tW2W_C2C);
- reg = &timing_data[3];
+ reg = &timing_data_reg_fields[3];
*reg_timing_data |= TIMING_VAL2REG(reg, val);
val = dmc->timings->tR2R_C2C / clk_period_ps;
val += dmc->timings->tR2R_C2C % clk_period_ps ? 1 : 0;
val = max(val, dmc->min_tck->tR2R_C2C);
- reg = &timing_data[4];
+ reg = &timing_data_reg_fields[4];
*reg_timing_data |= TIMING_VAL2REG(reg, val);
val = dmc->timings->tWL / clk_period_ps;
val += dmc->timings->tWL % clk_period_ps ? 1 : 0;
val = max(val, dmc->min_tck->tWL);
- reg = &timing_data[5];
+ reg = &timing_data_reg_fields[5];
*reg_timing_data |= TIMING_VAL2REG(reg, val);
val = dmc->timings->tDQSCK / clk_period_ps;
val += dmc->timings->tDQSCK % clk_period_ps ? 1 : 0;
val = max(val, dmc->min_tck->tDQSCK);
- reg = &timing_data[6];
+ reg = &timing_data_reg_fields[6];
*reg_timing_data |= TIMING_VAL2REG(reg, val);
val = dmc->timings->tRL / clk_period_ps;
val += dmc->timings->tRL % clk_period_ps ? 1 : 0;
val = max(val, dmc->min_tck->tRL);
- reg = &timing_data[7];
+ reg = &timing_data_reg_fields[7];
*reg_timing_data |= TIMING_VAL2REG(reg, val);
/* power related timings */
val = dmc->timings->tFAW / clk_period_ps;
val += dmc->timings->tFAW % clk_period_ps ? 1 : 0;
val = max(val, dmc->min_tck->tFAW);
- reg = &timing_power[0];
+ reg = &timing_power_reg_fields[0];
*reg_timing_power |= TIMING_VAL2REG(reg, val);
val = dmc->timings->tXSR / clk_period_ps;
val += dmc->timings->tXSR % clk_period_ps ? 1 : 0;
val = max(val, dmc->min_tck->tXSR);
- reg = &timing_power[1];
+ reg = &timing_power_reg_fields[1];
*reg_timing_power |= TIMING_VAL2REG(reg, val);
val = dmc->timings->tXP / clk_period_ps;
val += dmc->timings->tXP % clk_period_ps ? 1 : 0;
val = max(val, dmc->min_tck->tXP);
- reg = &timing_power[2];
+ reg = &timing_power_reg_fields[2];
*reg_timing_power |= TIMING_VAL2REG(reg, val);
val = dmc->timings->tCKE / clk_period_ps;
val += dmc->timings->tCKE % clk_period_ps ? 1 : 0;
val = max(val, dmc->min_tck->tCKE);
- reg = &timing_power[3];
+ reg = &timing_power_reg_fields[3];
*reg_timing_power |= TIMING_VAL2REG(reg, val);
val = dmc->timings->tMRD / clk_period_ps;
val += dmc->timings->tMRD % clk_period_ps ? 1 : 0;
val = max(val, dmc->min_tck->tMRD);
- reg = &timing_power[4];
+ reg = &timing_power_reg_fields[4];
*reg_timing_power |= TIMING_VAL2REG(reg, val);
return 0;
@@ -1263,8 +1300,6 @@ static int exynos5_dmc_init_clks(struct exynos5_dmc *dmc)
clk_set_parent(dmc->mout_mx_mspll_ccore, dmc->mout_spll);
- dmc->bypass_rate = clk_get_rate(dmc->mout_mx_mspll_ccore);
-
clk_prepare_enable(dmc->fout_bpll);
clk_prepare_enable(dmc->mout_bpll);
@@ -1332,7 +1367,6 @@ static int exynos5_performance_counters_init(struct exynos5_dmc *dmc)
/**
* exynos5_dmc_set_pause_on_switching() - Controls a pause feature in DMC
* @dmc: device which is used for changing this feature
- * @set: a boolean state passing enable/disable request
*
* There is a need of pausing DREX DMC when divider or MUX in clock tree
* changes its configuration. In such situation access to the memory is blocked
diff --git a/drivers/memory/tegra/tegra124-emc.c b/drivers/memory/tegra/tegra124-emc.c
index ba5cb1f4dfc2..76ace42a688a 100644
--- a/drivers/memory/tegra/tegra124-emc.c
+++ b/drivers/memory/tegra/tegra124-emc.c
@@ -1060,19 +1060,7 @@ static int tegra_emc_debug_available_rates_show(struct seq_file *s,
return 0;
}
-static int tegra_emc_debug_available_rates_open(struct inode *inode,
- struct file *file)
-{
- return single_open(file, tegra_emc_debug_available_rates_show,
- inode->i_private);
-}
-
-static const struct file_operations tegra_emc_debug_available_rates_fops = {
- .open = tegra_emc_debug_available_rates_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(tegra_emc_debug_available_rates);
static int tegra_emc_debug_min_rate_get(void *data, u64 *rate)
{
diff --git a/drivers/memory/tegra/tegra124.c b/drivers/memory/tegra/tegra124.c
index 493b5dc3a4b3..0cede24479bf 100644
--- a/drivers/memory/tegra/tegra124.c
+++ b/drivers/memory/tegra/tegra124.c
@@ -957,7 +957,6 @@ static const struct tegra_smmu_swgroup tegra124_swgroups[] = {
static const unsigned int tegra124_group_drm[] = {
TEGRA_SWGROUP_DC,
TEGRA_SWGROUP_DCB,
- TEGRA_SWGROUP_GPU,
TEGRA_SWGROUP_VIC,
};
diff --git a/drivers/memory/tegra/tegra186-emc.c b/drivers/memory/tegra/tegra186-emc.c
index 8478f59db432..fa8af17b0e2d 100644
--- a/drivers/memory/tegra/tegra186-emc.c
+++ b/drivers/memory/tegra/tegra186-emc.c
@@ -172,14 +172,8 @@ static int tegra186_emc_probe(struct platform_device *pdev)
return -ENOMEM;
emc->bpmp = tegra_bpmp_get(&pdev->dev);
- if (IS_ERR(emc->bpmp)) {
- err = PTR_ERR(emc->bpmp);
-
- if (err != -EPROBE_DEFER)
- dev_err(&pdev->dev, "failed to get BPMP: %d\n", err);
-
- return err;
- }
+ if (IS_ERR(emc->bpmp))
+ return dev_err_probe(&pdev->dev, PTR_ERR(emc->bpmp), "failed to get BPMP\n");
emc->clk = devm_clk_get(&pdev->dev, "emc");
if (IS_ERR(emc->clk)) {
diff --git a/drivers/memory/tegra/tegra210-emc-cc-r21021.c b/drivers/memory/tegra/tegra210-emc-cc-r21021.c
index ff55a17896fa..0ebfa8eccf0c 100644
--- a/drivers/memory/tegra/tegra210-emc-cc-r21021.c
+++ b/drivers/memory/tegra/tegra210-emc-cc-r21021.c
@@ -501,7 +501,6 @@ static u32 tegra210_emc_r21021_periodic_compensation(struct tegra210_emc *emc)
emc_cfg_o = emc_readl(emc, EMC_CFG);
emc_cfg = emc_cfg_o & ~(EMC_CFG_DYN_SELF_REF |
EMC_CFG_DRAM_ACPD |
- EMC_CFG_DRAM_CLKSTOP_PD |
EMC_CFG_DRAM_CLKSTOP_PD);
@@ -1044,7 +1043,7 @@ static void tegra210_emc_r21021_set_clock(struct tegra210_emc *emc, u32 clksrc)
!opt_cc_short_zcal && opt_short_zcal) {
value = (value & ~(EMC_ZCAL_WAIT_CNT_ZCAL_WAIT_CNT_MASK <<
EMC_ZCAL_WAIT_CNT_ZCAL_WAIT_CNT_SHIFT)) |
- ((zq_wait_long & EMC_ZCAL_WAIT_CNT_ZCAL_WAIT_CNT_MASK) <<
+ ((zq_wait_long & EMC_ZCAL_WAIT_CNT_ZCAL_WAIT_CNT_MASK) <<
EMC_MRS_WAIT_CNT_SHORT_WAIT_SHIFT);
} else if (offset == EMC_ZCAL_INTERVAL && opt_zcal_en_cc) {
value = 0; /* EMC_ZCAL_INTERVAL reset value. */
diff --git a/drivers/memory/tegra/tegra210.c b/drivers/memory/tegra/tegra210.c
index 7212d1d7b348..7fb8b5438bf4 100644
--- a/drivers/memory/tegra/tegra210.c
+++ b/drivers/memory/tegra/tegra210.c
@@ -842,7 +842,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = {
},
.la = {
.reg = 0x3dc,
- .shift = 0,
+ .shift = 16,
.mask = 0xff,
.def = 0x80,
},
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 97e848740e13..07d162b179fc 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -65,9 +65,10 @@ config RESET_HSDK
This enables the reset controller driver for HSDK board.
config RESET_IMX7
- bool "i.MX7/8 Reset Driver" if COMPILE_TEST
+ tristate "i.MX7/8 Reset Driver"
depends on HAS_IOMEM
- default SOC_IMX7D || (ARM64 && ARCH_MXC)
+ depends on SOC_IMX7D || (ARM64 && ARCH_MXC) || COMPILE_TEST
+ default y if SOC_IMX7D
select MFD_SYSCON
help
This enables the reset controller driver for i.MX7 SoCs.
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 01c0c7aa835c..a2df88e90011 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -32,7 +32,8 @@ static LIST_HEAD(reset_lookup_list);
* @refcnt: Number of gets of this reset_control
* @acquired: Only one reset_control may be acquired for a given rcdev and id.
* @shared: Is this a shared (1), or an exclusive (0) reset_control?
- * @deassert_cnt: Number of times this reset line has been deasserted
+ * @array: Is this an array of reset controls (1)?
+ * @deassert_count: Number of times this reset line has been deasserted
* @triggered_count: Number of times this reset line has been reset. Currently
* only used for shared resets, which means that the value
* will be either 0 or 1.
diff --git a/drivers/reset/reset-imx7.c b/drivers/reset/reset-imx7.c
index e8aa8691deb2..185a333df66c 100644
--- a/drivers/reset/reset-imx7.c
+++ b/drivers/reset/reset-imx7.c
@@ -8,7 +8,7 @@
*/
#include <linux/mfd/syscon.h>
-#include <linux/mod_devicetable.h>
+#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
@@ -178,6 +178,9 @@ static const struct imx7_src_signal imx8mq_src_signals[IMX8MQ_RESET_NUM] = {
[IMX8MQ_RESET_A53_SOC_DBG_RESET] = { SRC_A53RCR0, BIT(20) },
[IMX8MQ_RESET_A53_L2RESET] = { SRC_A53RCR0, BIT(21) },
[IMX8MQ_RESET_SW_NON_SCLR_M4C_RST] = { SRC_M4RCR, BIT(0) },
+ [IMX8MQ_RESET_SW_M4C_RST] = { SRC_M4RCR, BIT(1) },
+ [IMX8MQ_RESET_SW_M4P_RST] = { SRC_M4RCR, BIT(2) },
+ [IMX8MQ_RESET_M4_ENABLE] = { SRC_M4RCR, BIT(3) },
[IMX8MQ_RESET_OTG1_PHY_RESET] = { SRC_USBOPHY1_RCR, BIT(0) },
[IMX8MQ_RESET_OTG2_PHY_RESET] = { SRC_USBOPHY2_RCR, BIT(0) },
[IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N] = { SRC_MIPIPHY_RCR, BIT(1) },
@@ -238,6 +241,7 @@ static int imx8mq_reset_set(struct reset_controller_dev *rcdev,
case IMX8MQ_RESET_MIPI_DSI_DPI_RESET_N:
case IMX8MQ_RESET_MIPI_DSI_RESET_N:
case IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N:
+ case IMX8MQ_RESET_M4_ENABLE:
value = assert ? 0 : bit;
break;
}
@@ -386,6 +390,7 @@ static const struct of_device_id imx7_reset_dt_ids[] = {
{ .compatible = "fsl,imx8mp-src", .data = &variant_imx8mp },
{ /* sentinel */ },
};
+MODULE_DEVICE_TABLE(of, imx7_reset_dt_ids);
static struct platform_driver imx7_reset_driver = {
.probe = imx7_reset_probe,
@@ -394,4 +399,8 @@ static struct platform_driver imx7_reset_driver = {
.of_match_table = imx7_reset_dt_ids,
},
};
-builtin_platform_driver(imx7_reset_driver);
+module_platform_driver(imx7_reset_driver);
+
+MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
+MODULE_DESCRIPTION("NXP i.MX7 reset driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/reset/reset-zynqmp.c b/drivers/reset/reset-zynqmp.c
index 373ea8d4f7a1..ebd433fa09dd 100644
--- a/drivers/reset/reset-zynqmp.c
+++ b/drivers/reset/reset-zynqmp.c
@@ -9,12 +9,20 @@
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
#include <linux/firmware/xlnx-zynqmp.h>
+#include <linux/of_device.h>
#define ZYNQMP_NR_RESETS (ZYNQMP_PM_RESET_END - ZYNQMP_PM_RESET_START)
#define ZYNQMP_RESET_ID ZYNQMP_PM_RESET_START
+#define VERSAL_NR_RESETS 95
+
+struct zynqmp_reset_soc_data {
+ u32 reset_id;
+ u32 num_resets;
+};
struct zynqmp_reset_data {
struct reset_controller_dev rcdev;
+ const struct zynqmp_reset_soc_data *data;
};
static inline struct zynqmp_reset_data *
@@ -26,23 +34,28 @@ to_zynqmp_reset_data(struct reset_controller_dev *rcdev)
static int zynqmp_reset_assert(struct reset_controller_dev *rcdev,
unsigned long id)
{
- return zynqmp_pm_reset_assert(ZYNQMP_RESET_ID + id,
+ struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev);
+
+ return zynqmp_pm_reset_assert(priv->data->reset_id + id,
PM_RESET_ACTION_ASSERT);
}
static int zynqmp_reset_deassert(struct reset_controller_dev *rcdev,
unsigned long id)
{
- return zynqmp_pm_reset_assert(ZYNQMP_RESET_ID + id,
+ struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev);
+
+ return zynqmp_pm_reset_assert(priv->data->reset_id + id,
PM_RESET_ACTION_RELEASE);
}
static int zynqmp_reset_status(struct reset_controller_dev *rcdev,
unsigned long id)
{
+ struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev);
int val, err;
- err = zynqmp_pm_reset_get_status(ZYNQMP_RESET_ID + id, &val);
+ err = zynqmp_pm_reset_get_status(priv->data->reset_id + id, &val);
if (err)
return err;
@@ -52,10 +65,28 @@ static int zynqmp_reset_status(struct reset_controller_dev *rcdev,
static int zynqmp_reset_reset(struct reset_controller_dev *rcdev,
unsigned long id)
{
- return zynqmp_pm_reset_assert(ZYNQMP_RESET_ID + id,
+ struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev);
+
+ return zynqmp_pm_reset_assert(priv->data->reset_id + id,
PM_RESET_ACTION_PULSE);
}
+static int zynqmp_reset_of_xlate(struct reset_controller_dev *rcdev,
+ const struct of_phandle_args *reset_spec)
+{
+ return reset_spec->args[0];
+}
+
+static const struct zynqmp_reset_soc_data zynqmp_reset_data = {
+ .reset_id = ZYNQMP_RESET_ID,
+ .num_resets = ZYNQMP_NR_RESETS,
+};
+
+static const struct zynqmp_reset_soc_data versal_reset_data = {
+ .reset_id = 0,
+ .num_resets = VERSAL_NR_RESETS,
+};
+
static const struct reset_control_ops zynqmp_reset_ops = {
.reset = zynqmp_reset_reset,
.assert = zynqmp_reset_assert,
@@ -71,18 +102,25 @@ static int zynqmp_reset_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
+ priv->data = of_device_get_match_data(&pdev->dev);
+ if (!priv->data)
+ return -EINVAL;
+
platform_set_drvdata(pdev, priv);
priv->rcdev.ops = &zynqmp_reset_ops;
priv->rcdev.owner = THIS_MODULE;
priv->rcdev.of_node = pdev->dev.of_node;
- priv->rcdev.nr_resets = ZYNQMP_NR_RESETS;
+ priv->rcdev.nr_resets = priv->data->num_resets;
+ priv->rcdev.of_reset_n_cells = 1;
+ priv->rcdev.of_xlate = zynqmp_reset_of_xlate;
return devm_reset_controller_register(&pdev->dev, &priv->rcdev);
}
static const struct of_device_id zynqmp_reset_dt_ids[] = {
- { .compatible = "xlnx,zynqmp-reset", },
+ { .compatible = "xlnx,zynqmp-reset", .data = &zynqmp_reset_data, },
+ { .compatible = "xlnx,versal-reset", .data = &versal_reset_data, },
{ /* sentinel */ },
};
diff --git a/drivers/reset/sti/reset-syscfg.c b/drivers/reset/sti/reset-syscfg.c
index 91215bb88f62..99b63035fe72 100644
--- a/drivers/reset/sti/reset-syscfg.c
+++ b/drivers/reset/sti/reset-syscfg.c
@@ -17,7 +17,7 @@
#include "reset-syscfg.h"
/**
- * Reset channel regmap configuration
+ * struct syscfg_reset_channel - Reset channel regmap configuration
*
* @reset: regmap field for the channel's reset bit.
* @ack: regmap field for the channel's ack bit (optional).
@@ -28,8 +28,9 @@ struct syscfg_reset_channel {
};
/**
- * A reset controller which groups together a set of related reset bits, which
- * may be located in different system configuration registers.
+ * struct syscfg_reset_controller - A reset controller which groups together
+ * a set of related reset bits, which may be located in different system
+ * configuration registers.
*
* @rst: base reset controller structure.
* @active_low: are the resets in this controller active low, i.e. clearing
diff --git a/drivers/soc/amlogic/meson-ee-pwrc.c b/drivers/soc/amlogic/meson-ee-pwrc.c
index 43665b77aa9e..5164a4dc2352 100644
--- a/drivers/soc/amlogic/meson-ee-pwrc.c
+++ b/drivers/soc/amlogic/meson-ee-pwrc.c
@@ -15,6 +15,7 @@
#include <linux/reset.h>
#include <linux/clk.h>
#include <dt-bindings/power/meson8-power.h>
+#include <dt-bindings/power/meson-axg-power.h>
#include <dt-bindings/power/meson-g12a-power.h>
#include <dt-bindings/power/meson-gxbb-power.h>
#include <dt-bindings/power/meson-sm1-power.h>
@@ -134,6 +135,11 @@ static struct meson_ee_pwrc_top_domain sm1_pwrc_ge2d = SM1_EE_PD(19);
{ __reg, BIT(14) }, \
{ __reg, BIT(15) }
+static struct meson_ee_pwrc_mem_domain axg_pwrc_mem_vpu[] = {
+ VPU_MEMPD(HHI_VPU_MEM_PD_REG0),
+ VPU_HHI_MEMPD(HHI_MEM_PD_REG0),
+};
+
static struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_vpu[] = {
VPU_MEMPD(HHI_VPU_MEM_PD_REG0),
VPU_MEMPD(HHI_VPU_MEM_PD_REG1),
@@ -190,6 +196,10 @@ static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_ge2d[] = {
{ HHI_MEM_PD_REG0, GENMASK(25, 18) },
};
+static struct meson_ee_pwrc_mem_domain axg_pwrc_mem_audio[] = {
+ { HHI_MEM_PD_REG0, GENMASK(5, 4) },
+};
+
static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_audio[] = {
{ HHI_MEM_PD_REG0, GENMASK(5, 4) },
{ HHI_AUDIO_MEM_PD_REG0, GENMASK(1, 0) },
@@ -231,6 +241,13 @@ static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_audio[] = {
static bool pwrc_ee_get_power(struct meson_ee_pwrc_domain *pwrc_domain);
+static struct meson_ee_pwrc_domain_desc axg_pwrc_domains[] = {
+ [PWRC_AXG_VPU_ID] = VPU_PD("VPU", &gx_pwrc_vpu, axg_pwrc_mem_vpu,
+ pwrc_ee_get_power, 5, 2),
+ [PWRC_AXG_ETHERNET_MEM_ID] = MEM_PD("ETH", meson_pwrc_mem_eth),
+ [PWRC_AXG_AUDIO_ID] = MEM_PD("AUDIO", axg_pwrc_mem_audio),
+};
+
static struct meson_ee_pwrc_domain_desc g12a_pwrc_domains[] = {
[PWRC_G12A_VPU_ID] = VPU_PD("VPU", &gx_pwrc_vpu, g12a_pwrc_mem_vpu,
pwrc_ee_get_power, 11, 2),
@@ -433,8 +450,8 @@ static int meson_ee_pwrc_init_domain(struct platform_device *pdev,
if (ret)
return ret;
- ret = pm_genpd_init(&dom->base, &pm_domain_always_on_gov,
- false);
+ dom->base.flags = GENPD_FLAG_ALWAYS_ON;
+ ret = pm_genpd_init(&dom->base, NULL, false);
if (ret)
return ret;
} else {
@@ -529,6 +546,11 @@ static struct meson_ee_pwrc_domain_data meson_ee_g12a_pwrc_data = {
.domains = g12a_pwrc_domains,
};
+static struct meson_ee_pwrc_domain_data meson_ee_axg_pwrc_data = {
+ .count = ARRAY_SIZE(axg_pwrc_domains),
+ .domains = axg_pwrc_domains,
+};
+
static struct meson_ee_pwrc_domain_data meson_ee_gxbb_pwrc_data = {
.count = ARRAY_SIZE(gxbb_pwrc_domains),
.domains = gxbb_pwrc_domains,
@@ -563,6 +585,10 @@ static const struct of_device_id meson_ee_pwrc_match_table[] = {
.data = &meson_ee_m8b_pwrc_data,
},
{
+ .compatible = "amlogic,meson-axg-pwrc",
+ .data = &meson_ee_axg_pwrc_data,
+ },
+ {
.compatible = "amlogic,meson-gxbb-pwrc",
.data = &meson_ee_gxbb_pwrc_data,
},
diff --git a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c
index 511b6856225d..21b4bc811c00 100644
--- a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c
+++ b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c
@@ -339,8 +339,8 @@ static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev)
return ret;
}
- pm_genpd_init(&vpu_pd->genpd, &pm_domain_always_on_gov,
- powered_off);
+ vpu_pd->genpd.flags = GENPD_FLAG_ALWAYS_ON;
+ pm_genpd_init(&vpu_pd->genpd, NULL, powered_off);
return of_genpd_add_provider_simple(pdev->dev.of_node,
&vpu_pd->genpd);
diff --git a/drivers/soc/bcm/Kconfig b/drivers/soc/bcm/Kconfig
index 648e32693b7e..24f92a6e882a 100644
--- a/drivers/soc/bcm/Kconfig
+++ b/drivers/soc/bcm/Kconfig
@@ -22,6 +22,15 @@ config RASPBERRYPI_POWER
This enables support for the RPi power domains which can be enabled
or disabled via the RPi firmware.
+config SOC_BCM63XX
+ bool "Broadcom 63xx SoC drivers"
+ depends on BMIPS_GENERIC || COMPILE_TEST
+ help
+ Enables drivers for the Broadcom 63xx series of chips.
+ Drivers can be enabled individually within this menu.
+
+ If unsure, say N.
+
config SOC_BRCMSTB
bool "Broadcom STB SoC drivers"
depends on ARM || ARM64 || BMIPS_GENERIC || COMPILE_TEST
@@ -33,6 +42,7 @@ config SOC_BRCMSTB
If unsure, say N.
+source "drivers/soc/bcm/bcm63xx/Kconfig"
source "drivers/soc/bcm/brcmstb/Kconfig"
endmenu
diff --git a/drivers/soc/bcm/Makefile b/drivers/soc/bcm/Makefile
index d92268a829a9..7bc90e0bd773 100644
--- a/drivers/soc/bcm/Makefile
+++ b/drivers/soc/bcm/Makefile
@@ -1,4 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_BCM2835_POWER) += bcm2835-power.o
obj-$(CONFIG_RASPBERRYPI_POWER) += raspberrypi-power.o
+obj-$(CONFIG_SOC_BCM63XX) += bcm63xx/
obj-$(CONFIG_SOC_BRCMSTB) += brcmstb/
diff --git a/drivers/soc/bcm/bcm63xx/Kconfig b/drivers/soc/bcm/bcm63xx/Kconfig
new file mode 100644
index 000000000000..16f648a6c70a
--- /dev/null
+++ b/drivers/soc/bcm/bcm63xx/Kconfig
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0-only
+if SOC_BCM63XX
+
+config BCM63XX_POWER
+ bool "BCM63xx power domain driver"
+ depends on BMIPS_GENERIC || (COMPILE_TEST && OF)
+ select PM_GENERIC_DOMAINS if PM
+ help
+ This enables support for the BCM63xx power domains controller on
+ BCM6318, BCM6328, BCM6362 and BCM63268 SoCs.
+
+endif # SOC_BCM63XX
diff --git a/drivers/soc/bcm/bcm63xx/Makefile b/drivers/soc/bcm/bcm63xx/Makefile
new file mode 100644
index 000000000000..0710d5e018cc
--- /dev/null
+++ b/drivers/soc/bcm/bcm63xx/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_BCM63XX_POWER) += bcm63xx-power.o
diff --git a/drivers/soc/bcm/bcm63xx/bcm63xx-power.c b/drivers/soc/bcm/bcm63xx/bcm63xx-power.c
new file mode 100644
index 000000000000..515fe182dc34
--- /dev/null
+++ b/drivers/soc/bcm/bcm63xx/bcm63xx-power.c
@@ -0,0 +1,378 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * BCM63xx Power Domain Controller Driver
+ *
+ * Copyright (C) 2020 Álvaro Fernández Rojas <noltari@gmail.com>
+ */
+
+#include <dt-bindings/soc/bcm6318-pm.h>
+#include <dt-bindings/soc/bcm6328-pm.h>
+#include <dt-bindings/soc/bcm6362-pm.h>
+#include <dt-bindings/soc/bcm63268-pm.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+struct bcm63xx_power_dev {
+ struct generic_pm_domain genpd;
+ struct bcm63xx_power *power;
+ uint32_t mask;
+};
+
+struct bcm63xx_power {
+ void __iomem *base;
+ spinlock_t lock;
+ struct bcm63xx_power_dev *dev;
+ struct genpd_onecell_data genpd_data;
+ struct generic_pm_domain **genpd;
+};
+
+struct bcm63xx_power_data {
+ const char * const name;
+ uint8_t bit;
+ unsigned int flags;
+};
+
+static int bcm63xx_power_get_state(struct bcm63xx_power_dev *pmd, bool *is_on)
+{
+ struct bcm63xx_power *power = pmd->power;
+
+ if (!pmd->mask) {
+ *is_on = false;
+ return -EINVAL;
+ }
+
+ *is_on = !(__raw_readl(power->base) & pmd->mask);
+
+ return 0;
+}
+
+static int bcm63xx_power_set_state(struct bcm63xx_power_dev *pmd, bool on)
+{
+ struct bcm63xx_power *power = pmd->power;
+ unsigned long flags;
+ uint32_t val;
+
+ if (!pmd->mask)
+ return -EINVAL;
+
+ spin_lock_irqsave(&power->lock, flags);
+ val = __raw_readl(power->base);
+ if (on)
+ val &= ~pmd->mask;
+ else
+ val |= pmd->mask;
+ __raw_writel(val, power->base);
+ spin_unlock_irqrestore(&power->lock, flags);
+
+ return 0;
+}
+
+static int bcm63xx_power_on(struct generic_pm_domain *genpd)
+{
+ struct bcm63xx_power_dev *pmd = container_of(genpd,
+ struct bcm63xx_power_dev, genpd);
+
+ return bcm63xx_power_set_state(pmd, true);
+}
+
+static int bcm63xx_power_off(struct generic_pm_domain *genpd)
+{
+ struct bcm63xx_power_dev *pmd = container_of(genpd,
+ struct bcm63xx_power_dev, genpd);
+
+ return bcm63xx_power_set_state(pmd, false);
+}
+
+static int bcm63xx_power_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct resource *res;
+ const struct bcm63xx_power_data *entry, *table;
+ struct bcm63xx_power *power;
+ unsigned int ndom;
+ uint8_t max_bit = 0;
+ int ret;
+
+ power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL);
+ if (!power)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ power->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(power->base))
+ return PTR_ERR(power->base);
+
+ table = of_device_get_match_data(dev);
+ if (!table)
+ return -EINVAL;
+
+ power->genpd_data.num_domains = 0;
+ ndom = 0;
+ for (entry = table; entry->name; entry++) {
+ max_bit = max(max_bit, entry->bit);
+ ndom++;
+ }
+
+ if (!ndom)
+ return -ENODEV;
+
+ power->genpd_data.num_domains = max_bit + 1;
+
+ power->dev = devm_kcalloc(dev, power->genpd_data.num_domains,
+ sizeof(struct bcm63xx_power_dev),
+ GFP_KERNEL);
+ if (!power->dev)
+ return -ENOMEM;
+
+ power->genpd = devm_kcalloc(dev, power->genpd_data.num_domains,
+ sizeof(struct generic_pm_domain *),
+ GFP_KERNEL);
+ if (!power->genpd)
+ return -ENOMEM;
+
+ power->genpd_data.domains = power->genpd;
+
+ ndom = 0;
+ for (entry = table; entry->name; entry++) {
+ struct bcm63xx_power_dev *pmd = &power->dev[ndom];
+ bool is_on;
+
+ pmd->power = power;
+ pmd->mask = BIT(entry->bit);
+ pmd->genpd.name = entry->name;
+ pmd->genpd.flags = entry->flags;
+
+ ret = bcm63xx_power_get_state(pmd, &is_on);
+ if (ret)
+ dev_warn(dev, "unable to get current state for %s\n",
+ pmd->genpd.name);
+
+ pmd->genpd.power_on = bcm63xx_power_on;
+ pmd->genpd.power_off = bcm63xx_power_off;
+
+ pm_genpd_init(&pmd->genpd, NULL, !is_on);
+ power->genpd[entry->bit] = &pmd->genpd;
+
+ ndom++;
+ }
+
+ spin_lock_init(&power->lock);
+
+ ret = of_genpd_add_provider_onecell(np, &power->genpd_data);
+ if (ret) {
+ dev_err(dev, "failed to register genpd driver: %d\n", ret);
+ return ret;
+ }
+
+ dev_info(dev, "registered %u power domains\n", ndom);
+
+ return 0;
+}
+
+static const struct bcm63xx_power_data bcm6318_power_domains[] = {
+ {
+ .name = "pcie",
+ .bit = BCM6318_POWER_DOMAIN_PCIE,
+ }, {
+ .name = "usb",
+ .bit = BCM6318_POWER_DOMAIN_USB,
+ }, {
+ .name = "ephy0",
+ .bit = BCM6318_POWER_DOMAIN_EPHY0,
+ }, {
+ .name = "ephy1",
+ .bit = BCM6318_POWER_DOMAIN_EPHY1,
+ }, {
+ .name = "ephy2",
+ .bit = BCM6318_POWER_DOMAIN_EPHY2,
+ }, {
+ .name = "ephy3",
+ .bit = BCM6318_POWER_DOMAIN_EPHY3,
+ }, {
+ .name = "ldo2p5",
+ .bit = BCM6318_POWER_DOMAIN_LDO2P5,
+ .flags = GENPD_FLAG_ALWAYS_ON,
+ }, {
+ .name = "ldo2p9",
+ .bit = BCM6318_POWER_DOMAIN_LDO2P9,
+ .flags = GENPD_FLAG_ALWAYS_ON,
+ }, {
+ .name = "sw1p0",
+ .bit = BCM6318_POWER_DOMAIN_SW1P0,
+ .flags = GENPD_FLAG_ALWAYS_ON,
+ }, {
+ .name = "pad",
+ .bit = BCM6318_POWER_DOMAIN_PAD,
+ .flags = GENPD_FLAG_ALWAYS_ON,
+ }, {
+ /* sentinel */
+ },
+};
+
+static const struct bcm63xx_power_data bcm6328_power_domains[] = {
+ {
+ .name = "adsl2-mips",
+ .bit = BCM6328_POWER_DOMAIN_ADSL2_MIPS,
+ }, {
+ .name = "adsl2-phy",
+ .bit = BCM6328_POWER_DOMAIN_ADSL2_PHY,
+ }, {
+ .name = "adsl2-afe",
+ .bit = BCM6328_POWER_DOMAIN_ADSL2_AFE,
+ }, {
+ .name = "sar",
+ .bit = BCM6328_POWER_DOMAIN_SAR,
+ }, {
+ .name = "pcm",
+ .bit = BCM6328_POWER_DOMAIN_PCM,
+ }, {
+ .name = "usbd",
+ .bit = BCM6328_POWER_DOMAIN_USBD,
+ }, {
+ .name = "usbh",
+ .bit = BCM6328_POWER_DOMAIN_USBH,
+ }, {
+ .name = "pcie",
+ .bit = BCM6328_POWER_DOMAIN_PCIE,
+ }, {
+ .name = "robosw",
+ .bit = BCM6328_POWER_DOMAIN_ROBOSW,
+ }, {
+ .name = "ephy",
+ .bit = BCM6328_POWER_DOMAIN_EPHY,
+ }, {
+ /* sentinel */
+ },
+};
+
+static const struct bcm63xx_power_data bcm6362_power_domains[] = {
+ {
+ .name = "sar",
+ .bit = BCM6362_POWER_DOMAIN_SAR,
+ }, {
+ .name = "ipsec",
+ .bit = BCM6362_POWER_DOMAIN_IPSEC,
+ }, {
+ .name = "mips",
+ .bit = BCM6362_POWER_DOMAIN_MIPS,
+ .flags = GENPD_FLAG_ALWAYS_ON,
+ }, {
+ .name = "dect",
+ .bit = BCM6362_POWER_DOMAIN_DECT,
+ }, {
+ .name = "usbh",
+ .bit = BCM6362_POWER_DOMAIN_USBH,
+ }, {
+ .name = "usbd",
+ .bit = BCM6362_POWER_DOMAIN_USBD,
+ }, {
+ .name = "robosw",
+ .bit = BCM6362_POWER_DOMAIN_ROBOSW,
+ }, {
+ .name = "pcm",
+ .bit = BCM6362_POWER_DOMAIN_PCM,
+ }, {
+ .name = "periph",
+ .bit = BCM6362_POWER_DOMAIN_PERIPH,
+ .flags = GENPD_FLAG_ALWAYS_ON,
+ }, {
+ .name = "adsl-phy",
+ .bit = BCM6362_POWER_DOMAIN_ADSL_PHY,
+ }, {
+ .name = "gmii-pads",
+ .bit = BCM6362_POWER_DOMAIN_GMII_PADS,
+ }, {
+ .name = "fap",
+ .bit = BCM6362_POWER_DOMAIN_FAP,
+ }, {
+ .name = "pcie",
+ .bit = BCM6362_POWER_DOMAIN_PCIE,
+ }, {
+ .name = "wlan-pads",
+ .bit = BCM6362_POWER_DOMAIN_WLAN_PADS,
+ }, {
+ /* sentinel */
+ },
+};
+
+static const struct bcm63xx_power_data bcm63268_power_domains[] = {
+ {
+ .name = "sar",
+ .bit = BCM63268_POWER_DOMAIN_SAR,
+ }, {
+ .name = "ipsec",
+ .bit = BCM63268_POWER_DOMAIN_IPSEC,
+ }, {
+ .name = "mips",
+ .bit = BCM63268_POWER_DOMAIN_MIPS,
+ .flags = GENPD_FLAG_ALWAYS_ON,
+ }, {
+ .name = "dect",
+ .bit = BCM63268_POWER_DOMAIN_DECT,
+ }, {
+ .name = "usbh",
+ .bit = BCM63268_POWER_DOMAIN_USBH,
+ }, {
+ .name = "usbd",
+ .bit = BCM63268_POWER_DOMAIN_USBD,
+ }, {
+ .name = "robosw",
+ .bit = BCM63268_POWER_DOMAIN_ROBOSW,
+ }, {
+ .name = "pcm",
+ .bit = BCM63268_POWER_DOMAIN_PCM,
+ }, {
+ .name = "periph",
+ .bit = BCM63268_POWER_DOMAIN_PERIPH,
+ .flags = GENPD_FLAG_ALWAYS_ON,
+ }, {
+ .name = "vdsl-phy",
+ .bit = BCM63268_POWER_DOMAIN_VDSL_PHY,
+ }, {
+ .name = "vdsl-mips",
+ .bit = BCM63268_POWER_DOMAIN_VDSL_MIPS,
+ }, {
+ .name = "fap",
+ .bit = BCM63268_POWER_DOMAIN_FAP,
+ }, {
+ .name = "pcie",
+ .bit = BCM63268_POWER_DOMAIN_PCIE,
+ }, {
+ .name = "wlan-pads",
+ .bit = BCM63268_POWER_DOMAIN_WLAN_PADS,
+ }, {
+ /* sentinel */
+ },
+};
+
+static const struct of_device_id bcm63xx_power_of_match[] = {
+ {
+ .compatible = "brcm,bcm6318-power-controller",
+ .data = &bcm6318_power_domains,
+ }, {
+ .compatible = "brcm,bcm6328-power-controller",
+ .data = &bcm6328_power_domains,
+ }, {
+ .compatible = "brcm,bcm6362-power-controller",
+ .data = &bcm6362_power_domains,
+ }, {
+ .compatible = "brcm,bcm63268-power-controller",
+ .data = &bcm63268_power_domains,
+ }, {
+ /* sentinel */
+ }
+};
+
+static struct platform_driver bcm63xx_power_driver = {
+ .driver = {
+ .name = "bcm63xx-power-controller",
+ .of_match_table = bcm63xx_power_of_match,
+ },
+ .probe = bcm63xx_power_probe,
+};
+builtin_platform_driver(bcm63xx_power_driver);
diff --git a/drivers/soc/bcm/brcmstb/biuctrl.c b/drivers/soc/bcm/brcmstb/biuctrl.c
index 61731e01f94b..7f8dc302ae6e 100644
--- a/drivers/soc/bcm/brcmstb/biuctrl.c
+++ b/drivers/soc/bcm/brcmstb/biuctrl.c
@@ -13,6 +13,22 @@
#include <linux/syscore_ops.h>
#include <linux/soc/brcmstb/brcmstb.h>
+#define RACENPREF_MASK 0x3
+#define RACPREFINST_SHIFT 0
+#define RACENINST_SHIFT 2
+#define RACPREFDATA_SHIFT 4
+#define RACENDATA_SHIFT 6
+#define RAC_CPU_SHIFT 8
+#define RACCFG_MASK 0xff
+#define DPREF_LINE_2_SHIFT 24
+#define DPREF_LINE_2_MASK 0xff
+
+/* Bitmask to enable instruction and data prefetching with a 256-bytes stride */
+#define RAC_DATA_INST_EN_MASK (1 << RACPREFINST_SHIFT | \
+ RACENPREF_MASK << RACENINST_SHIFT | \
+ 1 << RACPREFDATA_SHIFT | \
+ RACENPREF_MASK << RACENDATA_SHIFT)
+
#define CPU_CREDIT_REG_MCPx_WR_PAIRING_EN_MASK 0x70000000
#define CPU_CREDIT_REG_MCPx_READ_CRED_MASK 0xf
#define CPU_CREDIT_REG_MCPx_WRITE_CRED_MASK 0xf
@@ -31,11 +47,21 @@ static void __iomem *cpubiuctrl_base;
static bool mcp_wr_pairing_en;
static const int *cpubiuctrl_regs;
+enum cpubiuctrl_regs {
+ CPU_CREDIT_REG = 0,
+ CPU_MCP_FLOW_REG,
+ CPU_WRITEBACK_CTRL_REG,
+ RAC_CONFIG0_REG,
+ RAC_CONFIG1_REG,
+ NUM_CPU_BIUCTRL_REGS,
+};
+
static inline u32 cbc_readl(int reg)
{
int offset = cpubiuctrl_regs[reg];
- if (offset == -1)
+ if (offset == -1 ||
+ (IS_ENABLED(CONFIG_CACHE_B15_RAC) && reg >= RAC_CONFIG0_REG))
return (u32)-1;
return readl_relaxed(cpubiuctrl_base + offset);
@@ -45,22 +71,19 @@ static inline void cbc_writel(u32 val, int reg)
{
int offset = cpubiuctrl_regs[reg];
- if (offset == -1)
+ if (offset == -1 ||
+ (IS_ENABLED(CONFIG_CACHE_B15_RAC) && reg >= RAC_CONFIG0_REG))
return;
writel(val, cpubiuctrl_base + offset);
}
-enum cpubiuctrl_regs {
- CPU_CREDIT_REG = 0,
- CPU_MCP_FLOW_REG,
- CPU_WRITEBACK_CTRL_REG
-};
-
static const int b15_cpubiuctrl_regs[] = {
[CPU_CREDIT_REG] = 0x184,
[CPU_MCP_FLOW_REG] = -1,
[CPU_WRITEBACK_CTRL_REG] = -1,
+ [RAC_CONFIG0_REG] = -1,
+ [RAC_CONFIG1_REG] = -1,
};
/* Odd cases, e.g: 7260A0 */
@@ -68,22 +91,26 @@ static const int b53_cpubiuctrl_no_wb_regs[] = {
[CPU_CREDIT_REG] = 0x0b0,
[CPU_MCP_FLOW_REG] = 0x0b4,
[CPU_WRITEBACK_CTRL_REG] = -1,
+ [RAC_CONFIG0_REG] = 0x78,
+ [RAC_CONFIG1_REG] = 0x7c,
};
static const int b53_cpubiuctrl_regs[] = {
[CPU_CREDIT_REG] = 0x0b0,
[CPU_MCP_FLOW_REG] = 0x0b4,
[CPU_WRITEBACK_CTRL_REG] = 0x22c,
+ [RAC_CONFIG0_REG] = 0x78,
+ [RAC_CONFIG1_REG] = 0x7c,
};
static const int a72_cpubiuctrl_regs[] = {
[CPU_CREDIT_REG] = 0x18,
[CPU_MCP_FLOW_REG] = 0x1c,
[CPU_WRITEBACK_CTRL_REG] = 0x20,
+ [RAC_CONFIG0_REG] = 0x08,
+ [RAC_CONFIG1_REG] = 0x0c,
};
-#define NUM_CPU_BIUCTRL_REGS 3
-
static int __init mcp_write_pairing_set(void)
{
u32 creds = 0;
@@ -110,6 +137,8 @@ static int __init mcp_write_pairing_set(void)
static const u32 a72_b53_mach_compat[] = {
0x7211,
0x7216,
+ 0x72164,
+ 0x72165,
0x7255,
0x7260,
0x7268,
@@ -117,6 +146,61 @@ static const u32 a72_b53_mach_compat[] = {
0x7278,
};
+/* The read-ahead cache present in the Brahma-B53 CPU is a special piece of
+ * hardware after the integrated L2 cache of the B53 CPU complex whose purpose
+ * is to prefetch instruction and/or data with a line size of either 64 bytes
+ * or 256 bytes. The rationale is that the data-bus of the CPU interface is
+ * optimized for 256-byte transactions, and enabling the read-ahead cache
+ * provides a significant performance boost (typically twice the performance
+ * for a memcpy benchmark application).
+ *
+ * The read-ahead cache is transparent for Virtual Address cache maintenance
+ * operations: IC IVAU, DC IVAC, DC CVAC, DC CVAU and DC CIVAC. So no special
+ * handling is needed for the DMA API above and beyond what is included in the
+ * arm64 implementation.
+ *
+ * In addition, since the Point of Unification is typically between L1 and L2
+ * for the Brahma-B53 processor no special read-ahead cache handling is needed
+ * for the IC IALLU and IC IALLUIS cache maintenance operations.
+ *
+ * However, it is not possible to specify the cache level (L3) for the cache
+ * maintenance instructions operating by set/way to operate on the read-ahead
+ * cache. The read-ahead cache will maintain coherency when inner cache lines
+ * are cleaned by set/way, but if it is necessary to invalidate inner cache
+ * lines by set/way to maintain coherency with system masters operating on
+ * shared memory that does not have hardware support for coherency, then it
+ * will also be necessary to explicitly invalidate the read-ahead cache.
+ */
+static void __init a72_b53_rac_enable_all(struct device_node *np)
+{
+ unsigned int cpu;
+ u32 enable = 0, pref_dist, shift;
+
+ if (IS_ENABLED(CONFIG_CACHE_B15_RAC))
+ return;
+
+ if (WARN(num_possible_cpus() > 4, "RAC only supports 4 CPUs\n"))
+ return;
+
+ pref_dist = cbc_readl(RAC_CONFIG1_REG);
+ for_each_possible_cpu(cpu) {
+ shift = cpu * RAC_CPU_SHIFT + RACPREFDATA_SHIFT;
+ enable |= RAC_DATA_INST_EN_MASK << (cpu * RAC_CPU_SHIFT);
+ if (cpubiuctrl_regs == a72_cpubiuctrl_regs) {
+ enable &= ~(RACENPREF_MASK << shift);
+ enable |= 3 << shift;
+ pref_dist |= 1 << (cpu + DPREF_LINE_2_SHIFT);
+ }
+ }
+
+ cbc_writel(enable, RAC_CONFIG0_REG);
+ cbc_writel(pref_dist, RAC_CONFIG1_REG);
+
+ pr_info("%pOF: Broadcom %s read-ahead cache\n",
+ np, cpubiuctrl_regs == a72_cpubiuctrl_regs ?
+ "Cortex-A72" : "Brahma-B53");
+}
+
static void __init mcp_a72_b53_set(void)
{
unsigned int i;
@@ -262,6 +346,7 @@ static int __init brcmstb_biuctrl_init(void)
return ret;
}
+ a72_b53_rac_enable_all(np);
mcp_a72_b53_set();
#ifdef CONFIG_PM_SLEEP
register_syscore_ops(&brcmstb_cpu_credit_syscore_ops);
diff --git a/drivers/soc/fsl/dpio/qbman-portal.c b/drivers/soc/fsl/dpio/qbman-portal.c
index 0ab85bfb116f..659b4a570d5b 100644
--- a/drivers/soc/fsl/dpio/qbman-portal.c
+++ b/drivers/soc/fsl/dpio/qbman-portal.c
@@ -647,7 +647,6 @@ int qbman_swp_enqueue_multiple_direct(struct qbman_swp *s,
const uint32_t *cl = (uint32_t *)d;
uint32_t eqcr_ci, eqcr_pi, half_mask, full_mask;
int i, num_enqueued = 0;
- uint64_t addr_cena;
spin_lock(&s->access_spinlock);
half_mask = (s->eqcr.pi_ci_mask>>1);
@@ -701,7 +700,6 @@ int qbman_swp_enqueue_multiple_direct(struct qbman_swp *s,
/* Flush all the cacheline without load/store in between */
eqcr_pi = s->eqcr.pi;
- addr_cena = (size_t)s->addr_cena;
for (i = 0; i < num_enqueued; i++)
eqcr_pi++;
s->eqcr.pi = eqcr_pi & full_mask;
diff --git a/drivers/soc/fsl/qbman/bman.c b/drivers/soc/fsl/qbman/bman.c
index f4fb527d8301..c5dd026fe889 100644
--- a/drivers/soc/fsl/qbman/bman.c
+++ b/drivers/soc/fsl/qbman/bman.c
@@ -660,7 +660,7 @@ int bm_shutdown_pool(u32 bpid)
}
done:
put_affine_portal();
- return 0;
+ return err;
}
struct gen_pool *bm_bpalloc;
diff --git a/drivers/soc/fsl/qbman/qman_test_api.c b/drivers/soc/fsl/qbman/qman_test_api.c
index 2895d062cf51..7066b2f1467c 100644
--- a/drivers/soc/fsl/qbman/qman_test_api.c
+++ b/drivers/soc/fsl/qbman/qman_test_api.c
@@ -86,7 +86,7 @@ static void fd_inc(struct qm_fd *fd)
len--;
qm_fd_set_param(fd, fmt, off, len);
- fd->cmd = cpu_to_be32(be32_to_cpu(fd->cmd) + 1);
+ be32_add_cpu(&fd->cmd, 1);
}
/* The only part of the 'fd' we can't memcmp() is the ppid */
diff --git a/drivers/soc/fsl/qe/ucc.c b/drivers/soc/fsl/qe/ucc.c
index cac0fb7693a0..21dbcd787cd5 100644
--- a/drivers/soc/fsl/qe/ucc.c
+++ b/drivers/soc/fsl/qe/ucc.c
@@ -523,7 +523,7 @@ int ucc_set_tdm_rxtx_clk(u32 tdm_num, enum qe_clock clock,
qe_mux_reg = &qe_immr->qmx;
- if (tdm_num > 7 || tdm_num < 0)
+ if (tdm_num > 7)
return -EINVAL;
/* The communications direction must be RX or TX */
diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c
index 6cf8a7a412bd..db7e7fc321b1 100644
--- a/drivers/soc/imx/gpcv2.c
+++ b/drivers/soc/imx/gpcv2.c
@@ -487,22 +487,17 @@ static int imx_pgc_domain_probe(struct platform_device *pdev)
domain->regulator = devm_regulator_get_optional(domain->dev, "power");
if (IS_ERR(domain->regulator)) {
- if (PTR_ERR(domain->regulator) != -ENODEV) {
- if (PTR_ERR(domain->regulator) != -EPROBE_DEFER)
- dev_err(domain->dev, "Failed to get domain's regulator\n");
- return PTR_ERR(domain->regulator);
- }
+ if (PTR_ERR(domain->regulator) != -ENODEV)
+ return dev_err_probe(domain->dev, PTR_ERR(domain->regulator),
+ "Failed to get domain's regulator\n");
} else if (domain->voltage) {
regulator_set_voltage(domain->regulator,
domain->voltage, domain->voltage);
}
ret = imx_pgc_get_clocks(domain);
- if (ret) {
- if (ret != -EPROBE_DEFER)
- dev_err(domain->dev, "Failed to get domain's clocks\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(domain->dev, ret, "Failed to get domain's clocks\n");
ret = pm_genpd_init(&domain->genpd, NULL, true);
if (ret) {
diff --git a/drivers/soc/mediatek/mtk-cmdq-helper.c b/drivers/soc/mediatek/mtk-cmdq-helper.c
index dc644cfb6419..505651b0d715 100644
--- a/drivers/soc/mediatek/mtk-cmdq-helper.c
+++ b/drivers/soc/mediatek/mtk-cmdq-helper.c
@@ -13,11 +13,16 @@
#define CMDQ_POLL_ENABLE_MASK BIT(0)
#define CMDQ_EOC_IRQ_EN BIT(0)
#define CMDQ_REG_TYPE 1
+#define CMDQ_JUMP_RELATIVE 1
struct cmdq_instruction {
union {
u32 value;
u32 mask;
+ struct {
+ u16 arg_c;
+ u16 src_reg;
+ };
};
union {
u16 offset;
@@ -223,15 +228,104 @@ int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys,
}
EXPORT_SYMBOL(cmdq_pkt_write_mask);
-int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event)
+int cmdq_pkt_read_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, u16 addr_low,
+ u16 reg_idx)
+{
+ struct cmdq_instruction inst = {};
+
+ inst.op = CMDQ_CODE_READ_S;
+ inst.dst_t = CMDQ_REG_TYPE;
+ inst.sop = high_addr_reg_idx;
+ inst.reg_dst = reg_idx;
+ inst.src_reg = addr_low;
+
+ return cmdq_pkt_append_command(pkt, inst);
+}
+EXPORT_SYMBOL(cmdq_pkt_read_s);
+
+int cmdq_pkt_write_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx,
+ u16 addr_low, u16 src_reg_idx)
+{
+ struct cmdq_instruction inst = {};
+
+ inst.op = CMDQ_CODE_WRITE_S;
+ inst.src_t = CMDQ_REG_TYPE;
+ inst.sop = high_addr_reg_idx;
+ inst.offset = addr_low;
+ inst.src_reg = src_reg_idx;
+
+ return cmdq_pkt_append_command(pkt, inst);
+}
+EXPORT_SYMBOL(cmdq_pkt_write_s);
+
+int cmdq_pkt_write_s_mask(struct cmdq_pkt *pkt, u16 high_addr_reg_idx,
+ u16 addr_low, u16 src_reg_idx, u32 mask)
+{
+ struct cmdq_instruction inst = {};
+ int err;
+
+ inst.op = CMDQ_CODE_MASK;
+ inst.mask = ~mask;
+ err = cmdq_pkt_append_command(pkt, inst);
+ if (err < 0)
+ return err;
+
+ inst.mask = 0;
+ inst.op = CMDQ_CODE_WRITE_S_MASK;
+ inst.src_t = CMDQ_REG_TYPE;
+ inst.sop = high_addr_reg_idx;
+ inst.offset = addr_low;
+ inst.src_reg = src_reg_idx;
+
+ return cmdq_pkt_append_command(pkt, inst);
+}
+EXPORT_SYMBOL(cmdq_pkt_write_s_mask);
+
+int cmdq_pkt_write_s_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx,
+ u16 addr_low, u32 value)
+{
+ struct cmdq_instruction inst = {};
+
+ inst.op = CMDQ_CODE_WRITE_S;
+ inst.sop = high_addr_reg_idx;
+ inst.offset = addr_low;
+ inst.value = value;
+
+ return cmdq_pkt_append_command(pkt, inst);
+}
+EXPORT_SYMBOL(cmdq_pkt_write_s_value);
+
+int cmdq_pkt_write_s_mask_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx,
+ u16 addr_low, u32 value, u32 mask)
+{
+ struct cmdq_instruction inst = {};
+ int err;
+
+ inst.op = CMDQ_CODE_MASK;
+ inst.mask = ~mask;
+ err = cmdq_pkt_append_command(pkt, inst);
+ if (err < 0)
+ return err;
+
+ inst.op = CMDQ_CODE_WRITE_S_MASK;
+ inst.sop = high_addr_reg_idx;
+ inst.offset = addr_low;
+ inst.value = value;
+
+ return cmdq_pkt_append_command(pkt, inst);
+}
+EXPORT_SYMBOL(cmdq_pkt_write_s_mask_value);
+
+int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event, bool clear)
{
struct cmdq_instruction inst = { {0} };
+ u32 clear_option = clear ? CMDQ_WFE_UPDATE : 0;
if (event >= CMDQ_MAX_EVENT)
return -EINVAL;
inst.op = CMDQ_CODE_WFE;
- inst.value = CMDQ_WFE_OPTION;
+ inst.value = CMDQ_WFE_OPTION | clear_option;
inst.event = event;
return cmdq_pkt_append_command(pkt, inst);
@@ -315,6 +409,18 @@ int cmdq_pkt_assign(struct cmdq_pkt *pkt, u16 reg_idx, u32 value)
}
EXPORT_SYMBOL(cmdq_pkt_assign);
+int cmdq_pkt_jump(struct cmdq_pkt *pkt, dma_addr_t addr)
+{
+ struct cmdq_instruction inst = {};
+
+ inst.op = CMDQ_CODE_JUMP;
+ inst.offset = CMDQ_JUMP_RELATIVE;
+ inst.value = addr >>
+ cmdq_get_shift_pa(((struct cmdq_client *)pkt->cl)->chan);
+ return cmdq_pkt_append_command(pkt, inst);
+}
+EXPORT_SYMBOL(cmdq_pkt_jump);
+
int cmdq_pkt_finalize(struct cmdq_pkt *pkt)
{
struct cmdq_instruction inst = { {0} };
@@ -329,7 +435,8 @@ int cmdq_pkt_finalize(struct cmdq_pkt *pkt)
/* JUMP to end */
inst.op = CMDQ_CODE_JUMP;
- inst.value = CMDQ_JUMP_PASS;
+ inst.value = CMDQ_JUMP_PASS >>
+ cmdq_get_shift_pa(((struct cmdq_client *)pkt->cl)->chan);
err = cmdq_pkt_append_command(pkt, inst);
return err;
diff --git a/drivers/soc/mediatek/mtk-infracfg.c b/drivers/soc/mediatek/mtk-infracfg.c
index 341c7ac250e3..4a123796aad3 100644
--- a/drivers/soc/mediatek/mtk-infracfg.c
+++ b/drivers/soc/mediatek/mtk-infracfg.c
@@ -19,7 +19,7 @@
/**
* mtk_infracfg_set_bus_protection - enable bus protection
- * @regmap: The infracfg regmap
+ * @infracfg: The infracfg regmap
* @mask: The mask containing the protection bits to be enabled.
* @reg_update: The boolean flag determines to set the protection bits
* by regmap_update_bits with enable register(PROTECTEN) or
@@ -50,7 +50,7 @@ int mtk_infracfg_set_bus_protection(struct regmap *infracfg, u32 mask,
/**
* mtk_infracfg_clear_bus_protection - disable bus protection
- * @regmap: The infracfg regmap
+ * @infracfg: The infracfg regmap
* @mask: The mask containing the protection bits to be disabled.
* @reg_update: The boolean flag determines to clear the protection bits
* by regmap_update_bits with enable register(PROTECTEN) or
diff --git a/drivers/soc/qcom/apr.c b/drivers/soc/qcom/apr.c
index 1f35b097c635..7abfc8c4fdc7 100644
--- a/drivers/soc/qcom/apr.c
+++ b/drivers/soc/qcom/apr.c
@@ -328,7 +328,7 @@ static int of_apr_add_pd_lookups(struct device *dev)
pds = pdr_add_lookup(apr->pdr, service_name, service_path);
if (IS_ERR(pds) && PTR_ERR(pds) != -EALREADY) {
- dev_err(dev, "pdr add lookup failed: %d\n", ret);
+ dev_err(dev, "pdr add lookup failed: %ld\n", PTR_ERR(pds));
return PTR_ERR(pds);
}
}
diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c
index 429b5a60a1ba..70fbe70c6213 100644
--- a/drivers/soc/qcom/llcc-qcom.c
+++ b/drivers/soc/qcom/llcc-qcom.c
@@ -387,7 +387,6 @@ static int qcom_llcc_remove(struct platform_device *pdev)
static struct regmap *qcom_llcc_init_mmio(struct platform_device *pdev,
const char *name)
{
- struct resource *res;
void __iomem *base;
struct regmap_config llcc_regmap_config = {
.reg_bits = 32,
@@ -396,11 +395,7 @@ static struct regmap *qcom_llcc_init_mmio(struct platform_device *pdev,
.fast_io = true,
};
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
- if (!res)
- return ERR_PTR(-ENODEV);
-
- base = devm_ioremap_resource(&pdev->dev, res);
+ base = devm_platform_ioremap_resource_byname(pdev, name);
if (IS_ERR(base))
return ERR_CAST(base);
diff --git a/drivers/soc/qcom/rpmh-internal.h b/drivers/soc/qcom/rpmh-internal.h
index ef60e790a750..344ba687c13b 100644
--- a/drivers/soc/qcom/rpmh-internal.h
+++ b/drivers/soc/qcom/rpmh-internal.h
@@ -8,6 +8,7 @@
#define __RPM_INTERNAL_H__
#include <linux/bitmap.h>
+#include <linux/wait.h>
#include <soc/qcom/tcs.h>
#define TCS_TYPE_NR 4
@@ -106,6 +107,8 @@ struct rpmh_ctrlr {
* @lock: Synchronize state of the controller. If RPMH's cache
* lock will also be held, the order is: drv->lock then
* cache_lock.
+ * @tcs_wait: Wait queue used to wait for @tcs_in_use to free up a
+ * slot
* @client: Handle to the DRV's client.
*/
struct rsc_drv {
@@ -118,6 +121,7 @@ struct rsc_drv {
struct tcs_group tcs[TCS_TYPE_NR];
DECLARE_BITMAP(tcs_in_use, MAX_TCS_NR);
spinlock_t lock;
+ wait_queue_head_t tcs_wait;
struct rpmh_ctrlr client;
};
diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index ae6675782581..a297911afe57 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -19,6 +19,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <linux/wait.h>
#include <soc/qcom/cmd-db.h>
#include <soc/qcom/tcs.h>
@@ -453,6 +454,7 @@ skip:
if (!drv->tcs[ACTIVE_TCS].num_tcs)
enable_tcs_irq(drv, i, false);
spin_unlock(&drv->lock);
+ wake_up(&drv->tcs_wait);
if (req)
rpmh_tx_done(req, err);
}
@@ -571,73 +573,34 @@ static int find_free_tcs(struct tcs_group *tcs)
}
/**
- * tcs_write() - Store messages into a TCS right now, or return -EBUSY.
+ * claim_tcs_for_req() - Claim a tcs in the given tcs_group; only for active.
* @drv: The controller.
+ * @tcs: The tcs_group used for ACTIVE_ONLY transfers.
* @msg: The data to be sent.
*
- * Grabs a TCS for ACTIVE_ONLY transfers and writes the messages to it.
+ * Claims a tcs in the given tcs_group while making sure that no existing cmd
+ * is in flight that would conflict with the one in @msg.
*
- * If there are no free TCSes for ACTIVE_ONLY transfers or if a command for
- * the same address is already transferring returns -EBUSY which means the
- * client should retry shortly.
+ * Context: Must be called with the drv->lock held since that protects
+ * tcs_in_use.
*
- * Return: 0 on success, -EBUSY if client should retry, or an error.
- * Client should have interrupts enabled for a bit before retrying.
+ * Return: The id of the claimed tcs or -EBUSY if a matching msg is in flight
+ * or the tcs_group is full.
*/
-static int tcs_write(struct rsc_drv *drv, const struct tcs_request *msg)
+static int claim_tcs_for_req(struct rsc_drv *drv, struct tcs_group *tcs,
+ const struct tcs_request *msg)
{
- struct tcs_group *tcs;
- int tcs_id;
- unsigned long flags;
int ret;
- tcs = get_tcs_for_msg(drv, msg);
- if (IS_ERR(tcs))
- return PTR_ERR(tcs);
-
- spin_lock_irqsave(&drv->lock, flags);
/*
* The h/w does not like if we send a request to the same address,
* when one is already in-flight or being processed.
*/
ret = check_for_req_inflight(drv, tcs, msg);
if (ret)
- goto unlock;
-
- ret = find_free_tcs(tcs);
- if (ret < 0)
- goto unlock;
- tcs_id = ret;
-
- tcs->req[tcs_id - tcs->offset] = msg;
- set_bit(tcs_id, drv->tcs_in_use);
- if (msg->state == RPMH_ACTIVE_ONLY_STATE && tcs->type != ACTIVE_TCS) {
- /*
- * Clear previously programmed WAKE commands in selected
- * repurposed TCS to avoid triggering them. tcs->slots will be
- * cleaned from rpmh_flush() by invoking rpmh_rsc_invalidate()
- */
- write_tcs_reg_sync(drv, RSC_DRV_CMD_ENABLE, tcs_id, 0);
- write_tcs_reg_sync(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, tcs_id, 0);
- enable_tcs_irq(drv, tcs_id, true);
- }
- spin_unlock_irqrestore(&drv->lock, flags);
-
- /*
- * These two can be done after the lock is released because:
- * - We marked "tcs_in_use" under lock.
- * - Once "tcs_in_use" has been marked nobody else could be writing
- * to these registers until the interrupt goes off.
- * - The interrupt can't go off until we trigger w/ the last line
- * of __tcs_set_trigger() below.
- */
- __tcs_buffer_write(drv, tcs_id, 0, msg);
- __tcs_set_trigger(drv, tcs_id, true);
+ return ret;
- return 0;
-unlock:
- spin_unlock_irqrestore(&drv->lock, flags);
- return ret;
+ return find_free_tcs(tcs);
}
/**
@@ -664,18 +627,47 @@ unlock:
*/
int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg)
{
- int ret;
+ struct tcs_group *tcs;
+ int tcs_id;
+ unsigned long flags;
- do {
- ret = tcs_write(drv, msg);
- if (ret == -EBUSY) {
- pr_info_ratelimited("TCS Busy, retrying RPMH message send: addr=%#x\n",
- msg->cmds[0].addr);
- udelay(10);
- }
- } while (ret == -EBUSY);
+ tcs = get_tcs_for_msg(drv, msg);
+ if (IS_ERR(tcs))
+ return PTR_ERR(tcs);
- return ret;
+ spin_lock_irqsave(&drv->lock, flags);
+
+ /* Wait forever for a free tcs. It better be there eventually! */
+ wait_event_lock_irq(drv->tcs_wait,
+ (tcs_id = claim_tcs_for_req(drv, tcs, msg)) >= 0,
+ drv->lock);
+
+ tcs->req[tcs_id - tcs->offset] = msg;
+ set_bit(tcs_id, drv->tcs_in_use);
+ if (msg->state == RPMH_ACTIVE_ONLY_STATE && tcs->type != ACTIVE_TCS) {
+ /*
+ * Clear previously programmed WAKE commands in selected
+ * repurposed TCS to avoid triggering them. tcs->slots will be
+ * cleaned from rpmh_flush() by invoking rpmh_rsc_invalidate()
+ */
+ write_tcs_reg_sync(drv, RSC_DRV_CMD_ENABLE, tcs_id, 0);
+ write_tcs_reg_sync(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, tcs_id, 0);
+ enable_tcs_irq(drv, tcs_id, true);
+ }
+ spin_unlock_irqrestore(&drv->lock, flags);
+
+ /*
+ * These two can be done after the lock is released because:
+ * - We marked "tcs_in_use" under lock.
+ * - Once "tcs_in_use" has been marked nobody else could be writing
+ * to these registers until the interrupt goes off.
+ * - The interrupt can't go off until we trigger w/ the last line
+ * of __tcs_set_trigger() below.
+ */
+ __tcs_buffer_write(drv, tcs_id, 0, msg);
+ __tcs_set_trigger(drv, tcs_id, true);
+
+ return 0;
}
/**
@@ -983,6 +975,7 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
return ret;
spin_lock_init(&drv->lock);
+ init_waitqueue_head(&drv->tcs_wait);
bitmap_zero(drv->tcs_in_use, MAX_TCS_NR);
irq = platform_get_irq(pdev, drv->id);
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index b25d0f7dac9e..b44ede48decc 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -194,6 +194,7 @@ static const struct soc_id soc_id[] = {
{ 186, "MSM8674" },
{ 194, "MSM8974PRO" },
{ 206, "MSM8916" },
+ { 207, "MSM8994" },
{ 208, "APQ8074-AA" },
{ 209, "APQ8074-AB" },
{ 210, "APQ8074PRO" },
@@ -214,6 +215,8 @@ static const struct soc_id soc_id[] = {
{ 248, "MSM8216" },
{ 249, "MSM8116" },
{ 250, "MSM8616" },
+ { 251, "MSM8992" },
+ { 253, "APQ8094" },
{ 291, "APQ8096" },
{ 305, "MSM8996SG" },
{ 310, "MSM8996AU" },
@@ -223,6 +226,8 @@ static const struct soc_id soc_id[] = {
{ 321, "SDM845" },
{ 341, "SDA845" },
{ 356, "SM8250" },
+ { 402, "IPQ6018" },
+ { 425, "SC7180" },
};
static const char *socinfo_machine(struct device *dev, unsigned int id)
diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig
index 30984659df90..b70bbc38efc6 100644
--- a/drivers/soc/renesas/Kconfig
+++ b/drivers/soc/renesas/Kconfig
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
-config SOC_RENESAS
+menuconfig SOC_RENESAS
bool "Renesas SoC driver support" if COMPILE_TEST && !ARCH_RENESAS
default y if ARCH_RENESAS
select SOC_BUS
@@ -49,126 +49,126 @@ if ARM && ARCH_RENESAS
#comment "Renesas ARM SoCs System Type"
config ARCH_EMEV2
- bool "Emma Mobile EV2"
+ bool "ARM32 Platform support for Emma Mobile EV2"
select HAVE_ARM_SCU if SMP
select SYS_SUPPORTS_EM_STI
-config ARCH_R7S72100
- bool "RZ/A1H (R7S72100)"
- select ARM_ERRATA_754322
- select PM
- select PM_GENERIC_DOMAINS
- select RENESAS_OSTM
- select RENESAS_RZA1_IRQC
- select SYS_SUPPORTS_SH_MTU2
+config ARCH_R8A7794
+ bool "ARM32 Platform support for R-Car E2"
+ select ARCH_RCAR_GEN2
+ select ARM_ERRATA_814220
+ select SYSC_R8A7794
-config ARCH_R7S9210
- bool "RZ/A2 (R7S9210)"
- select PM
- select PM_GENERIC_DOMAINS
- select RENESAS_OSTM
- select RENESAS_RZA1_IRQC
+config ARCH_R8A7779
+ bool "ARM32 Platform support for R-Car H1"
+ select ARCH_RCAR_GEN1
+ select ARM_ERRATA_754322
+ select ARM_GLOBAL_TIMER
+ select HAVE_ARM_SCU if SMP
+ select HAVE_ARM_TWD if SMP
+ select SYSC_R8A7779
-config ARCH_R8A73A4
- bool "R-Mobile APE6 (R8A73A40)"
- select ARCH_RMOBILE
+config ARCH_R8A7790
+ bool "ARM32 Platform support for R-Car H2"
+ select ARCH_RCAR_GEN2
select ARM_ERRATA_798181 if SMP
select ARM_ERRATA_814220
- select HAVE_ARM_ARCH_TIMER
- select RENESAS_IRQC
+ select I2C
+ select SYSC_R8A7790
-config ARCH_R8A7740
- bool "R-Mobile A1 (R8A77400)"
- select ARCH_RMOBILE
+config ARCH_R8A7778
+ bool "ARM32 Platform support for R-Car M1A"
+ select ARCH_RCAR_GEN1
select ARM_ERRATA_754322
- select RENESAS_INTC_IRQPIN
-config ARCH_R8A7742
- bool "RZ/G1H (R8A77420)"
+config ARCH_R8A7793
+ bool "ARM32 Platform support for R-Car M2-N"
select ARCH_RCAR_GEN2
select ARM_ERRATA_798181 if SMP
- select ARM_ERRATA_814220
- select SYSC_R8A7742
+ select I2C
+ select SYSC_R8A7791
-config ARCH_R8A7743
- bool "RZ/G1M (R8A77430)"
+config ARCH_R8A7791
+ bool "ARM32 Platform support for R-Car M2-W"
select ARCH_RCAR_GEN2
select ARM_ERRATA_798181 if SMP
- select SYSC_R8A7743
+ select I2C
+ select SYSC_R8A7791
-config ARCH_R8A7744
- bool "RZ/G1N (R8A77440)"
+config ARCH_R8A7792
+ bool "ARM32 Platform support for R-Car V2H"
select ARCH_RCAR_GEN2
select ARM_ERRATA_798181 if SMP
- select SYSC_R8A7743
+ select SYSC_R8A7792
-config ARCH_R8A7745
- bool "RZ/G1E (R8A77450)"
- select ARCH_RCAR_GEN2
- select ARM_ERRATA_814220
- select SYSC_R8A7745
+config ARCH_R8A7740
+ bool "ARM32 Platform support for R-Mobile A1"
+ select ARCH_RMOBILE
+ select ARM_ERRATA_754322
+ select RENESAS_INTC_IRQPIN
-config ARCH_R8A77470
- bool "RZ/G1C (R8A77470)"
- select ARCH_RCAR_GEN2
+config ARCH_R8A73A4
+ bool "ARM32 Platform support for R-Mobile APE6"
+ select ARCH_RMOBILE
+ select ARM_ERRATA_798181 if SMP
select ARM_ERRATA_814220
- select SYSC_R8A77470
+ select HAVE_ARM_ARCH_TIMER
+ select RENESAS_IRQC
-config ARCH_R8A7778
- bool "R-Car M1A (R8A77781)"
- select ARCH_RCAR_GEN1
+config ARCH_R7S72100
+ bool "ARM32 Platform support for RZ/A1H"
select ARM_ERRATA_754322
+ select PM
+ select PM_GENERIC_DOMAINS
+ select RENESAS_OSTM
+ select RENESAS_RZA1_IRQC
+ select SYS_SUPPORTS_SH_MTU2
-config ARCH_R8A7779
- bool "R-Car H1 (R8A77790)"
- select ARCH_RCAR_GEN1
- select ARM_ERRATA_754322
- select ARM_GLOBAL_TIMER
- select HAVE_ARM_SCU if SMP
- select HAVE_ARM_TWD if SMP
- select SYSC_R8A7779
+config ARCH_R7S9210
+ bool "ARM32 Platform support for RZ/A2"
+ select PM
+ select PM_GENERIC_DOMAINS
+ select RENESAS_OSTM
+ select RENESAS_RZA1_IRQC
-config ARCH_R8A7790
- bool "R-Car H2 (R8A77900)"
+config ARCH_R8A77470
+ bool "ARM32 Platform support for RZ/G1C"
select ARCH_RCAR_GEN2
- select ARM_ERRATA_798181 if SMP
select ARM_ERRATA_814220
- select I2C
- select SYSC_R8A7790
+ select SYSC_R8A77470
-config ARCH_R8A7791
- bool "R-Car M2-W (R8A77910)"
+config ARCH_R8A7745
+ bool "ARM32 Platform support for RZ/G1E"
select ARCH_RCAR_GEN2
- select ARM_ERRATA_798181 if SMP
- select I2C
- select SYSC_R8A7791
+ select ARM_ERRATA_814220
+ select SYSC_R8A7745
-config ARCH_R8A7792
- bool "R-Car V2H (R8A77920)"
+config ARCH_R8A7742
+ bool "ARM32 Platform support for RZ/G1H"
select ARCH_RCAR_GEN2
select ARM_ERRATA_798181 if SMP
- select SYSC_R8A7792
+ select ARM_ERRATA_814220
+ select SYSC_R8A7742
-config ARCH_R8A7793
- bool "R-Car M2-N (R8A7793)"
+config ARCH_R8A7743
+ bool "ARM32 Platform support for RZ/G1M"
select ARCH_RCAR_GEN2
select ARM_ERRATA_798181 if SMP
- select I2C
- select SYSC_R8A7791
+ select SYSC_R8A7743
-config ARCH_R8A7794
- bool "R-Car E2 (R8A77940)"
+config ARCH_R8A7744
+ bool "ARM32 Platform support for RZ/G1N"
select ARCH_RCAR_GEN2
- select ARM_ERRATA_814220
- select SYSC_R8A7794
+ select ARM_ERRATA_798181 if SMP
+ select SYSC_R8A7743
config ARCH_R9A06G032
- bool "RZ/N1D (R9A06G032)"
+ bool "ARM32 Platform support for RZ/N1D"
select ARCH_RZN1
select ARM_ERRATA_814220
config ARCH_SH73A0
- bool "SH-Mobile AG5 (R8A73A00)"
+ bool "ARM32 Platform support for SH-Mobile AG5"
select ARCH_RMOBILE
select ARM_ERRATA_754322
select ARM_GLOBAL_TIMER
@@ -180,193 +180,201 @@ endif # ARM
if ARM64
-config ARCH_R8A774A1
- bool "Renesas RZ/G2M SoC Platform"
- select ARCH_RCAR_GEN3
- select SYSC_R8A774A1
- help
- This enables support for the Renesas RZ/G2M SoC.
-
-config ARCH_R8A774B1
- bool "Renesas RZ/G2N SoC Platform"
- select ARCH_RCAR_GEN3
- select SYSC_R8A774B1
- help
- This enables support for the Renesas RZ/G2N SoC.
-
-config ARCH_R8A774C0
- bool "Renesas RZ/G2E SoC Platform"
+config ARCH_R8A77995
+ bool "ARM64 Platform support for R-Car D3"
select ARCH_RCAR_GEN3
- select SYSC_R8A774C0
+ select SYSC_R8A77995
help
- This enables support for the Renesas RZ/G2E SoC.
+ This enables support for the Renesas R-Car D3 SoC.
-config ARCH_R8A774E1
- bool "Renesas RZ/G2H SoC Platform"
+config ARCH_R8A77990
+ bool "ARM64 Platform support for R-Car E3"
select ARCH_RCAR_GEN3
- select SYSC_R8A774E1
+ select SYSC_R8A77990
help
- This enables support for the Renesas RZ/G2H SoC.
+ This enables support for the Renesas R-Car E3 SoC.
config ARCH_R8A77950
- bool "Renesas R-Car H3 ES1.x SoC Platform"
+ bool "ARM64 Platform support for R-Car H3 ES1.x"
select ARCH_RCAR_GEN3
select SYSC_R8A7795
help
This enables support for the Renesas R-Car H3 SoC (revision 1.x).
config ARCH_R8A77951
- bool "Renesas R-Car H3 ES2.0+ SoC Platform"
+ bool "ARM64 Platform support for R-Car H3 ES2.0+"
select ARCH_RCAR_GEN3
select SYSC_R8A7795
help
This enables support for the Renesas R-Car H3 SoC (revisions 2.0 and
later).
+config ARCH_R8A77965
+ bool "ARM64 Platform support for R-Car M3-N"
+ select ARCH_RCAR_GEN3
+ select SYSC_R8A77965
+ help
+ This enables support for the Renesas R-Car M3-N SoC.
+
config ARCH_R8A77960
- bool "Renesas R-Car M3-W SoC Platform"
+ bool "ARM64 Platform support for R-Car M3-W"
select ARCH_RCAR_GEN3
select SYSC_R8A77960
help
This enables support for the Renesas R-Car M3-W SoC.
config ARCH_R8A77961
- bool "Renesas R-Car M3-W+ SoC Platform"
+ bool "ARM64 Platform support for R-Car M3-W+"
select ARCH_RCAR_GEN3
select SYSC_R8A77961
help
This enables support for the Renesas R-Car M3-W+ SoC.
-config ARCH_R8A77965
- bool "Renesas R-Car M3-N SoC Platform"
+config ARCH_R8A77980
+ bool "ARM64 Platform support for R-Car V3H"
select ARCH_RCAR_GEN3
- select SYSC_R8A77965
+ select SYSC_R8A77980
help
- This enables support for the Renesas R-Car M3-N SoC.
+ This enables support for the Renesas R-Car V3H SoC.
config ARCH_R8A77970
- bool "Renesas R-Car V3M SoC Platform"
+ bool "ARM64 Platform support for R-Car V3M"
select ARCH_RCAR_GEN3
select SYSC_R8A77970
help
This enables support for the Renesas R-Car V3M SoC.
-config ARCH_R8A77980
- bool "Renesas R-Car V3H SoC Platform"
+config ARCH_R8A779A0
+ bool "ARM64 Platform support for R-Car V3U"
select ARCH_RCAR_GEN3
- select SYSC_R8A77980
+ select SYSC_R8A779A0
help
- This enables support for the Renesas R-Car V3H SoC.
+ This enables support for the Renesas R-Car V3U SoC.
-config ARCH_R8A77990
- bool "Renesas R-Car E3 SoC Platform"
+config ARCH_R8A774C0
+ bool "ARM64 Platform support for RZ/G2E"
select ARCH_RCAR_GEN3
- select SYSC_R8A77990
+ select SYSC_R8A774C0
help
- This enables support for the Renesas R-Car E3 SoC.
+ This enables support for the Renesas RZ/G2E SoC.
-config ARCH_R8A77995
- bool "Renesas R-Car D3 SoC Platform"
+config ARCH_R8A774E1
+ bool "ARM64 Platform support for RZ/G2H"
select ARCH_RCAR_GEN3
- select SYSC_R8A77995
+ select SYSC_R8A774E1
help
- This enables support for the Renesas R-Car D3 SoC.
+ This enables support for the Renesas RZ/G2H SoC.
+
+config ARCH_R8A774A1
+ bool "ARM64 Platform support for RZ/G2M"
+ select ARCH_RCAR_GEN3
+ select SYSC_R8A774A1
+ help
+ This enables support for the Renesas RZ/G2M SoC.
+
+config ARCH_R8A774B1
+ bool "ARM64 Platform support for RZ/G2N"
+ select ARCH_RCAR_GEN3
+ select SYSC_R8A774B1
+ help
+ This enables support for the Renesas RZ/G2N SoC.
endif # ARM64
-# SoC
-config SYSC_R8A7742
- bool "RZ/G1H System Controller support" if COMPILE_TEST
- select SYSC_RCAR
+config RST_RCAR
+ bool "Reset Controller support for R-Car" if COMPILE_TEST
-config SYSC_R8A7743
- bool "RZ/G1M System Controller support" if COMPILE_TEST
+config SYSC_RCAR
+ bool "System Controller support for R-Car" if COMPILE_TEST
+
+config SYSC_R8A77995
+ bool "System Controller support for R-Car D3" if COMPILE_TEST
select SYSC_RCAR
-config SYSC_R8A7745
- bool "RZ/G1E System Controller support" if COMPILE_TEST
+config SYSC_R8A7794
+ bool "System Controller support for R-Car E2" if COMPILE_TEST
select SYSC_RCAR
-config SYSC_R8A77470
- bool "RZ/G1C System Controller support" if COMPILE_TEST
+config SYSC_R8A77990
+ bool "System Controller support for R-Car E3" if COMPILE_TEST
select SYSC_RCAR
-config SYSC_R8A774A1
- bool "RZ/G2M System Controller support" if COMPILE_TEST
+config SYSC_R8A7779
+ bool "System Controller support for R-Car H1" if COMPILE_TEST
select SYSC_RCAR
-config SYSC_R8A774B1
- bool "RZ/G2N System Controller support" if COMPILE_TEST
+config SYSC_R8A7790
+ bool "System Controller support for R-Car H2" if COMPILE_TEST
select SYSC_RCAR
-config SYSC_R8A774C0
- bool "RZ/G2E System Controller support" if COMPILE_TEST
+config SYSC_R8A7795
+ bool "System Controller support for R-Car H3" if COMPILE_TEST
select SYSC_RCAR
-config SYSC_R8A774E1
- bool "RZ/G2H System Controller support" if COMPILE_TEST
+config SYSC_R8A7791
+ bool "System Controller support for R-Car M2-W/N" if COMPILE_TEST
select SYSC_RCAR
-config SYSC_R8A7779
- bool "R-Car H1 System Controller support" if COMPILE_TEST
+config SYSC_R8A77965
+ bool "System Controller support for R-Car M3-N" if COMPILE_TEST
select SYSC_RCAR
-config SYSC_R8A7790
- bool "R-Car H2 System Controller support" if COMPILE_TEST
+config SYSC_R8A77960
+ bool "System Controller support for R-Car M3-W" if COMPILE_TEST
select SYSC_RCAR
-config SYSC_R8A7791
- bool "R-Car M2-W/N System Controller support" if COMPILE_TEST
+config SYSC_R8A77961
+ bool "System Controller support for R-Car M3-W+" if COMPILE_TEST
select SYSC_RCAR
config SYSC_R8A7792
- bool "R-Car V2H System Controller support" if COMPILE_TEST
+ bool "System Controller support for R-Car V2H" if COMPILE_TEST
select SYSC_RCAR
-config SYSC_R8A7794
- bool "R-Car E2 System Controller support" if COMPILE_TEST
+config SYSC_R8A77980
+ bool "System Controller support for R-Car V3H" if COMPILE_TEST
select SYSC_RCAR
-config SYSC_R8A7795
- bool "R-Car H3 System Controller support" if COMPILE_TEST
+config SYSC_R8A77970
+ bool "System Controller support for R-Car V3M" if COMPILE_TEST
select SYSC_RCAR
-config SYSC_R8A77960
- bool "R-Car M3-W System Controller support" if COMPILE_TEST
- select SYSC_RCAR
+config SYSC_R8A779A0
+ bool "System Controller support for R-Car V3U" if COMPILE_TEST
-config SYSC_R8A77961
- bool "R-Car M3-W+ System Controller support" if COMPILE_TEST
- select SYSC_RCAR
+config SYSC_RMOBILE
+ bool "System Controller support for R-Mobile" if COMPILE_TEST
-config SYSC_R8A77965
- bool "R-Car M3-N System Controller support" if COMPILE_TEST
+config SYSC_R8A77470
+ bool "System Controller support for RZ/G1C" if COMPILE_TEST
select SYSC_RCAR
-config SYSC_R8A77970
- bool "R-Car V3M System Controller support" if COMPILE_TEST
+config SYSC_R8A7745
+ bool "System Controller support for RZ/G1E" if COMPILE_TEST
select SYSC_RCAR
-config SYSC_R8A77980
- bool "R-Car V3H System Controller support" if COMPILE_TEST
+config SYSC_R8A7742
+ bool "System Controller support for RZ/G1H" if COMPILE_TEST
select SYSC_RCAR
-config SYSC_R8A77990
- bool "R-Car E3 System Controller support" if COMPILE_TEST
+config SYSC_R8A7743
+ bool "System Controller support for RZ/G1M" if COMPILE_TEST
select SYSC_RCAR
-config SYSC_R8A77995
- bool "R-Car D3 System Controller support" if COMPILE_TEST
+config SYSC_R8A774C0
+ bool "System Controller support for RZ/G2E" if COMPILE_TEST
select SYSC_RCAR
-# Family
-config RST_RCAR
- bool "R-Car Reset Controller support" if COMPILE_TEST
+config SYSC_R8A774E1
+ bool "System Controller support for RZ/G2H" if COMPILE_TEST
+ select SYSC_RCAR
-config SYSC_RCAR
- bool "R-Car System Controller support" if COMPILE_TEST
+config SYSC_R8A774A1
+ bool "System Controller support for RZ/G2M" if COMPILE_TEST
+ select SYSC_RCAR
-config SYSC_RMOBILE
- bool "R-Mobile System Controller support" if COMPILE_TEST
+config SYSC_R8A774B1
+ bool "System Controller support for RZ/G2N" if COMPILE_TEST
+ select SYSC_RCAR
endif # SOC_RENESAS
diff --git a/drivers/soc/renesas/Makefile b/drivers/soc/renesas/Makefile
index 10a399fc486a..9b29bed2a597 100644
--- a/drivers/soc/renesas/Makefile
+++ b/drivers/soc/renesas/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_SYSC_R8A77970) += r8a77970-sysc.o
obj-$(CONFIG_SYSC_R8A77980) += r8a77980-sysc.o
obj-$(CONFIG_SYSC_R8A77990) += r8a77990-sysc.o
obj-$(CONFIG_SYSC_R8A77995) += r8a77995-sysc.o
+obj-$(CONFIG_SYSC_R8A779A0) += r8a779a0-sysc.o
ifdef CONFIG_SMP
obj-$(CONFIG_ARCH_R9A06G032) += r9a06g032-smp.o
endif
diff --git a/drivers/soc/renesas/r8a779a0-sysc.c b/drivers/soc/renesas/r8a779a0-sysc.c
new file mode 100644
index 000000000000..d464ffa1be33
--- /dev/null
+++ b/drivers/soc/renesas/r8a779a0-sysc.c
@@ -0,0 +1,448 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas R-Car V3U System Controller
+ *
+ * Copyright (C) 2020 Renesas Electronics Corp.
+ */
+
+#include <linux/bits.h>
+#include <linux/clk/renesas.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/of_address.h>
+#include <linux/pm_domain.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include <dt-bindings/power/r8a779a0-sysc.h>
+
+/*
+ * Power Domain flags
+ */
+#define PD_CPU BIT(0) /* Area contains main CPU core */
+#define PD_SCU BIT(1) /* Area contains SCU and L2 cache */
+#define PD_NO_CR BIT(2) /* Area lacks PWR{ON,OFF}CR registers */
+
+#define PD_CPU_NOCR PD_CPU | PD_NO_CR /* CPU area lacks CR */
+#define PD_ALWAYS_ON PD_NO_CR /* Always-on area */
+
+/*
+ * Description of a Power Area
+ */
+struct r8a779a0_sysc_area {
+ const char *name;
+ u8 pdr; /* PDRn */
+ int parent; /* -1 if none */
+ unsigned int flags; /* See PD_* */
+};
+
+/*
+ * SoC-specific Power Area Description
+ */
+struct r8a779a0_sysc_info {
+ const struct r8a779a0_sysc_area *areas;
+ unsigned int num_areas;
+};
+
+static struct r8a779a0_sysc_area r8a779a0_areas[] __initdata = {
+ { "always-on", R8A779A0_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
+ { "a3e0", R8A779A0_PD_A3E0, R8A779A0_PD_ALWAYS_ON, PD_SCU },
+ { "a3e1", R8A779A0_PD_A3E1, R8A779A0_PD_ALWAYS_ON, PD_SCU },
+ { "a2e0d0", R8A779A0_PD_A2E0D0, R8A779A0_PD_A3E0, PD_SCU },
+ { "a2e0d1", R8A779A0_PD_A2E0D1, R8A779A0_PD_A3E0, PD_SCU },
+ { "a2e1d0", R8A779A0_PD_A2E1D0, R8A779A0_PD_A3E1, PD_SCU },
+ { "a2e1d1", R8A779A0_PD_A2E1D1, R8A779A0_PD_A3E1, PD_SCU },
+ { "a1e0d0c0", R8A779A0_PD_A1E0D0C0, R8A779A0_PD_A2E0D0, PD_CPU_NOCR },
+ { "a1e0d0c1", R8A779A0_PD_A1E0D0C1, R8A779A0_PD_A2E0D0, PD_CPU_NOCR },
+ { "a1e0d1c0", R8A779A0_PD_A1E0D1C0, R8A779A0_PD_A2E0D1, PD_CPU_NOCR },
+ { "a1e0d1c1", R8A779A0_PD_A1E0D1C1, R8A779A0_PD_A2E0D1, PD_CPU_NOCR },
+ { "a1e1d0c0", R8A779A0_PD_A1E1D0C0, R8A779A0_PD_A2E1D0, PD_CPU_NOCR },
+ { "a1e1d0c1", R8A779A0_PD_A1E1D0C1, R8A779A0_PD_A2E1D0, PD_CPU_NOCR },
+ { "a1e1d1c0", R8A779A0_PD_A1E1D1C0, R8A779A0_PD_A2E1D1, PD_CPU_NOCR },
+ { "a1e1d1c1", R8A779A0_PD_A1E1D1C1, R8A779A0_PD_A2E1D1, PD_CPU_NOCR },
+ { "3dg-a", R8A779A0_PD_3DG_A, R8A779A0_PD_ALWAYS_ON },
+ { "3dg-b", R8A779A0_PD_3DG_B, R8A779A0_PD_3DG_A },
+ { "a3vip0", R8A779A0_PD_A3VIP0, R8A779A0_PD_ALWAYS_ON },
+ { "a3vip1", R8A779A0_PD_A3VIP1, R8A779A0_PD_ALWAYS_ON },
+ { "a3vip3", R8A779A0_PD_A3VIP3, R8A779A0_PD_ALWAYS_ON },
+ { "a3vip2", R8A779A0_PD_A3VIP2, R8A779A0_PD_ALWAYS_ON },
+ { "a3isp01", R8A779A0_PD_A3ISP01, R8A779A0_PD_ALWAYS_ON },
+ { "a3isp23", R8A779A0_PD_A3ISP23, R8A779A0_PD_ALWAYS_ON },
+ { "a3ir", R8A779A0_PD_A3IR, R8A779A0_PD_ALWAYS_ON },
+ { "a2cn0", R8A779A0_PD_A2CN0, R8A779A0_PD_A3IR },
+ { "a2imp01", R8A779A0_PD_A2IMP01, R8A779A0_PD_A3IR },
+ { "a2dp0", R8A779A0_PD_A2DP0, R8A779A0_PD_A3IR },
+ { "a2cv0", R8A779A0_PD_A2CV0, R8A779A0_PD_A3IR },
+ { "a2cv1", R8A779A0_PD_A2CV1, R8A779A0_PD_A3IR },
+ { "a2cv4", R8A779A0_PD_A2CV4, R8A779A0_PD_A3IR },
+ { "a2cv6", R8A779A0_PD_A2CV6, R8A779A0_PD_A3IR },
+ { "a2cn2", R8A779A0_PD_A2CN2, R8A779A0_PD_A3IR },
+ { "a2imp23", R8A779A0_PD_A2IMP23, R8A779A0_PD_A3IR },
+ { "a2dp1", R8A779A0_PD_A2DP0, R8A779A0_PD_A3IR },
+ { "a2cv2", R8A779A0_PD_A2CV0, R8A779A0_PD_A3IR },
+ { "a2cv3", R8A779A0_PD_A2CV1, R8A779A0_PD_A3IR },
+ { "a2cv5", R8A779A0_PD_A2CV4, R8A779A0_PD_A3IR },
+ { "a2cv7", R8A779A0_PD_A2CV6, R8A779A0_PD_A3IR },
+ { "a2cn1", R8A779A0_PD_A2CN1, R8A779A0_PD_A3IR },
+ { "a1cnn0", R8A779A0_PD_A1CNN0, R8A779A0_PD_A2CN0 },
+ { "a1cnn2", R8A779A0_PD_A1CNN2, R8A779A0_PD_A2CN2 },
+ { "a1dsp0", R8A779A0_PD_A1DSP0, R8A779A0_PD_A2CN2 },
+ { "a1cnn1", R8A779A0_PD_A1CNN1, R8A779A0_PD_A2CN1 },
+ { "a1dsp1", R8A779A0_PD_A1DSP1, R8A779A0_PD_A2CN1 },
+};
+
+static const struct r8a779a0_sysc_info r8a779a0_sysc_info __initconst = {
+ .areas = r8a779a0_areas,
+ .num_areas = ARRAY_SIZE(r8a779a0_areas),
+};
+
+/* SYSC Common */
+#define SYSCSR 0x000 /* SYSC Status Register */
+#define SYSCPONSR(x) (0x800 + ((x) * 0x4)) /* Power-ON Status Register 0 */
+#define SYSCPOFFSR(x) (0x808 + ((x) * 0x4)) /* Power-OFF Status Register */
+#define SYSCISCR(x) (0x810 + ((x) * 0x4)) /* Interrupt Status/Clear Register */
+#define SYSCIER(x) (0x820 + ((x) * 0x4)) /* Interrupt Enable Register */
+#define SYSCIMR(x) (0x830 + ((x) * 0x4)) /* Interrupt Mask Register */
+
+/* Power Domain Registers */
+#define PDRSR(n) (0x1000 + ((n) * 0x40))
+#define PDRONCR(n) (0x1004 + ((n) * 0x40))
+#define PDROFFCR(n) (0x1008 + ((n) * 0x40))
+#define PDRESR(n) (0x100C + ((n) * 0x40))
+
+/* PWRON/PWROFF */
+#define PWRON_PWROFF BIT(0) /* Power-ON/OFF request */
+
+/* PDRESR */
+#define PDRESR_ERR BIT(0)
+
+/* PDRSR */
+#define PDRSR_OFF BIT(0) /* Power-OFF state */
+#define PDRSR_ON BIT(4) /* Power-ON state */
+#define PDRSR_OFF_STATE BIT(8) /* Processing Power-OFF sequence */
+#define PDRSR_ON_STATE BIT(12) /* Processing Power-ON sequence */
+
+#define SYSCSR_BUSY GENMASK(1, 0) /* All bit sets is not busy */
+
+#define SYSCSR_TIMEOUT 10000
+#define SYSCSR_DELAY_US 10
+
+#define PDRESR_RETRIES 1000
+#define PDRESR_DELAY_US 10
+
+#define SYSCISR_TIMEOUT 10000
+#define SYSCISR_DELAY_US 10
+
+#define NUM_DOMAINS_EACH_REG BITS_PER_TYPE(u32)
+
+static void __iomem *r8a779a0_sysc_base;
+static DEFINE_SPINLOCK(r8a779a0_sysc_lock); /* SMP CPUs + I/O devices */
+
+static int r8a779a0_sysc_pwr_on_off(u8 pdr, bool on)
+{
+ unsigned int reg_offs;
+ u32 val;
+ int ret;
+
+ if (on)
+ reg_offs = PDRONCR(pdr);
+ else
+ reg_offs = PDROFFCR(pdr);
+
+ /* Wait until SYSC is ready to accept a power request */
+ ret = readl_poll_timeout_atomic(r8a779a0_sysc_base + SYSCSR, val,
+ (val & SYSCSR_BUSY) == SYSCSR_BUSY,
+ SYSCSR_DELAY_US, SYSCSR_TIMEOUT);
+ if (ret < 0)
+ return -EAGAIN;
+
+ /* Submit power shutoff or power resume request */
+ iowrite32(PWRON_PWROFF, r8a779a0_sysc_base + reg_offs);
+
+ return 0;
+}
+
+static int clear_irq_flags(unsigned int reg_idx, unsigned int isr_mask)
+{
+ u32 val;
+ int ret;
+
+ iowrite32(isr_mask, r8a779a0_sysc_base + SYSCISCR(reg_idx));
+
+ ret = readl_poll_timeout_atomic(r8a779a0_sysc_base + SYSCISCR(reg_idx),
+ val, !(val & isr_mask),
+ SYSCISR_DELAY_US, SYSCISR_TIMEOUT);
+ if (ret < 0) {
+ pr_err("\n %s : Can not clear IRQ flags in SYSCISCR", __func__);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int r8a779a0_sysc_power(u8 pdr, bool on)
+{
+ unsigned int isr_mask;
+ unsigned int reg_idx, bit_idx;
+ unsigned int status;
+ unsigned long flags;
+ int ret = 0;
+ u32 val;
+ int k;
+
+ spin_lock_irqsave(&r8a779a0_sysc_lock, flags);
+
+ reg_idx = pdr / NUM_DOMAINS_EACH_REG;
+ bit_idx = pdr % NUM_DOMAINS_EACH_REG;
+
+ isr_mask = BIT(bit_idx);
+
+ /*
+ * The interrupt source needs to be enabled, but masked, to prevent the
+ * CPU from receiving it.
+ */
+ iowrite32(ioread32(r8a779a0_sysc_base + SYSCIER(reg_idx)) | isr_mask,
+ r8a779a0_sysc_base + SYSCIER(reg_idx));
+ iowrite32(ioread32(r8a779a0_sysc_base + SYSCIMR(reg_idx)) | isr_mask,
+ r8a779a0_sysc_base + SYSCIMR(reg_idx));
+
+ ret = clear_irq_flags(reg_idx, isr_mask);
+ if (ret)
+ goto out;
+
+ /* Submit power shutoff or resume request until it was accepted */
+ for (k = 0; k < PDRESR_RETRIES; k++) {
+ ret = r8a779a0_sysc_pwr_on_off(pdr, on);
+ if (ret)
+ goto out;
+
+ status = ioread32(r8a779a0_sysc_base + PDRESR(pdr));
+ if (!(status & PDRESR_ERR))
+ break;
+
+ udelay(PDRESR_DELAY_US);
+ }
+
+ if (k == PDRESR_RETRIES) {
+ ret = -EIO;
+ goto out;
+ }
+
+ /* Wait until the power shutoff or resume request has completed * */
+ ret = readl_poll_timeout_atomic(r8a779a0_sysc_base + SYSCISCR(reg_idx),
+ val, (val & isr_mask),
+ SYSCISR_DELAY_US, SYSCISR_TIMEOUT);
+ if (ret < 0) {
+ ret = -EIO;
+ goto out;
+ }
+
+ /* Clear interrupt flags */
+ ret = clear_irq_flags(reg_idx, isr_mask);
+ if (ret)
+ goto out;
+
+ out:
+ spin_unlock_irqrestore(&r8a779a0_sysc_lock, flags);
+
+ pr_debug("sysc power %s domain %d: %08x -> %d\n", on ? "on" : "off",
+ pdr, ioread32(r8a779a0_sysc_base + SYSCISCR(reg_idx)), ret);
+ return ret;
+}
+
+static bool r8a779a0_sysc_power_is_off(u8 pdr)
+{
+ unsigned int st;
+
+ st = ioread32(r8a779a0_sysc_base + PDRSR(pdr));
+
+ if (st & PDRSR_OFF)
+ return true;
+
+ return false;
+}
+
+struct r8a779a0_sysc_pd {
+ struct generic_pm_domain genpd;
+ u8 pdr;
+ unsigned int flags;
+ char name[];
+};
+
+static inline struct r8a779a0_sysc_pd *to_r8a779a0_pd(struct generic_pm_domain *d)
+{
+ return container_of(d, struct r8a779a0_sysc_pd, genpd);
+}
+
+static int r8a779a0_sysc_pd_power_off(struct generic_pm_domain *genpd)
+{
+ struct r8a779a0_sysc_pd *pd = to_r8a779a0_pd(genpd);
+
+ pr_debug("%s: %s\n", __func__, genpd->name);
+ return r8a779a0_sysc_power(pd->pdr, false);
+}
+
+static int r8a779a0_sysc_pd_power_on(struct generic_pm_domain *genpd)
+{
+ struct r8a779a0_sysc_pd *pd = to_r8a779a0_pd(genpd);
+
+ pr_debug("%s: %s\n", __func__, genpd->name);
+ return r8a779a0_sysc_power(pd->pdr, true);
+}
+
+static int __init r8a779a0_sysc_pd_setup(struct r8a779a0_sysc_pd *pd)
+{
+ struct generic_pm_domain *genpd = &pd->genpd;
+ const char *name = pd->genpd.name;
+ int error;
+
+ if (pd->flags & PD_CPU) {
+ /*
+ * This domain contains a CPU core and therefore it should
+ * only be turned off if the CPU is not in use.
+ */
+ pr_debug("PM domain %s contains %s\n", name, "CPU");
+ genpd->flags |= GENPD_FLAG_ALWAYS_ON;
+ } else if (pd->flags & PD_SCU) {
+ /*
+ * This domain contains an SCU and cache-controller, and
+ * therefore it should only be turned off if the CPU cores are
+ * not in use.
+ */
+ pr_debug("PM domain %s contains %s\n", name, "SCU");
+ genpd->flags |= GENPD_FLAG_ALWAYS_ON;
+ } else if (pd->flags & PD_NO_CR) {
+ /*
+ * This domain cannot be turned off.
+ */
+ genpd->flags |= GENPD_FLAG_ALWAYS_ON;
+ }
+
+ if (!(pd->flags & (PD_CPU | PD_SCU))) {
+ /* Enable Clock Domain for I/O devices */
+ genpd->flags |= GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP;
+ genpd->attach_dev = cpg_mssr_attach_dev;
+ genpd->detach_dev = cpg_mssr_detach_dev;
+ }
+
+ genpd->power_off = r8a779a0_sysc_pd_power_off;
+ genpd->power_on = r8a779a0_sysc_pd_power_on;
+
+ if (pd->flags & (PD_CPU | PD_NO_CR)) {
+ /* Skip CPUs (handled by SMP code) and areas without control */
+ pr_debug("%s: Not touching %s\n", __func__, genpd->name);
+ goto finalize;
+ }
+
+ if (!r8a779a0_sysc_power_is_off(pd->pdr)) {
+ pr_debug("%s: %s is already powered\n", __func__, genpd->name);
+ goto finalize;
+ }
+
+ r8a779a0_sysc_power(pd->pdr, true);
+
+finalize:
+ error = pm_genpd_init(genpd, &simple_qos_governor, false);
+ if (error)
+ pr_err("Failed to init PM domain %s: %d\n", name, error);
+
+ return error;
+}
+
+static const struct of_device_id r8a779a0_sysc_matches[] __initconst = {
+ { .compatible = "renesas,r8a779a0-sysc", .data = &r8a779a0_sysc_info },
+ { /* sentinel */ }
+};
+
+struct r8a779a0_pm_domains {
+ struct genpd_onecell_data onecell_data;
+ struct generic_pm_domain *domains[R8A779A0_PD_ALWAYS_ON + 1];
+};
+
+static struct genpd_onecell_data *r8a779a0_sysc_onecell_data;
+
+static int __init r8a779a0_sysc_pd_init(void)
+{
+ const struct r8a779a0_sysc_info *info;
+ const struct of_device_id *match;
+ struct r8a779a0_pm_domains *domains;
+ struct device_node *np;
+ void __iomem *base;
+ unsigned int i;
+ int error;
+
+ np = of_find_matching_node_and_match(NULL, r8a779a0_sysc_matches, &match);
+ if (!np)
+ return -ENODEV;
+
+ info = match->data;
+
+ base = of_iomap(np, 0);
+ if (!base) {
+ pr_warn("%pOF: Cannot map regs\n", np);
+ error = -ENOMEM;
+ goto out_put;
+ }
+
+ r8a779a0_sysc_base = base;
+
+ domains = kzalloc(sizeof(*domains), GFP_KERNEL);
+ if (!domains) {
+ error = -ENOMEM;
+ goto out_put;
+ }
+
+ domains->onecell_data.domains = domains->domains;
+ domains->onecell_data.num_domains = ARRAY_SIZE(domains->domains);
+ r8a779a0_sysc_onecell_data = &domains->onecell_data;
+
+ for (i = 0; i < info->num_areas; i++) {
+ const struct r8a779a0_sysc_area *area = &info->areas[i];
+ struct r8a779a0_sysc_pd *pd;
+
+ if (!area->name) {
+ /* Skip NULLified area */
+ continue;
+ }
+
+ pd = kzalloc(sizeof(*pd) + strlen(area->name) + 1, GFP_KERNEL);
+ if (!pd) {
+ error = -ENOMEM;
+ goto out_put;
+ }
+
+ strcpy(pd->name, area->name);
+ pd->genpd.name = pd->name;
+ pd->pdr = area->pdr;
+ pd->flags = area->flags;
+
+ error = r8a779a0_sysc_pd_setup(pd);
+ if (error)
+ goto out_put;
+
+ domains->domains[area->pdr] = &pd->genpd;
+
+ if (area->parent < 0)
+ continue;
+
+ error = pm_genpd_add_subdomain(domains->domains[area->parent],
+ &pd->genpd);
+ if (error) {
+ pr_warn("Failed to add PM subdomain %s to parent %u\n",
+ area->name, area->parent);
+ goto out_put;
+ }
+ }
+
+ error = of_genpd_add_provider_onecell(np, &domains->onecell_data);
+
+out_put:
+ of_node_put(np);
+ return error;
+}
+early_initcall(r8a779a0_sysc_pd_init);
diff --git a/drivers/soc/renesas/rcar-rst.c b/drivers/soc/renesas/rcar-rst.c
index a932015ce9c1..8a1e402ea799 100644
--- a/drivers/soc/renesas/rcar-rst.c
+++ b/drivers/soc/renesas/rcar-rst.c
@@ -37,6 +37,10 @@ static const struct rst_config rcar_rst_gen3 __initconst = {
.modemr = 0x60,
};
+static const struct rst_config rcar_rst_r8a779a0 __initconst = {
+ .modemr = 0x00, /* MODEMR0 and it has CPG related bits */
+};
+
static const struct of_device_id rcar_rst_matches[] __initconst = {
/* RZ/G1 is handled like R-Car Gen2 */
{ .compatible = "renesas,r8a7742-rst", .data = &rcar_rst_gen2 },
@@ -67,6 +71,8 @@ static const struct of_device_id rcar_rst_matches[] __initconst = {
{ .compatible = "renesas,r8a77980-rst", .data = &rcar_rst_gen3 },
{ .compatible = "renesas,r8a77990-rst", .data = &rcar_rst_gen3 },
{ .compatible = "renesas,r8a77995-rst", .data = &rcar_rst_gen3 },
+ /* R-Car V3U */
+ { .compatible = "renesas,r8a779a0-rst", .data = &rcar_rst_r8a779a0 },
{ /* sentinel */ }
};
diff --git a/drivers/soc/renesas/renesas-soc.c b/drivers/soc/renesas/renesas-soc.c
index f815a6a8b88b..0f8eff4a641a 100644
--- a/drivers/soc/renesas/renesas-soc.c
+++ b/drivers/soc/renesas/renesas-soc.c
@@ -200,6 +200,11 @@ static const struct renesas_soc soc_rcar_d3 __initconst __maybe_unused = {
.id = 0x58,
};
+static const struct renesas_soc soc_rcar_v3u __initconst __maybe_unused = {
+ .family = &fam_rcar_gen3,
+ .id = 0x59,
+};
+
static const struct renesas_soc soc_shmobile_ag5 __initconst __maybe_unused = {
.family = &fam_shmobile,
.id = 0x37,
@@ -291,6 +296,9 @@ static const struct of_device_id renesas_socs[] __initconst = {
#ifdef CONFIG_ARCH_R8A77995
{ .compatible = "renesas,r8a77995", .data = &soc_rcar_d3 },
#endif
+#ifdef CONFIG_ARCH_R8A779A0
+ { .compatible = "renesas,r8a779a0", .data = &soc_rcar_v3u },
+#endif
#ifdef CONFIG_ARCH_SH73A0
{ .compatible = "renesas,sh73a0", .data = &soc_shmobile_ag5 },
#endif
diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c
index 1b0d50f36349..d4c7bd59429e 100644
--- a/drivers/soc/sunxi/sunxi_sram.c
+++ b/drivers/soc/sunxi/sunxi_sram.c
@@ -194,7 +194,7 @@ static const struct sunxi_sram_data *sunxi_sram_of_parse(struct device_node *nod
if (!data) {
ret = -EINVAL;
goto err;
- };
+ }
for (func = data->func; func->func; func++) {
if (val == func->val) {
diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c
index d1f8dd0289e6..94b60a692b51 100644
--- a/drivers/soc/tegra/fuse/fuse-tegra.c
+++ b/drivers/soc/tegra/fuse/fuse-tegra.c
@@ -49,6 +49,9 @@ static struct tegra_fuse *fuse = &(struct tegra_fuse) {
};
static const struct of_device_id tegra_fuse_match[] = {
+#ifdef CONFIG_ARCH_TEGRA_234_SOC
+ { .compatible = "nvidia,tegra234-efuse", .data = &tegra234_fuse_soc },
+#endif
#ifdef CONFIG_ARCH_TEGRA_194_SOC
{ .compatible = "nvidia,tegra194-efuse", .data = &tegra194_fuse_soc },
#endif
@@ -326,7 +329,8 @@ const struct attribute_group tegra_soc_attr_group = {
.attrs = tegra_soc_attr,
};
-#ifdef CONFIG_ARCH_TEGRA_194_SOC
+#if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \
+ IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC)
static ssize_t platform_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -336,7 +340,7 @@ static ssize_t platform_show(struct device *dev, struct device_attribute *attr,
* platform type is silicon and all other non-zero values indicate
* the type of simulation platform is being used.
*/
- return sprintf(buf, "%d\n", (tegra_read_chipid() >> 20) & 0xf);
+ return sprintf(buf, "%d\n", tegra_get_platform());
}
static DEVICE_ATTR_RO(platform);
diff --git a/drivers/soc/tegra/fuse/fuse-tegra30.c b/drivers/soc/tegra/fuse/fuse-tegra30.c
index 85accef41fa1..9ea7f0168457 100644
--- a/drivers/soc/tegra/fuse/fuse-tegra30.c
+++ b/drivers/soc/tegra/fuse/fuse-tegra30.c
@@ -356,3 +356,33 @@ const struct tegra_fuse_soc tegra194_fuse_soc = {
.soc_attr_group = &tegra194_soc_attr_group,
};
#endif
+
+#if defined(CONFIG_ARCH_TEGRA_234_SOC)
+static const struct nvmem_cell_lookup tegra234_fuse_lookups[] = {
+ {
+ .nvmem_name = "fuse",
+ .cell_name = "xusb-pad-calibration",
+ .dev_id = "3520000.padctl",
+ .con_id = "calibration",
+ }, {
+ .nvmem_name = "fuse",
+ .cell_name = "xusb-pad-calibration-ext",
+ .dev_id = "3520000.padctl",
+ .con_id = "calibration-ext",
+ },
+};
+
+static const struct tegra_fuse_info tegra234_fuse_info = {
+ .read = tegra30_fuse_read,
+ .size = 0x300,
+ .spare = 0x280,
+};
+
+const struct tegra_fuse_soc tegra234_fuse_soc = {
+ .init = tegra30_fuse_init,
+ .info = &tegra234_fuse_info,
+ .lookups = tegra234_fuse_lookups,
+ .num_lookups = ARRAY_SIZE(tegra234_fuse_lookups),
+ .soc_attr_group = &tegra194_soc_attr_group,
+};
+#endif
diff --git a/drivers/soc/tegra/fuse/fuse.h b/drivers/soc/tegra/fuse/fuse.h
index 9d4fc315a007..e057a58e2060 100644
--- a/drivers/soc/tegra/fuse/fuse.h
+++ b/drivers/soc/tegra/fuse/fuse.h
@@ -115,9 +115,17 @@ extern const struct tegra_fuse_soc tegra210_fuse_soc;
extern const struct tegra_fuse_soc tegra186_fuse_soc;
#endif
+#if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \
+ IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC)
+extern const struct attribute_group tegra194_soc_attr_group;
+#endif
+
#ifdef CONFIG_ARCH_TEGRA_194_SOC
extern const struct tegra_fuse_soc tegra194_fuse_soc;
-extern const struct attribute_group tegra194_soc_attr_group;
+#endif
+
+#ifdef CONFIG_ARCH_TEGRA_234_SOC
+extern const struct tegra_fuse_soc tegra234_fuse_soc;
#endif
#endif
diff --git a/drivers/soc/tegra/fuse/tegra-apbmisc.c b/drivers/soc/tegra/fuse/tegra-apbmisc.c
index 8e416ad91ee2..cee207d10024 100644
--- a/drivers/soc/tegra/fuse/tegra-apbmisc.c
+++ b/drivers/soc/tegra/fuse/tegra-apbmisc.c
@@ -47,6 +47,31 @@ u8 tegra_get_minor_rev(void)
return (tegra_read_chipid() >> 16) & 0xf;
}
+u8 tegra_get_platform(void)
+{
+ return (tegra_read_chipid() >> 20) & 0xf;
+}
+
+bool tegra_is_silicon(void)
+{
+ switch (tegra_get_chip_id()) {
+ case TEGRA194:
+ case TEGRA234:
+ if (tegra_get_platform() == 0)
+ return true;
+
+ return false;
+ }
+
+ /*
+ * Chips prior to Tegra194 have a different way of determining whether
+ * they are silicon or not. Since we never supported simulation on the
+ * older Tegra chips, don't bother extracting the information and just
+ * report that we're running on silicon.
+ */
+ return true;
+}
+
u32 tegra_read_straps(void)
{
WARN(!chipid, "Tegra ABP MISC not yet available\n");
@@ -70,6 +95,7 @@ static const struct of_device_id apbmisc_match[] __initconst = {
{ .compatible = "nvidia,tegra20-apbmisc", },
{ .compatible = "nvidia,tegra186-misc", },
{ .compatible = "nvidia,tegra194-misc", },
+ { .compatible = "nvidia,tegra234-misc", },
{},
};
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index b0bba8ab75bb..df9a5ca8c99c 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -336,45 +336,6 @@ struct tegra_pmc_soc {
bool has_blink_output;
};
-static const char * const tegra186_reset_sources[] = {
- "SYS_RESET",
- "AOWDT",
- "MCCPLEXWDT",
- "BPMPWDT",
- "SCEWDT",
- "SPEWDT",
- "APEWDT",
- "BCCPLEXWDT",
- "SENSOR",
- "AOTAG",
- "VFSENSOR",
- "SWREST",
- "SC7",
- "HSM",
- "CORESIGHT"
-};
-
-static const char * const tegra186_reset_levels[] = {
- "L0", "L1", "L2", "WARM"
-};
-
-static const char * const tegra30_reset_sources[] = {
- "POWER_ON_RESET",
- "WATCHDOG",
- "SENSOR",
- "SW_MAIN",
- "LP0"
-};
-
-static const char * const tegra210_reset_sources[] = {
- "POWER_ON_RESET",
- "WATCHDOG",
- "SENSOR",
- "SW_MAIN",
- "LP0",
- "AOTAG"
-};
-
/**
* struct tegra_pmc - NVIDIA Tegra PMC
* @dev: pointer to PMC device structure
@@ -2771,6 +2732,14 @@ static const u8 tegra30_cpu_powergates[] = {
TEGRA_POWERGATE_CPU3,
};
+static const char * const tegra30_reset_sources[] = {
+ "POWER_ON_RESET",
+ "WATCHDOG",
+ "SENSOR",
+ "SW_MAIN",
+ "LP0"
+};
+
static const struct tegra_pmc_soc tegra30_pmc_soc = {
.num_powergates = ARRAY_SIZE(tegra30_powergates),
.powergates = tegra30_powergates,
@@ -3048,6 +3017,15 @@ static const struct pinctrl_pin_desc tegra210_pin_descs[] = {
TEGRA210_IO_PAD_TABLE(TEGRA_IO_PIN_DESC)
};
+static const char * const tegra210_reset_sources[] = {
+ "POWER_ON_RESET",
+ "WATCHDOG",
+ "SENSOR",
+ "SW_MAIN",
+ "LP0",
+ "AOTAG"
+};
+
static const struct tegra_wake_event tegra210_wake_events[] = {
TEGRA_WAKE_IRQ("rtc", 16, 2),
TEGRA_WAKE_IRQ("pmu", 51, 86),
@@ -3180,6 +3158,28 @@ static void tegra186_pmc_setup_irq_polarity(struct tegra_pmc *pmc,
iounmap(wake);
}
+static const char * const tegra186_reset_sources[] = {
+ "SYS_RESET",
+ "AOWDT",
+ "MCCPLEXWDT",
+ "BPMPWDT",
+ "SCEWDT",
+ "SPEWDT",
+ "APEWDT",
+ "BCCPLEXWDT",
+ "SENSOR",
+ "AOTAG",
+ "VFSENSOR",
+ "SWREST",
+ "SC7",
+ "HSM",
+ "CORESIGHT"
+};
+
+static const char * const tegra186_reset_levels[] = {
+ "L0", "L1", "L2", "WARM"
+};
+
static const struct tegra_wake_event tegra186_wake_events[] = {
TEGRA_WAKE_IRQ("pmu", 24, 209),
TEGRA_WAKE_GPIO("power", 29, 1, TEGRA186_AON_GPIO(FF, 0)),
@@ -3349,7 +3349,75 @@ static const struct tegra_pmc_soc tegra194_pmc_soc = {
.has_blink_output = false,
};
+static const struct tegra_pmc_regs tegra234_pmc_regs = {
+ .scratch0 = 0x2000,
+ .dpd_req = 0,
+ .dpd_status = 0,
+ .dpd2_req = 0,
+ .dpd2_status = 0,
+ .rst_status = 0x70,
+ .rst_source_shift = 0x2,
+ .rst_source_mask = 0xfc,
+ .rst_level_shift = 0x0,
+ .rst_level_mask = 0x3,
+};
+
+static const char * const tegra234_reset_sources[] = {
+ "SYS_RESET_N",
+ "AOWDT",
+ "BCCPLEXWDT",
+ "BPMPWDT",
+ "SCEWDT",
+ "SPEWDT",
+ "APEWDT",
+ "LCCPLEXWDT",
+ "SENSOR",
+ "AOTAG",
+ "VFSENSOR",
+ "MAINSWRST",
+ "SC7",
+ "HSM",
+ "CSITE",
+ "RCEWDT",
+ "PVA0WDT",
+ "PVA1WDT",
+ "L1A_ASYNC",
+ "BPMPBOOT",
+ "FUSECRC",
+};
+
+static const struct tegra_pmc_soc tegra234_pmc_soc = {
+ .num_powergates = 0,
+ .powergates = NULL,
+ .num_cpu_powergates = 0,
+ .cpu_powergates = NULL,
+ .has_tsense_reset = false,
+ .has_gpu_clamps = false,
+ .needs_mbist_war = false,
+ .has_impl_33v_pwr = true,
+ .maybe_tz_only = false,
+ .num_io_pads = 0,
+ .io_pads = NULL,
+ .num_pin_descs = 0,
+ .pin_descs = NULL,
+ .regs = &tegra234_pmc_regs,
+ .init = NULL,
+ .setup_irq_polarity = tegra186_pmc_setup_irq_polarity,
+ .irq_set_wake = tegra186_pmc_irq_set_wake,
+ .irq_set_type = tegra186_pmc_irq_set_type,
+ .reset_sources = tegra234_reset_sources,
+ .num_reset_sources = ARRAY_SIZE(tegra234_reset_sources),
+ .reset_levels = tegra186_reset_levels,
+ .num_reset_levels = ARRAY_SIZE(tegra186_reset_levels),
+ .num_wake_events = 0,
+ .wake_events = NULL,
+ .pmc_clks_data = NULL,
+ .num_pmc_clks = 0,
+ .has_blink_output = false,
+};
+
static const struct of_device_id tegra_pmc_match[] = {
+ { .compatible = "nvidia,tegra234-pmc", .data = &tegra234_pmc_soc },
{ .compatible = "nvidia,tegra194-pmc", .data = &tegra194_pmc_soc },
{ .compatible = "nvidia,tegra186-pmc", .data = &tegra186_pmc_soc },
{ .compatible = "nvidia,tegra210-pmc", .data = &tegra210_pmc_soc },
diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig
index e192fb788836..f5b82ffa637b 100644
--- a/drivers/soc/ti/Kconfig
+++ b/drivers/soc/ti/Kconfig
@@ -101,6 +101,17 @@ config TI_K3_SOCINFO
platforms to provide information about the SoC family and
variant to user space.
+config TI_PRUSS
+ tristate "TI PRU-ICSS Subsystem Platform drivers"
+ depends on SOC_AM33XX || SOC_AM43XX || SOC_DRA7XX || ARCH_KEYSTONE || ARCH_K3
+ select MFD_SYSCON
+ help
+ TI PRU-ICSS Subsystem platform specific support.
+
+ Say Y or M here to support the Programmable Realtime Unit (PRU)
+ processors on various TI SoCs. It's safe to say N here if you're
+ not interested in the PRU or if you are unsure.
+
endif # SOC_TI
config TI_SCI_INTA_MSI_DOMAIN
diff --git a/drivers/soc/ti/Makefile b/drivers/soc/ti/Makefile
index 5463431ec96c..cc3c972fad2e 100644
--- a/drivers/soc/ti/Makefile
+++ b/drivers/soc/ti/Makefile
@@ -12,4 +12,5 @@ obj-$(CONFIG_TI_SCI_PM_DOMAINS) += ti_sci_pm_domains.o
obj-$(CONFIG_TI_SCI_INTA_MSI_DOMAIN) += ti_sci_inta_msi.o
obj-$(CONFIG_TI_K3_RINGACC) += k3-ringacc.o
obj-$(CONFIG_TI_K3_SOCINFO) += k3-socinfo.o
+obj-$(CONFIG_TI_PRUSS) += pruss.o
obj-$(CONFIG_POWER_AVS_OMAP) += smartreflex.o
diff --git a/drivers/soc/ti/k3-ringacc.c b/drivers/soc/ti/k3-ringacc.c
index 6dcc21dde0cb..1147dc4c1d59 100644
--- a/drivers/soc/ti/k3-ringacc.c
+++ b/drivers/soc/ti/k3-ringacc.c
@@ -10,6 +10,7 @@
#include <linux/init.h>
#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/sys_soc.h>
#include <linux/soc/ti/k3-ringacc.h>
#include <linux/soc/ti/ti_sci_protocol.h>
#include <linux/soc/ti/ti_sci_inta_msi.h>
@@ -208,6 +209,15 @@ struct k3_ringacc {
const struct k3_ringacc_ops *ops;
};
+/**
+ * struct k3_ringacc - Rings accelerator SoC data
+ *
+ * @dma_ring_reset_quirk: DMA reset w/a enable
+ */
+struct k3_ringacc_soc_data {
+ unsigned dma_ring_reset_quirk:1;
+};
+
static long k3_ringacc_ring_get_fifo_pos(struct k3_ring *ring)
{
return K3_RINGACC_FIFO_WINDOW_SIZE_BYTES -
@@ -1051,9 +1061,6 @@ static int k3_ringacc_probe_dt(struct k3_ringacc *ringacc)
return ret;
}
- ringacc->dma_ring_reset_quirk =
- of_property_read_bool(node, "ti,dma-ring-reset-quirk");
-
ringacc->tisci = ti_sci_get_by_phandle(node, "ti,sci");
if (IS_ERR(ringacc->tisci)) {
ret = PTR_ERR(ringacc->tisci);
@@ -1084,9 +1091,22 @@ static int k3_ringacc_probe_dt(struct k3_ringacc *ringacc)
ringacc->rm_gp_range);
}
+static const struct k3_ringacc_soc_data k3_ringacc_soc_data_sr1 = {
+ .dma_ring_reset_quirk = 1,
+};
+
+static const struct soc_device_attribute k3_ringacc_socinfo[] = {
+ { .family = "AM65X",
+ .revision = "SR1.0",
+ .data = &k3_ringacc_soc_data_sr1
+ },
+ {/* sentinel */}
+};
+
static int k3_ringacc_init(struct platform_device *pdev,
struct k3_ringacc *ringacc)
{
+ const struct soc_device_attribute *soc;
void __iomem *base_fifo, *base_rt;
struct device *dev = &pdev->dev;
struct resource *res;
@@ -1103,6 +1123,13 @@ static int k3_ringacc_init(struct platform_device *pdev,
if (ret)
return ret;
+ soc = soc_device_match(k3_ringacc_socinfo);
+ if (soc && soc->data) {
+ const struct k3_ringacc_soc_data *soc_data = soc->data;
+
+ ringacc->dma_ring_reset_quirk = soc_data->dma_ring_reset_quirk;
+ }
+
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rt");
base_rt = devm_ioremap_resource(dev, res);
if (IS_ERR(base_rt))
diff --git a/drivers/soc/ti/k3-socinfo.c b/drivers/soc/ti/k3-socinfo.c
index af0ba5288e58..bbbc2d2b7091 100644
--- a/drivers/soc/ti/k3-socinfo.c
+++ b/drivers/soc/ti/k3-socinfo.c
@@ -39,6 +39,7 @@ static const struct k3_soc_id {
} k3_soc_ids[] = {
{ 0xBB5A, "AM65X" },
{ 0xBB64, "J721E" },
+ { 0xBB6D, "J7200" },
};
static int
diff --git a/drivers/soc/ti/knav_dma.c b/drivers/soc/ti/knav_dma.c
index 6285cd8efb21..8c863ecb1c60 100644
--- a/drivers/soc/ti/knav_dma.c
+++ b/drivers/soc/ti/knav_dma.c
@@ -355,7 +355,7 @@ static void dma_debug_show_devices(struct seq_file *s,
}
}
-static int dma_debug_show(struct seq_file *s, void *v)
+static int knav_dma_debug_show(struct seq_file *s, void *v)
{
struct knav_dma_device *dma;
@@ -370,17 +370,7 @@ static int dma_debug_show(struct seq_file *s, void *v)
return 0;
}
-static int knav_dma_debug_open(struct inode *inode, struct file *file)
-{
- return single_open(file, dma_debug_show, NULL);
-}
-
-static const struct file_operations knav_dma_debug_ops = {
- .open = knav_dma_debug_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(knav_dma_debug);
static int of_channel_match_helper(struct device_node *np, const char *name,
const char **dma_instance)
@@ -778,7 +768,7 @@ static int knav_dma_probe(struct platform_device *pdev)
}
debugfs_create_file("knav_dma", S_IFREG | S_IRUGO, NULL, NULL,
- &knav_dma_debug_ops);
+ &knav_dma_debug_fops);
device_ready = true;
return ret;
diff --git a/drivers/soc/ti/knav_qmss_queue.c b/drivers/soc/ti/knav_qmss_queue.c
index aa071d96ef36..a460f201bf8e 100644
--- a/drivers/soc/ti/knav_qmss_queue.c
+++ b/drivers/soc/ti/knav_qmss_queue.c
@@ -478,17 +478,7 @@ static int knav_queue_debug_show(struct seq_file *s, void *v)
return 0;
}
-static int knav_queue_debug_open(struct inode *inode, struct file *file)
-{
- return single_open(file, knav_queue_debug_show, NULL);
-}
-
-static const struct file_operations knav_queue_debug_ops = {
- .open = knav_queue_debug_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(knav_queue_debug);
static inline int knav_queue_pdsp_wait(u32 * __iomem addr, unsigned timeout,
u32 flags)
@@ -1878,7 +1868,7 @@ static int knav_queue_probe(struct platform_device *pdev)
}
debugfs_create_file("qmss", S_IFREG | S_IRUGO, NULL, NULL,
- &knav_queue_debug_ops);
+ &knav_queue_debug_fops);
device_ready = true;
return 0;
diff --git a/drivers/soc/ti/pruss.c b/drivers/soc/ti/pruss.c
new file mode 100644
index 000000000000..cc0b4ad7a3d3
--- /dev/null
+++ b/drivers/soc/ti/pruss.c
@@ -0,0 +1,354 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * PRU-ICSS platform driver for various TI SoCs
+ *
+ * Copyright (C) 2014-2020 Texas Instruments Incorporated - http://www.ti.com/
+ * Author(s):
+ * Suman Anna <s-anna@ti.com>
+ * Andrew F. Davis <afd@ti.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/pruss_driver.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+/**
+ * struct pruss_private_data - PRUSS driver private data
+ * @has_no_sharedram: flag to indicate the absence of PRUSS Shared Data RAM
+ * @has_core_mux_clock: flag to indicate the presence of PRUSS core clock
+ */
+struct pruss_private_data {
+ bool has_no_sharedram;
+ bool has_core_mux_clock;
+};
+
+static void pruss_of_free_clk_provider(void *data)
+{
+ struct device_node *clk_mux_np = data;
+
+ of_clk_del_provider(clk_mux_np);
+ of_node_put(clk_mux_np);
+}
+
+static int pruss_clk_mux_setup(struct pruss *pruss, struct clk *clk_mux,
+ char *mux_name, struct device_node *clks_np)
+{
+ struct device_node *clk_mux_np;
+ struct device *dev = pruss->dev;
+ char *clk_mux_name;
+ unsigned int num_parents;
+ const char **parent_names;
+ void __iomem *reg;
+ u32 reg_offset;
+ int ret;
+
+ clk_mux_np = of_get_child_by_name(clks_np, mux_name);
+ if (!clk_mux_np) {
+ dev_err(dev, "%pOF is missing its '%s' node\n", clks_np,
+ mux_name);
+ return -ENODEV;
+ }
+
+ num_parents = of_clk_get_parent_count(clk_mux_np);
+ if (num_parents < 1) {
+ dev_err(dev, "mux-clock %pOF must have parents\n", clk_mux_np);
+ ret = -EINVAL;
+ goto put_clk_mux_np;
+ }
+
+ parent_names = devm_kcalloc(dev, sizeof(*parent_names), num_parents,
+ GFP_KERNEL);
+ if (!parent_names) {
+ ret = -ENOMEM;
+ goto put_clk_mux_np;
+ }
+
+ of_clk_parent_fill(clk_mux_np, parent_names, num_parents);
+
+ clk_mux_name = devm_kasprintf(dev, GFP_KERNEL, "%s.%pOFn",
+ dev_name(dev), clk_mux_np);
+ if (!clk_mux_name) {
+ ret = -ENOMEM;
+ goto put_clk_mux_np;
+ }
+
+ ret = of_property_read_u32(clk_mux_np, "reg", &reg_offset);
+ if (ret)
+ goto put_clk_mux_np;
+
+ reg = pruss->cfg_base + reg_offset;
+
+ clk_mux = clk_register_mux(NULL, clk_mux_name, parent_names,
+ num_parents, 0, reg, 0, 1, 0, NULL);
+ if (IS_ERR(clk_mux)) {
+ ret = PTR_ERR(clk_mux);
+ goto put_clk_mux_np;
+ }
+
+ ret = devm_add_action_or_reset(dev, (void(*)(void *))clk_unregister_mux,
+ clk_mux);
+ if (ret) {
+ dev_err(dev, "failed to add clkmux unregister action %d", ret);
+ goto put_clk_mux_np;
+ }
+
+ ret = of_clk_add_provider(clk_mux_np, of_clk_src_simple_get, clk_mux);
+ if (ret)
+ goto put_clk_mux_np;
+
+ ret = devm_add_action_or_reset(dev, pruss_of_free_clk_provider,
+ clk_mux_np);
+ if (ret) {
+ dev_err(dev, "failed to add clkmux free action %d", ret);
+ goto put_clk_mux_np;
+ }
+
+ return 0;
+
+put_clk_mux_np:
+ of_node_put(clk_mux_np);
+ return ret;
+}
+
+static int pruss_clk_init(struct pruss *pruss, struct device_node *cfg_node)
+{
+ const struct pruss_private_data *data;
+ struct device_node *clks_np;
+ struct device *dev = pruss->dev;
+ int ret = 0;
+
+ data = of_device_get_match_data(dev);
+ if (IS_ERR(data))
+ return -ENODEV;
+
+ clks_np = of_get_child_by_name(cfg_node, "clocks");
+ if (!clks_np) {
+ dev_err(dev, "%pOF is missing its 'clocks' node\n", clks_np);
+ return -ENODEV;
+ }
+
+ if (data && data->has_core_mux_clock) {
+ ret = pruss_clk_mux_setup(pruss, pruss->core_clk_mux,
+ "coreclk-mux", clks_np);
+ if (ret) {
+ dev_err(dev, "failed to setup coreclk-mux\n");
+ goto put_clks_node;
+ }
+ }
+
+ ret = pruss_clk_mux_setup(pruss, pruss->iep_clk_mux, "iepclk-mux",
+ clks_np);
+ if (ret) {
+ dev_err(dev, "failed to setup iepclk-mux\n");
+ goto put_clks_node;
+ }
+
+put_clks_node:
+ of_node_put(clks_np);
+
+ return ret;
+}
+
+static struct regmap_config regmap_conf = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+};
+
+static int pruss_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev_of_node(dev);
+ struct device_node *child;
+ struct pruss *pruss;
+ struct resource res;
+ int ret, i, index;
+ const struct pruss_private_data *data;
+ const char *mem_names[PRUSS_MEM_MAX] = { "dram0", "dram1", "shrdram2" };
+
+ data = of_device_get_match_data(&pdev->dev);
+ if (IS_ERR(data)) {
+ dev_err(dev, "missing private data\n");
+ return -ENODEV;
+ }
+
+ ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
+ if (ret) {
+ dev_err(dev, "failed to set the DMA coherent mask");
+ return ret;
+ }
+
+ pruss = devm_kzalloc(dev, sizeof(*pruss), GFP_KERNEL);
+ if (!pruss)
+ return -ENOMEM;
+
+ pruss->dev = dev;
+
+ child = of_get_child_by_name(np, "memories");
+ if (!child) {
+ dev_err(dev, "%pOF is missing its 'memories' node\n", child);
+ return -ENODEV;
+ }
+
+ for (i = 0; i < PRUSS_MEM_MAX; i++) {
+ /*
+ * On AM437x one of two PRUSS units don't contain Shared RAM,
+ * skip it
+ */
+ if (data && data->has_no_sharedram && i == PRUSS_MEM_SHRD_RAM2)
+ continue;
+
+ index = of_property_match_string(child, "reg-names",
+ mem_names[i]);
+ if (index < 0) {
+ of_node_put(child);
+ return index;
+ }
+
+ if (of_address_to_resource(child, index, &res)) {
+ of_node_put(child);
+ return -EINVAL;
+ }
+
+ pruss->mem_regions[i].va = devm_ioremap(dev, res.start,
+ resource_size(&res));
+ if (!pruss->mem_regions[i].va) {
+ dev_err(dev, "failed to parse and map memory resource %d %s\n",
+ i, mem_names[i]);
+ of_node_put(child);
+ return -ENOMEM;
+ }
+ pruss->mem_regions[i].pa = res.start;
+ pruss->mem_regions[i].size = resource_size(&res);
+
+ dev_dbg(dev, "memory %8s: pa %pa size 0x%zx va %pK\n",
+ mem_names[i], &pruss->mem_regions[i].pa,
+ pruss->mem_regions[i].size, pruss->mem_regions[i].va);
+ }
+ of_node_put(child);
+
+ platform_set_drvdata(pdev, pruss);
+
+ pm_runtime_enable(dev);
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ dev_err(dev, "couldn't enable module\n");
+ pm_runtime_put_noidle(dev);
+ goto rpm_disable;
+ }
+
+ child = of_get_child_by_name(np, "cfg");
+ if (!child) {
+ dev_err(dev, "%pOF is missing its 'cfg' node\n", child);
+ ret = -ENODEV;
+ goto rpm_put;
+ }
+
+ if (of_address_to_resource(child, 0, &res)) {
+ ret = -ENOMEM;
+ goto node_put;
+ }
+
+ pruss->cfg_base = devm_ioremap(dev, res.start, resource_size(&res));
+ if (!pruss->cfg_base) {
+ ret = -ENOMEM;
+ goto node_put;
+ }
+
+ regmap_conf.name = kasprintf(GFP_KERNEL, "%pOFn@%llx", child,
+ (u64)res.start);
+ regmap_conf.max_register = resource_size(&res) - 4;
+
+ pruss->cfg_regmap = devm_regmap_init_mmio(dev, pruss->cfg_base,
+ &regmap_conf);
+ kfree(regmap_conf.name);
+ if (IS_ERR(pruss->cfg_regmap)) {
+ dev_err(dev, "regmap_init_mmio failed for cfg, ret = %ld\n",
+ PTR_ERR(pruss->cfg_regmap));
+ ret = PTR_ERR(pruss->cfg_regmap);
+ goto node_put;
+ }
+
+ ret = pruss_clk_init(pruss, child);
+ if (ret) {
+ dev_err(dev, "failed to setup coreclk-mux\n");
+ goto node_put;
+ }
+
+ ret = devm_of_platform_populate(dev);
+ if (ret) {
+ dev_err(dev, "failed to register child devices\n");
+ goto node_put;
+ }
+
+ of_node_put(child);
+
+ return 0;
+
+node_put:
+ of_node_put(child);
+rpm_put:
+ pm_runtime_put_sync(dev);
+rpm_disable:
+ pm_runtime_disable(dev);
+ return ret;
+}
+
+static int pruss_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+
+ devm_of_platform_depopulate(dev);
+
+ pm_runtime_put_sync(dev);
+ pm_runtime_disable(dev);
+
+ return 0;
+}
+
+/* instance-specific driver private data */
+static const struct pruss_private_data am437x_pruss1_data = {
+ .has_no_sharedram = false,
+};
+
+static const struct pruss_private_data am437x_pruss0_data = {
+ .has_no_sharedram = true,
+};
+
+static const struct pruss_private_data am65x_j721e_pruss_data = {
+ .has_core_mux_clock = true,
+};
+
+static const struct of_device_id pruss_of_match[] = {
+ { .compatible = "ti,am3356-pruss" },
+ { .compatible = "ti,am4376-pruss0", .data = &am437x_pruss0_data, },
+ { .compatible = "ti,am4376-pruss1", .data = &am437x_pruss1_data, },
+ { .compatible = "ti,am5728-pruss" },
+ { .compatible = "ti,k2g-pruss" },
+ { .compatible = "ti,am654-icssg", .data = &am65x_j721e_pruss_data, },
+ { .compatible = "ti,j721e-icssg", .data = &am65x_j721e_pruss_data, },
+ {},
+};
+MODULE_DEVICE_TABLE(of, pruss_of_match);
+
+static struct platform_driver pruss_driver = {
+ .driver = {
+ .name = "pruss",
+ .of_match_table = pruss_of_match,
+ },
+ .probe = pruss_probe,
+ .remove = pruss_remove,
+};
+module_platform_driver(pruss_driver);
+
+MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
+MODULE_DESCRIPTION("PRU-ICSS Subsystem Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/ti/ti_sci_pm_domains.c b/drivers/soc/ti/ti_sci_pm_domains.c
index 8c2a2f23982c..af2126d2b2ff 100644
--- a/drivers/soc/ti/ti_sci_pm_domains.c
+++ b/drivers/soc/ti/ti_sci_pm_domains.c
@@ -9,7 +9,6 @@
#include <linux/err.h>
#include <linux/module.h>
-#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
@@ -18,150 +17,95 @@
#include <dt-bindings/soc/ti,sci_pm_domain.h>
/**
- * struct ti_sci_genpd_dev_data: holds data needed for every device attached
- * to this genpd
- * @idx: index of the device that identifies it with the system
- * control processor.
- * @exclusive: Permissions for exclusive request or shared request of the
- * device.
+ * struct ti_sci_genpd_provider: holds common TI SCI genpd provider data
+ * @ti_sci: handle to TI SCI protocol driver that provides ops to
+ * communicate with system control processor.
+ * @dev: pointer to dev for the driver for devm allocs
+ * @pd_list: list of all the power domains on the device
+ * @data: onecell data for genpd core
*/
-struct ti_sci_genpd_dev_data {
- int idx;
- u8 exclusive;
+struct ti_sci_genpd_provider {
+ const struct ti_sci_handle *ti_sci;
+ struct device *dev;
+ struct list_head pd_list;
+ struct genpd_onecell_data data;
};
/**
* struct ti_sci_pm_domain: TI specific data needed for power domain
- * @ti_sci: handle to TI SCI protocol driver that provides ops to
- * communicate with system control processor.
- * @dev: pointer to dev for the driver for devm allocs
+ * @idx: index of the device that identifies it with the system
+ * control processor.
+ * @exclusive: Permissions for exclusive request or shared request of the
+ * device.
* @pd: generic_pm_domain for use with the genpd framework
+ * @node: link for the genpd list
+ * @parent: link to the parent TI SCI genpd provider
*/
struct ti_sci_pm_domain {
- const struct ti_sci_handle *ti_sci;
- struct device *dev;
+ int idx;
+ u8 exclusive;
struct generic_pm_domain pd;
+ struct list_head node;
+ struct ti_sci_genpd_provider *parent;
};
#define genpd_to_ti_sci_pd(gpd) container_of(gpd, struct ti_sci_pm_domain, pd)
-/**
- * ti_sci_dev_id(): get prepopulated ti_sci id from struct dev
- * @dev: pointer to device associated with this genpd
- *
- * Returns device_id stored from ti,sci_id property
- */
-static int ti_sci_dev_id(struct device *dev)
-{
- struct generic_pm_domain_data *genpd_data = dev_gpd_data(dev);
- struct ti_sci_genpd_dev_data *sci_dev_data = genpd_data->data;
-
- return sci_dev_data->idx;
-}
-
-static u8 is_ti_sci_dev_exclusive(struct device *dev)
-{
- struct generic_pm_domain_data *genpd_data = dev_gpd_data(dev);
- struct ti_sci_genpd_dev_data *sci_dev_data = genpd_data->data;
-
- return sci_dev_data->exclusive;
-}
-
-/**
- * ti_sci_dev_to_sci_handle(): get pointer to ti_sci_handle
- * @dev: pointer to device associated with this genpd
- *
- * Returns ti_sci_handle to be used to communicate with system
- * control processor.
+/*
+ * ti_sci_pd_power_off(): genpd power down hook
+ * @domain: pointer to the powerdomain to power off
*/
-static const struct ti_sci_handle *ti_sci_dev_to_sci_handle(struct device *dev)
+static int ti_sci_pd_power_off(struct generic_pm_domain *domain)
{
- struct generic_pm_domain *pd = pd_to_genpd(dev->pm_domain);
- struct ti_sci_pm_domain *ti_sci_genpd = genpd_to_ti_sci_pd(pd);
+ struct ti_sci_pm_domain *pd = genpd_to_ti_sci_pd(domain);
+ const struct ti_sci_handle *ti_sci = pd->parent->ti_sci;
- return ti_sci_genpd->ti_sci;
+ return ti_sci->ops.dev_ops.put_device(ti_sci, pd->idx);
}
-/**
- * ti_sci_dev_start(): genpd device start hook called to turn device on
- * @dev: pointer to device associated with this genpd to be powered on
+/*
+ * ti_sci_pd_power_on(): genpd power up hook
+ * @domain: pointer to the powerdomain to power on
*/
-static int ti_sci_dev_start(struct device *dev)
+static int ti_sci_pd_power_on(struct generic_pm_domain *domain)
{
- const struct ti_sci_handle *ti_sci = ti_sci_dev_to_sci_handle(dev);
- int idx = ti_sci_dev_id(dev);
+ struct ti_sci_pm_domain *pd = genpd_to_ti_sci_pd(domain);
+ const struct ti_sci_handle *ti_sci = pd->parent->ti_sci;
- if (is_ti_sci_dev_exclusive(dev))
- return ti_sci->ops.dev_ops.get_device_exclusive(ti_sci, idx);
+ if (pd->exclusive)
+ return ti_sci->ops.dev_ops.get_device_exclusive(ti_sci,
+ pd->idx);
else
- return ti_sci->ops.dev_ops.get_device(ti_sci, idx);
+ return ti_sci->ops.dev_ops.get_device(ti_sci, pd->idx);
}
-/**
- * ti_sci_dev_stop(): genpd device stop hook called to turn device off
- * @dev: pointer to device associated with this genpd to be powered off
+/*
+ * ti_sci_pd_xlate(): translation service for TI SCI genpds
+ * @genpdspec: DT identification data for the genpd
+ * @data: genpd core data for all the powerdomains on the device
*/
-static int ti_sci_dev_stop(struct device *dev)
+static struct generic_pm_domain *ti_sci_pd_xlate(
+ struct of_phandle_args *genpdspec,
+ void *data)
{
- const struct ti_sci_handle *ti_sci = ti_sci_dev_to_sci_handle(dev);
- int idx = ti_sci_dev_id(dev);
+ struct genpd_onecell_data *genpd_data = data;
+ unsigned int idx = genpdspec->args[0];
- return ti_sci->ops.dev_ops.put_device(ti_sci, idx);
-}
+ if (genpdspec->args_count < 2)
+ return ERR_PTR(-EINVAL);
-static int ti_sci_pd_attach_dev(struct generic_pm_domain *domain,
- struct device *dev)
-{
- struct device_node *np = dev->of_node;
- struct of_phandle_args pd_args;
- struct ti_sci_pm_domain *ti_sci_genpd = genpd_to_ti_sci_pd(domain);
- const struct ti_sci_handle *ti_sci = ti_sci_genpd->ti_sci;
- struct ti_sci_genpd_dev_data *sci_dev_data;
- struct generic_pm_domain_data *genpd_data;
- int idx, ret = 0;
-
- ret = of_parse_phandle_with_args(np, "power-domains",
- "#power-domain-cells", 0, &pd_args);
- if (ret < 0)
- return ret;
-
- if (pd_args.args_count != 1 && pd_args.args_count != 2)
- return -EINVAL;
-
- idx = pd_args.args[0];
-
- /*
- * Check the validity of the requested idx, if the index is not valid
- * the PMMC will return a NAK here and we will not allocate it.
- */
- ret = ti_sci->ops.dev_ops.is_valid(ti_sci, idx);
- if (ret)
- return -EINVAL;
-
- sci_dev_data = kzalloc(sizeof(*sci_dev_data), GFP_KERNEL);
- if (!sci_dev_data)
- return -ENOMEM;
+ if (idx >= genpd_data->num_domains) {
+ pr_err("%s: invalid domain index %u\n", __func__, idx);
+ return ERR_PTR(-EINVAL);
+ }
- sci_dev_data->idx = idx;
- /* Enable the exclusive permissions by default */
- sci_dev_data->exclusive = TI_SCI_PD_EXCLUSIVE;
- if (pd_args.args_count == 2)
- sci_dev_data->exclusive = pd_args.args[1] & 0x1;
+ if (!genpd_data->domains[idx])
+ return ERR_PTR(-ENOENT);
- genpd_data = dev_gpd_data(dev);
- genpd_data->data = sci_dev_data;
+ genpd_to_ti_sci_pd(genpd_data->domains[idx])->exclusive =
+ genpdspec->args[1];
- return 0;
-}
-
-static void ti_sci_pd_detach_dev(struct generic_pm_domain *domain,
- struct device *dev)
-{
- struct generic_pm_domain_data *genpd_data = dev_gpd_data(dev);
- struct ti_sci_genpd_dev_data *sci_dev_data = genpd_data->data;
-
- kfree(sci_dev_data);
- genpd_data->data = NULL;
+ return genpd_data->domains[idx];
}
static const struct of_device_id ti_sci_pm_domain_matches[] = {
@@ -173,33 +117,80 @@ MODULE_DEVICE_TABLE(of, ti_sci_pm_domain_matches);
static int ti_sci_pm_domain_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
- struct ti_sci_pm_domain *ti_sci_pd;
+ struct ti_sci_genpd_provider *pd_provider;
+ struct ti_sci_pm_domain *pd;
+ struct device_node *np = NULL;
+ struct of_phandle_args args;
int ret;
+ u32 max_id = 0;
+ int index;
- ti_sci_pd = devm_kzalloc(dev, sizeof(*ti_sci_pd), GFP_KERNEL);
- if (!ti_sci_pd)
+ pd_provider = devm_kzalloc(dev, sizeof(*pd_provider), GFP_KERNEL);
+ if (!pd_provider)
return -ENOMEM;
- ti_sci_pd->ti_sci = devm_ti_sci_get_handle(dev);
- if (IS_ERR(ti_sci_pd->ti_sci))
- return PTR_ERR(ti_sci_pd->ti_sci);
+ pd_provider->ti_sci = devm_ti_sci_get_handle(dev);
+ if (IS_ERR(pd_provider->ti_sci))
+ return PTR_ERR(pd_provider->ti_sci);
+
+ pd_provider->dev = dev;
+
+ INIT_LIST_HEAD(&pd_provider->pd_list);
+
+ /* Find highest device ID used for power domains */
+ while (1) {
+ np = of_find_node_with_property(np, "power-domains");
+ if (!np)
+ break;
+
+ index = 0;
+
+ while (1) {
+ ret = of_parse_phandle_with_args(np, "power-domains",
+ "#power-domain-cells",
+ index, &args);
+ if (ret)
+ break;
+
+ if (args.args_count >= 1 && args.np == dev->of_node) {
+ if (args.args[0] > max_id)
+ max_id = args.args[0];
+
+ pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+ if (!pd)
+ return -ENOMEM;
+
+ pd->pd.name = devm_kasprintf(dev, GFP_KERNEL,
+ "pd:%d",
+ args.args[0]);
+ if (!pd->pd.name)
+ return -ENOMEM;
- ti_sci_pd->dev = dev;
+ pd->pd.power_off = ti_sci_pd_power_off;
+ pd->pd.power_on = ti_sci_pd_power_on;
+ pd->idx = args.args[0];
+ pd->parent = pd_provider;
- ti_sci_pd->pd.name = "ti_sci_pd";
+ pm_genpd_init(&pd->pd, NULL, true);
- ti_sci_pd->pd.attach_dev = ti_sci_pd_attach_dev;
- ti_sci_pd->pd.detach_dev = ti_sci_pd_detach_dev;
+ list_add(&pd->node, &pd_provider->pd_list);
+ }
+ index++;
+ }
+ }
- ti_sci_pd->pd.dev_ops.start = ti_sci_dev_start;
- ti_sci_pd->pd.dev_ops.stop = ti_sci_dev_stop;
+ pd_provider->data.domains =
+ devm_kcalloc(dev, max_id + 1,
+ sizeof(*pd_provider->data.domains),
+ GFP_KERNEL);
- pm_genpd_init(&ti_sci_pd->pd, NULL, true);
+ pd_provider->data.num_domains = max_id + 1;
+ pd_provider->data.xlate = ti_sci_pd_xlate;
- ret = of_genpd_add_provider_simple(np, &ti_sci_pd->pd);
+ list_for_each_entry(pd, &pd_provider->pd_list, node)
+ pd_provider->data.domains[pd->idx] = &pd->pd;
- return ret;
+ return of_genpd_add_provider_onecell(dev->of_node, &pd_provider->data);
}
static struct platform_driver ti_sci_pm_domains_driver = {
diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
index b373b1b08b6d..cf4718c6d35d 100644
--- a/drivers/tee/optee/core.c
+++ b/drivers/tee/optee/core.c
@@ -216,6 +216,8 @@ static void optee_get_version(struct tee_device *teedev,
if (optee->sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
v.gen_caps |= TEE_GEN_CAP_REG_MEM;
+ if (optee->sec_caps & OPTEE_SMC_SEC_CAP_MEMREF_NULL)
+ v.gen_caps |= TEE_GEN_CAP_MEMREF_NULL;
*vers = v;
}
@@ -262,6 +264,11 @@ static int optee_open(struct tee_context *ctx)
mutex_init(&ctxdata->mutex);
INIT_LIST_HEAD(&ctxdata->sess_list);
+ if (optee->sec_caps & OPTEE_SMC_SEC_CAP_MEMREF_NULL)
+ ctx->cap_memref_null = true;
+ else
+ ctx->cap_memref_null = false;
+
ctx->data = ctxdata;
return 0;
}
diff --git a/drivers/tee/optee/optee_msg.h b/drivers/tee/optee/optee_msg.h
index 795bc19ae17a..7b2d919da2ac 100644
--- a/drivers/tee/optee/optee_msg.h
+++ b/drivers/tee/optee/optee_msg.h
@@ -419,4 +419,25 @@ struct optee_msg_arg {
*/
#define OPTEE_MSG_RPC_CMD_SHM_FREE 7
+/*
+ * Access a device on an i2c bus
+ *
+ * [in] param[0].u.value.a mode: RD(0), WR(1)
+ * [in] param[0].u.value.b i2c adapter
+ * [in] param[0].u.value.c i2c chip
+ *
+ * [in] param[1].u.value.a i2c control flags
+ *
+ * [in/out] memref[2] buffer to exchange the transfer data
+ * with the secure world
+ *
+ * [out] param[3].u.value.a bytes transferred by the driver
+ */
+#define OPTEE_MSG_RPC_CMD_I2C_TRANSFER 21
+/* I2C master transfer modes */
+#define OPTEE_MSG_RPC_CMD_I2C_TRANSFER_RD 0
+#define OPTEE_MSG_RPC_CMD_I2C_TRANSFER_WR 1
+/* I2C master control flags */
+#define OPTEE_MSG_RPC_CMD_I2C_FLAGS_TEN_BIT BIT(0)
+
#endif /* _OPTEE_MSG_H */
diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
index 8b71839a357e..e25b216a14ef 100644
--- a/drivers/tee/optee/optee_private.h
+++ b/drivers/tee/optee/optee_private.h
@@ -17,6 +17,7 @@
/* Some Global Platform error codes used in this driver */
#define TEEC_SUCCESS 0x00000000
#define TEEC_ERROR_BAD_PARAMETERS 0xFFFF0006
+#define TEEC_ERROR_NOT_SUPPORTED 0xFFFF000A
#define TEEC_ERROR_COMMUNICATION 0xFFFF000E
#define TEEC_ERROR_OUT_OF_MEMORY 0xFFFF000C
#define TEEC_ERROR_SHORT_BUFFER 0xFFFF0010
diff --git a/drivers/tee/optee/optee_smc.h b/drivers/tee/optee/optee_smc.h
index c72122d9c997..777ad54d4c2c 100644
--- a/drivers/tee/optee/optee_smc.h
+++ b/drivers/tee/optee/optee_smc.h
@@ -215,6 +215,9 @@ struct optee_smc_get_shm_config_result {
*/
#define OPTEE_SMC_SEC_CAP_DYNAMIC_SHM BIT(2)
+/* Secure world supports Shared Memory with a NULL buffer reference */
+#define OPTEE_SMC_SEC_CAP_MEMREF_NULL BIT(4)
+
#define OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES 9
#define OPTEE_SMC_EXCHANGE_CAPABILITIES \
OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES)
diff --git a/drivers/tee/optee/rpc.c b/drivers/tee/optee/rpc.c
index b4ade54d1f28..1e3614e4798f 100644
--- a/drivers/tee/optee/rpc.c
+++ b/drivers/tee/optee/rpc.c
@@ -7,6 +7,7 @@
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/tee_drv.h>
#include "optee_private.h"
@@ -49,6 +50,97 @@ bad:
arg->ret = TEEC_ERROR_BAD_PARAMETERS;
}
+#if IS_REACHABLE(CONFIG_I2C)
+static void handle_rpc_func_cmd_i2c_transfer(struct tee_context *ctx,
+ struct optee_msg_arg *arg)
+{
+ struct i2c_client client = { 0 };
+ struct tee_param *params;
+ size_t i;
+ int ret = -EOPNOTSUPP;
+ u8 attr[] = {
+ TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+ TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+ TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT,
+ TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT,
+ };
+
+ if (arg->num_params != ARRAY_SIZE(attr)) {
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+ return;
+ }
+
+ params = kmalloc_array(arg->num_params, sizeof(struct tee_param),
+ GFP_KERNEL);
+ if (!params) {
+ arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
+ return;
+ }
+
+ if (optee_from_msg_param(params, arg->num_params, arg->params))
+ goto bad;
+
+ for (i = 0; i < arg->num_params; i++) {
+ if (params[i].attr != attr[i])
+ goto bad;
+ }
+
+ client.adapter = i2c_get_adapter(params[0].u.value.b);
+ if (!client.adapter)
+ goto bad;
+
+ if (params[1].u.value.a & OPTEE_MSG_RPC_CMD_I2C_FLAGS_TEN_BIT) {
+ if (!i2c_check_functionality(client.adapter,
+ I2C_FUNC_10BIT_ADDR)) {
+ i2c_put_adapter(client.adapter);
+ goto bad;
+ }
+
+ client.flags = I2C_CLIENT_TEN;
+ }
+
+ client.addr = params[0].u.value.c;
+ snprintf(client.name, I2C_NAME_SIZE, "i2c%d", client.adapter->nr);
+
+ switch (params[0].u.value.a) {
+ case OPTEE_MSG_RPC_CMD_I2C_TRANSFER_RD:
+ ret = i2c_master_recv(&client, params[2].u.memref.shm->kaddr,
+ params[2].u.memref.size);
+ break;
+ case OPTEE_MSG_RPC_CMD_I2C_TRANSFER_WR:
+ ret = i2c_master_send(&client, params[2].u.memref.shm->kaddr,
+ params[2].u.memref.size);
+ break;
+ default:
+ i2c_put_adapter(client.adapter);
+ goto bad;
+ }
+
+ if (ret < 0) {
+ arg->ret = TEEC_ERROR_COMMUNICATION;
+ } else {
+ params[3].u.value.a = ret;
+ if (optee_to_msg_param(arg->params, arg->num_params, params))
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+ else
+ arg->ret = TEEC_SUCCESS;
+ }
+
+ i2c_put_adapter(client.adapter);
+ kfree(params);
+ return;
+bad:
+ kfree(params);
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+}
+#else
+static void handle_rpc_func_cmd_i2c_transfer(struct tee_context *ctx,
+ struct optee_msg_arg *arg)
+{
+ arg->ret = TEEC_ERROR_NOT_SUPPORTED;
+}
+#endif
+
static struct wq_entry *wq_entry_get(struct optee_wait_queue *wq, u32 key)
{
struct wq_entry *w;
@@ -382,6 +474,9 @@ static void handle_rpc_func_cmd(struct tee_context *ctx, struct optee *optee,
case OPTEE_MSG_RPC_CMD_SHM_FREE:
handle_rpc_func_cmd_shm_free(ctx, arg);
break;
+ case OPTEE_MSG_RPC_CMD_I2C_TRANSFER:
+ handle_rpc_func_cmd_i2c_transfer(ctx, arg);
+ break;
default:
handle_rpc_supp_cmd(ctx, arg);
}
diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
index 64637e09a095..f53bf336c0a2 100644
--- a/drivers/tee/tee_core.c
+++ b/drivers/tee/tee_core.c
@@ -383,25 +383,38 @@ static int params_from_user(struct tee_context *ctx, struct tee_param *params,
case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
/*
- * If we fail to get a pointer to a shared memory
- * object (and increase the ref count) from an
- * identifier we return an error. All pointers that
- * has been added in params have an increased ref
- * count. It's the callers responibility to do
- * tee_shm_put() on all resolved pointers.
+ * If a NULL pointer is passed to a TA in the TEE,
+ * the ip.c IOCTL parameters is set to TEE_MEMREF_NULL
+ * indicating a NULL memory reference.
*/
- shm = tee_shm_get_from_id(ctx, ip.c);
- if (IS_ERR(shm))
- return PTR_ERR(shm);
-
- /*
- * Ensure offset + size does not overflow offset
- * and does not overflow the size of the referred
- * shared memory object.
- */
- if ((ip.a + ip.b) < ip.a ||
- (ip.a + ip.b) > shm->size) {
- tee_shm_put(shm);
+ if (ip.c != TEE_MEMREF_NULL) {
+ /*
+ * If we fail to get a pointer to a shared
+ * memory object (and increase the ref count)
+ * from an identifier we return an error. All
+ * pointers that has been added in params have
+ * an increased ref count. It's the callers
+ * responibility to do tee_shm_put() on all
+ * resolved pointers.
+ */
+ shm = tee_shm_get_from_id(ctx, ip.c);
+ if (IS_ERR(shm))
+ return PTR_ERR(shm);
+
+ /*
+ * Ensure offset + size does not overflow
+ * offset and does not overflow the size of
+ * the referred shared memory object.
+ */
+ if ((ip.a + ip.b) < ip.a ||
+ (ip.a + ip.b) > shm->size) {
+ tee_shm_put(shm);
+ return -EINVAL;
+ }
+ } else if (ctx->cap_memref_null) {
+ /* Pass NULL pointer to OP-TEE */
+ shm = NULL;
+ } else {
return -EINVAL;
}
@@ -917,7 +930,6 @@ struct tee_device *tee_device_alloc(const struct tee_desc *teedesc,
cdev_init(&teedev->cdev, &tee_fops);
teedev->cdev.owner = teedesc->owner;
- teedev->cdev.kobj.parent = &teedev->dev.kobj;
dev_set_drvdata(&teedev->dev, driver_data);
device_initialize(&teedev->dev);
@@ -963,9 +975,7 @@ static struct attribute *tee_dev_attrs[] = {
NULL
};
-static const struct attribute_group tee_dev_group = {
- .attrs = tee_dev_attrs,
-};
+ATTRIBUTE_GROUPS(tee_dev);
/**
* tee_device_register() - Registers a TEE device
@@ -985,39 +995,19 @@ int tee_device_register(struct tee_device *teedev)
return -EINVAL;
}
- rc = cdev_add(&teedev->cdev, teedev->dev.devt, 1);
- if (rc) {
- dev_err(&teedev->dev,
- "unable to cdev_add() %s, major %d, minor %d, err=%d\n",
- teedev->name, MAJOR(teedev->dev.devt),
- MINOR(teedev->dev.devt), rc);
- return rc;
- }
+ teedev->dev.groups = tee_dev_groups;
- rc = device_add(&teedev->dev);
+ rc = cdev_device_add(&teedev->cdev, &teedev->dev);
if (rc) {
dev_err(&teedev->dev,
- "unable to device_add() %s, major %d, minor %d, err=%d\n",
+ "unable to cdev_device_add() %s, major %d, minor %d, err=%d\n",
teedev->name, MAJOR(teedev->dev.devt),
MINOR(teedev->dev.devt), rc);
- goto err_device_add;
- }
-
- rc = sysfs_create_group(&teedev->dev.kobj, &tee_dev_group);
- if (rc) {
- dev_err(&teedev->dev,
- "failed to create sysfs attributes, err=%d\n", rc);
- goto err_sysfs_create_group;
+ return rc;
}
teedev->flags |= TEE_DEVICE_FLAG_REGISTERED;
return 0;
-
-err_sysfs_create_group:
- device_del(&teedev->dev);
-err_device_add:
- cdev_del(&teedev->cdev);
- return rc;
}
EXPORT_SYMBOL_GPL(tee_device_register);
@@ -1060,11 +1050,8 @@ void tee_device_unregister(struct tee_device *teedev)
if (!teedev)
return;
- if (teedev->flags & TEE_DEVICE_FLAG_REGISTERED) {
- sysfs_remove_group(&teedev->dev.kobj, &tee_dev_group);
- cdev_del(&teedev->cdev);
- device_del(&teedev->dev);
- }
+ if (teedev->flags & TEE_DEVICE_FLAG_REGISTERED)
+ cdev_device_del(&teedev->cdev, &teedev->dev);
tee_device_put(teedev);
wait_for_completion(&teedev->c_no_users);
diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c
index 827ac3d0fea9..00472f5ce22e 100644
--- a/drivers/tee/tee_shm.c
+++ b/drivers/tee/tee_shm.c
@@ -12,6 +12,22 @@
#include <linux/uio.h>
#include "tee_private.h"
+static void release_registered_pages(struct tee_shm *shm)
+{
+ if (shm->pages) {
+ if (shm->flags & TEE_SHM_USER_MAPPED) {
+ unpin_user_pages(shm->pages, shm->num_pages);
+ } else {
+ size_t n;
+
+ for (n = 0; n < shm->num_pages; n++)
+ put_page(shm->pages[n]);
+ }
+
+ kfree(shm->pages);
+ }
+}
+
static void tee_shm_release(struct tee_shm *shm)
{
struct tee_device *teedev = shm->ctx->teedev;
@@ -32,17 +48,13 @@ static void tee_shm_release(struct tee_shm *shm)
poolm->ops->free(poolm, shm);
} else if (shm->flags & TEE_SHM_REGISTER) {
- size_t n;
int rc = teedev->desc->ops->shm_unregister(shm->ctx, shm);
if (rc)
dev_err(teedev->dev.parent,
"unregister shm %p failed: %d", shm, rc);
- for (n = 0; n < shm->num_pages; n++)
- put_page(shm->pages[n]);
-
- kfree(shm->pages);
+ release_registered_pages(shm);
}
teedev_ctx_put(shm->ctx);
@@ -228,7 +240,7 @@ struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr,
}
if (flags & TEE_SHM_USER_MAPPED) {
- rc = get_user_pages_fast(start, num_pages, FOLL_WRITE,
+ rc = pin_user_pages_fast(start, num_pages, FOLL_WRITE,
shm->pages);
} else {
struct kvec *kiov;
@@ -292,18 +304,12 @@ struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr,
return shm;
err:
if (shm) {
- size_t n;
-
if (shm->id >= 0) {
mutex_lock(&teedev->mutex);
idr_remove(&teedev->idr, shm->id);
mutex_unlock(&teedev->mutex);
}
- if (shm->pages) {
- for (n = 0; n < shm->num_pages; n++)
- put_page(shm->pages[n]);
- kfree(shm->pages);
- }
+ release_registered_pages(shm);
}
kfree(shm);
teedev_ctx_put(ctx);