From 3ecbf05be159a95e1d23ba9b3b21c5bc2941ba6b Mon Sep 17 00:00:00 2001 From: Pawel Moll Date: Mon, 24 Sep 2012 14:55:40 +0100 Subject: [PATCH 1/5] mfd: Versatile Express config infrastructure Versatile Express platform has an elaborated configuration system, consisting of microcontrollers residing on the mother- and daughterboards known as Motherboard/Daughterboard Configuration Controller (MCC and DCC). The controllers are responsible for the platform initialization (reset generation, flash programming, FPGA bitfiles loading etc.) but also control clock generators, voltage regulators, gather environmental data like temperature, power consumption etc. Even the video output switch (FPGA) is controlled that way. Those devices are _not_ visible in the main address space and the usual communication channel uses some kind of a bridge in the peripheral block sending commands (requests) to the controllers and receiving responses. It can take up to 500 microseconds for a transaction to be completed, therefore it is important to provide a non-blocking interface to it. This patch adds an abstraction of this infrastructure. Bridge drivers can register themselves with the framework. Then, a driver of a device can request an abstract "function" - the request will be redirected to a bridge referred by thedd "arm,vexpress,config-bridge" property of the device tree node. Signed-off-by: Pawel Moll --- .../devicetree/bindings/arm/vexpress.txt | 68 ++++- drivers/mfd/Kconfig | 6 + drivers/mfd/Makefile | 1 + drivers/mfd/vexpress-config.c | 277 ++++++++++++++++++ include/linux/vexpress.h | 85 ++++++ 5 files changed, 436 insertions(+), 1 deletion(-) create mode 100644 drivers/mfd/vexpress-config.c create mode 100644 include/linux/vexpress.h diff --git a/Documentation/devicetree/bindings/arm/vexpress.txt b/Documentation/devicetree/bindings/arm/vexpress.txt index ec8b50cbb2e8..5d9996b9eabf 100644 --- a/Documentation/devicetree/bindings/arm/vexpress.txt +++ b/Documentation/devicetree/bindings/arm/vexpress.txt @@ -11,6 +11,10 @@ the motherboard file using a /include/ directive. As the motherboard can be initialized in one of two different configurations ("memory maps"), care must be taken to include the correct one. + +Root node +--------- + Required properties in the root node: - compatible value: compatible = "arm,vexpress,", "arm,vexpress"; @@ -45,6 +49,10 @@ Optional properties in the root node: - Coretile Express A9x4 (V2P-CA9) HBI-0225: arm,hbi = <0x225>; + +CPU nodes +--------- + Top-level standard "cpus" node is required. It must contain a node with device_type = "cpu" property for every available core, eg.: @@ -59,6 +67,52 @@ with device_type = "cpu" property for every available core, eg.: }; }; + +Configuration infrastructure +---------------------------- + +The platform has an elaborated configuration system, consisting of +microcontrollers residing on the mother- and daughterboards known +as Motherboard/Daughterboard Configuration Controller (MCC and DCC). +The controllers are responsible for the platform initialization +(reset generation, flash programming, FPGA bitfiles loading etc.) +but also control clock generators, voltage regulators, gather +environmental data like temperature, power consumption etc. Even +the video output switch (FPGA) is controlled that way. + +Nodes describing devices controlled by this infrastructure should +point at the bridge device node: +- bridge phandle: + arm,vexpress,config-bridge = ; +This property can be also defined in a parent node (eg. for a DCC) +and is effective for all children. + + +Platform topology +----------------- + +As Versatile Express can be configured in number of physically +different setups, the device tree should describe platform topology. +Root node and main motherboard node must define the following +property, describing physical location of the children nodes: +- site number: + arm,vexpress,site = ; + where 0 means motherboard, 1 or 2 are daugtherboard sites, + 0xf means "master" site (site containing main CPU tile) +- when daughterboards are stacked on one site, their position + in the stack be be described with: + arm,vexpress,position = ; +- when describing tiles consisting more than one DCC, its number + can be described with: + arm,vexpress,dcc = ; + +Any of the numbers above defaults to zero if not defined in +the node or any of its parent. + + +Motherboard +----------- + The motherboard description file provides a single "motherboard" node using 2 address cells corresponding to the Static Memory Bus used between the motherboard and the tile. The first cell defines the Chip @@ -96,13 +150,16 @@ The tile description must define "ranges", "interrupt-map-mask" and "interrupt-map" properties to translate the motherboard's address and interrupt space into one used by the tile's processor. -Abbreviated example: + +Example of a VE tile description (simplified) +--------------------------------------------- /dts-v1/; / { model = "V2P-CA5s"; arm,hbi = <0x225>; + arm,vexpress,site = <0xf>; compatible = "arm,vexpress-v2p-ca5s", "arm,vexpress"; interrupt-parent = <&gic>; #address-cells = <1>; @@ -134,6 +191,15 @@ Abbreviated example: <0x2c000100 0x100>; }; + dcc { + compatible = "simple-bus"; + arm,vexpress,config-bridge = <&v2m_sysreg>; + + osc@0 { + compatible = "arm,vexpress-osc"; + }; + }; + motherboard { /* CS0 is visible at 0x08000000 */ ranges = <0 0 0x08000000 0x04000000>; diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index acab3ef8a310..637bcdf8ce77 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1070,3 +1070,9 @@ config MCP_UCB1200_TS depends on MCP_UCB1200 && INPUT endmenu + +config VEXPRESS_CONFIG + bool + help + Platform configuration infrastructure for the ARM Ltd. + Versatile Express. diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index d8ccb630ddb0..e807164f68da 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -138,3 +138,4 @@ obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o obj-$(CONFIG_MFD_SYSCON) += syscon.o obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o +obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o diff --git a/drivers/mfd/vexpress-config.c b/drivers/mfd/vexpress-config.c new file mode 100644 index 000000000000..fae15d880758 --- /dev/null +++ b/drivers/mfd/vexpress-config.c @@ -0,0 +1,277 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Copyright (C) 2012 ARM Limited + */ + +#define pr_fmt(fmt) "vexpress-config: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define VEXPRESS_CONFIG_MAX_BRIDGES 2 + +struct vexpress_config_bridge { + struct device_node *node; + struct vexpress_config_bridge_info *info; + struct list_head transactions; + spinlock_t transactions_lock; +} vexpress_config_bridges[VEXPRESS_CONFIG_MAX_BRIDGES]; + +static DECLARE_BITMAP(vexpress_config_bridges_map, + ARRAY_SIZE(vexpress_config_bridges)); +static DEFINE_MUTEX(vexpress_config_bridges_mutex); + +struct vexpress_config_bridge *vexpress_config_bridge_register( + struct device_node *node, + struct vexpress_config_bridge_info *info) +{ + struct vexpress_config_bridge *bridge; + int i; + + pr_debug("Registering bridge '%s'\n", info->name); + + mutex_lock(&vexpress_config_bridges_mutex); + i = find_first_zero_bit(vexpress_config_bridges_map, + ARRAY_SIZE(vexpress_config_bridges)); + if (i >= ARRAY_SIZE(vexpress_config_bridges)) { + pr_err("Can't register more bridges!\n"); + mutex_unlock(&vexpress_config_bridges_mutex); + return NULL; + } + __set_bit(i, vexpress_config_bridges_map); + bridge = &vexpress_config_bridges[i]; + + bridge->node = node; + bridge->info = info; + INIT_LIST_HEAD(&bridge->transactions); + spin_lock_init(&bridge->transactions_lock); + + mutex_unlock(&vexpress_config_bridges_mutex); + + return bridge; +} + +void vexpress_config_bridge_unregister(struct vexpress_config_bridge *bridge) +{ + struct vexpress_config_bridge __bridge = *bridge; + int i; + + mutex_lock(&vexpress_config_bridges_mutex); + for (i = 0; i < ARRAY_SIZE(vexpress_config_bridges); i++) + if (&vexpress_config_bridges[i] == bridge) + __clear_bit(i, vexpress_config_bridges_map); + mutex_unlock(&vexpress_config_bridges_mutex); + + WARN_ON(!list_empty(&__bridge.transactions)); + while (!list_empty(&__bridge.transactions)) + cpu_relax(); +} + + +struct vexpress_config_func { + struct vexpress_config_bridge *bridge; + void *func; +}; + +struct vexpress_config_func *__vexpress_config_func_get(struct device *dev, + struct device_node *node) +{ + struct device_node *bridge_node; + struct vexpress_config_func *func; + int i; + + if (WARN_ON(dev && node && dev->of_node != node)) + return NULL; + if (dev && !node) + node = dev->of_node; + + func = kzalloc(sizeof(*func), GFP_KERNEL); + if (!func) + return NULL; + + bridge_node = of_node_get(node); + while (bridge_node) { + const __be32 *prop = of_get_property(bridge_node, + "arm,vexpress,config-bridge", NULL); + + if (prop) { + bridge_node = of_find_node_by_phandle( + be32_to_cpup(prop)); + break; + } + + bridge_node = of_get_next_parent(bridge_node); + } + + mutex_lock(&vexpress_config_bridges_mutex); + for (i = 0; i < ARRAY_SIZE(vexpress_config_bridges); i++) { + struct vexpress_config_bridge *bridge = + &vexpress_config_bridges[i]; + + if (test_bit(i, vexpress_config_bridges_map) && + bridge->node == bridge_node) { + func->bridge = bridge; + func->func = bridge->info->func_get(dev, node); + break; + } + } + mutex_unlock(&vexpress_config_bridges_mutex); + + if (!func->func) { + of_node_put(node); + kfree(func); + return NULL; + } + + return func; +} + +void vexpress_config_func_put(struct vexpress_config_func *func) +{ + func->bridge->info->func_put(func->func); + of_node_put(func->bridge->node); + kfree(func); +} + + +struct vexpress_config_trans { + struct vexpress_config_func *func; + int offset; + bool write; + u32 *data; + int status; + struct completion completion; + struct list_head list; +}; + +static void vexpress_config_dump_trans(const char *what, + struct vexpress_config_trans *trans) +{ + pr_debug("%s %s trans %p func 0x%p offset %d data 0x%x status %d\n", + what, trans->write ? "write" : "read", trans, + trans->func->func, trans->offset, + trans->data ? *trans->data : 0, trans->status); +} + +static int vexpress_config_schedule(struct vexpress_config_trans *trans) +{ + int status; + struct vexpress_config_bridge *bridge = trans->func->bridge; + unsigned long flags; + + init_completion(&trans->completion); + trans->status = -EFAULT; + + spin_lock_irqsave(&bridge->transactions_lock, flags); + + vexpress_config_dump_trans("Executing", trans); + + if (list_empty(&bridge->transactions)) + status = bridge->info->func_exec(trans->func->func, + trans->offset, trans->write, trans->data); + else + status = VEXPRESS_CONFIG_STATUS_WAIT; + + switch (status) { + case VEXPRESS_CONFIG_STATUS_DONE: + vexpress_config_dump_trans("Finished", trans); + trans->status = status; + break; + case VEXPRESS_CONFIG_STATUS_WAIT: + list_add_tail(&trans->list, &bridge->transactions); + break; + } + + spin_unlock_irqrestore(&bridge->transactions_lock, flags); + + return status; +} + +void vexpress_config_complete(struct vexpress_config_bridge *bridge, + int status) +{ + struct vexpress_config_trans *trans; + unsigned long flags; + + spin_lock_irqsave(&bridge->transactions_lock, flags); + + trans = list_first_entry(&bridge->transactions, + struct vexpress_config_trans, list); + vexpress_config_dump_trans("Completed", trans); + + trans->status = status; + list_del(&trans->list); + + if (!list_empty(&bridge->transactions)) { + vexpress_config_dump_trans("Pending", trans); + + bridge->info->func_exec(trans->func->func, trans->offset, + trans->write, trans->data); + } + spin_unlock_irqrestore(&bridge->transactions_lock, flags); + + complete(&trans->completion); +} + +int vexpress_config_wait(struct vexpress_config_trans *trans) +{ + wait_for_completion(&trans->completion); + + return trans->status; +} + + +int vexpress_config_read(struct vexpress_config_func *func, int offset, + u32 *data) +{ + struct vexpress_config_trans trans = { + .func = func, + .offset = offset, + .write = false, + .data = data, + .status = 0, + }; + int status = vexpress_config_schedule(&trans); + + if (status == VEXPRESS_CONFIG_STATUS_WAIT) + status = vexpress_config_wait(&trans); + + return status; +} +EXPORT_SYMBOL(vexpress_config_read); + +int vexpress_config_write(struct vexpress_config_func *func, int offset, + u32 data) +{ + struct vexpress_config_trans trans = { + .func = func, + .offset = offset, + .write = true, + .data = &data, + .status = 0, + }; + int status = vexpress_config_schedule(&trans); + + if (status == VEXPRESS_CONFIG_STATUS_WAIT) + status = vexpress_config_wait(&trans); + + return status; +} +EXPORT_SYMBOL(vexpress_config_write); diff --git a/include/linux/vexpress.h b/include/linux/vexpress.h new file mode 100644 index 000000000000..c2d877a7b691 --- /dev/null +++ b/include/linux/vexpress.h @@ -0,0 +1,85 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Copyright (C) 2012 ARM Limited + */ + +#ifndef _LINUX_VEXPRESS_H +#define _LINUX_VEXPRESS_H + +#include + +#define VEXPRESS_SITE_MB 0 +#define VEXPRESS_SITE_DB1 1 +#define VEXPRESS_SITE_DB2 2 +#define VEXPRESS_SITE_MASTER 0xf + +#define VEXPRESS_CONFIG_STATUS_DONE 0 +#define VEXPRESS_CONFIG_STATUS_WAIT 1 + +/* Config bridge API */ + +/** + * struct vexpress_config_bridge_info - description of the platform + * configuration infrastructure bridge. + * + * @name: Bridge name + * + * @func_get: Obtains pointer to a configuration function for a given + * device or a Device Tree node, to be used with @func_put + * and @func_exec. The node pointer should take precedence + * over device pointer when both are passed. + * + * @func_put: Tells the bridge that the function will not be used any + * more, so all allocated resources can be released. + * + * @func_exec: Executes a configuration function read or write operation. + * The offset selects a 32 bit word of the value accessed. + * Must return VEXPRESS_CONFIG_STATUS_DONE when operation + * is finished immediately, VEXPRESS_CONFIG_STATUS_WAIT when + * will be completed in some time or negative value in case + * of error. + */ +struct vexpress_config_bridge_info { + const char *name; + void *(*func_get)(struct device *dev, struct device_node *node); + void (*func_put)(void *func); + int (*func_exec)(void *func, int offset, bool write, u32 *data); +}; + +struct vexpress_config_bridge; + +struct vexpress_config_bridge *vexpress_config_bridge_register( + struct device_node *node, + struct vexpress_config_bridge_info *info); +void vexpress_config_bridge_unregister(struct vexpress_config_bridge *bridge); + +void vexpress_config_complete(struct vexpress_config_bridge *bridge, + int status); + +/* Config function API */ + +struct vexpress_config_func; + +struct vexpress_config_func *__vexpress_config_func_get(struct device *dev, + struct device_node *node); +#define vexpress_config_func_get_by_dev(dev) \ + __vexpress_config_func_get(dev, NULL) +#define vexpress_config_func_get_by_node(node) \ + __vexpress_config_func_get(NULL, node) +void vexpress_config_func_put(struct vexpress_config_func *func); + +/* Both may sleep! */ +int vexpress_config_read(struct vexpress_config_func *func, int offset, + u32 *data); +int vexpress_config_write(struct vexpress_config_func *func, int offset, + u32 data); + +#endif From 88e0abcd7a8171ca7af3402373e7bd81fe9b6754 Mon Sep 17 00:00:00 2001 From: Pawel Moll Date: Tue, 18 Sep 2012 12:24:57 +0100 Subject: [PATCH 2/5] mfd: Versatile Express system registers driver This is a platform driver for Versatile Express' "system register" block. It's a random collection of registers providing the following functionality: - low level platform functions like board ID access; in order to use those, the driver must be initialized early, either statically or based on the DT - config bus bridge via "system control" interface; as the response from the controller does not generate interrupt (yet), the status register is periodically polled using a timer - pseudo GPIO lines providing MMC card status and Flash WP# signal control - LED interface for a set of 8 LEDs on the motherboard, with "heartbeat", "mmc0" and "cpu0" to "cpu5" as default triggers Signed-off-by: Pawel Moll --- .../bindings/arm/vexpress-sysreg.txt | 50 ++ drivers/mfd/Makefile | 2 +- drivers/mfd/vexpress-sysreg.c | 552 ++++++++++++++++++ include/linux/vexpress.h | 25 + 4 files changed, 628 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/arm/vexpress-sysreg.txt create mode 100644 drivers/mfd/vexpress-sysreg.c diff --git a/Documentation/devicetree/bindings/arm/vexpress-sysreg.txt b/Documentation/devicetree/bindings/arm/vexpress-sysreg.txt new file mode 100644 index 000000000000..9cf3f25544c7 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/vexpress-sysreg.txt @@ -0,0 +1,50 @@ +ARM Versatile Express system registers +-------------------------------------- + +This is a system control registers block, providing multiple low level +platform functions like board detection and identification, software +interrupt generation, MMC and NOR Flash control etc. + +Required node properties: +- compatible value : = "arm,vexpress,sysreg"; +- reg : physical base address and the size of the registers window +- gpio-controller : specifies that the node is a GPIO controller +- #gpio-cells : size of the GPIO specifier, should be 2: + - first cell is the pseudo-GPIO line number: + 0 - MMC CARDIN + 1 - MMC WPROT + 2 - NOR FLASH WPn + - second cell can take standard GPIO flags (currently ignored). + +Example: + v2m_sysreg: sysreg@10000000 { + compatible = "arm,vexpress-sysreg"; + reg = <0x10000000 0x1000>; + gpio-controller; + #gpio-cells = <2>; + }; + +This block also can also act a bridge to the platform's configuration +bus via "system control" interface, addressing devices with site number, +position in the board stack, config controller, function and device +numbers - see motherboard's TRM for more details. + +The node describing a config device must refer to the sysreg node via +"arm,vexpress,config-bridge" phandle (can be also defined in the node's +parent) and relies on the board topology properties - see main vexpress +node documentation for more details. It must must also define the +following property: +- arm,vexpress-sysreg,func : must contain two cells: + - first cell defines function number (eg. 1 for clock generator, + 2 for voltage regulators etc.) + - device number (eg. osc 0, osc 1 etc.) + +Example: + mcc { + arm,vexpress,config-bridge = <&v2m_sysreg>; + + osc@0 { + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 0>; + }; + }; diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index e807164f68da..296817c6c06f 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -138,4 +138,4 @@ obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o obj-$(CONFIG_MFD_SYSCON) += syscon.o obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o -obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o +obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o vexpress-sysreg.o diff --git a/drivers/mfd/vexpress-sysreg.c b/drivers/mfd/vexpress-sysreg.c new file mode 100644 index 000000000000..059d6b17b14a --- /dev/null +++ b/drivers/mfd/vexpress-sysreg.c @@ -0,0 +1,552 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Copyright (C) 2012 ARM Limited + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SYS_ID 0x000 +#define SYS_SW 0x004 +#define SYS_LED 0x008 +#define SYS_100HZ 0x024 +#define SYS_FLAGS 0x030 +#define SYS_FLAGSSET 0x030 +#define SYS_FLAGSCLR 0x034 +#define SYS_NVFLAGS 0x038 +#define SYS_NVFLAGSSET 0x038 +#define SYS_NVFLAGSCLR 0x03c +#define SYS_MCI 0x048 +#define SYS_FLASH 0x04c +#define SYS_CFGSW 0x058 +#define SYS_24MHZ 0x05c +#define SYS_MISC 0x060 +#define SYS_DMA 0x064 +#define SYS_PROCID0 0x084 +#define SYS_PROCID1 0x088 +#define SYS_CFGDATA 0x0a0 +#define SYS_CFGCTRL 0x0a4 +#define SYS_CFGSTAT 0x0a8 + +#define SYS_HBI_MASK 0xfff +#define SYS_ID_HBI_SHIFT 16 +#define SYS_PROCIDx_HBI_SHIFT 0 + +#define SYS_MCI_CARDIN (1 << 0) +#define SYS_MCI_WPROT (1 << 1) + +#define SYS_FLASH_WPn (1 << 0) + +#define SYS_MISC_MASTERSITE (1 << 14) + +#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_ERR (1 << 1) +#define SYS_CFGSTAT_COMPLETE (1 << 0) + + +static void __iomem *vexpress_sysreg_base; +static struct device *vexpress_sysreg_dev; +static int vexpress_master_site; + + +void vexpress_flags_set(u32 data) +{ + writel(~0, vexpress_sysreg_base + SYS_FLAGSCLR); + writel(data, vexpress_sysreg_base + SYS_FLAGSSET); +} + +u32 vexpress_get_procid(int site) +{ + if (site == VEXPRESS_SITE_MASTER) + site = vexpress_master_site; + + return readl(vexpress_sysreg_base + (site == VEXPRESS_SITE_DB1 ? + SYS_PROCID0 : SYS_PROCID1)); +} + +u32 vexpress_get_hbi(int site) +{ + u32 id; + + switch (site) { + case VEXPRESS_SITE_MB: + id = readl(vexpress_sysreg_base + SYS_ID); + return (id >> SYS_ID_HBI_SHIFT) & SYS_HBI_MASK; + case VEXPRESS_SITE_MASTER: + case VEXPRESS_SITE_DB1: + case VEXPRESS_SITE_DB2: + id = vexpress_get_procid(site); + return (id >> SYS_PROCIDx_HBI_SHIFT) & SYS_HBI_MASK; + } + + return ~0; +} + +void __iomem *vexpress_get_24mhz_clock_base(void) +{ + return vexpress_sysreg_base + SYS_24MHZ; +} + + +static void vexpress_sysreg_find_prop(struct device_node *node, + const char *name, u32 *val) +{ + of_node_get(node); + while (node) { + if (of_property_read_u32(node, name, val) == 0) { + of_node_put(node); + return; + } + node = of_get_next_parent(node); + } +} + +unsigned __vexpress_get_site(struct device *dev, struct device_node *node) +{ + u32 site = 0; + + WARN_ON(dev && node && dev->of_node != node); + if (dev && !node) + node = dev->of_node; + + if (node) { + vexpress_sysreg_find_prop(node, "arm,vexpress,site", &site); + } else if (dev && dev->bus == &platform_bus_type) { + struct platform_device *pdev = to_platform_device(dev); + + if (pdev->num_resources == 1 && + pdev->resource[0].flags == IORESOURCE_BUS) + site = pdev->resource[0].start; + } else if (dev && strncmp(dev_name(dev), "ct:", 3) == 0) { + site = VEXPRESS_SITE_MASTER; + } + + if (site == VEXPRESS_SITE_MASTER) + site = vexpress_master_site; + + return site; +} + + +struct vexpress_sysreg_config_func { + u32 template; + u32 device; +}; + +static struct vexpress_config_bridge *vexpress_sysreg_config_bridge; +static struct timer_list vexpress_sysreg_config_timer; +static u32 *vexpress_sysreg_config_data; +static int vexpress_sysreg_config_tries; + +static void *vexpress_sysreg_config_func_get(struct device *dev, + struct device_node *node) +{ + struct vexpress_sysreg_config_func *config_func; + u32 site; + u32 position = 0; + u32 dcc = 0; + u32 func_device[2]; + int err = -EFAULT; + + if (node) { + of_node_get(node); + vexpress_sysreg_find_prop(node, "arm,vexpress,site", &site); + vexpress_sysreg_find_prop(node, "arm,vexpress,position", + &position); + vexpress_sysreg_find_prop(node, "arm,vexpress,dcc", &dcc); + err = of_property_read_u32_array(node, + "arm,vexpress-sysreg,func", func_device, + ARRAY_SIZE(func_device)); + of_node_put(node); + } else if (dev && dev->bus == &platform_bus_type) { + struct platform_device *pdev = to_platform_device(dev); + + if (pdev->num_resources == 1 && + pdev->resource[0].flags == IORESOURCE_BUS) { + site = pdev->resource[0].start; + func_device[0] = pdev->resource[0].end; + func_device[1] = pdev->id; + err = 0; + } + } + if (err) + return NULL; + + config_func = kzalloc(sizeof(*config_func), GFP_KERNEL); + if (!config_func) + return NULL; + + config_func->template = SYS_CFGCTRL_DCC(dcc); + config_func->template |= SYS_CFGCTRL_FUNC(func_device[0]); + config_func->template |= SYS_CFGCTRL_SITE(site == VEXPRESS_SITE_MASTER ? + vexpress_master_site : site); + config_func->template |= SYS_CFGCTRL_POSITION(position); + config_func->device |= func_device[1]; + + dev_dbg(vexpress_sysreg_dev, "func 0x%p = 0x%x, %d\n", config_func, + config_func->template, config_func->device); + + return config_func; +} + +static void vexpress_sysreg_config_func_put(void *func) +{ + kfree(func); +} + +static int vexpress_sysreg_config_func_exec(void *func, int offset, + bool write, u32 *data) +{ + int status; + struct vexpress_sysreg_config_func *config_func = func; + u32 command; + + if (WARN_ON(!vexpress_sysreg_base)) + return -ENOENT; + + command = readl(vexpress_sysreg_base + SYS_CFGCTRL); + if (WARN_ON(command & SYS_CFGCTRL_START)) + return -EBUSY; + + command = SYS_CFGCTRL_START; + command |= write ? SYS_CFGCTRL_WRITE : 0; + command |= config_func->template; + command |= SYS_CFGCTRL_DEVICE(config_func->device + offset); + + /* Use a canary for reads */ + if (!write) + *data = 0xdeadbeef; + + dev_dbg(vexpress_sysreg_dev, "command %x, data %x\n", + command, *data); + writel(*data, vexpress_sysreg_base + SYS_CFGDATA); + writel(0, vexpress_sysreg_base + SYS_CFGSTAT); + writel(command, vexpress_sysreg_base + SYS_CFGCTRL); + mb(); + + if (vexpress_sysreg_dev) { + /* Schedule completion check */ + if (!write) + vexpress_sysreg_config_data = data; + vexpress_sysreg_config_tries = 100; + mod_timer(&vexpress_sysreg_config_timer, + jiffies + usecs_to_jiffies(100)); + status = VEXPRESS_CONFIG_STATUS_WAIT; + } else { + /* Early execution, no timer available, have to spin */ + u32 cfgstat; + + do { + cpu_relax(); + cfgstat = readl(vexpress_sysreg_base + SYS_CFGSTAT); + } while (!cfgstat); + + if (!write && (cfgstat & SYS_CFGSTAT_COMPLETE)) + *data = readl(vexpress_sysreg_base + SYS_CFGDATA); + status = VEXPRESS_CONFIG_STATUS_DONE; + + if (cfgstat & SYS_CFGSTAT_ERR) + status = -EINVAL; + } + + return status; +} + +struct vexpress_config_bridge_info vexpress_sysreg_config_bridge_info = { + .name = "vexpress-sysreg", + .func_get = vexpress_sysreg_config_func_get, + .func_put = vexpress_sysreg_config_func_put, + .func_exec = vexpress_sysreg_config_func_exec, +}; + +static void vexpress_sysreg_config_complete(unsigned long data) +{ + int status = VEXPRESS_CONFIG_STATUS_DONE; + u32 cfgstat = readl(vexpress_sysreg_base + SYS_CFGSTAT); + + if (cfgstat & SYS_CFGSTAT_ERR) + status = -EINVAL; + if (!vexpress_sysreg_config_tries--) + status = -ETIMEDOUT; + + if (status < 0) { + dev_err(vexpress_sysreg_dev, "error %d\n", status); + } else if (!(cfgstat & SYS_CFGSTAT_COMPLETE)) { + mod_timer(&vexpress_sysreg_config_timer, + jiffies + usecs_to_jiffies(50)); + return; + } + + if (vexpress_sysreg_config_data) { + *vexpress_sysreg_config_data = readl(vexpress_sysreg_base + + SYS_CFGDATA); + dev_dbg(vexpress_sysreg_dev, "read data %x\n", + *vexpress_sysreg_config_data); + vexpress_sysreg_config_data = NULL; + } + + vexpress_config_complete(vexpress_sysreg_config_bridge, status); +} + + +void __init vexpress_sysreg_early_init(void __iomem *base) +{ + struct device_node *node = of_find_compatible_node(NULL, NULL, + "arm,vexpress-sysreg"); + + if (node) + base = of_iomap(node, 0); + + if (WARN_ON(!base)) + return; + + vexpress_sysreg_base = base; + + if (readl(vexpress_sysreg_base + SYS_MISC) & SYS_MISC_MASTERSITE) + vexpress_master_site = VEXPRESS_SITE_DB2; + else + vexpress_master_site = VEXPRESS_SITE_DB1; + + vexpress_sysreg_config_bridge = vexpress_config_bridge_register( + node, &vexpress_sysreg_config_bridge_info); + WARN_ON(!vexpress_sysreg_config_bridge); +} + +void __init vexpress_sysreg_of_early_init(void) +{ + vexpress_sysreg_early_init(NULL); +} + + +static struct vexpress_sysreg_gpio { + unsigned long reg; + u32 value; +} vexpress_sysreg_gpios[] = { + [VEXPRESS_GPIO_MMC_CARDIN] = { + .reg = SYS_MCI, + .value = SYS_MCI_CARDIN, + }, + [VEXPRESS_GPIO_MMC_WPROT] = { + .reg = SYS_MCI, + .value = SYS_MCI_WPROT, + }, + [VEXPRESS_GPIO_FLASH_WPn] = { + .reg = SYS_FLASH, + .value = SYS_FLASH_WPn, + }, +}; + +static int vexpress_sysreg_gpio_direction_input(struct gpio_chip *chip, + unsigned offset) +{ + return 0; +} + +static int vexpress_sysreg_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + return 0; +} + +static int vexpress_sysreg_gpio_get(struct gpio_chip *chip, + unsigned offset) +{ + struct vexpress_sysreg_gpio *gpio = &vexpress_sysreg_gpios[offset]; + u32 reg_value = readl(vexpress_sysreg_base + gpio->reg); + + return !!(reg_value & gpio->value); +} + +static void vexpress_sysreg_gpio_set(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct vexpress_sysreg_gpio *gpio = &vexpress_sysreg_gpios[offset]; + u32 reg_value = readl(vexpress_sysreg_base + gpio->reg); + + if (value) + reg_value |= gpio->value; + else + reg_value &= ~gpio->value; + + writel(reg_value, vexpress_sysreg_base + gpio->reg); +} + +static struct gpio_chip vexpress_sysreg_gpio_chip = { + .label = "vexpress-sysreg", + .direction_input = vexpress_sysreg_gpio_direction_input, + .direction_output = vexpress_sysreg_gpio_direction_output, + .get = vexpress_sysreg_gpio_get, + .set = vexpress_sysreg_gpio_set, + .ngpio = ARRAY_SIZE(vexpress_sysreg_gpios), + .base = 0, +}; + + +static ssize_t vexpress_sysreg_sys_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "0x%08x\n", readl(vexpress_sysreg_base + SYS_ID)); +} + +DEVICE_ATTR(sys_id, S_IRUGO, vexpress_sysreg_sys_id_show, NULL); + +static int __devinit vexpress_sysreg_probe(struct platform_device *pdev) +{ + int err; + struct resource *res = platform_get_resource(pdev, + IORESOURCE_MEM, 0); + + if (!devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), pdev->name)) { + dev_err(&pdev->dev, "Failed to request memory region!\n"); + return -EBUSY; + } + + if (!vexpress_sysreg_base) + vexpress_sysreg_base = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + + if (!vexpress_sysreg_base) { + dev_err(&pdev->dev, "Failed to obtain base address!\n"); + return -EFAULT; + } + + setup_timer(&vexpress_sysreg_config_timer, + vexpress_sysreg_config_complete, 0); + + vexpress_sysreg_gpio_chip.dev = &pdev->dev; + err = gpiochip_add(&vexpress_sysreg_gpio_chip); + if (err) { + vexpress_config_bridge_unregister( + vexpress_sysreg_config_bridge); + dev_err(&pdev->dev, "Failed to register GPIO chip! (%d)\n", + err); + return err; + } + + vexpress_sysreg_dev = &pdev->dev; + + device_create_file(vexpress_sysreg_dev, &dev_attr_sys_id); + + return 0; +} + +static const struct of_device_id vexpress_sysreg_match[] = { + { .compatible = "arm,vexpress-sysreg", }, + {}, +}; + +static struct platform_driver vexpress_sysreg_driver = { + .driver = { + .name = "vexpress-sysreg", + .of_match_table = vexpress_sysreg_match, + }, + .probe = vexpress_sysreg_probe, +}; + +static int __init vexpress_sysreg_init(void) +{ + return platform_driver_register(&vexpress_sysreg_driver); +} +core_initcall(vexpress_sysreg_init); + + +#if defined(CONFIG_LEDS_CLASS) + +struct vexpress_sysreg_led { + u32 mask; + struct led_classdev cdev; +} vexpress_sysreg_leds[] = { + { .mask = 1 << 0, .cdev.name = "v2m:green:user1", + .cdev.default_trigger = "heartbeat", }, + { .mask = 1 << 1, .cdev.name = "v2m:green:user2", + .cdev.default_trigger = "mmc0", }, + { .mask = 1 << 2, .cdev.name = "v2m:green:user3", + .cdev.default_trigger = "cpu0", }, + { .mask = 1 << 3, .cdev.name = "v2m:green:user4", + .cdev.default_trigger = "cpu1", }, + { .mask = 1 << 4, .cdev.name = "v2m:green:user5", + .cdev.default_trigger = "cpu2", }, + { .mask = 1 << 5, .cdev.name = "v2m:green:user6", + .cdev.default_trigger = "cpu3", }, + { .mask = 1 << 6, .cdev.name = "v2m:green:user7", + .cdev.default_trigger = "cpu4", }, + { .mask = 1 << 7, .cdev.name = "v2m:green:user8", + .cdev.default_trigger = "cpu5", }, +}; + +static DEFINE_SPINLOCK(vexpress_sysreg_leds_lock); + +static void vexpress_sysreg_led_brightness_set(struct led_classdev *cdev, + enum led_brightness brightness) +{ + struct vexpress_sysreg_led *led = container_of(cdev, + struct vexpress_sysreg_led, cdev); + unsigned long flags; + u32 val; + + spin_lock_irqsave(&vexpress_sysreg_leds_lock, flags); + + val = readl(vexpress_sysreg_base + SYS_LED); + if (brightness == LED_OFF) + val &= ~led->mask; + else + val |= led->mask; + writel(val, vexpress_sysreg_base + SYS_LED); + + spin_unlock_irqrestore(&vexpress_sysreg_leds_lock, flags); +} + +static int __init vexpress_sysreg_init_leds(void) +{ + struct vexpress_sysreg_led *led; + int i; + + /* Clear all user LEDs */ + writel(0, vexpress_sysreg_base + SYS_LED); + + for (i = 0, led = vexpress_sysreg_leds; + i < ARRAY_SIZE(vexpress_sysreg_leds); i++, led++) { + int err; + + led->cdev.brightness_set = vexpress_sysreg_led_brightness_set; + err = led_classdev_register(vexpress_sysreg_dev, &led->cdev); + if (err) { + dev_err(vexpress_sysreg_dev, + "Failed to register LED %d! (%d)\n", + i, err); + while (led--, i--) + led_classdev_unregister(&led->cdev); + return err; + } + } + + return 0; +} +device_initcall(vexpress_sysreg_init_leds); + +#endif diff --git a/include/linux/vexpress.h b/include/linux/vexpress.h index c2d877a7b691..09c81d7a22de 100644 --- a/include/linux/vexpress.h +++ b/include/linux/vexpress.h @@ -24,6 +24,17 @@ #define VEXPRESS_CONFIG_STATUS_DONE 0 #define VEXPRESS_CONFIG_STATUS_WAIT 1 +#define VEXPRESS_GPIO_MMC_CARDIN 0 +#define VEXPRESS_GPIO_MMC_WPROT 1 +#define VEXPRESS_GPIO_FLASH_WPn 2 + +#define VEXPRESS_RES_FUNC(_site, _func) \ +{ \ + .start = (_site), \ + .end = (_func), \ + .flags = IORESOURCE_BUS, \ +} + /* Config bridge API */ /** @@ -82,4 +93,18 @@ int vexpress_config_read(struct vexpress_config_func *func, int offset, int vexpress_config_write(struct vexpress_config_func *func, int offset, u32 data); +/* Platform control */ + +u32 vexpress_get_procid(int site); +u32 vexpress_get_hbi(int site); +void *vexpress_get_24mhz_clock_base(void); +void vexpress_flags_set(u32 data); + +#define vexpress_get_site_by_node(node) __vexpress_get_site(NULL, node) +#define vexpress_get_site_by_dev(dev) __vexpress_get_site(dev, NULL) +unsigned __vexpress_get_site(struct device *dev, struct device_node *node); + +void vexpress_sysreg_early_init(void __iomem *base); +void vexpress_sysreg_of_early_init(void); + #endif From 842839a37a9a9ac12d88930b6605c620fc09bc1d Mon Sep 17 00:00:00 2001 From: Pawel Moll Date: Mon, 17 Sep 2012 16:43:30 +0100 Subject: [PATCH 3/5] ARM: vexpress: Add config bus components and clocks to DTs Add description of all functions provided by Versatile Express motherboard and daughterboards configuration controllers and clock dependencies between devices. Signed-off-by: Pawel Moll --- arch/arm/boot/dts/vexpress-v2m-rs1.dtsi | 135 ++++++++++++++- arch/arm/boot/dts/vexpress-v2m.dtsi | 135 ++++++++++++++- arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts | 110 ++++++++++++ arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts | 175 ++++++++++++++++++++ arch/arm/boot/dts/vexpress-v2p-ca5s.dts | 73 ++++++++ arch/arm/boot/dts/vexpress-v2p-ca9.dts | 125 ++++++++++++++ 6 files changed, 749 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi index d8a827bd2bf3..9a7b6922f83b 100644 --- a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi +++ b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi @@ -24,6 +24,7 @@ motherboard { compatible = "simple-bus"; + arm,vexpress,site = <0>; arm,v2m-memory-map = "rs1"; #address-cells = <2>; /* SMB chipselect number and offset */ #size-cells = <1>; @@ -72,14 +73,20 @@ #size-cells = <1>; ranges = <0 3 0 0x200000>; - sysreg@010000 { + v2m_sysreg: sysreg@010000 { compatible = "arm,vexpress-sysreg"; reg = <0x010000 0x1000>; + gpio-controller; + #gpio-cells = <2>; }; - sysctl@020000 { + v2m_sysctl: sysctl@020000 { compatible = "arm,sp810", "arm,primecell"; reg = <0x020000 0x1000>; + clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&smbclk>; + clock-names = "refclk", "timclk", "apb_pclk"; + #clock-cells = <1>; + clock-output-names = "timerclken0", "timerclken1", "timerclken2", "timerclken3"; }; /* PCI-E I2C bus */ @@ -100,66 +107,92 @@ compatible = "arm,pl041", "arm,primecell"; reg = <0x040000 0x1000>; interrupts = <11>; + clocks = <&smbclk>; + clock-names = "apb_pclk"; }; mmci@050000 { compatible = "arm,pl180", "arm,primecell"; reg = <0x050000 0x1000>; interrupts = <9 10>; + cd-gpios = <&v2m_sysreg 0 0>; + wp-gpios = <&v2m_sysreg 1 0>; + max-frequency = <12000000>; + vmmc-supply = <&v2m_fixed_3v3>; + clocks = <&v2m_clk24mhz>, <&smbclk>; + clock-names = "mclk", "apb_pclk"; }; kmi@060000 { compatible = "arm,pl050", "arm,primecell"; reg = <0x060000 0x1000>; interrupts = <12>; + clocks = <&v2m_clk24mhz>, <&smbclk>; + clock-names = "KMIREFCLK", "apb_pclk"; }; kmi@070000 { compatible = "arm,pl050", "arm,primecell"; reg = <0x070000 0x1000>; interrupts = <13>; + clocks = <&v2m_clk24mhz>, <&smbclk>; + clock-names = "KMIREFCLK", "apb_pclk"; }; v2m_serial0: uart@090000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x090000 0x1000>; interrupts = <5>; + clocks = <&v2m_oscclk2>, <&smbclk>; + clock-names = "uartclk", "apb_pclk"; }; v2m_serial1: uart@0a0000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x0a0000 0x1000>; interrupts = <6>; + clocks = <&v2m_oscclk2>, <&smbclk>; + clock-names = "uartclk", "apb_pclk"; }; v2m_serial2: uart@0b0000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x0b0000 0x1000>; interrupts = <7>; + clocks = <&v2m_oscclk2>, <&smbclk>; + clock-names = "uartclk", "apb_pclk"; }; v2m_serial3: uart@0c0000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x0c0000 0x1000>; interrupts = <8>; + clocks = <&v2m_oscclk2>, <&smbclk>; + clock-names = "uartclk", "apb_pclk"; }; wdt@0f0000 { compatible = "arm,sp805", "arm,primecell"; reg = <0x0f0000 0x1000>; interrupts = <0>; + clocks = <&v2m_refclk32khz>, <&smbclk>; + clock-names = "wdogclk", "apb_pclk"; }; v2m_timer01: timer@110000 { compatible = "arm,sp804", "arm,primecell"; reg = <0x110000 0x1000>; interrupts = <2>; + clocks = <&v2m_sysctl 0>, <&v2m_sysctl 1>, <&smbclk>; + clock-names = "timclken1", "timclken2", "apb_pclk"; }; v2m_timer23: timer@120000 { compatible = "arm,sp804", "arm,primecell"; reg = <0x120000 0x1000>; interrupts = <3>; + clocks = <&v2m_sysctl 2>, <&v2m_sysctl 3>, <&smbclk>; + clock-names = "timclken1", "timclken2", "apb_pclk"; }; /* DVI I2C bus */ @@ -185,6 +218,8 @@ compatible = "arm,pl031", "arm,primecell"; reg = <0x170000 0x1000>; interrupts = <4>; + clocks = <&smbclk>; + clock-names = "apb_pclk"; }; compact-flash@1a0000 { @@ -198,6 +233,8 @@ compatible = "arm,pl111", "arm,primecell"; reg = <0x1f0000 0x1000>; interrupts = <14>; + clocks = <&v2m_oscclk1>, <&smbclk>; + clock-names = "clcdclk", "apb_pclk"; }; }; @@ -208,5 +245,99 @@ regulator-max-microvolt = <3300000>; regulator-always-on; }; + + v2m_clk24mhz: clk24mhz { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + clock-output-names = "v2m:clk24mhz"; + }; + + v2m_refclk1mhz: refclk1mhz { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <1000000>; + clock-output-names = "v2m:refclk1mhz"; + }; + + v2m_refclk32khz: refclk32khz { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <32768>; + clock-output-names = "v2m:refclk32khz"; + }; + + mcc { + compatible = "arm,vexpress,config-bus"; + arm,vexpress,config-bridge = <&v2m_sysreg>; + + osc@0 { + /* MCC static memory clock */ + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 0>; + freq-range = <25000000 60000000>; + #clock-cells = <0>; + clock-output-names = "v2m:oscclk0"; + }; + + v2m_oscclk1: osc@1 { + /* CLCD clock */ + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 1>; + freq-range = <23750000 63500000>; + #clock-cells = <0>; + clock-output-names = "v2m:oscclk1"; + }; + + v2m_oscclk2: osc@2 { + /* IO FPGA peripheral clock */ + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 2>; + freq-range = <24000000 24000000>; + #clock-cells = <0>; + clock-output-names = "v2m:oscclk2"; + }; + + volt@0 { + /* Logic level voltage */ + compatible = "arm,vexpress-volt"; + arm,vexpress-sysreg,func = <2 0>; + regulator-name = "VIO"; + regulator-always-on; + label = "VIO"; + }; + + temp@0 { + /* MCC internal operating temperature */ + compatible = "arm,vexpress-temp"; + arm,vexpress-sysreg,func = <4 0>; + label = "MCC"; + }; + + reset@0 { + compatible = "arm,vexpress-reset"; + arm,vexpress-sysreg,func = <5 0>; + }; + + muxfpga@0 { + compatible = "arm,vexpress-muxfpga"; + arm,vexpress-sysreg,func = <7 0>; + }; + + shutdown@0 { + compatible = "arm,vexpress-shutdown"; + arm,vexpress-sysreg,func = <8 0>; + }; + + reboot@0 { + compatible = "arm,vexpress-reboot"; + arm,vexpress-sysreg,func = <9 0>; + }; + + dvimode@0 { + compatible = "arm,vexpress-dvimode"; + arm,vexpress-sysreg,func = <11 0>; + }; + }; }; }; diff --git a/arch/arm/boot/dts/vexpress-v2m.dtsi b/arch/arm/boot/dts/vexpress-v2m.dtsi index dba53fd026bb..4d321a832dbd 100644 --- a/arch/arm/boot/dts/vexpress-v2m.dtsi +++ b/arch/arm/boot/dts/vexpress-v2m.dtsi @@ -24,6 +24,7 @@ motherboard { compatible = "simple-bus"; + arm,vexpress,site = <0>; #address-cells = <2>; /* SMB chipselect number and offset */ #size-cells = <1>; #interrupt-cells = <1>; @@ -71,14 +72,20 @@ #size-cells = <1>; ranges = <0 7 0 0x20000>; - sysreg@00000 { + v2m_sysreg: sysreg@00000 { compatible = "arm,vexpress-sysreg"; reg = <0x00000 0x1000>; + gpio-controller; + #gpio-cells = <2>; }; - sysctl@01000 { + v2m_sysctl: sysctl@01000 { compatible = "arm,sp810", "arm,primecell"; reg = <0x01000 0x1000>; + clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&smbclk>; + clock-names = "refclk", "timclk", "apb_pclk"; + #clock-cells = <1>; + clock-output-names = "timerclken0", "timerclken1", "timerclken2", "timerclken3"; }; /* PCI-E I2C bus */ @@ -99,66 +106,92 @@ compatible = "arm,pl041", "arm,primecell"; reg = <0x04000 0x1000>; interrupts = <11>; + clocks = <&smbclk>; + clock-names = "apb_pclk"; }; mmci@05000 { compatible = "arm,pl180", "arm,primecell"; reg = <0x05000 0x1000>; interrupts = <9 10>; + cd-gpios = <&v2m_sysreg 0 0>; + wp-gpios = <&v2m_sysreg 1 0>; + max-frequency = <12000000>; + vmmc-supply = <&v2m_fixed_3v3>; + clocks = <&v2m_clk24mhz>, <&smbclk>; + clock-names = "mclk", "apb_pclk"; }; kmi@06000 { compatible = "arm,pl050", "arm,primecell"; reg = <0x06000 0x1000>; interrupts = <12>; + clocks = <&v2m_clk24mhz>, <&smbclk>; + clock-names = "KMIREFCLK", "apb_pclk"; }; kmi@07000 { compatible = "arm,pl050", "arm,primecell"; reg = <0x07000 0x1000>; interrupts = <13>; + clocks = <&v2m_clk24mhz>, <&smbclk>; + clock-names = "KMIREFCLK", "apb_pclk"; }; v2m_serial0: uart@09000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x09000 0x1000>; interrupts = <5>; + clocks = <&v2m_oscclk2>, <&smbclk>; + clock-names = "uartclk", "apb_pclk"; }; v2m_serial1: uart@0a000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x0a000 0x1000>; interrupts = <6>; + clocks = <&v2m_oscclk2>, <&smbclk>; + clock-names = "uartclk", "apb_pclk"; }; v2m_serial2: uart@0b000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x0b000 0x1000>; interrupts = <7>; + clocks = <&v2m_oscclk2>, <&smbclk>; + clock-names = "uartclk", "apb_pclk"; }; v2m_serial3: uart@0c000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x0c000 0x1000>; interrupts = <8>; + clocks = <&v2m_oscclk2>, <&smbclk>; + clock-names = "uartclk", "apb_pclk"; }; wdt@0f000 { compatible = "arm,sp805", "arm,primecell"; reg = <0x0f000 0x1000>; interrupts = <0>; + clocks = <&v2m_refclk32khz>, <&smbclk>; + clock-names = "wdogclk", "apb_pclk"; }; v2m_timer01: timer@11000 { compatible = "arm,sp804", "arm,primecell"; reg = <0x11000 0x1000>; interrupts = <2>; + clocks = <&v2m_sysctl 0>, <&v2m_sysctl 1>, <&smbclk>; + clock-names = "timclken1", "timclken2", "apb_pclk"; }; v2m_timer23: timer@12000 { compatible = "arm,sp804", "arm,primecell"; reg = <0x12000 0x1000>; interrupts = <3>; + clocks = <&v2m_sysctl 2>, <&v2m_sysctl 3>, <&smbclk>; + clock-names = "timclken1", "timclken2", "apb_pclk"; }; /* DVI I2C bus */ @@ -184,6 +217,8 @@ compatible = "arm,pl031", "arm,primecell"; reg = <0x17000 0x1000>; interrupts = <4>; + clocks = <&smbclk>; + clock-names = "apb_pclk"; }; compact-flash@1a000 { @@ -197,6 +232,8 @@ compatible = "arm,pl111", "arm,primecell"; reg = <0x1f000 0x1000>; interrupts = <14>; + clocks = <&v2m_oscclk1>, <&smbclk>; + clock-names = "clcdclk", "apb_pclk"; }; }; @@ -207,5 +244,99 @@ regulator-max-microvolt = <3300000>; regulator-always-on; }; + + v2m_clk24mhz: clk24mhz { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + clock-output-names = "v2m:clk24mhz"; + }; + + v2m_refclk1mhz: refclk1mhz { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <1000000>; + clock-output-names = "v2m:refclk1mhz"; + }; + + v2m_refclk32khz: refclk32khz { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <32768>; + clock-output-names = "v2m:refclk32khz"; + }; + + mcc { + compatible = "arm,vexpress,config-bus"; + arm,vexpress,config-bridge = <&v2m_sysreg>; + + osc@0 { + /* MCC static memory clock */ + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 0>; + freq-range = <25000000 60000000>; + #clock-cells = <0>; + clock-output-names = "v2m:oscclk0"; + }; + + v2m_oscclk1: osc@1 { + /* CLCD clock */ + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 1>; + freq-range = <23750000 63500000>; + #clock-cells = <0>; + clock-output-names = "v2m:oscclk1"; + }; + + v2m_oscclk2: osc@2 { + /* IO FPGA peripheral clock */ + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 2>; + freq-range = <24000000 24000000>; + #clock-cells = <0>; + clock-output-names = "v2m:oscclk2"; + }; + + volt@0 { + /* Logic level voltage */ + compatible = "arm,vexpress-volt"; + arm,vexpress-sysreg,func = <2 0>; + regulator-name = "VIO"; + regulator-always-on; + label = "VIO"; + }; + + temp@0 { + /* MCC internal operating temperature */ + compatible = "arm,vexpress-temp"; + arm,vexpress-sysreg,func = <4 0>; + label = "MCC"; + }; + + reset@0 { + compatible = "arm,vexpress-reset"; + arm,vexpress-sysreg,func = <5 0>; + }; + + muxfpga@0 { + compatible = "arm,vexpress-muxfpga"; + arm,vexpress-sysreg,func = <7 0>; + }; + + shutdown@0 { + compatible = "arm,vexpress-shutdown"; + arm,vexpress-sysreg,func = <8 0>; + }; + + reboot@0 { + compatible = "arm,vexpress-reboot"; + arm,vexpress-sysreg,func = <9 0>; + }; + + dvimode@0 { + compatible = "arm,vexpress-dvimode"; + arm,vexpress-sysreg,func = <11 0>; + }; + }; }; }; diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts b/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts index d12b34ca0568..4bbed10de45b 100644 --- a/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts +++ b/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts @@ -12,6 +12,7 @@ / { model = "V2P-CA15"; arm,hbi = <0x237>; + arm,vexpress,site = <0xf>; compatible = "arm,vexpress,v2p-ca15,tc1", "arm,vexpress,v2p-ca15", "arm,vexpress"; interrupt-parent = <&gic>; #address-cells = <2>; @@ -54,17 +55,24 @@ compatible = "arm,hdlcd"; reg = <0 0x2b000000 0 0x1000>; interrupts = <0 85 4>; + clocks = <&oscclk5>; + clock-names = "pxlclk"; }; memory-controller@2b0a0000 { compatible = "arm,pl341", "arm,primecell"; reg = <0 0x2b0a0000 0 0x1000>; + clocks = <&oscclk7>; + clock-names = "apb_pclk"; }; wdt@2b060000 { compatible = "arm,sp805", "arm,primecell"; + status = "disabled"; reg = <0 0x2b060000 0 0x1000>; interrupts = <98>; + clocks = <&oscclk7>; + clock-names = "apb_pclk"; }; gic: interrupt-controller@2c001000 { @@ -84,6 +92,8 @@ reg = <0 0x7ffd0000 0 0x1000>; interrupts = <0 86 4>, <0 87 4>; + clocks = <&oscclk7>; + clock-names = "apb_pclk"; }; dma@7ffb0000 { @@ -94,6 +104,8 @@ <0 89 4>, <0 90 4>, <0 91 4>; + clocks = <&oscclk7>; + clock-names = "apb_pclk"; }; timer { @@ -110,6 +122,104 @@ <0 69 4>; }; + dcc { + compatible = "arm,vexpress,config-bus"; + arm,vexpress,config-bridge = <&v2m_sysreg>; + + osc@0 { + /* CPU PLL reference clock */ + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 0>; + freq-range = <50000000 60000000>; + #clock-cells = <0>; + clock-output-names = "oscclk0"; + }; + + osc@4 { + /* Multiplexed AXI master clock */ + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 4>; + freq-range = <20000000 40000000>; + #clock-cells = <0>; + clock-output-names = "oscclk4"; + }; + + oscclk5: osc@5 { + /* HDLCD PLL reference clock */ + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 5>; + freq-range = <23750000 165000000>; + #clock-cells = <0>; + clock-output-names = "oscclk5"; + }; + + smbclk: osc@6 { + /* SMB clock */ + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 6>; + freq-range = <20000000 50000000>; + #clock-cells = <0>; + clock-output-names = "oscclk6"; + }; + + oscclk7: osc@7 { + /* SYS PLL reference clock */ + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 7>; + freq-range = <20000000 60000000>; + #clock-cells = <0>; + clock-output-names = "oscclk7"; + }; + + osc@8 { + /* DDR2 PLL reference clock */ + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 8>; + freq-range = <40000000 40000000>; + #clock-cells = <0>; + clock-output-names = "oscclk8"; + }; + + volt@0 { + /* CPU core voltage */ + compatible = "arm,vexpress-volt"; + arm,vexpress-sysreg,func = <2 0>; + regulator-name = "Cores"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1050000>; + regulator-always-on; + label = "Cores"; + }; + + amp@0 { + /* Total current for the two cores */ + compatible = "arm,vexpress-amp"; + arm,vexpress-sysreg,func = <3 0>; + label = "Cores"; + }; + + temp@0 { + /* DCC internal temperature */ + compatible = "arm,vexpress-temp"; + arm,vexpress-sysreg,func = <4 0>; + label = "DCC"; + }; + + power@0 { + /* Total power */ + compatible = "arm,vexpress-power"; + arm,vexpress-sysreg,func = <12 0>; + label = "Cores"; + }; + + energy@0 { + /* Total energy */ + compatible = "arm,vexpress-energy"; + arm,vexpress-sysreg,func = <13 0>; + label = "Cores"; + }; + }; + motherboard { ranges = <0 0 0 0x08000000 0x04000000>, <1 0 0 0x14000000 0x04000000>, diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts index 4890a81c5467..3f4e1d00f4be 100644 --- a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts +++ b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts @@ -12,6 +12,7 @@ / { model = "V2P-CA15_CA7"; arm,hbi = <0x249>; + arm,vexpress,site = <0xf>; compatible = "arm,vexpress,v2p-ca15_a7", "arm,vexpress"; interrupt-parent = <&gic>; #address-cells = <2>; @@ -74,17 +75,23 @@ compatible = "arm,sp805", "arm,primecell"; reg = <0 0x2a490000 0 0x1000>; interrupts = <98>; + clocks = <&oscclk6a>, <&oscclk6a>; + clock-names = "wdogclk", "apb_pclk"; }; hdlcd@2b000000 { compatible = "arm,hdlcd"; reg = <0 0x2b000000 0 0x1000>; interrupts = <0 85 4>; + clocks = <&oscclk5>; + clock-names = "pxlclk"; }; memory-controller@2b0a0000 { compatible = "arm,pl341", "arm,primecell"; reg = <0 0x2b0a0000 0 0x1000>; + clocks = <&oscclk6a>; + clock-names = "apb_pclk"; }; gic: interrupt-controller@2c001000 { @@ -104,6 +111,8 @@ reg = <0 0x7ffd0000 0 0x1000>; interrupts = <0 86 4>, <0 87 4>; + clocks = <&oscclk6a>; + clock-names = "apb_pclk"; }; dma@7ff00000 { @@ -114,6 +123,8 @@ <0 89 4>, <0 90 4>, <0 91 4>; + clocks = <&oscclk6a>; + clock-names = "apb_pclk"; }; timer { @@ -130,6 +141,170 @@ <0 69 4>; }; + oscclk6a: oscclk6a { + /* Reference 24MHz clock */ + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + clock-output-names = "oscclk6a"; + }; + + dcc { + compatible = "arm,vexpress,config-bus"; + arm,vexpress,config-bridge = <&v2m_sysreg>; + + osc@0 { + /* A15 PLL 0 reference clock */ + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 0>; + freq-range = <17000000 50000000>; + #clock-cells = <0>; + clock-output-names = "oscclk0"; + }; + + osc@1 { + /* A15 PLL 1 reference clock */ + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 1>; + freq-range = <17000000 50000000>; + #clock-cells = <0>; + clock-output-names = "oscclk1"; + }; + + osc@2 { + /* A7 PLL 0 reference clock */ + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 2>; + freq-range = <17000000 50000000>; + #clock-cells = <0>; + clock-output-names = "oscclk2"; + }; + + osc@3 { + /* A7 PLL 1 reference clock */ + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 3>; + freq-range = <17000000 50000000>; + #clock-cells = <0>; + clock-output-names = "oscclk3"; + }; + + osc@4 { + /* External AXI master clock */ + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 4>; + freq-range = <20000000 40000000>; + #clock-cells = <0>; + clock-output-names = "oscclk4"; + }; + + oscclk5: osc@5 { + /* HDLCD PLL reference clock */ + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 5>; + freq-range = <23750000 165000000>; + #clock-cells = <0>; + clock-output-names = "oscclk5"; + }; + + smbclk: osc@6 { + /* Static memory controller clock */ + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 6>; + freq-range = <20000000 40000000>; + #clock-cells = <0>; + clock-output-names = "oscclk6"; + }; + + osc@7 { + /* SYS PLL reference clock */ + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 7>; + freq-range = <17000000 50000000>; + #clock-cells = <0>; + clock-output-names = "oscclk7"; + }; + + osc@8 { + /* DDR2 PLL reference clock */ + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 8>; + freq-range = <20000000 50000000>; + #clock-cells = <0>; + clock-output-names = "oscclk8"; + }; + + volt@0 { + /* A15 CPU core voltage */ + compatible = "arm,vexpress-volt"; + arm,vexpress-sysreg,func = <2 0>; + regulator-name = "A15 Vcore"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1050000>; + regulator-always-on; + label = "A15 Vcore"; + }; + + volt@1 { + /* A7 CPU core voltage */ + compatible = "arm,vexpress-volt"; + arm,vexpress-sysreg,func = <2 1>; + regulator-name = "A7 Vcore"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1050000>; + regulator-always-on; + label = "A7 Vcore"; + }; + + amp@0 { + /* Total current for the two A15 cores */ + compatible = "arm,vexpress-amp"; + arm,vexpress-sysreg,func = <3 0>; + label = "A15 Icore"; + }; + + amp@1 { + /* Total current for the three A7 cores */ + compatible = "arm,vexpress-amp"; + arm,vexpress-sysreg,func = <3 1>; + label = "A7 Icore"; + }; + + temp@0 { + /* DCC internal temperature */ + compatible = "arm,vexpress-temp"; + arm,vexpress-sysreg,func = <4 0>; + label = "DCC"; + }; + + power@0 { + /* Total power for the two A15 cores */ + compatible = "arm,vexpress-power"; + arm,vexpress-sysreg,func = <12 0>; + label = "A15 Pcore"; + }; + power@1 { + /* Total power for the three A7 cores */ + compatible = "arm,vexpress-power"; + arm,vexpress-sysreg,func = <12 1>; + label = "A7 Pcore"; + }; + + energy@0 { + /* Total energy for the two A15 cores */ + compatible = "arm,vexpress-energy"; + arm,vexpress-sysreg,func = <13 0>; + label = "A15 Jcore"; + }; + + energy@2 { + /* Total energy for the three A7 cores */ + compatible = "arm,vexpress-energy"; + arm,vexpress-sysreg,func = <13 2>; + label = "A7 Jcore"; + }; + }; + motherboard { ranges = <0 0 0 0x08000000 0x04000000>, <1 0 0 0x14000000 0x04000000>, diff --git a/arch/arm/boot/dts/vexpress-v2p-ca5s.dts b/arch/arm/boot/dts/vexpress-v2p-ca5s.dts index 18917a0f8604..f3c1f2a44072 100644 --- a/arch/arm/boot/dts/vexpress-v2p-ca5s.dts +++ b/arch/arm/boot/dts/vexpress-v2p-ca5s.dts @@ -12,6 +12,7 @@ / { model = "V2P-CA5s"; arm,hbi = <0x225>; + arm,vexpress,site = <0xf>; compatible = "arm,vexpress,v2p-ca5s", "arm,vexpress"; interrupt-parent = <&gic>; #address-cells = <1>; @@ -56,11 +57,15 @@ compatible = "arm,hdlcd"; reg = <0x2a110000 0x1000>; interrupts = <0 85 4>; + clocks = <&oscclk3>; + clock-names = "pxlclk"; }; memory-controller@2a150000 { compatible = "arm,pl341", "arm,primecell"; reg = <0x2a150000 0x1000>; + clocks = <&oscclk1>; + clock-names = "apb_pclk"; }; memory-controller@2a190000 { @@ -68,6 +73,8 @@ reg = <0x2a190000 0x1000>; interrupts = <0 86 4>, <0 87 4>; + clocks = <&oscclk1>; + clock-names = "apb_pclk"; }; scu@2c000000 { @@ -109,6 +116,72 @@ <0 69 4>; }; + dcc { + compatible = "arm,vexpress,config-bus"; + arm,vexpress,config-bridge = <&v2m_sysreg>; + + osc@0 { + /* CPU and internal AXI reference clock */ + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 0>; + freq-range = <50000000 100000000>; + #clock-cells = <0>; + clock-output-names = "oscclk0"; + }; + + oscclk1: osc@1 { + /* Multiplexed AXI master clock */ + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 1>; + freq-range = <5000000 50000000>; + #clock-cells = <0>; + clock-output-names = "oscclk1"; + }; + + osc@2 { + /* DDR2 */ + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 2>; + freq-range = <80000000 120000000>; + #clock-cells = <0>; + clock-output-names = "oscclk2"; + }; + + oscclk3: osc@3 { + /* HDLCD */ + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 3>; + freq-range = <23750000 165000000>; + #clock-cells = <0>; + clock-output-names = "oscclk3"; + }; + + osc@4 { + /* Test chip gate configuration */ + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 4>; + freq-range = <80000000 80000000>; + #clock-cells = <0>; + clock-output-names = "oscclk4"; + }; + + smbclk: osc@5 { + /* SMB clock */ + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 5>; + freq-range = <25000000 60000000>; + #clock-cells = <0>; + clock-output-names = "oscclk5"; + }; + + temp@0 { + /* DCC internal operating temperature */ + compatible = "arm,vexpress-temp"; + arm,vexpress-sysreg,func = <4 0>; + label = "DCC"; + }; + }; + motherboard { ranges = <0 0 0x08000000 0x04000000>, <1 0 0x14000000 0x04000000>, diff --git a/arch/arm/boot/dts/vexpress-v2p-ca9.dts b/arch/arm/boot/dts/vexpress-v2p-ca9.dts index 3f0c736d31d6..005259db541d 100644 --- a/arch/arm/boot/dts/vexpress-v2p-ca9.dts +++ b/arch/arm/boot/dts/vexpress-v2p-ca9.dts @@ -12,6 +12,7 @@ / { model = "V2P-CA9"; arm,hbi = <0x191>; + arm,vexpress,site = <0xf>; compatible = "arm,vexpress,v2p-ca9", "arm,vexpress"; interrupt-parent = <&gic>; #address-cells = <1>; @@ -70,11 +71,15 @@ compatible = "arm,pl111", "arm,primecell"; reg = <0x10020000 0x1000>; interrupts = <0 44 4>; + clocks = <&oscclk1>, <&oscclk2>; + clock-names = "clcdclk", "apb_pclk"; }; memory-controller@100e0000 { compatible = "arm,pl341", "arm,primecell"; reg = <0x100e0000 0x1000>; + clocks = <&oscclk2>; + clock-names = "apb_pclk"; }; memory-controller@100e1000 { @@ -82,6 +87,8 @@ reg = <0x100e1000 0x1000>; interrupts = <0 45 4>, <0 46 4>; + clocks = <&oscclk2>; + clock-names = "apb_pclk"; }; timer@100e4000 { @@ -89,12 +96,16 @@ reg = <0x100e4000 0x1000>; interrupts = <0 48 4>, <0 49 4>; + clocks = <&oscclk2>, <&oscclk2>; + clock-names = "timclk", "apb_pclk"; }; watchdog@100e5000 { compatible = "arm,sp805", "arm,primecell"; reg = <0x100e5000 0x1000>; interrupts = <0 51 4>; + clocks = <&oscclk2>, <&oscclk2>; + clock-names = "wdogclk", "apb_pclk"; }; scu@1e000000 { @@ -140,6 +151,120 @@ <0 63 4>; }; + dcc { + compatible = "arm,vexpress,config-bus"; + arm,vexpress,config-bridge = <&v2m_sysreg>; + + osc@0 { + /* ACLK clock to the AXI master port on the test chip */ + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 0>; + freq-range = <30000000 50000000>; + #clock-cells = <0>; + clock-output-names = "extsaxiclk"; + }; + + oscclk1: osc@1 { + /* Reference clock for the CLCD */ + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 1>; + freq-range = <10000000 80000000>; + #clock-cells = <0>; + clock-output-names = "clcdclk"; + }; + + smbclk: oscclk2: osc@2 { + /* Reference clock for the test chip internal PLLs */ + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 2>; + freq-range = <33000000 100000000>; + #clock-cells = <0>; + clock-output-names = "tcrefclk"; + }; + + volt@0 { + /* Test Chip internal logic voltage */ + compatible = "arm,vexpress-volt"; + arm,vexpress-sysreg,func = <2 0>; + regulator-name = "VD10"; + regulator-always-on; + label = "VD10"; + }; + + volt@1 { + /* PL310, L2 cache, RAM cell supply (not PL310 logic) */ + compatible = "arm,vexpress-volt"; + arm,vexpress-sysreg,func = <2 1>; + regulator-name = "VD10_S2"; + regulator-always-on; + label = "VD10_S2"; + }; + + volt@2 { + /* Cortex-A9 system supply, Cores, MPEs, SCU and PL310 logic */ + compatible = "arm,vexpress-volt"; + arm,vexpress-sysreg,func = <2 2>; + regulator-name = "VD10_S3"; + regulator-always-on; + label = "VD10_S3"; + }; + + volt@3 { + /* DDR2 SDRAM and Test Chip DDR2 I/O supply */ + compatible = "arm,vexpress-volt"; + arm,vexpress-sysreg,func = <2 3>; + regulator-name = "VCC1V8"; + regulator-always-on; + label = "VCC1V8"; + }; + + volt@4 { + /* DDR2 SDRAM VTT termination voltage */ + compatible = "arm,vexpress-volt"; + arm,vexpress-sysreg,func = <2 4>; + regulator-name = "DDR2VTT"; + regulator-always-on; + label = "DDR2VTT"; + }; + + volt@5 { + /* Local board supply for miscellaneous logic external to the Test Chip */ + arm,vexpress-sysreg,func = <2 5>; + compatible = "arm,vexpress-volt"; + regulator-name = "VCC3V3"; + regulator-always-on; + label = "VCC3V3"; + }; + + amp@0 { + /* PL310, L2 cache, RAM cell supply (not PL310 logic) */ + compatible = "arm,vexpress-amp"; + arm,vexpress-sysreg,func = <3 0>; + label = "VD10_S2"; + }; + + amp@1 { + /* Cortex-A9 system supply, Cores, MPEs, SCU and PL310 logic */ + compatible = "arm,vexpress-amp"; + arm,vexpress-sysreg,func = <3 1>; + label = "VD10_S3"; + }; + + power@0 { + /* PL310, L2 cache, RAM cell supply (not PL310 logic) */ + compatible = "arm,vexpress-power"; + arm,vexpress-sysreg,func = <12 0>; + label = "PVD10_S2"; + }; + + power@1 { + /* Cortex-A9 system supply, Cores, MPEs, SCU and PL310 logic */ + compatible = "arm,vexpress-power"; + arm,vexpress-sysreg,func = <12 1>; + label = "PVD10_S3"; + }; + }; + motherboard { ranges = <0 0 0x40000000 0x04000000>, <1 0 0x44000000 0x04000000>, From 38669e045dbf8f62a008898a7fb1e93975b3817c Mon Sep 17 00:00:00 2001 From: Pawel Moll Date: Tue, 9 Oct 2012 12:56:36 +0100 Subject: [PATCH 4/5] ARM: vexpress: Start using new Versatile Express infrastructure This patch starts using all the configuration infrastructure. - generic GPIO library is forced now - sysreg GPIOs are used as MMC CD and WP information sources; thanks to this MMCI auxiliary data is not longer necessary - DVI muxer and mode control is removed from non-DT V2P-CA9 code as this is now handled by the vexpress-dvi driver - clock generators control is removed as is being handled by the common clock driver now - the sysreg and sysctl control is now delegated to the appropriate drivers and all related code was removed - NOR Flash set_vpp function has been removed as the control bit used does _not_ control its VPP line, but the #WP signal instead (which is de facto unusable in case of Linux MTD drivers); this also allowed the remove its DT auxiliary data The non-DT code defines only minimal required number of the config devices. Device Trees are updated to make use of all new features. Signed-off-by: Pawel Moll --- arch/arm/include/asm/hardware/sp810.h | 6 - arch/arm/mach-vexpress/Kconfig | 4 +- arch/arm/mach-vexpress/Makefile | 2 +- arch/arm/mach-vexpress/ct-ca9x4.c | 41 +-- .../mach-vexpress/include/mach/motherboard.h | 81 ----- arch/arm/mach-vexpress/platsmp.c | 3 +- arch/arm/mach-vexpress/v2m.c | 332 +++++------------- include/linux/vexpress.h | 11 + 8 files changed, 110 insertions(+), 370 deletions(-) diff --git a/arch/arm/include/asm/hardware/sp810.h b/arch/arm/include/asm/hardware/sp810.h index afd7e916472f..6636430dd0e6 100644 --- a/arch/arm/include/asm/hardware/sp810.h +++ b/arch/arm/include/asm/hardware/sp810.h @@ -50,12 +50,6 @@ #define SCPCELLID2 0xFF8 #define SCPCELLID3 0xFFC -#define SCCTRL_TIMEREN0SEL_REFCLK (0 << 15) -#define SCCTRL_TIMEREN0SEL_TIMCLK (1 << 15) - -#define SCCTRL_TIMEREN1SEL_REFCLK (0 << 17) -#define SCCTRL_TIMEREN1SEL_TIMCLK (1 << 17) - #define SCCTRL_TIMERENnSEL_SHIFT(n) (15 + ((n) * 2)) static inline void sysctl_soft_reset(void __iomem *base) diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig index c95296066203..99e63f5f99d1 100644 --- a/arch/arm/mach-vexpress/Kconfig +++ b/arch/arm/mach-vexpress/Kconfig @@ -1,11 +1,12 @@ config ARCH_VEXPRESS bool "ARM Ltd. Versatile Express family" if ARCH_MULTI_V7 - select ARCH_WANT_OPTIONAL_GPIOLIB + select ARCH_REQUIRE_GPIOLIB select ARM_AMBA select ARM_GIC select ARM_TIMER_SP804 select CLKDEV_LOOKUP select COMMON_CLK + select COMMON_CLK_VERSATILE select CPU_V7 select GENERIC_CLOCKEVENTS select HAVE_CLK @@ -17,6 +18,7 @@ config ARCH_VEXPRESS select PLAT_VERSATILE select PLAT_VERSATILE_CLCD select REGULATOR_FIXED_VOLTAGE if REGULATOR + select VEXPRESS_CONFIG help This option enables support for systems using Cortex processor based ARM core and logic (FPGA) tiles on the Versatile Express motherboard, diff --git a/arch/arm/mach-vexpress/Makefile b/arch/arm/mach-vexpress/Makefile index 42703e8b4d3b..80b64971fbdd 100644 --- a/arch/arm/mach-vexpress/Makefile +++ b/arch/arm/mach-vexpress/Makefile @@ -4,7 +4,7 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \ -I$(srctree)/arch/arm/plat-versatile/include -obj-y := v2m.o +obj-y := v2m.o reset.o obj-$(CONFIG_ARCH_VEXPRESS_CA9X4) += ct-ca9x4.o obj-$(CONFIG_SMP) += platsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o diff --git a/arch/arm/mach-vexpress/ct-ca9x4.c b/arch/arm/mach-vexpress/ct-ca9x4.c index 4f471fa3e3c5..60838ddb8564 100644 --- a/arch/arm/mach-vexpress/ct-ca9x4.c +++ b/arch/arm/mach-vexpress/ct-ca9x4.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -64,19 +65,6 @@ static void __init ct_ca9x4_init_irq(void) ca9x4_twd_init(); } -static void ct_ca9x4_clcd_enable(struct clcd_fb *fb) -{ - u32 site = v2m_get_master_site(); - - /* - * Old firmware was using the "site" component of the command - * to control the DVI muxer (while it should be always 0 ie. MB). - * Newer firmware uses the data register. Keep both for compatibility. - */ - v2m_cfg_write(SYS_CFG_MUXFPGA | SYS_CFG_SITE(site), site); - v2m_cfg_write(SYS_CFG_DVIMODE | SYS_CFG_SITE(SYS_CFG_SITE_MB), 2); -} - static int ct_ca9x4_clcd_setup(struct clcd_fb *fb) { unsigned long framesize = 1024 * 768 * 2; @@ -93,7 +81,6 @@ static struct clcd_board ct_ca9x4_clcd_data = { .caps = CLCD_CAP_5551 | CLCD_CAP_565, .check = clcdfb_check, .decode = clcdfb_decode, - .enable = ct_ca9x4_clcd_enable, .setup = ct_ca9x4_clcd_setup, .mmap = versatile_clcd_mmap_dma, .remove = versatile_clcd_remove_dma, @@ -111,14 +98,6 @@ static struct amba_device *ct_ca9x4_amba_devs[] __initdata = { &gpio_device, }; - -static struct v2m_osc ct_osc1 = { - .osc = 1, - .rate_min = 10000000, - .rate_max = 80000000, - .rate_default = 23750000, -}; - static struct resource pmu_resources[] = { [0] = { .start = IRQ_CT_CA9X4_PMU_CPU0, @@ -149,10 +128,18 @@ static struct platform_device pmu_device = { .resource = pmu_resources, }; +static struct platform_device osc1_device = { + .name = "vexpress-osc", + .id = 1, + .num_resources = 1, + .resource = (struct resource []) { + VEXPRESS_RES_FUNC(0xf, 1), + }, +}; + static void __init ct_ca9x4_init(void) { int i; - struct clk *clk; #ifdef CONFIG_CACHE_L2X0 void __iomem *l2x0_base = ioremap(CT_CA9X4_L2CC, SZ_4K); @@ -164,14 +151,14 @@ static void __init ct_ca9x4_init(void) l2x0_init(l2x0_base, 0x00400000, 0xfe0fffff); #endif - ct_osc1.site = v2m_get_master_site(); - clk = v2m_osc_register("ct:osc1", &ct_osc1); - clk_register_clkdev(clk, NULL, "ct:clcd"); - for (i = 0; i < ARRAY_SIZE(ct_ca9x4_amba_devs); i++) amba_device_register(ct_ca9x4_amba_devs[i], &iomem_resource); platform_device_register(&pmu_device); + platform_device_register(&osc1_device); + + WARN_ON(clk_register_clkdev(vexpress_osc_setup(&osc1_device.dev), + NULL, "ct:clcd")); } #ifdef CONFIG_SMP diff --git a/arch/arm/mach-vexpress/include/mach/motherboard.h b/arch/arm/mach-vexpress/include/mach/motherboard.h index 1e388c7bf4d7..68abc8b72781 100644 --- a/arch/arm/mach-vexpress/include/mach/motherboard.h +++ b/arch/arm/mach-vexpress/include/mach/motherboard.h @@ -1,8 +1,6 @@ #ifndef __MACH_MOTHERBOARD_H #define __MACH_MOTHERBOARD_H -#include - /* * Physical addresses, offset from V2M_PA_CS0-3 */ @@ -41,31 +39,6 @@ #define V2M_CF (V2M_PA_CS7 + 0x0001a000) #define V2M_CLCD (V2M_PA_CS7 + 0x0001f000) -/* - * Offsets from SYSREGS base - */ -#define V2M_SYS_ID 0x000 -#define V2M_SYS_SW 0x004 -#define V2M_SYS_LED 0x008 -#define V2M_SYS_100HZ 0x024 -#define V2M_SYS_FLAGS 0x030 -#define V2M_SYS_FLAGSSET 0x030 -#define V2M_SYS_FLAGSCLR 0x034 -#define V2M_SYS_NVFLAGS 0x038 -#define V2M_SYS_NVFLAGSSET 0x038 -#define V2M_SYS_NVFLAGSCLR 0x03c -#define V2M_SYS_MCI 0x048 -#define V2M_SYS_FLASH 0x03c -#define V2M_SYS_CFGSW 0x058 -#define V2M_SYS_24MHZ 0x05c -#define V2M_SYS_MISC 0x060 -#define V2M_SYS_DMA 0x064 -#define V2M_SYS_PROCID0 0x084 -#define V2M_SYS_PROCID1 0x088 -#define V2M_SYS_CFGDATA 0x0a0 -#define V2M_SYS_CFGCTRL 0x0a4 -#define V2M_SYS_CFGSTAT 0x0a8 - /* * Interrupts. Those in {} are for AMBA devices @@ -90,43 +63,6 @@ #define IRQ_V2M_PCIE (32 + 17) -/* - * Configuration - */ -#define SYS_CFG_START (1 << 31) -#define SYS_CFG_WRITE (1 << 30) -#define SYS_CFG_OSC (1 << 20) -#define SYS_CFG_VOLT (2 << 20) -#define SYS_CFG_AMP (3 << 20) -#define SYS_CFG_TEMP (4 << 20) -#define SYS_CFG_RESET (5 << 20) -#define SYS_CFG_SCC (6 << 20) -#define SYS_CFG_MUXFPGA (7 << 20) -#define SYS_CFG_SHUTDOWN (8 << 20) -#define SYS_CFG_REBOOT (9 << 20) -#define SYS_CFG_DVIMODE (11 << 20) -#define SYS_CFG_POWER (12 << 20) -#define SYS_CFG_SITE(n) ((n) << 16) -#define SYS_CFG_SITE_MB 0 -#define SYS_CFG_SITE_DB1 1 -#define SYS_CFG_SITE_DB2 2 -#define SYS_CFG_STACK(n) ((n) << 12) - -#define SYS_CFG_ERR (1 << 1) -#define SYS_CFG_COMPLETE (1 << 0) - -int v2m_cfg_write(u32 devfn, u32 data); -int v2m_cfg_read(u32 devfn, u32 *data); -void v2m_flags_set(u32 data); - -/* - * Miscellaneous - */ -#define SYS_MISC_MASTERSITE (1 << 14) -#define SYS_PROCIDx_HBI_MASK 0xfff - -int v2m_get_master_site(void); - /* * Core tile IDs */ @@ -149,21 +85,4 @@ struct ct_desc { extern struct ct_desc *ct_desc; -/* - * OSC clock provider - */ -struct v2m_osc { - struct clk_hw hw; - u8 site; /* 0 = motherboard, 1 = site 1, 2 = site 2 */ - u8 stack; /* board stack position */ - u16 osc; - unsigned long rate_min; - unsigned long rate_max; - unsigned long rate_default; -}; - -#define to_v2m_osc(osc) container_of(osc, struct v2m_osc, hw) - -struct clk *v2m_osc_register(const char *name, struct v2m_osc *osc); - #endif diff --git a/arch/arm/mach-vexpress/platsmp.c b/arch/arm/mach-vexpress/platsmp.c index 7db27c8c05cc..c5d70de9bb4e 100644 --- a/arch/arm/mach-vexpress/platsmp.c +++ b/arch/arm/mach-vexpress/platsmp.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -193,7 +194,7 @@ static void __init vexpress_smp_prepare_cpus(unsigned int max_cpus) * until it receives a soft interrupt, and then the * secondary CPU branches to this address. */ - v2m_flags_set(virt_to_phys(versatile_secondary_startup)); + vexpress_flags_set(virt_to_phys(versatile_secondary_startup)); } struct smp_operations __initdata vexpress_smp_ops = { diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c index 560e0df728f8..99d4172816be 100644 --- a/arch/arm/mach-vexpress/v2m.c +++ b/arch/arm/mach-vexpress/v2m.c @@ -16,11 +16,10 @@ #include #include #include -#include -#include #include #include #include +#include #include #include @@ -33,7 +32,6 @@ #include #include #include -#include #include #include @@ -58,22 +56,6 @@ static struct map_desc v2m_io_desc[] __initdata = { }, }; -static void __iomem *v2m_sysreg_base; - -static void __init v2m_sysctl_init(void __iomem *base) -{ - u32 scctrl; - - if (WARN_ON(!base)) - return; - - /* Select 1MHz TIMCLK as the reference clock for SP804 timers */ - scctrl = readl(base + SCCTRL); - scctrl |= SCCTRL_TIMEREN0SEL_TIMCLK; - scctrl |= SCCTRL_TIMEREN1SEL_TIMCLK; - writel(scctrl, base + SCCTRL); -} - static void __init v2m_sp804_init(void __iomem *base, unsigned int irq) { if (WARN_ON(!base || irq == NO_IRQ)) @@ -87,69 +69,6 @@ static void __init v2m_sp804_init(void __iomem *base, unsigned int irq) } -static DEFINE_SPINLOCK(v2m_cfg_lock); - -int v2m_cfg_write(u32 devfn, u32 data) -{ - /* Configuration interface broken? */ - u32 val; - - printk("%s: writing %08x to %08x\n", __func__, data, devfn); - - devfn |= SYS_CFG_START | SYS_CFG_WRITE; - - spin_lock(&v2m_cfg_lock); - val = readl(v2m_sysreg_base + V2M_SYS_CFGSTAT); - writel(val & ~SYS_CFG_COMPLETE, v2m_sysreg_base + V2M_SYS_CFGSTAT); - - writel(data, v2m_sysreg_base + V2M_SYS_CFGDATA); - writel(devfn, v2m_sysreg_base + V2M_SYS_CFGCTRL); - - do { - val = readl(v2m_sysreg_base + V2M_SYS_CFGSTAT); - } while (val == 0); - spin_unlock(&v2m_cfg_lock); - - return !!(val & SYS_CFG_ERR); -} - -int v2m_cfg_read(u32 devfn, u32 *data) -{ - u32 val; - - devfn |= SYS_CFG_START; - - spin_lock(&v2m_cfg_lock); - writel(0, v2m_sysreg_base + V2M_SYS_CFGSTAT); - writel(devfn, v2m_sysreg_base + V2M_SYS_CFGCTRL); - - mb(); - - do { - cpu_relax(); - val = readl(v2m_sysreg_base + V2M_SYS_CFGSTAT); - } while (val == 0); - - *data = readl(v2m_sysreg_base + V2M_SYS_CFGDATA); - spin_unlock(&v2m_cfg_lock); - - return !!(val & SYS_CFG_ERR); -} - -void __init v2m_flags_set(u32 data) -{ - writel(~0, v2m_sysreg_base + V2M_SYS_FLAGSCLR); - writel(data, v2m_sysreg_base + V2M_SYS_FLAGSSET); -} - -int v2m_get_master_site(void) -{ - u32 misc = readl(v2m_sysreg_base + V2M_SYS_MISC); - - return misc & SYS_MISC_MASTERSITE ? SYS_CFG_SITE_DB2 : SYS_CFG_SITE_DB1; -} - - static struct resource v2m_pcie_i2c_resource = { .start = V2M_SERIAL_BUS_PCI, .end = V2M_SERIAL_BUS_PCI + SZ_4K - 1, @@ -237,14 +156,8 @@ static struct platform_device v2m_usb_device = { .dev.platform_data = &v2m_usb_config, }; -static void v2m_flash_set_vpp(struct platform_device *pdev, int on) -{ - writel(on != 0, v2m_sysreg_base + V2M_SYS_FLASH); -} - static struct physmap_flash_data v2m_flash_data = { .width = 4, - .set_vpp = v2m_flash_set_vpp, }; static struct resource v2m_flash_resources[] = { @@ -291,14 +204,61 @@ static struct platform_device v2m_cf_device = { .dev.platform_data = &v2m_pata_data, }; -static unsigned int v2m_mmci_status(struct device *dev) -{ - return readl(v2m_sysreg_base + V2M_SYS_MCI) & (1 << 0); -} - static struct mmci_platform_data v2m_mmci_data = { .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, - .status = v2m_mmci_status, + .gpio_wp = VEXPRESS_GPIO_MMC_WPROT, + .gpio_cd = VEXPRESS_GPIO_MMC_CARDIN, +}; + +static struct resource v2m_sysreg_resources[] = { + { + .start = V2M_SYSREGS, + .end = V2M_SYSREGS + 0xfff, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device v2m_sysreg_device = { + .name = "vexpress-sysreg", + .id = -1, + .resource = v2m_sysreg_resources, + .num_resources = ARRAY_SIZE(v2m_sysreg_resources), +}; + +static struct platform_device v2m_muxfpga_device = { + .name = "vexpress-muxfpga", + .id = 0, + .num_resources = 1, + .resource = (struct resource []) { + VEXPRESS_RES_FUNC(0, 7), + } +}; + +static struct platform_device v2m_shutdown_device = { + .name = "vexpress-shutdown", + .id = 0, + .num_resources = 1, + .resource = (struct resource []) { + VEXPRESS_RES_FUNC(0, 8), + } +}; + +static struct platform_device v2m_reboot_device = { + .name = "vexpress-reboot", + .id = 0, + .num_resources = 1, + .resource = (struct resource []) { + VEXPRESS_RES_FUNC(0, 9), + } +}; + +static struct platform_device v2m_dvimode_device = { + .name = "vexpress-dvimode", + .id = 0, + .num_resources = 1, + .resource = (struct resource []) { + VEXPRESS_RES_FUNC(0, 11), + } }; static AMBA_APB_DEVICE(aaci, "mb:aaci", 0, V2M_AACI, IRQ_V2M_AACI, NULL); @@ -325,123 +285,9 @@ static struct amba_device *v2m_amba_devs[] __initdata = { &rtc_device, }; - -static unsigned long v2m_osc_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct v2m_osc *osc = to_v2m_osc(hw); - - return !parent_rate ? osc->rate_default : parent_rate; -} - -static long v2m_osc_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) -{ - struct v2m_osc *osc = to_v2m_osc(hw); - - if (WARN_ON(rate < osc->rate_min)) - rate = osc->rate_min; - - if (WARN_ON(rate > osc->rate_max)) - rate = osc->rate_max; - - return rate; -} - -static int v2m_osc_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct v2m_osc *osc = to_v2m_osc(hw); - - v2m_cfg_write(SYS_CFG_OSC | SYS_CFG_SITE(osc->site) | - SYS_CFG_STACK(osc->stack) | osc->osc, rate); - - return 0; -} - -static struct clk_ops v2m_osc_ops = { - .recalc_rate = v2m_osc_recalc_rate, - .round_rate = v2m_osc_round_rate, - .set_rate = v2m_osc_set_rate, -}; - -struct clk * __init v2m_osc_register(const char *name, struct v2m_osc *osc) -{ - struct clk_init_data init; - - WARN_ON(osc->site > 2); - WARN_ON(osc->stack > 15); - WARN_ON(osc->osc > 4095); - - init.name = name; - init.ops = &v2m_osc_ops; - init.flags = CLK_IS_ROOT; - init.num_parents = 0; - - osc->hw.init = &init; - - return clk_register(NULL, &osc->hw); -} - -static struct v2m_osc v2m_mb_osc1 = { - .site = SYS_CFG_SITE_MB, - .osc = 1, - .rate_min = 23750000, - .rate_max = 63500000, - .rate_default = 23750000, -}; - -static const char *v2m_ref_clk_periphs[] __initconst = { - "mb:wdt", "1000f000.wdt", "1c0f0000.wdt", /* SP805 WDT */ -}; - -static const char *v2m_osc1_periphs[] __initconst = { - "mb:clcd", "1001f000.clcd", "1c1f0000.clcd", /* PL111 CLCD */ -}; - -static const char *v2m_osc2_periphs[] __initconst = { - "mb:mmci", "10005000.mmci", "1c050000.mmci", /* PL180 MMCI */ - "mb:kmi0", "10006000.kmi", "1c060000.kmi", /* PL050 KMI0 */ - "mb:kmi1", "10007000.kmi", "1c070000.kmi", /* PL050 KMI1 */ - "mb:uart0", "10009000.uart", "1c090000.uart", /* PL011 UART0 */ - "mb:uart1", "1000a000.uart", "1c0a0000.uart", /* PL011 UART1 */ - "mb:uart2", "1000b000.uart", "1c0b0000.uart", /* PL011 UART2 */ - "mb:uart3", "1000c000.uart", "1c0c0000.uart", /* PL011 UART3 */ -}; - -static void __init v2m_clk_init(void) -{ - struct clk *clk; - int i; - - clk = clk_register_fixed_rate(NULL, "dummy_apb_pclk", NULL, - CLK_IS_ROOT, 0); - WARN_ON(clk_register_clkdev(clk, "apb_pclk", NULL)); - - clk = clk_register_fixed_rate(NULL, "mb:ref_clk", NULL, - CLK_IS_ROOT, 32768); - for (i = 0; i < ARRAY_SIZE(v2m_ref_clk_periphs); i++) - WARN_ON(clk_register_clkdev(clk, NULL, v2m_ref_clk_periphs[i])); - - clk = clk_register_fixed_rate(NULL, "mb:sp804_clk", NULL, - CLK_IS_ROOT, 1000000); - WARN_ON(clk_register_clkdev(clk, "v2m-timer0", "sp804")); - WARN_ON(clk_register_clkdev(clk, "v2m-timer1", "sp804")); - - clk = v2m_osc_register("mb:osc1", &v2m_mb_osc1); - for (i = 0; i < ARRAY_SIZE(v2m_osc1_periphs); i++) - WARN_ON(clk_register_clkdev(clk, NULL, v2m_osc1_periphs[i])); - - clk = clk_register_fixed_rate(NULL, "mb:osc2", NULL, - CLK_IS_ROOT, 24000000); - for (i = 0; i < ARRAY_SIZE(v2m_osc2_periphs); i++) - WARN_ON(clk_register_clkdev(clk, NULL, v2m_osc2_periphs[i])); -} - static void __init v2m_timer_init(void) { - v2m_sysctl_init(ioremap(V2M_SYSCTL, SZ_4K)); - v2m_clk_init(); + vexpress_clk_init(ioremap(V2M_SYSCTL, SZ_4K)); v2m_sp804_init(ioremap(V2M_TIMER01, SZ_4K), IRQ_V2M_TIMER0); } @@ -453,19 +299,7 @@ static void __init v2m_init_early(void) { if (ct_desc->init_early) ct_desc->init_early(); - versatile_sched_clock_init(v2m_sysreg_base + V2M_SYS_24MHZ, 24000000); -} - -static void v2m_power_off(void) -{ - if (v2m_cfg_write(SYS_CFG_SHUTDOWN | SYS_CFG_SITE(SYS_CFG_SITE_MB), 0)) - printk(KERN_EMERG "Unable to shutdown\n"); -} - -static void v2m_restart(char str, const char *cmd) -{ - if (v2m_cfg_write(SYS_CFG_REBOOT | SYS_CFG_SITE(SYS_CFG_SITE_MB), 0)) - printk(KERN_EMERG "Unable to reboot\n"); + versatile_sched_clock_init(vexpress_get_24mhz_clock_base(), 24000000); } struct ct_desc *ct_desc; @@ -482,7 +316,7 @@ static void __init v2m_populate_ct_desc(void) u32 current_tile_id; ct_desc = NULL; - current_tile_id = readl(v2m_sysreg_base + V2M_SYS_PROCID0) + current_tile_id = vexpress_get_procid(VEXPRESS_SITE_MASTER) & V2M_CT_ID_MASK; for (i = 0; i < ARRAY_SIZE(ct_descs) && !ct_desc; ++i) @@ -498,7 +332,7 @@ static void __init v2m_populate_ct_desc(void) static void __init v2m_map_io(void) { iotable_init(v2m_io_desc, ARRAY_SIZE(v2m_io_desc)); - v2m_sysreg_base = ioremap(V2M_SYSREGS, SZ_4K); + vexpress_sysreg_early_init(ioremap(V2M_SYSREGS, SZ_4K)); v2m_populate_ct_desc(); ct_desc->map_io(); } @@ -515,6 +349,12 @@ static void __init v2m_init(void) regulator_register_fixed(0, v2m_eth_supplies, ARRAY_SIZE(v2m_eth_supplies)); + platform_device_register(&v2m_muxfpga_device); + platform_device_register(&v2m_shutdown_device); + platform_device_register(&v2m_reboot_device); + platform_device_register(&v2m_dvimode_device); + + platform_device_register(&v2m_sysreg_device); platform_device_register(&v2m_pcie_i2c_device); platform_device_register(&v2m_ddc_i2c_device); platform_device_register(&v2m_flash_device); @@ -525,7 +365,7 @@ static void __init v2m_init(void) for (i = 0; i < ARRAY_SIZE(v2m_amba_devs); i++) amba_device_register(v2m_amba_devs[i], &iomem_resource); - pm_power_off = v2m_power_off; + pm_power_off = vexpress_power_off; ct_desc->init_tile(); } @@ -539,7 +379,7 @@ MACHINE_START(VEXPRESS, "ARM-Versatile Express") .timer = &v2m_timer, .handle_irq = gic_handle_irq, .init_machine = v2m_init, - .restart = v2m_restart, + .restart = vexpress_restart, MACHINE_END static struct map_desc v2m_rs1_io_desc __initdata = { @@ -580,20 +420,13 @@ void __init v2m_dt_map_io(void) void __init v2m_dt_init_early(void) { - struct device_node *node; u32 dt_hbi; - node = of_find_compatible_node(NULL, NULL, "arm,vexpress-sysreg"); - v2m_sysreg_base = of_iomap(node, 0); - if (WARN_ON(!v2m_sysreg_base)) - return; + vexpress_sysreg_of_early_init(); /* Confirm board type against DT property, if available */ if (of_property_read_u32(allnodes, "arm,hbi", &dt_hbi) == 0) { - int site = v2m_get_master_site(); - u32 id = readl(v2m_sysreg_base + (site == SYS_CFG_SITE_DB2 ? - V2M_SYS_PROCID1 : V2M_SYS_PROCID0)); - u32 hbi = id & SYS_PROCIDx_HBI_MASK; + u32 hbi = vexpress_get_hbi(VEXPRESS_SITE_MASTER); if (WARN_ON(dt_hbi != hbi)) pr_warning("vexpress: DT HBI (%x) is not matching " @@ -617,10 +450,7 @@ static void __init v2m_dt_timer_init(void) const char *path; int err; - node = of_find_compatible_node(NULL, NULL, "arm,sp810"); - v2m_sysctl_init(of_iomap(node, 0)); - - v2m_clk_init(); + vexpress_clk_of_init(); err = of_property_read_string(of_aliases, "arm,v2m_timer", &path); if (WARN_ON(err)) @@ -631,33 +461,29 @@ static void __init v2m_dt_timer_init(void) twd_local_timer_of_register(); if (arch_timer_sched_clock_init() != 0) - versatile_sched_clock_init(v2m_sysreg_base + V2M_SYS_24MHZ, 24000000); + versatile_sched_clock_init(vexpress_get_24mhz_clock_base(), + 24000000); } static struct sys_timer v2m_dt_timer = { .init = v2m_dt_timer_init, }; -static struct of_dev_auxdata v2m_dt_auxdata_lookup[] __initdata = { - OF_DEV_AUXDATA("arm,vexpress-flash", V2M_NOR0, "physmap-flash", - &v2m_flash_data), - OF_DEV_AUXDATA("arm,primecell", V2M_MMCI, "mb:mmci", &v2m_mmci_data), - /* RS1 memory map */ - OF_DEV_AUXDATA("arm,vexpress-flash", 0x08000000, "physmap-flash", - &v2m_flash_data), - OF_DEV_AUXDATA("arm,primecell", 0x1c050000, "mb:mmci", &v2m_mmci_data), +static const struct of_device_id v2m_dt_bus_match[] __initconst = { + { .compatible = "simple-bus", }, + { .compatible = "arm,amba-bus", }, + { .compatible = "arm,vexpress,config-bus", }, {} }; static void __init v2m_dt_init(void) { l2x0_of_init(0x00400000, 0xfe0fffff); - of_platform_populate(NULL, of_default_bus_match_table, - v2m_dt_auxdata_lookup, NULL); - pm_power_off = v2m_power_off; + of_platform_populate(NULL, v2m_dt_bus_match, NULL, NULL); + pm_power_off = vexpress_power_off; } -const static char *v2m_dt_match[] __initconst = { +static const char * const v2m_dt_match[] __initconst = { "arm,vexpress", "xen,xenvm", NULL, @@ -672,5 +498,5 @@ DT_MACHINE_START(VEXPRESS_DT, "ARM-Versatile Express") .timer = &v2m_dt_timer, .init_machine = v2m_dt_init, .handle_irq = gic_handle_irq, - .restart = v2m_restart, + .restart = vexpress_restart, MACHINE_END diff --git a/include/linux/vexpress.h b/include/linux/vexpress.h index 09c81d7a22de..c52215ff4245 100644 --- a/include/linux/vexpress.h +++ b/include/linux/vexpress.h @@ -107,4 +107,15 @@ unsigned __vexpress_get_site(struct device *dev, struct device_node *node); void vexpress_sysreg_early_init(void __iomem *base); void vexpress_sysreg_of_early_init(void); +void vexpress_power_off(void); +void vexpress_restart(char str, const char *cmd); + +/* Clocks */ + +struct clk *vexpress_osc_setup(struct device *dev); +void vexpress_osc_of_setup(struct device_node *node); + +void vexpress_clk_init(void __iomem *sp810_base); +void vexpress_clk_of_init(void); + #endif From 433683a66401adb0150792e725cc4f631c94de46 Mon Sep 17 00:00:00 2001 From: Pawel Moll Date: Tue, 16 Oct 2012 15:27:12 +0100 Subject: [PATCH 5/5] ARM: vexpress: Remove motherboard dependencies in the DTS files The way the VE motherboard Device Trees were constructed enforced naming and structure of daughterboard files. This patch makes it possible to simply include the motherboard description anywhere in the main Device Tree and retires the "arm,v2m-timer" alias - any of the motherboard SP804 timers will be used instead. Signed-off-by: Pawel Moll --- .../devicetree/bindings/arm/vexpress.txt | 32 +++++++++++++------ arch/arm/boot/dts/vexpress-v2m-rs1.dtsi | 11 +++---- arch/arm/boot/dts/vexpress-v2m.dtsi | 11 +++---- arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts | 11 +++++-- arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts | 11 +++++-- arch/arm/boot/dts/vexpress-v2p-ca5s.dts | 11 +++++-- arch/arm/boot/dts/vexpress-v2p-ca9.dts | 11 +++++-- arch/arm/mach-vexpress/v2m.c | 19 ++++++----- 8 files changed, 73 insertions(+), 44 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/vexpress.txt b/Documentation/devicetree/bindings/arm/vexpress.txt index 5d9996b9eabf..ae49161e478a 100644 --- a/Documentation/devicetree/bindings/arm/vexpress.txt +++ b/Documentation/devicetree/bindings/arm/vexpress.txt @@ -141,14 +141,19 @@ can be used to obtain required phandle in the tile's "aliases" node: - SP804 timers: v2m_timer01 and v2m_timer23 -Current Linux implementation requires a "arm,v2m_timer" alias -pointing at one of the motherboard's SP804 timers, if it is to be -used as the system timer. This alias should be defined in the -motherboard files. - -The tile description must define "ranges", "interrupt-map-mask" and -"interrupt-map" properties to translate the motherboard's address -and interrupt space into one used by the tile's processor. +The tile description should define a "smb" node, describing the +Static Memory Bus between the tile and motherboard. It must define +the following properties: +- "simple-bus" compatible value (to ensure creation of the children) + compatible = "simple-bus"; +- mapping of the SMB CS/offset addresses into main address space: + #address-cells = <2>; + #size-cells = <1>; + ranges = <...>; +- interrupts mapping: + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 63>; + interrupt-map = <...>; Example of a VE tile description (simplified) @@ -200,13 +205,20 @@ Example of a VE tile description (simplified) }; }; - motherboard { + smb { + compatible = "simple-bus"; + + #address-cells = <2>; + #size-cells = <1>; /* CS0 is visible at 0x08000000 */ ranges = <0 0 0x08000000 0x04000000>; + + #interrupt-cells = <1>; interrupt-map-mask = <0 0 63>; /* Active high IRQ 0 is connected to GIC's SPI0 */ interrupt-map = <0 0 0 &gic 0 0 4>; + + /include/ "vexpress-v2m-rs1.dtsi" }; }; -/include/ "vexpress-v2m-rs1.dtsi" diff --git a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi index 9a7b6922f83b..ac870fb3fa0d 100644 --- a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi +++ b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi @@ -17,18 +17,16 @@ * CHANGES TO vexpress-v2m.dtsi! */ -/ { - aliases { - arm,v2m_timer = &v2m_timer01; - }; - motherboard { - compatible = "simple-bus"; + model = "V2M-P1"; + arm,hbi = <0x190>; arm,vexpress,site = <0>; arm,v2m-memory-map = "rs1"; + compatible = "arm,vexpress,v2m-p1", "simple-bus"; #address-cells = <2>; /* SMB chipselect number and offset */ #size-cells = <1>; #interrupt-cells = <1>; + ranges; flash@0,00000000 { compatible = "arm,vexpress-flash", "cfi-flash"; @@ -340,4 +338,3 @@ }; }; }; -}; diff --git a/arch/arm/boot/dts/vexpress-v2m.dtsi b/arch/arm/boot/dts/vexpress-v2m.dtsi index 4d321a832dbd..f1420368355b 100644 --- a/arch/arm/boot/dts/vexpress-v2m.dtsi +++ b/arch/arm/boot/dts/vexpress-v2m.dtsi @@ -17,17 +17,15 @@ * CHANGES TO vexpress-v2m-rs1.dtsi! */ -/ { - aliases { - arm,v2m_timer = &v2m_timer01; - }; - motherboard { - compatible = "simple-bus"; + model = "V2M-P1"; + arm,hbi = <0x190>; arm,vexpress,site = <0>; + compatible = "arm,vexpress,v2m-p1", "simple-bus"; #address-cells = <2>; /* SMB chipselect number and offset */ #size-cells = <1>; #interrupt-cells = <1>; + ranges; flash@0,00000000 { compatible = "arm,vexpress-flash", "cfi-flash"; @@ -339,4 +337,3 @@ }; }; }; -}; diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts b/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts index 4bbed10de45b..a3d37ec2655d 100644 --- a/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts +++ b/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts @@ -220,7 +220,11 @@ }; }; - motherboard { + smb { + compatible = "simple-bus"; + + #address-cells = <2>; + #size-cells = <1>; ranges = <0 0 0 0x08000000 0x04000000>, <1 0 0 0x14000000 0x04000000>, <2 0 0 0x18000000 0x04000000>, @@ -228,6 +232,7 @@ <4 0 0 0x0c000000 0x04000000>, <5 0 0 0x10000000 0x04000000>; + #interrupt-cells = <1>; interrupt-map-mask = <0 0 63>; interrupt-map = <0 0 0 &gic 0 0 4>, <0 0 1 &gic 0 1 4>, @@ -272,7 +277,7 @@ <0 0 40 &gic 0 40 4>, <0 0 41 &gic 0 41 4>, <0 0 42 &gic 0 42 4>; + + /include/ "vexpress-v2m-rs1.dtsi" }; }; - -/include/ "vexpress-v2m-rs1.dtsi" diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts index 3f4e1d00f4be..1fc405a9ecfb 100644 --- a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts +++ b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts @@ -305,7 +305,11 @@ }; }; - motherboard { + smb { + compatible = "simple-bus"; + + #address-cells = <2>; + #size-cells = <1>; ranges = <0 0 0 0x08000000 0x04000000>, <1 0 0 0x14000000 0x04000000>, <2 0 0 0x18000000 0x04000000>, @@ -313,6 +317,7 @@ <4 0 0 0x0c000000 0x04000000>, <5 0 0 0x10000000 0x04000000>; + #interrupt-cells = <1>; interrupt-map-mask = <0 0 63>; interrupt-map = <0 0 0 &gic 0 0 4>, <0 0 1 &gic 0 1 4>, @@ -357,7 +362,7 @@ <0 0 40 &gic 0 40 4>, <0 0 41 &gic 0 41 4>, <0 0 42 &gic 0 42 4>; + + /include/ "vexpress-v2m-rs1.dtsi" }; }; - -/include/ "vexpress-v2m-rs1.dtsi" diff --git a/arch/arm/boot/dts/vexpress-v2p-ca5s.dts b/arch/arm/boot/dts/vexpress-v2p-ca5s.dts index f3c1f2a44072..6328cbc71d30 100644 --- a/arch/arm/boot/dts/vexpress-v2p-ca5s.dts +++ b/arch/arm/boot/dts/vexpress-v2p-ca5s.dts @@ -182,7 +182,11 @@ }; }; - motherboard { + smb { + compatible = "simple-bus"; + + #address-cells = <2>; + #size-cells = <1>; ranges = <0 0 0x08000000 0x04000000>, <1 0 0x14000000 0x04000000>, <2 0 0x18000000 0x04000000>, @@ -190,6 +194,7 @@ <4 0 0x0c000000 0x04000000>, <5 0 0x10000000 0x04000000>; + #interrupt-cells = <1>; interrupt-map-mask = <0 0 63>; interrupt-map = <0 0 0 &gic 0 0 4>, <0 0 1 &gic 0 1 4>, @@ -234,7 +239,7 @@ <0 0 40 &gic 0 40 4>, <0 0 41 &gic 0 41 4>, <0 0 42 &gic 0 42 4>; + + /include/ "vexpress-v2m-rs1.dtsi" }; }; - -/include/ "vexpress-v2m-rs1.dtsi" diff --git a/arch/arm/boot/dts/vexpress-v2p-ca9.dts b/arch/arm/boot/dts/vexpress-v2p-ca9.dts index 005259db541d..1420bb14d95c 100644 --- a/arch/arm/boot/dts/vexpress-v2p-ca9.dts +++ b/arch/arm/boot/dts/vexpress-v2p-ca9.dts @@ -265,13 +265,18 @@ }; }; - motherboard { + smb { + compatible = "simple-bus"; + + #address-cells = <2>; + #size-cells = <1>; ranges = <0 0 0x40000000 0x04000000>, <1 0 0x44000000 0x04000000>, <2 0 0x48000000 0x04000000>, <3 0 0x4c000000 0x04000000>, <7 0 0x10000000 0x00020000>; + #interrupt-cells = <1>; interrupt-map-mask = <0 0 63>; interrupt-map = <0 0 0 &gic 0 0 4>, <0 0 1 &gic 0 1 4>, @@ -316,7 +321,7 @@ <0 0 40 &gic 0 40 4>, <0 0 41 &gic 0 41 4>, <0 0 42 &gic 0 42 4>; + + /include/ "vexpress-v2m.dtsi" }; }; - -/include/ "vexpress-v2m.dtsi" diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c index 99d4172816be..4e168e81fb42 100644 --- a/arch/arm/mach-vexpress/v2m.c +++ b/arch/arm/mach-vexpress/v2m.c @@ -446,17 +446,20 @@ static void __init v2m_dt_init_irq(void) static void __init v2m_dt_timer_init(void) { - struct device_node *node; - const char *path; - int err; + struct device_node *node = NULL; vexpress_clk_of_init(); - err = of_property_read_string(of_aliases, "arm,v2m_timer", &path); - if (WARN_ON(err)) - return; - node = of_find_node_by_path(path); - v2m_sp804_init(of_iomap(node, 0), irq_of_parse_and_map(node, 0)); + do { + node = of_find_compatible_node(node, NULL, "arm,sp804"); + } while (node && vexpress_get_site_by_node(node) != VEXPRESS_SITE_MB); + if (node) { + pr_info("Using SP804 '%s' as a clock & events source\n", + node->full_name); + v2m_sp804_init(of_iomap(node, 0), + irq_of_parse_and_map(node, 0)); + } + if (arch_timer_of_register() != 0) twd_local_timer_of_register();