summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2020-05-15 23:04:40 +0200
committerArnd Bergmann <arnd@arndb.de>2020-05-15 23:04:40 +0200
commita875e0e5a2a307b4c35127f225d0b0b4be2bc75e (patch)
tree835c0c615d5133650849781b6b79c326b220be0c /drivers
parent5df04698bd39c71243220be353aa9def4e1bacd1 (diff)
parent848685c25da99d871bbd87369f3c3d6eead661ac (diff)
downloadlinux-next-a875e0e5a2a307b4c35127f225d0b0b4be2bc75e.tar.gz
linux-next-a875e0e5a2a307b4c35127f225d0b0b4be2bc75e.zip
Merge tag 'vexpress-modules-for-soc-v2' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux into arm/soc
VExpress modularization This series enables building various Versatile Express platform drivers as modules. The primary target is the Fast Model FVP which is supported in Android. As Android is moving towards their GKI, or generic kernel, the hardware support has to be in modules. Currently ARCH_VEXPRESS enables several built-in only drivers. Some of these are needed, but some are only needed for older 32-bit VExpress platforms and can just be disabled. * tag 'vexpress-modules-for-soc-v2' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux: ARM: vexpress: Don't select VEXPRESS_CONFIG bus: vexpress-config: Support building as module vexpress: Move setting master site to vexpress-config bus bus: vexpress-config: simplify config bus probing bus: vexpress-config: Merge vexpress-syscfg into vexpress-config mfd: vexpress-sysreg: Support building as a module mfd: vexpress-sysreg: Use devres API variants mfd: vexpress-sysreg: Drop unused syscon child devices mfd: vexpress-sysreg: Drop selecting CONFIG_CLKSRC_MMIO clk: vexpress-osc: Support building as a module clk: vexpress-osc: Use the devres clock API variants clk: versatile: Only enable SP810 on 32-bit by default clk: versatile: Rework kconfig structure amba: Retry adding deferred devices at late_initcall arm64: vexpress: Don't select CONFIG_POWER_RESET_VEXPRESS ARM: vexpress: Move vexpress_flags_set() into arch code Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/amba/bus.c14
-rw-r--r--drivers/bus/Kconfig2
-rw-r--r--drivers/bus/vexpress-config.c354
-rw-r--r--drivers/clk/Makefile2
-rw-r--r--drivers/clk/versatile/Kconfig26
-rw-r--r--drivers/clk/versatile/clk-vexpress-osc.c20
-rw-r--r--drivers/mfd/Kconfig5
-rw-r--r--drivers/mfd/vexpress-sysreg.c99
-rw-r--r--drivers/misc/Kconfig9
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/vexpress-syscfg.c280
11 files changed, 330 insertions, 482 deletions
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
index fe1523664816..e797995fc65b 100644
--- a/drivers/amba/bus.c
+++ b/drivers/amba/bus.c
@@ -505,7 +505,7 @@ static DECLARE_DELAYED_WORK(deferred_retry_work, amba_deferred_retry_func);
#define DEFERRED_DEVICE_TIMEOUT (msecs_to_jiffies(5 * 1000))
-static void amba_deferred_retry_func(struct work_struct *dummy)
+static int amba_deferred_retry(void)
{
struct deferred_device *ddev, *tmp;
@@ -521,11 +521,19 @@ static void amba_deferred_retry_func(struct work_struct *dummy)
kfree(ddev);
}
+ mutex_unlock(&deferred_devices_lock);
+
+ return 0;
+}
+late_initcall(amba_deferred_retry);
+
+static void amba_deferred_retry_func(struct work_struct *dummy)
+{
+ amba_deferred_retry();
+
if (!list_empty(&deferred_devices))
schedule_delayed_work(&deferred_retry_work,
DEFERRED_DEVICE_TIMEOUT);
-
- mutex_unlock(&deferred_devices_lock);
}
/**
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index d4c8898868fc..2d73d4b6c9a6 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -192,7 +192,7 @@ config UNIPHIER_SYSTEM_BUS
needed to use on-board devices connected to UniPhier SoCs.
config VEXPRESS_CONFIG
- bool "Versatile Express configuration bus"
+ tristate "Versatile Express configuration bus"
default y if ARCH_VEXPRESS
depends on ARM || ARM64
depends on OF
diff --git a/drivers/bus/vexpress-config.c b/drivers/bus/vexpress-config.c
index ff70575b2db6..a58ac0c8e282 100644
--- a/drivers/bus/vexpress-config.c
+++ b/drivers/bus/vexpress-config.c
@@ -6,10 +6,61 @@
#include <linux/err.h>
#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/of_device.h>
+#include <linux/sched/signal.h>
+#include <linux/slab.h>
#include <linux/vexpress.h>
+#define SYS_MISC 0x0
+#define SYS_MISC_MASTERSITE (1 << 14)
+
+#define SYS_PROCID0 0x24
+#define SYS_PROCID1 0x28
+#define SYS_HBI_MASK 0xfff
+#define SYS_PROCIDx_HBI_SHIFT 0
+
+#define SYS_CFGDATA 0x40
+
+#define SYS_CFGCTRL 0x44
+#define SYS_CFGCTRL_START (1 << 31)
+#define SYS_CFGCTRL_WRITE (1 << 30)
+#define SYS_CFGCTRL_DCC(n) (((n) & 0xf) << 26)
+#define SYS_CFGCTRL_FUNC(n) (((n) & 0x3f) << 20)
+#define SYS_CFGCTRL_SITE(n) (((n) & 0x3) << 16)
+#define SYS_CFGCTRL_POSITION(n) (((n) & 0xf) << 12)
+#define SYS_CFGCTRL_DEVICE(n) (((n) & 0xfff) << 0)
+
+#define SYS_CFGSTAT 0x48
+#define SYS_CFGSTAT_ERR (1 << 1)
+#define SYS_CFGSTAT_COMPLETE (1 << 0)
+
+#define VEXPRESS_SITE_MB 0
+#define VEXPRESS_SITE_DB1 1
+#define VEXPRESS_SITE_DB2 2
+#define VEXPRESS_SITE_MASTER 0xf
+
+struct vexpress_syscfg {
+ struct device *dev;
+ void __iomem *base;
+ struct list_head funcs;
+};
+
+struct vexpress_syscfg_func {
+ struct list_head list;
+ struct vexpress_syscfg *syscfg;
+ struct regmap *regmap;
+ int num_templates;
+ u32 template[]; /* Keep it last! */
+};
+
+struct vexpress_config_bridge_ops {
+ struct regmap * (*regmap_init)(struct device *dev, void *context);
+ void (*regmap_exit)(struct regmap *regmap, void *context);
+};
struct vexpress_config_bridge {
struct vexpress_config_bridge_ops *ops;
@@ -18,26 +69,20 @@ struct vexpress_config_bridge {
static DEFINE_MUTEX(vexpress_config_mutex);
-static struct class *vexpress_config_class;
static u32 vexpress_config_site_master = VEXPRESS_SITE_MASTER;
-void vexpress_config_set_master(u32 site)
+static void vexpress_config_set_master(u32 site)
{
vexpress_config_site_master = site;
}
-u32 vexpress_config_get_master(void)
-{
- return vexpress_config_site_master;
-}
-
-void vexpress_config_lock(void *arg)
+static void vexpress_config_lock(void *arg)
{
mutex_lock(&vexpress_config_mutex);
}
-void vexpress_config_unlock(void *arg)
+static void vexpress_config_unlock(void *arg)
{
mutex_unlock(&vexpress_config_mutex);
}
@@ -59,7 +104,7 @@ static void vexpress_config_find_prop(struct device_node *node,
}
}
-int vexpress_config_get_topo(struct device_node *node, u32 *site,
+static int vexpress_config_get_topo(struct device_node *node, u32 *site,
u32 *position, u32 *dcc)
{
vexpress_config_find_prop(node, "arm,vexpress,site", site);
@@ -88,9 +133,6 @@ struct regmap *devm_regmap_init_vexpress_config(struct device *dev)
struct regmap *regmap;
struct regmap **res;
- if (WARN_ON(dev->parent->class != vexpress_config_class))
- return ERR_PTR(-ENODEV);
-
bridge = dev_get_drvdata(dev->parent);
if (WARN_ON(!bridge))
return ERR_PTR(-EINVAL);
@@ -113,91 +155,265 @@ struct regmap *devm_regmap_init_vexpress_config(struct device *dev)
}
EXPORT_SYMBOL_GPL(devm_regmap_init_vexpress_config);
-struct device *vexpress_config_bridge_register(struct device *parent,
- struct vexpress_config_bridge_ops *ops, void *context)
+static int vexpress_syscfg_exec(struct vexpress_syscfg_func *func,
+ int index, bool write, u32 *data)
{
- struct device *dev;
- struct vexpress_config_bridge *bridge;
+ struct vexpress_syscfg *syscfg = func->syscfg;
+ u32 command, status;
+ int tries;
+ long timeout;
- if (!vexpress_config_class) {
- vexpress_config_class = class_create(THIS_MODULE,
- "vexpress-config");
- if (IS_ERR(vexpress_config_class))
- return (void *)vexpress_config_class;
+ if (WARN_ON(index >= func->num_templates))
+ return -EINVAL;
+
+ command = readl(syscfg->base + SYS_CFGCTRL);
+ if (WARN_ON(command & SYS_CFGCTRL_START))
+ return -EBUSY;
+
+ command = func->template[index];
+ command |= SYS_CFGCTRL_START;
+ command |= write ? SYS_CFGCTRL_WRITE : 0;
+
+ /* Use a canary for reads */
+ if (!write)
+ *data = 0xdeadbeef;
+
+ dev_dbg(syscfg->dev, "func %p, command %x, data %x\n",
+ func, command, *data);
+ writel(*data, syscfg->base + SYS_CFGDATA);
+ writel(0, syscfg->base + SYS_CFGSTAT);
+ writel(command, syscfg->base + SYS_CFGCTRL);
+ mb();
+
+ /* The operation can take ages... Go to sleep, 100us initially */
+ tries = 100;
+ timeout = 100;
+ do {
+ if (!irqs_disabled()) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(usecs_to_jiffies(timeout));
+ if (signal_pending(current))
+ return -EINTR;
+ } else {
+ udelay(timeout);
+ }
+
+ status = readl(syscfg->base + SYS_CFGSTAT);
+ if (status & SYS_CFGSTAT_ERR)
+ return -EFAULT;
+
+ if (timeout > 20)
+ timeout -= 20;
+ } while (--tries && !(status & SYS_CFGSTAT_COMPLETE));
+ if (WARN_ON_ONCE(!tries))
+ return -ETIMEDOUT;
+
+ if (!write) {
+ *data = readl(syscfg->base + SYS_CFGDATA);
+ dev_dbg(syscfg->dev, "func %p, read data %x\n", func, *data);
}
- dev = device_create(vexpress_config_class, parent, 0,
- NULL, "%s.bridge", dev_name(parent));
+ return 0;
+}
+
+static int vexpress_syscfg_read(void *context, unsigned int index,
+ unsigned int *val)
+{
+ struct vexpress_syscfg_func *func = context;
+
+ return vexpress_syscfg_exec(func, index, false, val);
+}
+
+static int vexpress_syscfg_write(void *context, unsigned int index,
+ unsigned int val)
+{
+ struct vexpress_syscfg_func *func = context;
+
+ return vexpress_syscfg_exec(func, index, true, &val);
+}
+
+static struct regmap_config vexpress_syscfg_regmap_config = {
+ .lock = vexpress_config_lock,
+ .unlock = vexpress_config_unlock,
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_read = vexpress_syscfg_read,
+ .reg_write = vexpress_syscfg_write,
+ .reg_format_endian = REGMAP_ENDIAN_LITTLE,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
+};
+
- if (IS_ERR(dev))
- return dev;
+static struct regmap *vexpress_syscfg_regmap_init(struct device *dev,
+ void *context)
+{
+ int err;
+ struct vexpress_syscfg *syscfg = context;
+ struct vexpress_syscfg_func *func;
+ struct property *prop;
+ const __be32 *val = NULL;
+ __be32 energy_quirk[4];
+ int num;
+ u32 site, position, dcc;
+ int i;
+
+ err = vexpress_config_get_topo(dev->of_node, &site,
+ &position, &dcc);
+ if (err)
+ return ERR_PTR(err);
+
+ prop = of_find_property(dev->of_node,
+ "arm,vexpress-sysreg,func", NULL);
+ if (!prop)
+ return ERR_PTR(-EINVAL);
- bridge = devm_kmalloc(dev, sizeof(*bridge), GFP_KERNEL);
- if (!bridge) {
- put_device(dev);
- device_unregister(dev);
+ num = prop->length / sizeof(u32) / 2;
+ val = prop->value;
+
+ /*
+ * "arm,vexpress-energy" function used to be described
+ * by its first device only, now it requires both
+ */
+ if (num == 1 && of_device_is_compatible(dev->of_node,
+ "arm,vexpress-energy")) {
+ num = 2;
+ energy_quirk[0] = *val;
+ energy_quirk[2] = *val++;
+ energy_quirk[1] = *val;
+ energy_quirk[3] = cpu_to_be32(be32_to_cpup(val) + 1);
+ val = energy_quirk;
+ }
+
+ func = kzalloc(struct_size(func, template, num), GFP_KERNEL);
+ if (!func)
return ERR_PTR(-ENOMEM);
+
+ func->syscfg = syscfg;
+ func->num_templates = num;
+
+ for (i = 0; i < num; i++) {
+ u32 function, device;
+
+ function = be32_to_cpup(val++);
+ device = be32_to_cpup(val++);
+
+ dev_dbg(dev, "func %p: %u/%u/%u/%u/%u\n",
+ func, site, position, dcc,
+ function, device);
+
+ func->template[i] = SYS_CFGCTRL_DCC(dcc);
+ func->template[i] |= SYS_CFGCTRL_SITE(site);
+ func->template[i] |= SYS_CFGCTRL_POSITION(position);
+ func->template[i] |= SYS_CFGCTRL_FUNC(function);
+ func->template[i] |= SYS_CFGCTRL_DEVICE(device);
}
- bridge->ops = ops;
- bridge->context = context;
- dev_set_drvdata(dev, bridge);
+ vexpress_syscfg_regmap_config.max_register = num - 1;
- dev_dbg(parent, "Registered bridge '%s', parent node %p\n",
- dev_name(dev), parent->of_node);
+ func->regmap = regmap_init(dev, NULL, func,
+ &vexpress_syscfg_regmap_config);
- return dev;
-}
+ if (IS_ERR(func->regmap)) {
+ void *err = func->regmap;
+ kfree(func);
+ return err;
+ }
+
+ list_add(&func->list, &syscfg->funcs);
-static int vexpress_config_node_match(struct device *dev, const void *data)
+ return func->regmap;
+}
+
+static void vexpress_syscfg_regmap_exit(struct regmap *regmap, void *context)
{
- const struct device_node *node = data;
+ struct vexpress_syscfg *syscfg = context;
+ struct vexpress_syscfg_func *func, *tmp;
- dev_dbg(dev, "Parent node %p, looking for %p\n",
- dev->parent->of_node, node);
+ regmap_exit(regmap);
- return dev->parent->of_node == node;
+ list_for_each_entry_safe(func, tmp, &syscfg->funcs, list) {
+ if (func->regmap == regmap) {
+ list_del(&syscfg->funcs);
+ kfree(func);
+ break;
+ }
+ }
}
-static int vexpress_config_populate(struct device_node *node)
+static struct vexpress_config_bridge_ops vexpress_syscfg_bridge_ops = {
+ .regmap_init = vexpress_syscfg_regmap_init,
+ .regmap_exit = vexpress_syscfg_regmap_exit,
+};
+
+
+static int vexpress_syscfg_probe(struct platform_device *pdev)
{
- struct device_node *bridge;
- struct device *parent;
- int ret;
+ struct vexpress_syscfg *syscfg;
+ struct resource *res;
+ struct vexpress_config_bridge *bridge;
+ struct device_node *node;
+ int master;
+ u32 dt_hbi;
+
+ syscfg = devm_kzalloc(&pdev->dev, sizeof(*syscfg), GFP_KERNEL);
+ if (!syscfg)
+ return -ENOMEM;
+ syscfg->dev = &pdev->dev;
+ INIT_LIST_HEAD(&syscfg->funcs);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ syscfg->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(syscfg->base))
+ return PTR_ERR(syscfg->base);
- bridge = of_parse_phandle(node, "arm,vexpress,config-bridge", 0);
+ bridge = devm_kmalloc(&pdev->dev, sizeof(*bridge), GFP_KERNEL);
if (!bridge)
- return -EINVAL;
+ return -ENOMEM;
- parent = class_find_device(vexpress_config_class, NULL, bridge,
- vexpress_config_node_match);
- of_node_put(bridge);
- if (WARN_ON(!parent))
- return -ENODEV;
+ bridge->ops = &vexpress_syscfg_bridge_ops;
+ bridge->context = syscfg;
- ret = of_platform_populate(node, NULL, NULL, parent);
+ dev_set_drvdata(&pdev->dev, bridge);
- put_device(parent);
+ master = readl(syscfg->base + SYS_MISC) & SYS_MISC_MASTERSITE ?
+ VEXPRESS_SITE_DB2 : VEXPRESS_SITE_DB1;
+ vexpress_config_set_master(master);
- return ret;
-}
+ /* Confirm board type against DT property, if available */
+ if (of_property_read_u32(of_root, "arm,hbi", &dt_hbi) == 0) {
+ u32 id = readl(syscfg->base + (master == VEXPRESS_SITE_DB1 ?
+ SYS_PROCID0 : SYS_PROCID1));
+ u32 hbi = (id >> SYS_PROCIDx_HBI_SHIFT) & SYS_HBI_MASK;
-static int __init vexpress_config_init(void)
-{
- int err = 0;
- struct device_node *node;
+ if (WARN_ON(dt_hbi != hbi))
+ dev_warn(&pdev->dev, "DT HBI (%x) is not matching hardware (%x)!\n",
+ dt_hbi, hbi);
+ }
- /* Need the config devices early, before the "normal" devices... */
for_each_compatible_node(node, NULL, "arm,vexpress,config-bus") {
- err = vexpress_config_populate(node);
- if (err) {
- of_node_put(node);
- break;
- }
+ struct device_node *bridge_np;
+
+ bridge_np = of_parse_phandle(node, "arm,vexpress,config-bridge", 0);
+ if (bridge_np != pdev->dev.parent->of_node)
+ continue;
+
+ of_platform_populate(node, NULL, NULL, &pdev->dev);
}
- return err;
+ return 0;
}
-postcore_initcall(vexpress_config_init);
+static const struct platform_device_id vexpress_syscfg_id_table[] = {
+ { "vexpress-syscfg", },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, vexpress_syscfg_id_table);
+
+static struct platform_driver vexpress_syscfg_driver = {
+ .driver.name = "vexpress-syscfg",
+ .id_table = vexpress_syscfg_id_table,
+ .probe = vexpress_syscfg_probe,
+};
+module_platform_driver(vexpress_syscfg_driver);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index f4169cc2fd31..fb30c16e1596 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -114,7 +114,7 @@ obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-y += ti/
obj-$(CONFIG_CLK_UNIPHIER) += uniphier/
obj-$(CONFIG_ARCH_U8500) += ux500/
-obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/
+obj-y += versatile/
ifeq ($(CONFIG_COMMON_CLK), y)
obj-$(CONFIG_X86) += x86/
endif
diff --git a/drivers/clk/versatile/Kconfig b/drivers/clk/versatile/Kconfig
index c2618f1477a2..a0ed412e8396 100644
--- a/drivers/clk/versatile/Kconfig
+++ b/drivers/clk/versatile/Kconfig
@@ -1,33 +1,35 @@
# SPDX-License-Identifier: GPL-2.0-only
-config ICST
- bool
-config COMMON_CLK_VERSATILE
- bool "Clock driver for ARM Reference designs"
- depends on ARCH_INTEGRATOR || ARCH_REALVIEW || \
- ARCH_VERSATILE || ARCH_VEXPRESS || ARM64 || \
- COMPILE_TEST
+menuconfig COMMON_CLK_VERSATILE
+ bool "Clock driver for ARM Reference designs" if COMPILE_TEST
+ default y if ARCH_INTEGRATOR || ARCH_REALVIEW || \
+ ARCH_VERSATILE || ARCH_VEXPRESS
+
+if COMMON_CLK_VERSATILE
+
+config ICST
+ bool "Clock driver for ARM Reference designs ICST"
select REGMAP_MMIO
---help---
Supports clocking on ARM Reference designs:
- Integrator/AP and Integrator/CP
- RealView PB1176, EB, PB11MP and PBX
- - Versatile Express
config CLK_SP810
bool "Clock driver for ARM SP810 System Controller"
- depends on COMMON_CLK_VERSATILE
- default y if ARCH_VEXPRESS
+ default y if (ARCH_VEXPRESS && ARM)
---help---
Supports clock muxing (REFCLK/TIMCLK to TIMERCLKEN0-3) capabilities
of the ARM SP810 System Controller cell.
config CLK_VEXPRESS_OSC
- bool "Clock driver for Versatile Express OSC clock generators"
- depends on COMMON_CLK_VERSATILE
+ tristate "Clock driver for Versatile Express OSC clock generators"
depends on VEXPRESS_CONFIG
+ select REGMAP_MMIO
default y if ARCH_VEXPRESS
---help---
Simple regmap-based driver driving clock generators on Versatile
Express platforms hidden behind its configuration infrastructure,
commonly known as OSCs.
+
+endif
diff --git a/drivers/clk/versatile/clk-vexpress-osc.c b/drivers/clk/versatile/clk-vexpress-osc.c
index 7ade146a3ea9..b2b32fa2d7c3 100644
--- a/drivers/clk/versatile/clk-vexpress-osc.c
+++ b/drivers/clk/versatile/clk-vexpress-osc.c
@@ -7,6 +7,7 @@
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
+#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -65,8 +66,8 @@ static int vexpress_osc_probe(struct platform_device *pdev)
{
struct clk_init_data init;
struct vexpress_osc *osc;
- struct clk *clk;
u32 range[2];
+ int ret;
osc = devm_kzalloc(&pdev->dev, sizeof(*osc), GFP_KERNEL);
if (!osc)
@@ -92,11 +93,11 @@ static int vexpress_osc_probe(struct platform_device *pdev)
osc->hw.init = &init;
- clk = clk_register(NULL, &osc->hw);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
+ ret = devm_clk_hw_register(&pdev->dev, &osc->hw);
+ if (ret < 0)
+ return ret;
- of_clk_add_provider(pdev->dev.of_node, of_clk_src_simple_get, clk);
+ devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_simple_get, &osc->hw);
clk_hw_set_rate_range(&osc->hw, osc->rate_min, osc->rate_max);
dev_dbg(&pdev->dev, "Registered clock '%s'\n", init.name);
@@ -108,6 +109,7 @@ static const struct of_device_id vexpress_osc_of_match[] = {
{ .compatible = "arm,vexpress-osc", },
{}
};
+MODULE_DEVICE_TABLE(of, vexpress_osc_of_match);
static struct platform_driver vexpress_osc_driver = {
.driver = {
@@ -116,9 +118,5 @@ static struct platform_driver vexpress_osc_driver = {
},
.probe = vexpress_osc_probe,
};
-
-static int __init vexpress_osc_init(void)
-{
- return platform_driver_register(&vexpress_osc_driver);
-}
-core_initcall(vexpress_osc_init);
+module_platform_driver(vexpress_osc_driver);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 0a59249198d3..792766558328 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -2028,10 +2028,9 @@ config MCP_UCB1200_TS
endmenu
config MFD_VEXPRESS_SYSREG
- bool "Versatile Express System Registers"
- depends on VEXPRESS_CONFIG && GPIOLIB && !ARCH_USES_GETTIMEOFFSET
+ tristate "Versatile Express System Registers"
+ depends on VEXPRESS_CONFIG && GPIOLIB
default y
- select CLKSRC_MMIO
select GPIO_GENERIC_PLATFORM
select MFD_CORE
select MFD_SYSCON
diff --git a/drivers/mfd/vexpress-sysreg.c b/drivers/mfd/vexpress-sysreg.c
index c68ff56dbdb1..aaf24af287dd 100644
--- a/drivers/mfd/vexpress-sysreg.c
+++ b/drivers/mfd/vexpress-sysreg.c
@@ -8,13 +8,12 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/mfd/core.h>
-#include <linux/of_address.h>
+#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_data/syscon.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/stat.h>
-#include <linux/vexpress.h>
#define SYS_ID 0x000
#define SYS_SW 0x004
@@ -37,35 +36,8 @@
#define SYS_CFGCTRL 0x0a4
#define SYS_CFGSTAT 0x0a8
-#define SYS_HBI_MASK 0xfff
-#define SYS_PROCIDx_HBI_SHIFT 0
-
-#define SYS_MISC_MASTERSITE (1 << 14)
-
-void vexpress_flags_set(u32 data)
-{
- static void __iomem *base;
-
- if (!base) {
- struct device_node *node = of_find_compatible_node(NULL, NULL,
- "arm,vexpress-sysreg");
-
- base = of_iomap(node, 0);
- }
-
- if (WARN_ON(!base))
- return;
-
- writel(~0, base + SYS_FLAGSCLR);
- writel(data, base + SYS_FLAGSSET);
-}
-
/* The sysreg block is just a random collection of various functions... */
-static struct syscon_platform_data vexpress_sysreg_sys_id_pdata = {
- .label = "sys_id",
-};
-
static struct bgpio_pdata vexpress_sysreg_sys_led_pdata = {
.label = "sys_led",
.base = -1,
@@ -84,24 +56,8 @@ static struct bgpio_pdata vexpress_sysreg_sys_flash_pdata = {
.ngpio = 1,
};
-static struct syscon_platform_data vexpress_sysreg_sys_misc_pdata = {
- .label = "sys_misc",
-};
-
-static struct syscon_platform_data vexpress_sysreg_sys_procid_pdata = {
- .label = "sys_procid",
-};
-
static struct mfd_cell vexpress_sysreg_cells[] = {
{
- .name = "syscon",
- .num_resources = 1,
- .resources = (struct resource []) {
- DEFINE_RES_MEM(SYS_ID, 0x4),
- },
- .platform_data = &vexpress_sysreg_sys_id_pdata,
- .pdata_size = sizeof(vexpress_sysreg_sys_id_pdata),
- }, {
.name = "basic-mmio-gpio",
.of_compatible = "arm,vexpress-sysreg,sys_led",
.num_resources = 1,
@@ -129,26 +85,10 @@ static struct mfd_cell vexpress_sysreg_cells[] = {
.platform_data = &vexpress_sysreg_sys_flash_pdata,
.pdata_size = sizeof(vexpress_sysreg_sys_flash_pdata),
}, {
- .name = "syscon",
- .num_resources = 1,
- .resources = (struct resource []) {
- DEFINE_RES_MEM(SYS_MISC, 0x4),
- },
- .platform_data = &vexpress_sysreg_sys_misc_pdata,
- .pdata_size = sizeof(vexpress_sysreg_sys_misc_pdata),
- }, {
- .name = "syscon",
- .num_resources = 1,
- .resources = (struct resource []) {
- DEFINE_RES_MEM(SYS_PROCID0, 0x8),
- },
- .platform_data = &vexpress_sysreg_sys_procid_pdata,
- .pdata_size = sizeof(vexpress_sysreg_sys_procid_pdata),
- }, {
.name = "vexpress-syscfg",
.num_resources = 1,
.resources = (struct resource []) {
- DEFINE_RES_MEM(SYS_CFGDATA, 0xc),
+ DEFINE_RES_MEM(SYS_MISC, 0x4c),
},
}
};
@@ -158,8 +98,6 @@ static int vexpress_sysreg_probe(struct platform_device *pdev)
struct resource *mem;
void __iomem *base;
struct gpio_chip *mmc_gpio_chip;
- int master;
- u32 dt_hbi;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem)
@@ -169,21 +107,6 @@ static int vexpress_sysreg_probe(struct platform_device *pdev)
if (!base)
return -ENOMEM;
- master = readl(base + SYS_MISC) & SYS_MISC_MASTERSITE ?
- VEXPRESS_SITE_DB2 : VEXPRESS_SITE_DB1;
- vexpress_config_set_master(master);
-
- /* Confirm board type against DT property, if available */
- if (of_property_read_u32(of_root, "arm,hbi", &dt_hbi) == 0) {
- u32 id = readl(base + (master == VEXPRESS_SITE_DB1 ?
- SYS_PROCID0 : SYS_PROCID1));
- u32 hbi = (id >> SYS_PROCIDx_HBI_SHIFT) & SYS_HBI_MASK;
-
- if (WARN_ON(dt_hbi != hbi))
- dev_warn(&pdev->dev, "DT HBI (%x) is not matching hardware (%x)!\n",
- dt_hbi, hbi);
- }
-
/*
* Duplicated SYS_MCI pseudo-GPIO controller for compatibility with
* older trees using sysreg node for MMC control lines.
@@ -195,9 +118,9 @@ static int vexpress_sysreg_probe(struct platform_device *pdev)
bgpio_init(mmc_gpio_chip, &pdev->dev, 0x4, base + SYS_MCI,
NULL, NULL, NULL, NULL, 0);
mmc_gpio_chip->ngpio = 2;
- gpiochip_add_data(mmc_gpio_chip, NULL);
+ devm_gpiochip_add_data(&pdev->dev, mmc_gpio_chip, NULL);
- return mfd_add_devices(&pdev->dev, PLATFORM_DEVID_AUTO,
+ return devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_AUTO,
vexpress_sysreg_cells,
ARRAY_SIZE(vexpress_sysreg_cells), mem, 0, NULL);
}
@@ -206,6 +129,7 @@ static const struct of_device_id vexpress_sysreg_match[] = {
{ .compatible = "arm,vexpress-sysreg", },
{},
};
+MODULE_DEVICE_TABLE(of, vexpress_sysreg_match);
static struct platform_driver vexpress_sysreg_driver = {
.driver = {
@@ -215,14 +139,5 @@ static struct platform_driver vexpress_sysreg_driver = {
.probe = vexpress_sysreg_probe,
};
-static int __init vexpress_sysreg_init(void)
-{
- struct device_node *node;
-
- /* Need the sysreg early, before any other device... */
- for_each_matching_node(node, vexpress_sysreg_match)
- of_platform_device_create(node, NULL, NULL);
-
- return platform_driver_register(&vexpress_sysreg_driver);
-}
-core_initcall(vexpress_sysreg_init);
+module_platform_driver(vexpress_sysreg_driver);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 99e151475d8f..edd5dd5ebfdc 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -423,15 +423,6 @@ config SRAM
config SRAM_EXEC
bool
-config VEXPRESS_SYSCFG
- bool "Versatile Express System Configuration driver"
- depends on VEXPRESS_CONFIG
- default y
- help
- ARM Ltd. Versatile Express uses specialised platform configuration
- bus. System Configuration interface is one of the possible means
- of generating transactions on this bus.
-
config PCI_ENDPOINT_TEST
depends on PCI
select CRC32
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 9abf2923d831..c7bd01ac6291 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -49,7 +49,6 @@ obj-$(CONFIG_SRAM_EXEC) += sram-exec.o
obj-y += mic/
obj-$(CONFIG_GENWQE) += genwqe/
obj-$(CONFIG_ECHO) += echo/
-obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o
obj-$(CONFIG_CXL_BASE) += cxl/
obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o
obj-$(CONFIG_OCXL) += ocxl/
diff --git a/drivers/misc/vexpress-syscfg.c b/drivers/misc/vexpress-syscfg.c
deleted file mode 100644
index a431787c0898..000000000000
--- a/drivers/misc/vexpress-syscfg.c
+++ /dev/null
@@ -1,280 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- *
- * Copyright (C) 2014 ARM Limited
- */
-
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/sched/signal.h>
-#include <linux/slab.h>
-#include <linux/syscore_ops.h>
-#include <linux/vexpress.h>
-
-
-#define SYS_CFGDATA 0x0
-
-#define SYS_CFGCTRL 0x4
-#define SYS_CFGCTRL_START (1 << 31)
-#define SYS_CFGCTRL_WRITE (1 << 30)
-#define SYS_CFGCTRL_DCC(n) (((n) & 0xf) << 26)
-#define SYS_CFGCTRL_FUNC(n) (((n) & 0x3f) << 20)
-#define SYS_CFGCTRL_SITE(n) (((n) & 0x3) << 16)
-#define SYS_CFGCTRL_POSITION(n) (((n) & 0xf) << 12)
-#define SYS_CFGCTRL_DEVICE(n) (((n) & 0xfff) << 0)
-
-#define SYS_CFGSTAT 0x8
-#define SYS_CFGSTAT_ERR (1 << 1)
-#define SYS_CFGSTAT_COMPLETE (1 << 0)
-
-
-struct vexpress_syscfg {
- struct device *dev;
- void __iomem *base;
- struct list_head funcs;
-};
-
-struct vexpress_syscfg_func {
- struct list_head list;
- struct vexpress_syscfg *syscfg;
- struct regmap *regmap;
- int num_templates;
- u32 template[]; /* Keep it last! */
-};
-
-
-static int vexpress_syscfg_exec(struct vexpress_syscfg_func *func,
- int index, bool write, u32 *data)
-{
- struct vexpress_syscfg *syscfg = func->syscfg;
- u32 command, status;
- int tries;
- long timeout;
-
- if (WARN_ON(index >= func->num_templates))
- return -EINVAL;
-
- command = readl(syscfg->base + SYS_CFGCTRL);
- if (WARN_ON(command & SYS_CFGCTRL_START))
- return -EBUSY;
-
- command = func->template[index];
- command |= SYS_CFGCTRL_START;
- command |= write ? SYS_CFGCTRL_WRITE : 0;
-
- /* Use a canary for reads */
- if (!write)
- *data = 0xdeadbeef;
-
- dev_dbg(syscfg->dev, "func %p, command %x, data %x\n",
- func, command, *data);
- writel(*data, syscfg->base + SYS_CFGDATA);
- writel(0, syscfg->base + SYS_CFGSTAT);
- writel(command, syscfg->base + SYS_CFGCTRL);
- mb();
-
- /* The operation can take ages... Go to sleep, 100us initially */
- tries = 100;
- timeout = 100;
- do {
- if (!irqs_disabled()) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(usecs_to_jiffies(timeout));
- if (signal_pending(current))
- return -EINTR;
- } else {
- udelay(timeout);
- }
-
- status = readl(syscfg->base + SYS_CFGSTAT);
- if (status & SYS_CFGSTAT_ERR)
- return -EFAULT;
-
- if (timeout > 20)
- timeout -= 20;
- } while (--tries && !(status & SYS_CFGSTAT_COMPLETE));
- if (WARN_ON_ONCE(!tries))
- return -ETIMEDOUT;
-
- if (!write) {
- *data = readl(syscfg->base + SYS_CFGDATA);
- dev_dbg(syscfg->dev, "func %p, read data %x\n", func, *data);
- }
-
- return 0;
-}
-
-static int vexpress_syscfg_read(void *context, unsigned int index,
- unsigned int *val)
-{
- struct vexpress_syscfg_func *func = context;
-
- return vexpress_syscfg_exec(func, index, false, val);
-}
-
-static int vexpress_syscfg_write(void *context, unsigned int index,
- unsigned int val)
-{
- struct vexpress_syscfg_func *func = context;
-
- return vexpress_syscfg_exec(func, index, true, &val);
-}
-
-static struct regmap_config vexpress_syscfg_regmap_config = {
- .lock = vexpress_config_lock,
- .unlock = vexpress_config_unlock,
- .reg_bits = 32,
- .val_bits = 32,
- .reg_read = vexpress_syscfg_read,
- .reg_write = vexpress_syscfg_write,
- .reg_format_endian = REGMAP_ENDIAN_LITTLE,
- .val_format_endian = REGMAP_ENDIAN_LITTLE,
-};
-
-
-static struct regmap *vexpress_syscfg_regmap_init(struct device *dev,
- void *context)
-{
- int err;
- struct vexpress_syscfg *syscfg = context;
- struct vexpress_syscfg_func *func;
- struct property *prop;
- const __be32 *val = NULL;
- __be32 energy_quirk[4];
- int num;
- u32 site, position, dcc;
- int i;
-
- err = vexpress_config_get_topo(dev->of_node, &site,
- &position, &dcc);
- if (err)
- return ERR_PTR(err);
-
- prop = of_find_property(dev->of_node,
- "arm,vexpress-sysreg,func", NULL);
- if (!prop)
- return ERR_PTR(-EINVAL);
-
- num = prop->length / sizeof(u32) / 2;
- val = prop->value;
-
- /*
- * "arm,vexpress-energy" function used to be described
- * by its first device only, now it requires both
- */
- if (num == 1 && of_device_is_compatible(dev->of_node,
- "arm,vexpress-energy")) {
- num = 2;
- energy_quirk[0] = *val;
- energy_quirk[2] = *val++;
- energy_quirk[1] = *val;
- energy_quirk[3] = cpu_to_be32(be32_to_cpup(val) + 1);
- val = energy_quirk;
- }
-
- func = kzalloc(struct_size(func, template, num), GFP_KERNEL);
- if (!func)
- return ERR_PTR(-ENOMEM);
-
- func->syscfg = syscfg;
- func->num_templates = num;
-
- for (i = 0; i < num; i++) {
- u32 function, device;
-
- function = be32_to_cpup(val++);
- device = be32_to_cpup(val++);
-
- dev_dbg(dev, "func %p: %u/%u/%u/%u/%u\n",
- func, site, position, dcc,
- function, device);
-
- func->template[i] = SYS_CFGCTRL_DCC(dcc);
- func->template[i] |= SYS_CFGCTRL_SITE(site);
- func->template[i] |= SYS_CFGCTRL_POSITION(position);
- func->template[i] |= SYS_CFGCTRL_FUNC(function);
- func->template[i] |= SYS_CFGCTRL_DEVICE(device);
- }
-
- vexpress_syscfg_regmap_config.max_register = num - 1;
-
- func->regmap = regmap_init(dev, NULL, func,
- &vexpress_syscfg_regmap_config);
-
- if (IS_ERR(func->regmap)) {
- void *err = func->regmap;
-
- kfree(func);
- return err;
- }
-
- list_add(&func->list, &syscfg->funcs);
-
- return func->regmap;
-}
-
-static void vexpress_syscfg_regmap_exit(struct regmap *regmap, void *context)
-{
- struct vexpress_syscfg *syscfg = context;
- struct vexpress_syscfg_func *func, *tmp;
-
- regmap_exit(regmap);
-
- list_for_each_entry_safe(func, tmp, &syscfg->funcs, list) {
- if (func->regmap == regmap) {
- list_del(&syscfg->funcs);
- kfree(func);
- break;
- }
- }
-}
-
-static struct vexpress_config_bridge_ops vexpress_syscfg_bridge_ops = {
- .regmap_init = vexpress_syscfg_regmap_init,
- .regmap_exit = vexpress_syscfg_regmap_exit,
-};
-
-
-static int vexpress_syscfg_probe(struct platform_device *pdev)
-{
- struct vexpress_syscfg *syscfg;
- struct resource *res;
- struct device *bridge;
-
- syscfg = devm_kzalloc(&pdev->dev, sizeof(*syscfg), GFP_KERNEL);
- if (!syscfg)
- return -ENOMEM;
- syscfg->dev = &pdev->dev;
- INIT_LIST_HEAD(&syscfg->funcs);
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- syscfg->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(syscfg->base))
- return PTR_ERR(syscfg->base);
-
- /* Must use dev.parent (MFD), as that's where DT phandle points at... */
- bridge = vexpress_config_bridge_register(pdev->dev.parent,
- &vexpress_syscfg_bridge_ops, syscfg);
-
- return PTR_ERR_OR_ZERO(bridge);
-}
-
-static const struct platform_device_id vexpress_syscfg_id_table[] = {
- { "vexpress-syscfg", },
- {},
-};
-
-static struct platform_driver vexpress_syscfg_driver = {
- .driver.name = "vexpress-syscfg",
- .id_table = vexpress_syscfg_id_table,
- .probe = vexpress_syscfg_probe,
-};
-
-static int __init vexpress_syscfg_init(void)
-{
- return platform_driver_register(&vexpress_syscfg_driver);
-}
-core_initcall(vexpress_syscfg_init);