From 0ce8cf2f31d661a27b7656e791acacb86eb58739 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Wed, 4 Mar 2015 20:01:13 -0600 Subject: Documentation: dt: add common bindings for hwspinlock This patch adds the generic common bindings used to represent a hwlock device and use/request locks in a device-tree build. Each hwspinlock provider should have the '#hwlock-cells' property, which represents the number of cells to be used for representing a specific hwspinlock. Client users shall use the property 'hwlocks' for requesting specific lock(s). Note that the document is named hwlock.txt deliberately to keep it a bit more generic. Cc: Rob Herring Signed-off-by: Suman Anna Reviewed-by: Bjorn Andersson Acked-by: Mark Rutland Signed-off-by: Ohad Ben-Cohen diff --git a/Documentation/devicetree/bindings/hwlock/hwlock.txt b/Documentation/devicetree/bindings/hwlock/hwlock.txt new file mode 100644 index 0000000..085d1f5 --- /dev/null +++ b/Documentation/devicetree/bindings/hwlock/hwlock.txt @@ -0,0 +1,59 @@ +Generic hwlock bindings +======================= + +Generic bindings that are common to all the hwlock platform specific driver +implementations. + +Please also look through the individual platform specific hwlock binding +documentations for identifying any additional properties specific to that +platform. + +hwlock providers: +================= + +Required properties: +- #hwlock-cells: Specifies the number of cells needed to represent a + specific lock. + +hwlock users: +============= + +Consumers that require specific hwlock(s) should specify them using the +property "hwlocks", and an optional "hwlock-names" property. + +Required properties: +- hwlocks: List of phandle to a hwlock provider node and an + associated hwlock args specifier as indicated by + #hwlock-cells. The list can have just a single hwlock + or multiple hwlocks, with each hwlock represented by + a phandle and a corresponding args specifier. + +Optional properties: +- hwlock-names: List of hwlock name strings defined in the same order + as the hwlocks, with one name per hwlock. Consumers can + use the hwlock-names to match and get a specific hwlock. + + +1. Example of a node using a single specific hwlock: + +The following example has a node requesting a hwlock in the bank defined by +the node hwlock1. hwlock1 is a hwlock provider with an argument specifier +of length 1. + + node { + ... + hwlocks = <&hwlock1 2>; + ... + }; + +2. Example of a node using multiple specific hwlocks: + +The following example has a node requesting two hwlocks, a hwlock within +the hwlock device node 'hwlock1' with #hwlock-cells value of 1, and another +hwlock within the hwlock device node 'hwlock2' with #hwlock-cells value of 2. + + node { + ... + hwlocks = <&hwlock1 2>, <&hwlock2 0 3>; + ... + }; -- cgit v0.10.2 From fb7737e949e31d8a71acee6bbb670f32dbd2a2c0 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Wed, 4 Mar 2015 20:01:14 -0600 Subject: hwspinlock/core: add device tree support This patch adds a new OF-friendly API of_hwspin_lock_get_id() for hwspinlock clients to use/request locks from a hwspinlock device instantiated through a device-tree blob. This new API can be used by hwspinlock clients to get the id for a specific lock using the phandle + args specifier, so that it can be requested using the available hwspin_lock_request_specific() API. Signed-off-by: Suman Anna Reviewed-by: Bjorn Andersson [small comment clarification] Signed-off-by: Ohad Ben-Cohen diff --git a/Documentation/hwspinlock.txt b/Documentation/hwspinlock.txt index 62f7d4e..61c1ee9 100644 --- a/Documentation/hwspinlock.txt +++ b/Documentation/hwspinlock.txt @@ -48,6 +48,16 @@ independent, drivers. ids for predefined purposes. Should be called from a process context (might sleep). + int of_hwspin_lock_get_id(struct device_node *np, int index); + - retrieve the global lock id for an OF phandle-based specific lock. + This function provides a means for DT users of a hwspinlock module + to get the global lock id of a specific hwspinlock, so that it can + be requested using the normal hwspin_lock_request_specific() API. + The function returns a lock id number on success, -EPROBE_DEFER if + the hwspinlock device is not yet registered with the core, or other + error values. + Should be called from a process context (might sleep). + int hwspin_lock_free(struct hwspinlock *hwlock); - free a previously-assigned hwspinlock; returns 0 on success, or an appropriate error code on failure (e.g. -EINVAL if the hwspinlock diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c index 461a0d7..52f708b 100644 --- a/drivers/hwspinlock/hwspinlock_core.c +++ b/drivers/hwspinlock/hwspinlock_core.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "hwspinlock_internal.h" @@ -257,6 +258,84 @@ void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags) } EXPORT_SYMBOL_GPL(__hwspin_unlock); +/** + * of_hwspin_lock_simple_xlate - translate hwlock_spec to return a lock id + * @bank: the hwspinlock device bank + * @hwlock_spec: hwlock specifier as found in the device tree + * + * This is a simple translation function, suitable for hwspinlock platform + * drivers that only has a lock specifier length of 1. + * + * Returns a relative index of the lock within a specified bank on success, + * or -EINVAL on invalid specifier cell count. + */ +static inline int +of_hwspin_lock_simple_xlate(const struct of_phandle_args *hwlock_spec) +{ + if (WARN_ON(hwlock_spec->args_count != 1)) + return -EINVAL; + + return hwlock_spec->args[0]; +} + +/** + * of_hwspin_lock_get_id() - get lock id for an OF phandle-based specific lock + * @np: device node from which to request the specific hwlock + * @index: index of the hwlock in the list of values + * + * This function provides a means for DT users of the hwspinlock module to + * get the global lock id of a specific hwspinlock using the phandle of the + * hwspinlock device, so that it can be requested using the normal + * hwspin_lock_request_specific() API. + * + * Returns the global lock id number on success, -EPROBE_DEFER if the hwspinlock + * device is not yet registered, -EINVAL on invalid args specifier value or an + * appropriate error as returned from the OF parsing of the DT client node. + */ +int of_hwspin_lock_get_id(struct device_node *np, int index) +{ + struct of_phandle_args args; + struct hwspinlock *hwlock; + struct radix_tree_iter iter; + void **slot; + int id; + int ret; + + ret = of_parse_phandle_with_args(np, "hwlocks", "#hwlock-cells", index, + &args); + if (ret) + return ret; + + /* Find the hwspinlock device: we need its base_id */ + ret = -EPROBE_DEFER; + rcu_read_lock(); + radix_tree_for_each_slot(slot, &hwspinlock_tree, &iter, 0) { + hwlock = radix_tree_deref_slot(slot); + if (unlikely(!hwlock)) + continue; + + if (hwlock->bank->dev->of_node == args.np) { + ret = 0; + break; + } + } + rcu_read_unlock(); + if (ret < 0) + goto out; + + id = of_hwspin_lock_simple_xlate(&args); + if (id < 0 || id >= hwlock->bank->num_locks) { + ret = -EINVAL; + goto out; + } + id += hwlock->bank->base_id; + +out: + of_node_put(args.np); + return ret ? ret : id; +} +EXPORT_SYMBOL_GPL(of_hwspin_lock_get_id); + static int hwspin_lock_register_single(struct hwspinlock *hwlock, int id) { struct hwspinlock *tmp; diff --git a/include/linux/hwspinlock.h b/include/linux/hwspinlock.h index 3343298..859d673 100644 --- a/include/linux/hwspinlock.h +++ b/include/linux/hwspinlock.h @@ -26,6 +26,7 @@ #define HWLOCK_IRQ 0x02 /* Disable interrupts, don't save state */ struct device; +struct device_node; struct hwspinlock; struct hwspinlock_device; struct hwspinlock_ops; @@ -66,6 +67,7 @@ int hwspin_lock_unregister(struct hwspinlock_device *bank); struct hwspinlock *hwspin_lock_request(void); struct hwspinlock *hwspin_lock_request_specific(unsigned int id); int hwspin_lock_free(struct hwspinlock *hwlock); +int of_hwspin_lock_get_id(struct device_node *np, int index); int hwspin_lock_get_id(struct hwspinlock *hwlock); int __hwspin_lock_timeout(struct hwspinlock *, unsigned int, int, unsigned long *); @@ -120,6 +122,11 @@ void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags) { } +static inline int of_hwspin_lock_get_id(struct device_node *np, int index) +{ + return 0; +} + static inline int hwspin_lock_get_id(struct hwspinlock *hwlock) { return 0; -- cgit v0.10.2 From 67140ed1c9d518565e6e2b86ba761652eb9bf3c4 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Wed, 4 Mar 2015 20:01:15 -0600 Subject: Documentation: dt: add the omap hwspinlock bindings document HwSpinlock IP is present only on OMAP4 and other newer SoCs, which are all device-tree boot only. This patch adds the DT bindings information for OMAP hwspinlock module. Cc: Rob Herring Signed-off-by: Suman Anna Acked-by: Mark Rutland Signed-off-by: Ohad Ben-Cohen diff --git a/Documentation/devicetree/bindings/hwlock/omap-hwspinlock.txt b/Documentation/devicetree/bindings/hwlock/omap-hwspinlock.txt new file mode 100644 index 0000000..2c9804f --- /dev/null +++ b/Documentation/devicetree/bindings/hwlock/omap-hwspinlock.txt @@ -0,0 +1,26 @@ +OMAP4+ HwSpinlock Driver +======================== + +Required properties: +- compatible: Should be "ti,omap4-hwspinlock" for + OMAP44xx, OMAP54xx, AM33xx, AM43xx, DRA7xx SoCs +- reg: Contains the hwspinlock module register address space + (base address and length) +- ti,hwmods: Name of the hwmod associated with the hwspinlock device +- #hwlock-cells: Should be 1. The OMAP hwspinlock users will use a + 0-indexed relative hwlock number as the argument + specifier value for requesting a specific hwspinlock + within a hwspinlock bank. + +Please look at the generic hwlock binding for usage information for consumers, +"Documentation/devicetree/bindings/hwlock/hwlock.txt" + +Example: + +/* OMAP4 */ +hwspinlock: spinlock@4a0f6000 { + compatible = "ti,omap4-hwspinlock"; + reg = <0x4a0f6000 0x1000>; + ti,hwmods = "spinlock"; + #hwlock-cells = <1>; +}; -- cgit v0.10.2 From 65bd4341d61678494ea14994d0d7df73644ca014 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Wed, 4 Mar 2015 20:01:16 -0600 Subject: hwspinlock/omap: add support for dt nodes HwSpinlock IP is present only on OMAP4 and other newer SoCs, which are all device-tree boot only. This patch adds the base support for parsing the DT nodes, and removes the code dealing with the traditional platform device instantiation. Signed-off-by: Suman Anna [tony@atomide.com: ack for legacy file removal] Acked-by: Tony Lindgren [comment on the imperfect always-zero base_id] Signed-off-by: Ohad Ben-Cohen diff --git a/MAINTAINERS b/MAINTAINERS index 2e5bbc0..5fe8941 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7095,7 +7095,6 @@ M: Ohad Ben-Cohen L: linux-omap@vger.kernel.org S: Maintained F: drivers/hwspinlock/omap_hwspinlock.c -F: arch/arm/mach-omap2/hwspinlock.c OMAP MMC SUPPORT M: Jarkko Lavinen diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index ec002bd..9a2c88e 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -277,8 +277,5 @@ obj-y += $(nand-m) $(nand-y) smsc911x-$(CONFIG_SMSC911X) := gpmc-smsc911x.o obj-y += $(smsc911x-m) $(smsc911x-y) -ifneq ($(CONFIG_HWSPINLOCK_OMAP),) -obj-y += hwspinlock.o -endif obj-y += common-board-devices.o twl-common.o dss-common.o diff --git a/arch/arm/mach-omap2/hwspinlock.c b/arch/arm/mach-omap2/hwspinlock.c deleted file mode 100644 index ef175ac..0000000 --- a/arch/arm/mach-omap2/hwspinlock.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * OMAP hardware spinlock device initialization - * - * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com - * - * Contact: Simon Que - * Hari Kanigeri - * - * 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. - */ - -#include -#include -#include -#include - -#include "soc.h" -#include "omap_hwmod.h" -#include "omap_device.h" - -static struct hwspinlock_pdata omap_hwspinlock_pdata __initdata = { - .base_id = 0, -}; - -static int __init hwspinlocks_init(void) -{ - int retval = 0; - struct omap_hwmod *oh; - struct platform_device *pdev; - const char *oh_name = "spinlock"; - const char *dev_name = "omap_hwspinlock"; - - /* - * Hwmod lookup will fail in case our platform doesn't support the - * hardware spinlock module, so it is safe to run this initcall - * on all omaps - */ - oh = omap_hwmod_lookup(oh_name); - if (oh == NULL) - return -EINVAL; - - pdev = omap_device_build(dev_name, 0, oh, &omap_hwspinlock_pdata, - sizeof(struct hwspinlock_pdata)); - if (IS_ERR(pdev)) { - pr_err("Can't build omap_device for %s:%s\n", dev_name, - oh_name); - retval = PTR_ERR(pdev); - } - - return retval; -} -/* early board code might need to reserve specific hwspinlock instances */ -omap_postcore_initcall(hwspinlocks_init); diff --git a/drivers/hwspinlock/omap_hwspinlock.c b/drivers/hwspinlock/omap_hwspinlock.c index 47a275c..ad2f8ca 100644 --- a/drivers/hwspinlock/omap_hwspinlock.c +++ b/drivers/hwspinlock/omap_hwspinlock.c @@ -1,7 +1,7 @@ /* * OMAP hardware spinlock driver * - * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2010-2015 Texas Instruments Incorporated - http://www.ti.com * * Contact: Simon Que * Hari Kanigeri @@ -27,6 +27,7 @@ #include #include #include +#include #include #include "hwspinlock_internal.h" @@ -80,14 +81,16 @@ static const struct hwspinlock_ops omap_hwspinlock_ops = { static int omap_hwspinlock_probe(struct platform_device *pdev) { - struct hwspinlock_pdata *pdata = pdev->dev.platform_data; + struct device_node *node = pdev->dev.of_node; struct hwspinlock_device *bank; struct hwspinlock *hwlock; struct resource *res; void __iomem *io_base; int num_locks, i, ret; + /* Only a single hwspinlock block device is supported */ + int base_id = 0; - if (!pdata) + if (!node) return -ENODEV; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -141,7 +144,7 @@ static int omap_hwspinlock_probe(struct platform_device *pdev) hwlock->priv = io_base + LOCK_BASE_OFFSET + sizeof(u32) * i; ret = hwspin_lock_register(bank, &pdev->dev, &omap_hwspinlock_ops, - pdata->base_id, num_locks); + base_id, num_locks); if (ret) goto reg_fail; @@ -174,11 +177,18 @@ static int omap_hwspinlock_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id omap_hwspinlock_of_match[] = { + { .compatible = "ti,omap4-hwspinlock", }, + { /* end */ }, +}; +MODULE_DEVICE_TABLE(of, omap_hwspinlock_of_match); + static struct platform_driver omap_hwspinlock_driver = { .probe = omap_hwspinlock_probe, .remove = omap_hwspinlock_remove, .driver = { .name = "omap_hwspinlock", + .of_match_table = of_match_ptr(omap_hwspinlock_of_match), }, }; -- cgit v0.10.2 From 5b5711f0f1aff1b25ee48da279de4f0c202f7a68 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Tue, 24 Mar 2015 10:11:04 -0700 Subject: DT: hwspinlock: Add binding documentation for Qualcomm hwmutex Add binding documentation for the Qualcomm Hardware Mutex. Signed-off-by: Bjorn Andersson Acked-by: Kumar Gala Reviewed-by: Andy Gross Reviewed-by: Jeffrey Hugo Signed-off-by: Ohad Ben-Cohen diff --git a/Documentation/devicetree/bindings/hwlock/qcom-hwspinlock.txt b/Documentation/devicetree/bindings/hwlock/qcom-hwspinlock.txt new file mode 100644 index 0000000..4563f52 --- /dev/null +++ b/Documentation/devicetree/bindings/hwlock/qcom-hwspinlock.txt @@ -0,0 +1,39 @@ +Qualcomm Hardware Mutex Block: + +The hardware block provides mutexes utilized between different processors on +the SoC as part of the communication protocol used by these processors. + +- compatible: + Usage: required + Value type: + Definition: must be one of: + "qcom,sfpb-mutex", + "qcom,tcsr-mutex" + +- syscon: + Usage: required + Value type: + Definition: one cell containing: + syscon phandle + offset of the hwmutex block within the syscon + stride of the hwmutex registers + +- #hwlock-cells: + Usage: required + Value type: + Definition: must be 1, the specified cell represent the lock id + (hwlock standard property, see hwlock.txt) + +Example: + + tcsr_mutex_block: syscon@fd484000 { + compatible = "syscon"; + reg = <0xfd484000 0x2000>; + }; + + hwlock@fd484000 { + compatible = "qcom,tcsr-mutex"; + syscon = <&tcsr_mutex_block 0 0x80>; + + #hwlock-cells = <1>; + }; -- cgit v0.10.2 From 19a0f61224d2d91860fa8291ab63cb104ee86bdd Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Tue, 24 Mar 2015 10:11:05 -0700 Subject: hwspinlock: qcom: Add support for Qualcomm HW Mutex block Add driver for Qualcomm Hardware Mutex block found in many Qualcomm SoCs. Based on initial effort by Kumar Gala Signed-off-by: Bjorn Andersson Reviewed-by: Andy Gross Reviewed-by: Jeffrey Hugo Signed-off-by: Ohad Ben-Cohen diff --git a/drivers/hwspinlock/Kconfig b/drivers/hwspinlock/Kconfig index 3612cb5..b5b4f52 100644 --- a/drivers/hwspinlock/Kconfig +++ b/drivers/hwspinlock/Kconfig @@ -18,6 +18,18 @@ config HWSPINLOCK_OMAP If unsure, say N. +config HWSPINLOCK_QCOM + tristate "Qualcomm Hardware Spinlock device" + depends on ARCH_QCOM + select HWSPINLOCK + select MFD_SYSCON + help + Say y here to support the Qualcomm Hardware Mutex functionality, which + provides a synchronisation mechanism for the various processors on + the SoC. + + If unsure, say N. + config HSEM_U8500 tristate "STE Hardware Semaphore functionality" depends on ARCH_U8500 diff --git a/drivers/hwspinlock/Makefile b/drivers/hwspinlock/Makefile index 93eb64b..68f95d9 100644 --- a/drivers/hwspinlock/Makefile +++ b/drivers/hwspinlock/Makefile @@ -4,4 +4,5 @@ obj-$(CONFIG_HWSPINLOCK) += hwspinlock_core.o obj-$(CONFIG_HWSPINLOCK_OMAP) += omap_hwspinlock.o +obj-$(CONFIG_HWSPINLOCK_QCOM) += qcom_hwspinlock.o obj-$(CONFIG_HSEM_U8500) += u8500_hsem.o diff --git a/drivers/hwspinlock/qcom_hwspinlock.c b/drivers/hwspinlock/qcom_hwspinlock.c new file mode 100644 index 0000000..93b62e0 --- /dev/null +++ b/drivers/hwspinlock/qcom_hwspinlock.c @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2015, Sony Mobile Communications AB + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hwspinlock_internal.h" + +#define QCOM_MUTEX_APPS_PROC_ID 1 +#define QCOM_MUTEX_NUM_LOCKS 32 + +static int qcom_hwspinlock_trylock(struct hwspinlock *lock) +{ + struct regmap_field *field = lock->priv; + u32 lock_owner; + int ret; + + ret = regmap_field_write(field, QCOM_MUTEX_APPS_PROC_ID); + if (ret) + return ret; + + ret = regmap_field_read(field, &lock_owner); + if (ret) + return ret; + + return lock_owner == QCOM_MUTEX_APPS_PROC_ID; +} + +static void qcom_hwspinlock_unlock(struct hwspinlock *lock) +{ + struct regmap_field *field = lock->priv; + u32 lock_owner; + int ret; + + ret = regmap_field_read(field, &lock_owner); + if (ret) { + pr_err("%s: unable to query spinlock owner\n", __func__); + return; + } + + if (lock_owner != QCOM_MUTEX_APPS_PROC_ID) { + pr_err("%s: spinlock not owned by us (actual owner is %d)\n", + __func__, lock_owner); + } + + ret = regmap_field_write(field, 0); + if (ret) + pr_err("%s: failed to unlock spinlock\n", __func__); +} + +static const struct hwspinlock_ops qcom_hwspinlock_ops = { + .trylock = qcom_hwspinlock_trylock, + .unlock = qcom_hwspinlock_unlock, +}; + +static const struct of_device_id qcom_hwspinlock_of_match[] = { + { .compatible = "qcom,sfpb-mutex" }, + { .compatible = "qcom,tcsr-mutex" }, + { } +}; +MODULE_DEVICE_TABLE(of, qcom_hwspinlock_of_match); + +static int qcom_hwspinlock_probe(struct platform_device *pdev) +{ + struct hwspinlock_device *bank; + struct device_node *syscon; + struct reg_field field; + struct regmap *regmap; + size_t array_size; + u32 stride; + u32 base; + int ret; + int i; + + syscon = of_parse_phandle(pdev->dev.of_node, "syscon", 0); + if (!syscon) { + dev_err(&pdev->dev, "no syscon property\n"); + return -ENODEV; + } + + regmap = syscon_node_to_regmap(syscon); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + ret = of_property_read_u32_index(pdev->dev.of_node, "syscon", 1, &base); + if (ret < 0) { + dev_err(&pdev->dev, "no offset in syscon\n"); + return -EINVAL; + } + + ret = of_property_read_u32_index(pdev->dev.of_node, "syscon", 2, &stride); + if (ret < 0) { + dev_err(&pdev->dev, "no stride syscon\n"); + return -EINVAL; + } + + array_size = QCOM_MUTEX_NUM_LOCKS * sizeof(struct hwspinlock); + bank = devm_kzalloc(&pdev->dev, sizeof(*bank) + array_size, GFP_KERNEL); + if (!bank) + return -ENOMEM; + + platform_set_drvdata(pdev, bank); + + for (i = 0; i < QCOM_MUTEX_NUM_LOCKS; i++) { + field.reg = base + i * stride; + field.lsb = 0; + field.msb = 32; + + bank->lock[i].priv = devm_regmap_field_alloc(&pdev->dev, + regmap, field); + } + + pm_runtime_enable(&pdev->dev); + + ret = hwspin_lock_register(bank, &pdev->dev, &qcom_hwspinlock_ops, + 0, QCOM_MUTEX_NUM_LOCKS); + if (ret) + pm_runtime_disable(&pdev->dev); + + return ret; +} + +static int qcom_hwspinlock_remove(struct platform_device *pdev) +{ + struct hwspinlock_device *bank = platform_get_drvdata(pdev); + int ret; + + ret = hwspin_lock_unregister(bank); + if (ret) { + dev_err(&pdev->dev, "%s failed: %d\n", __func__, ret); + return ret; + } + + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static struct platform_driver qcom_hwspinlock_driver = { + .probe = qcom_hwspinlock_probe, + .remove = qcom_hwspinlock_remove, + .driver = { + .name = "qcom_hwspinlock", + .of_match_table = qcom_hwspinlock_of_match, + }, +}; + +static int __init qcom_hwspinlock_init(void) +{ + return platform_driver_register(&qcom_hwspinlock_driver); +} +/* board init code might need to reserve hwspinlocks for predefined purposes */ +postcore_initcall(qcom_hwspinlock_init); + +static void __exit qcom_hwspinlock_exit(void) +{ + platform_driver_unregister(&qcom_hwspinlock_driver); +} +module_exit(qcom_hwspinlock_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Hardware spinlock driver for Qualcomm SoCs"); -- cgit v0.10.2 From cc16d664e21ef640faaf51e9952384cf90b92d9f Mon Sep 17 00:00:00 2001 From: Wei Chen Date: Tue, 26 May 2015 08:28:29 +0000 Subject: hwspinlock: add a CSR atlas7 driver Add hwspinlock support for the CSR atlas7 SoC. The Hardware Spinlock device on atlas7 provides hardware assistance for synchronization between the multiple processors in the system (dual Cortex-A7, CAN bus Cortex-M3 and audio DSP). Reviewed-by: Suman Anna Reviewed-by: Bjorn Andersson Signed-off-by: Wei Chen Signed-off-by: Barry Song Signed-off-by: Ohad Ben-Cohen diff --git a/drivers/hwspinlock/Kconfig b/drivers/hwspinlock/Kconfig index b5b4f52..73a4016 100644 --- a/drivers/hwspinlock/Kconfig +++ b/drivers/hwspinlock/Kconfig @@ -30,6 +30,18 @@ config HWSPINLOCK_QCOM If unsure, say N. +config HWSPINLOCK_SIRF + tristate "SIRF Hardware Spinlock device" + depends on ARCH_SIRF + select HWSPINLOCK + help + Say y here to support the SIRF Hardware Spinlock device, which + provides a synchronisation mechanism for the various processors + on the SoC. + + It's safe to say n here if you're not interested in SIRF hardware + spinlock or just want a bare minimum kernel. + config HSEM_U8500 tristate "STE Hardware Semaphore functionality" depends on ARCH_U8500 diff --git a/drivers/hwspinlock/Makefile b/drivers/hwspinlock/Makefile index 68f95d9..6b59cb5a 100644 --- a/drivers/hwspinlock/Makefile +++ b/drivers/hwspinlock/Makefile @@ -5,4 +5,5 @@ obj-$(CONFIG_HWSPINLOCK) += hwspinlock_core.o obj-$(CONFIG_HWSPINLOCK_OMAP) += omap_hwspinlock.o obj-$(CONFIG_HWSPINLOCK_QCOM) += qcom_hwspinlock.o +obj-$(CONFIG_HWSPINLOCK_SIRF) += sirf_hwspinlock.o obj-$(CONFIG_HSEM_U8500) += u8500_hsem.o diff --git a/drivers/hwspinlock/sirf_hwspinlock.c b/drivers/hwspinlock/sirf_hwspinlock.c new file mode 100644 index 0000000..1601854 --- /dev/null +++ b/drivers/hwspinlock/sirf_hwspinlock.c @@ -0,0 +1,136 @@ +/* + * SIRF hardware spinlock driver + * + * Copyright (c) 2015 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hwspinlock_internal.h" + +struct sirf_hwspinlock { + void __iomem *io_base; + struct hwspinlock_device bank; +}; + +/* Number of Hardware Spinlocks*/ +#define HW_SPINLOCK_NUMBER 30 + +/* Hardware spinlock register offsets */ +#define HW_SPINLOCK_BASE 0x404 +#define HW_SPINLOCK_OFFSET(x) (HW_SPINLOCK_BASE + 0x4 * (x)) + +static int sirf_hwspinlock_trylock(struct hwspinlock *lock) +{ + void __iomem *lock_addr = lock->priv; + + /* attempt to acquire the lock by reading value == 1 from it */ + return !!readl(lock_addr); +} + +static void sirf_hwspinlock_unlock(struct hwspinlock *lock) +{ + void __iomem *lock_addr = lock->priv; + + /* release the lock by writing 0 to it */ + writel(0, lock_addr); +} + +static const struct hwspinlock_ops sirf_hwspinlock_ops = { + .trylock = sirf_hwspinlock_trylock, + .unlock = sirf_hwspinlock_unlock, +}; + +static int sirf_hwspinlock_probe(struct platform_device *pdev) +{ + struct sirf_hwspinlock *hwspin; + struct hwspinlock *hwlock; + int idx, ret; + + if (!pdev->dev.of_node) + return -ENODEV; + + hwspin = devm_kzalloc(&pdev->dev, sizeof(*hwspin) + + sizeof(*hwlock) * HW_SPINLOCK_NUMBER, GFP_KERNEL); + if (!hwspin) + return -ENOMEM; + + /* retrieve io base */ + hwspin->io_base = of_iomap(pdev->dev.of_node, 0); + if (!hwspin->io_base) + return -ENOMEM; + + for (idx = 0; idx < HW_SPINLOCK_NUMBER; idx++) { + hwlock = &hwspin->bank.lock[idx]; + hwlock->priv = hwspin->io_base + HW_SPINLOCK_OFFSET(idx); + } + + platform_set_drvdata(pdev, hwspin); + + pm_runtime_enable(&pdev->dev); + + ret = hwspin_lock_register(&hwspin->bank, &pdev->dev, + &sirf_hwspinlock_ops, 0, + HW_SPINLOCK_NUMBER); + if (ret) + goto reg_failed; + + return 0; + +reg_failed: + pm_runtime_disable(&pdev->dev); + iounmap(hwspin->io_base); + + return ret; +} + +static int sirf_hwspinlock_remove(struct platform_device *pdev) +{ + struct sirf_hwspinlock *hwspin = platform_get_drvdata(pdev); + int ret; + + ret = hwspin_lock_unregister(&hwspin->bank); + if (ret) { + dev_err(&pdev->dev, "%s failed: %d\n", __func__, ret); + return ret; + } + + pm_runtime_disable(&pdev->dev); + + iounmap(hwspin->io_base); + + return 0; +} + +static const struct of_device_id sirf_hwpinlock_ids[] = { + { .compatible = "sirf,hwspinlock", }, + {}, +}; +MODULE_DEVICE_TABLE(of, sirf_hwpinlock_ids); + +static struct platform_driver sirf_hwspinlock_driver = { + .probe = sirf_hwspinlock_probe, + .remove = sirf_hwspinlock_remove, + .driver = { + .name = "atlas7_hwspinlock", + .of_match_table = of_match_ptr(sirf_hwpinlock_ids), + }, +}; + +module_platform_driver(sirf_hwspinlock_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("SIRF Hardware spinlock driver"); +MODULE_AUTHOR("Wei Chen "); -- cgit v0.10.2 From b97cadee805e49e823ffd5ad692bb4a9bbda248e Mon Sep 17 00:00:00 2001 From: Wei Chen Date: Tue, 26 May 2015 08:28:30 +0000 Subject: DT: hwspinlock: add the CSR atlas7 hwspinlock bindings document The Hardware Spinlock device on atlas7 provides hardware assistance for synchronization between the multiple processors in the system (dual Cortex-A7, CAN bus Cortex-M3 and audio DSP). This patch adds the DT bindings information for this hwspinlock module. Reviewed-by: Suman Anna Reviewed-by: Bjorn Andersson Signed-off-by: Wei Chen Signed-off-by: Barry Song Signed-off-by: Ohad Ben-Cohen diff --git a/Documentation/devicetree/bindings/hwlock/sirf,hwspinlock.txt b/Documentation/devicetree/bindings/hwlock/sirf,hwspinlock.txt new file mode 100644 index 0000000..9bb1240a6 --- /dev/null +++ b/Documentation/devicetree/bindings/hwlock/sirf,hwspinlock.txt @@ -0,0 +1,28 @@ +SIRF Hardware spinlock device Binding +----------------------------------------------- + +Required properties : +- compatible : shall contain only one of the following: + "sirf,hwspinlock" + +- reg : the register address of hwspinlock + +- #hwlock-cells : hwlock users only use the hwlock id to represent a specific + hwlock, so the number of cells should be <1> here. + +Please look at the generic hwlock binding for usage information for consumers, +"Documentation/devicetree/bindings/hwlock/hwlock.txt" + +Example of hwlock provider: + hwlock { + compatible = "sirf,hwspinlock"; + reg = <0x13240000 0x00010000>; + #hwlock-cells = <1>; + }; + +Example of hwlock users: + node { + ... + hwlocks = <&hwlock 2>; + ... + }; -- cgit v0.10.2 From bd5717a4632cdecafe82d03de7dcb3b1876e2828 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 26 Jun 2015 14:47:21 -0700 Subject: hwspinlock: qcom: Correct msb in regmap_field msb of the regmap_field was mistakenly given the value 32, to set all bits in the regmap update mask; although incorrect this worked until 921cc294, where the mask calculation was corrected. Signed-off-by: Bjorn Andersson Signed-off-by: Ohad Ben-Cohen diff --git a/drivers/hwspinlock/qcom_hwspinlock.c b/drivers/hwspinlock/qcom_hwspinlock.c index 93b62e0..c752447 100644 --- a/drivers/hwspinlock/qcom_hwspinlock.c +++ b/drivers/hwspinlock/qcom_hwspinlock.c @@ -123,7 +123,7 @@ static int qcom_hwspinlock_probe(struct platform_device *pdev) for (i = 0; i < QCOM_MUTEX_NUM_LOCKS; i++) { field.reg = base + i * stride; field.lsb = 0; - field.msb = 32; + field.msb = 31; bank->lock[i].priv = devm_regmap_field_alloc(&pdev->dev, regmap, field); -- cgit v0.10.2