diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-06-05 05:47:11 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-06-05 05:47:11 +0300 |
commit | 694b5a5d313f3997764b67d52bab66ec7e59e714 (patch) | |
tree | 9805ee9750144aa7dec19492ee5af6f3cc5362fe /drivers | |
parent | 587f17018a2c6c414e41a312b002faaef60cf423 (diff) | |
parent | d2353bad2c1eef7a1228645fbb21e7887c633d12 (diff) | |
download | linux-694b5a5d313f3997764b67d52bab66ec7e59e714.tar.xz |
Merge tag 'arm-soc-5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
Pull ARM SoC updates from Arnd Bergmann:
"One new platform gets added, the Realtek RTD1195, which is an older
Cortex-a7 based relative of the RTD12xx chips that are already
supported in arch/arm64. The platform may also be extended to support
running 32-bit kernels on those 64-bit chips for memory-constrained
machines.
In the Renesas shmobile platform, we gain support for "RZ/G1H" or
R8A7742, an eight-core chip based on Cortex-A15 and Cortex-A7 cores,
originally released in 2016 as one of the last high-end 32-bit
designs.
There is ongoing cleanup for the integrator, tegra, imx, and omap2
platforms, with integrator getting very close to the goal of having
zero code in arch/arm/, and omap2 moving more of the chip specifics
from old board code into device tree files.
The Versatile Express platform is made more modular, with built-in
drivers now becoming loadable modules. This is part of a greater
effort for the Android OS to have a common kernel binary for all
platforms and any platform specific code in loadable modules.
The PXA platform drops support for Compulab's pxa2xx boards that had
rather unusual flash and PCI drivers but no known users remaining. All
device drivers specific to those boards can now get removed as well.
Across platforms, there is ongoing cleanup, with Geert and Rob
revisiting some a lot of Kconfig options"
* tag 'arm-soc-5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (94 commits)
ARM: omap2: fix omap5_realtime_timer_init definition
ARM: zynq: Don't select CONFIG_ICST
ARM: OMAP2+: Fix regression for using local timer on non-SMP SoCs
clk: versatile: Fix kconfig dependency on COMMON_CLK_VERSATILE
ARM: davinci: fix build failure without I2C
power: reset: vexpress: fix build issue
power: vexpress: cleanup: use builtin_platform_driver
power: vexpress: add suppress_bind_attrs to true
Revert "ARM: vexpress: Don't select VEXPRESS_CONFIG"
MAINTAINERS: pxa: remove Compulab arm/pxa support
ARM: pxa: remove Compulab pxa2xx boards
bus: arm-integrator-lm: Fix return value check in integrator_ap_lm_probe()
soc: imx: move cpu code to drivers/soc/imx
ARM: imx: move cpu definitions into a header
ARM: imx: use device_initcall for imx_soc_device_init
ARM: imx: pcm037: make pcm970_sja1000_platform_data static
bus: ti-sysc: Timers no longer need legacy quirk handling
ARM: OMAP2+: Drop old timer code for dmtimer and 32k counter
ARM: dts: Configure system timers for omap2
ARM: dts: Configure system timers for ti81xx
...
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); |