diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/amba/bus.c | 14 | ||||
-rw-r--r-- | drivers/bus/Kconfig | 11 | ||||
-rw-r--r-- | drivers/bus/Makefile | 2 | ||||
-rw-r--r-- | drivers/bus/arm-integrator-lm.c | 128 | ||||
-rw-r--r-- | drivers/bus/ti-sysc.c | 25 | ||||
-rw-r--r-- | drivers/bus/vexpress-config.c | 354 | ||||
-rw-r--r-- | drivers/clk/Makefile | 2 | ||||
-rw-r--r-- | drivers/clk/ti/clk-816x.c | 1 | ||||
-rw-r--r-- | drivers/clk/versatile/Kconfig | 21 | ||||
-rw-r--r-- | drivers/clk/versatile/clk-impd1.c | 121 | ||||
-rw-r--r-- | drivers/clk/versatile/clk-vexpress-osc.c | 20 | ||||
-rw-r--r-- | drivers/firmware/tegra/bpmp.c | 9 | ||||
-rw-r--r-- | drivers/firmware/trusted_foundations.c | 21 | ||||
-rw-r--r-- | drivers/mfd/Kconfig | 5 | ||||
-rw-r--r-- | drivers/mfd/vexpress-sysreg.c | 99 | ||||
-rw-r--r-- | drivers/misc/Kconfig | 9 | ||||
-rw-r--r-- | drivers/misc/Makefile | 1 | ||||
-rw-r--r-- | drivers/misc/vexpress-syscfg.c | 280 | ||||
-rw-r--r-- | drivers/power/reset/Kconfig | 2 | ||||
-rw-r--r-- | drivers/power/reset/vexpress-poweroff.c | 8 | ||||
-rw-r--r-- | drivers/soc/imx/Makefile | 3 | ||||
-rw-r--r-- | drivers/soc/imx/soc-imx.c | 192 |
22 files changed, 703 insertions, 625 deletions
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index 8558b629880b..ecc304149067 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 6d4e4497b59b..2d73d4b6c9a6 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig @@ -20,6 +20,15 @@ config ARM_CCI400_PORT_CTRL Low level power management driver for CCI400 cache coherent interconnect for ARM platforms. +config ARM_INTEGRATOR_LM + bool "ARM Integrator Logic Module bus" + depends on HAS_IOMEM + depends on ARCH_INTEGRATOR || COMPILE_TEST + default ARCH_INTEGRATOR + help + Say y here to enable support for the ARM Logic Module bus + found on the ARM Integrator AP (Application Platform) + config BRCMSTB_GISB_ARB bool "Broadcom STB GISB bus arbiter" depends on ARM || ARM64 || MIPS @@ -183,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/Makefile b/drivers/bus/Makefile index 05f32cd694a4..97552b427f12 100644 --- a/drivers/bus/Makefile +++ b/drivers/bus/Makefile @@ -5,7 +5,7 @@ # Interconnect bus drivers for ARM platforms obj-$(CONFIG_ARM_CCI) += arm-cci.o - +obj-$(CONFIG_ARM_INTEGRATOR_LM) += arm-integrator-lm.o obj-$(CONFIG_HISILICON_LPC) += hisi_lpc.o obj-$(CONFIG_BRCMSTB_GISB_ARB) += brcmstb_gisb.o obj-$(CONFIG_MOXTET) += moxtet.o diff --git a/drivers/bus/arm-integrator-lm.c b/drivers/bus/arm-integrator-lm.c new file mode 100644 index 000000000000..845b6c43fef8 --- /dev/null +++ b/drivers/bus/arm-integrator-lm.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ARM Integrator Logical Module bus driver + * Copyright (C) 2020 Linaro Ltd. + * Author: Linus Walleij <linus.walleij@linaro.org> + * + * See the device tree bindings for this block for more details on the + * hardware. + */ + +#include <linux/module.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_platform.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/bitops.h> +#include <linux/mfd/syscon.h> +#include <linux/regmap.h> + +/* All information about the connected logic modules are in here */ +#define INTEGRATOR_SC_DEC_OFFSET 0x10 + +/* Base address for the expansion modules */ +#define INTEGRATOR_AP_EXP_BASE 0xc0000000 +#define INTEGRATOR_AP_EXP_STRIDE 0x10000000 + +static int integrator_lm_populate(int num, struct device *dev) +{ + struct device_node *np = dev->of_node; + struct device_node *child; + u32 base; + int ret; + + base = INTEGRATOR_AP_EXP_BASE + (num * INTEGRATOR_AP_EXP_STRIDE); + + /* Walk over the child nodes and see what chipselects we use */ + for_each_available_child_of_node(np, child) { + struct resource res; + + ret = of_address_to_resource(child, 0, &res); + if (ret) { + dev_info(dev, "no valid address on child\n"); + continue; + } + + /* First populate the syscon then any devices */ + if (res.start == base) { + dev_info(dev, "populate module @0x%08x from DT\n", + base); + ret = of_platform_default_populate(child, NULL, dev); + if (ret) { + dev_err(dev, "failed to populate module\n"); + return ret; + } + } + } + + return 0; +} + +static const struct of_device_id integrator_ap_syscon_match[] = { + { .compatible = "arm,integrator-ap-syscon"}, + { }, +}; + +static int integrator_ap_lm_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *syscon; + static struct regmap *map; + u32 val; + int ret; + int i; + + /* Look up the system controller */ + syscon = of_find_matching_node(NULL, integrator_ap_syscon_match); + if (!syscon) { + dev_err(dev, + "could not find Integrator/AP system controller\n"); + return -ENODEV; + } + map = syscon_node_to_regmap(syscon); + if (IS_ERR(map)) { + dev_err(dev, + "could not find Integrator/AP system controller\n"); + return PTR_ERR(map); + } + + ret = regmap_read(map, INTEGRATOR_SC_DEC_OFFSET, &val); + if (ret) { + dev_err(dev, "could not read from Integrator/AP syscon\n"); + return ret; + } + + /* Loop over the connected modules */ + for (i = 0; i < 4; i++) { + if (!(val & BIT(4 + i))) + continue; + + dev_info(dev, "detected module in slot %d\n", i); + ret = integrator_lm_populate(i, dev); + if (ret) + return ret; + } + + return 0; +} + +static const struct of_device_id integrator_ap_lm_match[] = { + { .compatible = "arm,integrator-ap-lm"}, + { }, +}; + +static struct platform_driver integrator_ap_lm_driver = { + .probe = integrator_ap_lm_probe, + .driver = { + .name = "integratorap-lm", + .of_match_table = integrator_ap_lm_match, + }, +}; +module_platform_driver(integrator_ap_lm_driver); +MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>"); +MODULE_DESCRIPTION("Integrator AP Logical Module driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index e5f5f48d69d2..3affd180baac 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -1275,13 +1275,6 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { SYSC_QUIRK_LEGACY_IDLE), SYSC_QUIRK("smartreflex", 0, -ENODEV, 0x38, -ENODEV, 0x00000000, 0xffffffff, SYSC_QUIRK_LEGACY_IDLE), - SYSC_QUIRK("timer", 0, 0, 0x10, 0x14, 0x00000015, 0xffffffff, - 0), - /* Some timers on omap4 and later */ - SYSC_QUIRK("timer", 0, 0, 0x10, -ENODEV, 0x50002100, 0xffffffff, - 0), - SYSC_QUIRK("timer", 0, 0, 0x10, -ENODEV, 0x4fff1301, 0xffff00ff, - 0), SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000046, 0xffffffff, SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE), SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000052, 0xffffffff, @@ -1404,6 +1397,13 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { SYSC_QUIRK("slimbus", 0, 0, 0x10, -ENODEV, 0x40002903, 0xffffffff, 0), SYSC_QUIRK("spinlock", 0, 0, 0x10, -ENODEV, 0x50020000, 0xffffffff, 0), SYSC_QUIRK("rng", 0, 0x1fe0, 0x1fe4, -ENODEV, 0x00000020, 0xffffffff, 0), + SYSC_QUIRK("timer", 0, 0, 0x10, 0x14, 0x00000013, 0xffffffff, 0), + SYSC_QUIRK("timer", 0, 0, 0x10, 0x14, 0x00000015, 0xffffffff, 0), + /* Some timers on omap4 and later */ + SYSC_QUIRK("timer", 0, 0, 0x10, -ENODEV, 0x50002100, 0xffffffff, 0), + SYSC_QUIRK("timer", 0, 0, 0x10, -ENODEV, 0x4fff1301, 0xffff00ff, 0), + SYSC_QUIRK("timer32k", 0, 0, 0x4, -ENODEV, 0x00000040, 0xffffffff, 0), + SYSC_QUIRK("timer32k", 0, 0, 0x4, -ENODEV, 0x00000011, 0xffffffff, 0), SYSC_QUIRK("timer32k", 0, 0, 0x4, -ENODEV, 0x00000060, 0xffffffff, 0), SYSC_QUIRK("tpcc", 0, 0, -ENODEV, -ENODEV, 0x40014c00, 0xffffffff, 0), SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000004, 0xffffffff, 0), @@ -2744,6 +2744,17 @@ static int sysc_init_soc(struct sysc *ddata) if (match && match->data) sysc_soc->soc = (int)match->data; + /* Ignore devices that are not available on HS and EMU SoCs */ + if (!sysc_soc->general_purpose) { + switch (sysc_soc->soc) { + case SOC_3430 ... SOC_3630: + sysc_add_disabled(0x48304000); /* timer12 */ + break; + default: + break; + }; + } + match = soc_device_match(sysc_soc_feat_match); if (!match) return 0; 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/ti/clk-816x.c b/drivers/clk/ti/clk-816x.c index 7d215cdf9dda..9daf3825f289 100644 --- a/drivers/clk/ti/clk-816x.c +++ b/drivers/clk/ti/clk-816x.c @@ -73,6 +73,7 @@ static const char *enable_init_clks[] = { "ddr_pll_clk1", "ddr_pll_clk2", "ddr_pll_clk3", + "sysclk6_ck", }; int __init dm816x_dt_clk_init(void) diff --git a/drivers/clk/versatile/Kconfig b/drivers/clk/versatile/Kconfig index c2618f1477a2..8c1b0e8e8d32 100644 --- a/drivers/clk/versatile/Kconfig +++ b/drivers/clk/versatile/Kconfig @@ -1,33 +1,32 @@ # SPDX-License-Identifier: GPL-2.0-only -config ICST - bool -config COMMON_CLK_VERSATILE - bool "Clock driver for ARM Reference designs" +menu "Clock driver for ARM Reference designs" depends on ARCH_INTEGRATOR || ARCH_REALVIEW || \ - ARCH_VERSATILE || ARCH_VEXPRESS || ARM64 || \ - COMPILE_TEST + ARCH_VERSATILE || ARCH_VEXPRESS || COMPILE_TEST + +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. + +endmenu diff --git a/drivers/clk/versatile/clk-impd1.c b/drivers/clk/versatile/clk-impd1.c index f9f4babe3ca6..ca798249544d 100644 --- a/drivers/clk/versatile/clk-impd1.c +++ b/drivers/clk/versatile/clk-impd1.c @@ -8,7 +8,6 @@ #include <linux/err.h> #include <linux/io.h> #include <linux/platform_device.h> -#include <linux/platform_data/clk-integrator.h> #include <linux/module.h> #include <linux/mfd/syscon.h> #include <linux/regmap.h> @@ -20,26 +19,6 @@ #define IMPD1_OSC2 0x04 #define IMPD1_LOCK 0x08 -struct impd1_clk { - char *pclkname; - struct clk *pclk; - char *vco1name; - struct clk *vco1clk; - char *vco2name; - struct clk *vco2clk; - struct clk *mmciclk; - char *uartname; - struct clk *uartclk; - char *spiname; - struct clk *spiclk; - char *scname; - struct clk *scclk; - struct clk_lookup *clks[15]; -}; - -/* One entry for each connected IM-PD1 LM */ -static struct impd1_clk impd1_clks[4]; - /* * There are two VCO's on the IM-PD1 */ @@ -80,106 +59,6 @@ static const struct clk_icst_desc impd1_icst2_desc = { .lock_offset = IMPD1_LOCK, }; -/** - * integrator_impd1_clk_init() - set up the integrator clock tree - * @base: base address of the logic module (LM) - * @id: the ID of this LM - */ -void integrator_impd1_clk_init(void __iomem *base, unsigned int id) -{ - struct impd1_clk *imc; - struct clk *clk; - struct clk *pclk; - int i; - - if (id > 3) { - pr_crit("no more than 4 LMs can be attached\n"); - return; - } - imc = &impd1_clks[id]; - - /* Register the fixed rate PCLK */ - imc->pclkname = kasprintf(GFP_KERNEL, "lm%x-pclk", id); - pclk = clk_register_fixed_rate(NULL, imc->pclkname, NULL, 0, 0); - imc->pclk = pclk; - - imc->vco1name = kasprintf(GFP_KERNEL, "lm%x-vco1", id); - clk = icst_clk_register(NULL, &impd1_icst1_desc, imc->vco1name, NULL, - base); - imc->vco1clk = clk; - imc->clks[0] = clkdev_alloc(pclk, "apb_pclk", "lm%x:01000", id); - imc->clks[1] = clkdev_alloc(clk, NULL, "lm%x:01000", id); - - /* VCO2 is also called "CLK2" */ - imc->vco2name = kasprintf(GFP_KERNEL, "lm%x-vco2", id); - clk = icst_clk_register(NULL, &impd1_icst2_desc, imc->vco2name, NULL, - base); - imc->vco2clk = clk; - - /* MMCI uses CLK2 right off */ - imc->clks[2] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00700", id); - imc->clks[3] = clkdev_alloc(clk, NULL, "lm%x:00700", id); - - /* UART reference clock divides CLK2 by a fixed factor 4 */ - imc->uartname = kasprintf(GFP_KERNEL, "lm%x-uartclk", id); - clk = clk_register_fixed_factor(NULL, imc->uartname, imc->vco2name, - CLK_IGNORE_UNUSED, 1, 4); - imc->uartclk = clk; - imc->clks[4] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00100", id); - imc->clks[5] = clkdev_alloc(clk, NULL, "lm%x:00100", id); - imc->clks[6] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00200", id); - imc->clks[7] = clkdev_alloc(clk, NULL, "lm%x:00200", id); - - /* SPI PL022 clock divides CLK2 by a fixed factor 64 */ - imc->spiname = kasprintf(GFP_KERNEL, "lm%x-spiclk", id); - clk = clk_register_fixed_factor(NULL, imc->spiname, imc->vco2name, - CLK_IGNORE_UNUSED, 1, 64); - imc->clks[8] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00300", id); - imc->clks[9] = clkdev_alloc(clk, NULL, "lm%x:00300", id); - - /* The GPIO blocks and AACI have only PCLK */ - imc->clks[10] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00400", id); - imc->clks[11] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00500", id); - imc->clks[12] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00800", id); - - /* Smart Card clock divides CLK2 by a fixed factor 4 */ - imc->scname = kasprintf(GFP_KERNEL, "lm%x-scclk", id); - clk = clk_register_fixed_factor(NULL, imc->scname, imc->vco2name, - CLK_IGNORE_UNUSED, 1, 4); - imc->scclk = clk; - imc->clks[13] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00600", id); - imc->clks[14] = clkdev_alloc(clk, NULL, "lm%x:00600", id); - - for (i = 0; i < ARRAY_SIZE(imc->clks); i++) - clkdev_add(imc->clks[i]); -} -EXPORT_SYMBOL_GPL(integrator_impd1_clk_init); - -void integrator_impd1_clk_exit(unsigned int id) -{ - int i; - struct impd1_clk *imc; - - if (id > 3) - return; - imc = &impd1_clks[id]; - - for (i = 0; i < ARRAY_SIZE(imc->clks); i++) - clkdev_drop(imc->clks[i]); - clk_unregister(imc->spiclk); - clk_unregister(imc->uartclk); - clk_unregister(imc->vco2clk); - clk_unregister(imc->vco1clk); - clk_unregister(imc->pclk); - kfree(imc->scname); - kfree(imc->spiname); - kfree(imc->uartname); - kfree(imc->vco2name); - kfree(imc->vco1name); - kfree(imc->pclkname); -} -EXPORT_SYMBOL_GPL(integrator_impd1_clk_exit); - static int integrator_impd1_clk_spawn(struct device *dev, struct device_node *parent, struct device_node *np) 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/firmware/tegra/bpmp.c b/drivers/firmware/tegra/bpmp.c index 6741fcda0c37..fe6702df24bf 100644 --- a/drivers/firmware/tegra/bpmp.c +++ b/drivers/firmware/tegra/bpmp.c @@ -6,6 +6,7 @@ #include <linux/clk/tegra.h> #include <linux/genalloc.h> #include <linux/mailbox_client.h> +#include <linux/module.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_device.h> @@ -869,12 +870,8 @@ static struct platform_driver tegra_bpmp_driver = { .name = "tegra-bpmp", .of_match_table = tegra_bpmp_match, .pm = &tegra_bpmp_pm_ops, + .suppress_bind_attrs = true, }, .probe = tegra_bpmp_probe, }; - -static int __init tegra_bpmp_init(void) -{ - return platform_driver_register(&tegra_bpmp_driver); -} -core_initcall(tegra_bpmp_init); +builtin_platform_driver(tegra_bpmp_driver); diff --git a/drivers/firmware/trusted_foundations.c b/drivers/firmware/trusted_foundations.c index fc544e19b0a1..1389fa9418a7 100644 --- a/drivers/firmware/trusted_foundations.c +++ b/drivers/firmware/trusted_foundations.c @@ -19,6 +19,7 @@ #define TF_CACHE_ENABLE 1 #define TF_CACHE_DISABLE 2 +#define TF_CACHE_REENABLE 4 #define TF_SET_CPU_BOOT_ADDR_SMC 0xfffff200 @@ -29,6 +30,7 @@ #define TF_CPU_PM_S1 0xffffffe4 #define TF_CPU_PM_S1_NOFLUSH_L2 0xffffffe7 +static unsigned long tf_idle_mode = TF_PM_MODE_NONE; static unsigned long cpu_boot_addr; static void tf_generic_smc(u32 type, u32 arg1, u32 arg2) @@ -85,25 +87,40 @@ static int tf_prepare_idle(unsigned long mode) cpu_boot_addr); break; + case TF_PM_MODE_NONE: + break; + default: return -EINVAL; } + tf_idle_mode = mode; + return 0; } #ifdef CONFIG_CACHE_L2X0 static void tf_cache_write_sec(unsigned long val, unsigned int reg) { - u32 l2x0_way_mask = 0xff; + u32 enable_op, l2x0_way_mask = 0xff; switch (reg) { case L2X0_CTRL: if (l2x0_saved_regs.aux_ctrl & L310_AUX_CTRL_ASSOCIATIVITY_16) l2x0_way_mask = 0xffff; + switch (tf_idle_mode) { + case TF_PM_MODE_LP2: + enable_op = TF_CACHE_REENABLE; + break; + + default: + enable_op = TF_CACHE_ENABLE; + break; + } + if (val == L2X0_CTRL_EN) - tf_generic_smc(TF_CACHE_MAINT, TF_CACHE_ENABLE, + tf_generic_smc(TF_CACHE_MAINT, enable_op, l2x0_saved_regs.aux_ctrl); else tf_generic_smc(TF_CACHE_MAINT, TF_CACHE_DISABLE, diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 2df22de1e8d4..4f8b73d92df3 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -2078,10 +2078,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); diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index 890380302080..df479c49be49 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -184,7 +184,7 @@ config POWER_RESET_VERSATILE config POWER_RESET_VEXPRESS bool "ARM Versatile Express power-off and reset driver" depends on ARM || ARM64 - depends on VEXPRESS_CONFIG + depends on VEXPRESS_CONFIG=y help Power off and reset support for the ARM Ltd. Versatile Express boards. diff --git a/drivers/power/reset/vexpress-poweroff.c b/drivers/power/reset/vexpress-poweroff.c index 90cbaa8341e3..1fdbcbd95fc2 100644 --- a/drivers/power/reset/vexpress-poweroff.c +++ b/drivers/power/reset/vexpress-poweroff.c @@ -143,11 +143,7 @@ static struct platform_driver vexpress_reset_driver = { .driver = { .name = "vexpress-reset", .of_match_table = vexpress_reset_of_match, + .suppress_bind_attrs = true, }, }; - -static int __init vexpress_reset_init(void) -{ - return platform_driver_register(&vexpress_reset_driver); -} -device_initcall(vexpress_reset_init); +builtin_platform_driver(vexpress_reset_driver); diff --git a/drivers/soc/imx/Makefile b/drivers/soc/imx/Makefile index 103e2c93c342..446143241fe7 100644 --- a/drivers/soc/imx/Makefile +++ b/drivers/soc/imx/Makefile @@ -1,4 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only +ifeq ($(CONFIG_ARM),y) +obj-$(CONFIG_ARCH_MXC) += soc-imx.o +endif obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o obj-$(CONFIG_SOC_IMX8M) += soc-imx8m.o diff --git a/drivers/soc/imx/soc-imx.c b/drivers/soc/imx/soc-imx.c new file mode 100644 index 000000000000..fec3d672b606 --- /dev/null +++ b/drivers/soc/imx/soc-imx.c @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2020 NXP + */ + +#include <linux/mfd/syscon.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <linux/sys_soc.h> + +#include <soc/imx/cpu.h> +#include <soc/imx/revision.h> + +#define OCOTP_UID_H 0x420 +#define OCOTP_UID_L 0x410 + +#define OCOTP_ULP_UID_1 0x4b0 +#define OCOTP_ULP_UID_2 0x4c0 +#define OCOTP_ULP_UID_3 0x4d0 +#define OCOTP_ULP_UID_4 0x4e0 + +static int __init imx_soc_device_init(void) +{ + struct soc_device_attribute *soc_dev_attr; + const char *ocotp_compat = NULL; + struct soc_device *soc_dev; + struct device_node *root; + struct regmap *ocotp = NULL; + const char *soc_id; + u64 soc_uid = 0; + u32 val; + int ret; + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) + return -ENOMEM; + + soc_dev_attr->family = "Freescale i.MX"; + + root = of_find_node_by_path("/"); + ret = of_property_read_string(root, "model", &soc_dev_attr->machine); + of_node_put(root); + if (ret) + goto free_soc; + + switch (__mxc_cpu_type) { + case MXC_CPU_MX1: + soc_id = "i.MX1"; + break; + case MXC_CPU_MX21: + soc_id = "i.MX21"; + break; + case MXC_CPU_MX25: + soc_id = "i.MX25"; + break; + case MXC_CPU_MX27: + soc_id = "i.MX27"; + break; + case MXC_CPU_MX31: + soc_id = "i.MX31"; + break; + case MXC_CPU_MX35: + soc_id = "i.MX35"; + break; + case MXC_CPU_MX51: + soc_id = "i.MX51"; + break; + case MXC_CPU_MX53: + soc_id = "i.MX53"; + break; + case MXC_CPU_IMX6SL: + ocotp_compat = "fsl,imx6sl-ocotp"; + soc_id = "i.MX6SL"; + break; + case MXC_CPU_IMX6DL: + ocotp_compat = "fsl,imx6q-ocotp"; + soc_id = "i.MX6DL"; + break; + case MXC_CPU_IMX6SX: + ocotp_compat = "fsl,imx6sx-ocotp"; + soc_id = "i.MX6SX"; + break; + case MXC_CPU_IMX6Q: + ocotp_compat = "fsl,imx6q-ocotp"; + soc_id = "i.MX6Q"; + break; + case MXC_CPU_IMX6UL: + ocotp_compat = "fsl,imx6ul-ocotp"; + soc_id = "i.MX6UL"; + break; + case MXC_CPU_IMX6ULL: + ocotp_compat = "fsl,imx6ull-ocotp"; + soc_id = "i.MX6ULL"; + break; + case MXC_CPU_IMX6ULZ: + ocotp_compat = "fsl,imx6ull-ocotp"; + soc_id = "i.MX6ULZ"; + break; + case MXC_CPU_IMX6SLL: + ocotp_compat = "fsl,imx6sll-ocotp"; + soc_id = "i.MX6SLL"; + break; + case MXC_CPU_IMX7D: + ocotp_compat = "fsl,imx7d-ocotp"; + soc_id = "i.MX7D"; + break; + case MXC_CPU_IMX7ULP: + ocotp_compat = "fsl,imx7ulp-ocotp"; + soc_id = "i.MX7ULP"; + break; + case MXC_CPU_VF500: + ocotp_compat = "fsl,vf610-ocotp"; + soc_id = "VF500"; + break; + case MXC_CPU_VF510: + ocotp_compat = "fsl,vf610-ocotp"; + soc_id = "VF510"; + break; + case MXC_CPU_VF600: + ocotp_compat = "fsl,vf610-ocotp"; + soc_id = "VF600"; + break; + case MXC_CPU_VF610: + ocotp_compat = "fsl,vf610-ocotp"; + soc_id = "VF610"; + break; + default: + soc_id = "Unknown"; + } + soc_dev_attr->soc_id = soc_id; + + if (ocotp_compat) { + ocotp = syscon_regmap_lookup_by_compatible(ocotp_compat); + if (IS_ERR(ocotp)) + pr_err("%s: failed to find %s regmap!\n", __func__, ocotp_compat); + } + + if (!IS_ERR_OR_NULL(ocotp)) { + if (__mxc_cpu_type == MXC_CPU_IMX7ULP) { + regmap_read(ocotp, OCOTP_ULP_UID_4, &val); + soc_uid = val & 0xffff; + regmap_read(ocotp, OCOTP_ULP_UID_3, &val); + soc_uid <<= 16; + soc_uid |= val & 0xffff; + regmap_read(ocotp, OCOTP_ULP_UID_2, &val); + soc_uid <<= 16; + soc_uid |= val & 0xffff; + regmap_read(ocotp, OCOTP_ULP_UID_1, &val); + soc_uid <<= 16; + soc_uid |= val & 0xffff; + } else { + regmap_read(ocotp, OCOTP_UID_H, &val); + soc_uid = val; + regmap_read(ocotp, OCOTP_UID_L, &val); + soc_uid <<= 32; + soc_uid |= val; + } + } + + soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d.%d", + (imx_get_soc_revision() >> 4) & 0xf, + imx_get_soc_revision() & 0xf); + if (!soc_dev_attr->revision) { + ret = -ENOMEM; + goto free_soc; + } + + soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX", soc_uid); + if (!soc_dev_attr->serial_number) { + ret = -ENOMEM; + goto free_rev; + } + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { + ret = PTR_ERR(soc_dev); + goto free_serial_number; + } + + return 0; + +free_serial_number: + kfree(soc_dev_attr->serial_number); +free_rev: + kfree(soc_dev_attr->revision); +free_soc: + kfree(soc_dev_attr); + return ret; +} +device_initcall(imx_soc_device_init); |