ipq806x: add hwspinlock support

This change cherry-picks the following 3 changes from linux-next:
*fb7737 hwspinlock/core: add device tree support
*19a0f6 hwspinlock: qcom: Add support for Qualcomm HW Mutex block
*bd5717 hwspinlock: qcom: Correct msb in regmap_field

We're also adding a patch to add the hardware spinlock device nodes on
IPQ806x platforms (033-soc-qcom-Add-sfbp-device-to-IPQ806x-dts.patch).

Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>

SVN-Revision: 46655
This commit is contained in:
John Crispin 2015-08-17 06:17:47 +00:00
parent 6856535e29
commit 6b775f4517
19 changed files with 958 additions and 28 deletions

View file

@ -0,0 +1,167 @@
From fb7737e949e31d8a71acee6bbb670f32dbd2a2c0 Mon Sep 17 00:00:00 2001
From: Suman Anna <s-anna@ti.com>
Date: Wed, 4 Mar 2015 20:01:14 -0600
Subject: [PATCH] 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 <s-anna@ti.com>
Reviewed-by: Bjorn Andersson <bjorn.andersson@sonymobile.com>
[small comment clarification]
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
---
Documentation/hwspinlock.txt | 10 +++++
drivers/hwspinlock/hwspinlock_core.c | 79 ++++++++++++++++++++++++++++++++++++
include/linux/hwspinlock.h | 7 ++++
3 files changed, 96 insertions(+)
--- 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
--- a/drivers/hwspinlock/hwspinlock_core.c
+++ b/drivers/hwspinlock/hwspinlock_core.c
@@ -27,6 +27,7 @@
#include <linux/hwspinlock.h>
#include <linux/pm_runtime.h>
#include <linux/mutex.h>
+#include <linux/of.h>
#include "hwspinlock_internal.h"
@@ -257,6 +258,84 @@ void __hwspin_unlock(struct hwspinlock *
}
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;
--- 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 hwspin
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 *
{
}
+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;

View file

@ -0,0 +1,234 @@
From 19a0f61224d2d91860fa8291ab63cb104ee86bdd Mon Sep 17 00:00:00 2001
From: Bjorn Andersson <bjorn.andersson@sonymobile.com>
Date: Tue, 24 Mar 2015 10:11:05 -0700
Subject: [PATCH] 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 <galak@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@sonymobile.com>
Reviewed-by: Andy Gross <agross@codeaurora.org>
Reviewed-by: Jeffrey Hugo <jhugo@codeaurora.org>
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
---
drivers/hwspinlock/Kconfig | 12 +++
drivers/hwspinlock/Makefile | 1 +
drivers/hwspinlock/qcom_hwspinlock.c | 181 +++++++++++++++++++++++++++++++++++
3 files changed, 194 insertions(+)
create mode 100644 drivers/hwspinlock/qcom_hwspinlock.c
--- 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
--- 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
--- /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 <linux/hwspinlock.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#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");

View file

@ -0,0 +1,26 @@
From bd5717a4632cdecafe82d03de7dcb3b1876e2828 Mon Sep 17 00:00:00 2001
From: Bjorn Andersson <bjorn.andersson@sonymobile.com>
Date: Fri, 26 Jun 2015 14:47:21 -0700
Subject: [PATCH] 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 <bjorn.andersson@sonymobile.com>
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
---
drivers/hwspinlock/qcom_hwspinlock.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/hwspinlock/qcom_hwspinlock.c
+++ b/drivers/hwspinlock/qcom_hwspinlock.c
@@ -123,7 +123,7 @@ static int qcom_hwspinlock_probe(struct
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);

View file

@ -0,0 +1,34 @@
From c7c482da19a5e4ba7101198c21c2434056b0b2da Mon Sep 17 00:00:00 2001
From: Mathieu Olivari <mathieu@codeaurora.org>
Date: Thu, 13 Aug 2015 09:45:26 -0700
Subject: [PATCH 1/3] ARM: qcom: add SFPB nodes to IPQ806x dts
Add one new node to the ipq806x.dtsi file to declare & register the
hardware spinlock devices. This mechanism is required to be used by
other drivers such as SMEM.
Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
---
arch/arm/boot/dts/qcom-ipq8064.dtsi | 11 +++++++++++
1 file changed, 11 insertions(+)
--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
@@ -291,5 +291,17 @@
#clock-cells = <1>;
#reset-cells = <1>;
};
+
+ sfpb_mutex_block: syscon@1200600 {
+ compatible = "syscon";
+ reg = <0x01200600 0x100>;
+ };
};
+
+ sfpb_mutex: sfpb-mutex {
+ compatible = "qcom,sfpb-mutex";
+ syscon = <&sfpb_mutex_block 4 4>;
+
+ #hwlock-cells = <1>;
+ };
};

View file

@ -32,9 +32,9 @@
};
--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
@@ -291,5 +291,90 @@
#clock-cells = <1>;
#reset-cells = <1>;
@@ -296,6 +296,91 @@
compatible = "syscon";
reg = <0x01200600 0x100>;
};
+
+ hs_phy_1: phy@100f8800 {
@ -122,4 +122,5 @@
+ };
+
};
};
sfpb_mutex: sfpb-mutex {

View file

@ -134,8 +134,8 @@ Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
/ {
model = "Qualcomm IPQ8064";
@@ -306,6 +308,129 @@
#reset-cells = <1>;
@@ -311,6 +313,129 @@
reg = <0x01200600 0x100>;
};
+ pcie0: pci@1b500000 {

View file

@ -1,6 +1,6 @@
--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
@@ -336,15 +336,21 @@
@@ -341,15 +341,21 @@
clocks = <&gcc PCIE_A_CLK>,
<&gcc PCIE_H_CLK>,
@ -26,7 +26,7 @@
status = "disabled";
};
@@ -377,15 +383,21 @@
@@ -382,15 +388,21 @@
clocks = <&gcc PCIE_1_A_CLK>,
<&gcc PCIE_1_H_CLK>,
@ -52,7 +52,7 @@
status = "disabled";
};
@@ -418,15 +430,21 @@
@@ -423,15 +435,21 @@
clocks = <&gcc PCIE_2_A_CLK>,
<&gcc PCIE_2_H_CLK>,

View file

@ -13,7 +13,7 @@ Signed-off-by: Andy Gross <agross@codeaurora.org>
--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
@@ -657,5 +657,25 @@
@@ -662,6 +662,26 @@
};
};
@ -38,4 +38,5 @@ Signed-off-by: Andy Gross <agross@codeaurora.org>
+ };
+
};
};
sfpb_mutex: sfpb-mutex {

View file

@ -26,7 +26,7 @@ arch/arm/boot/dts/qcom-ipq8064.dtsi | 15 +++++++++++++++
--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
@@ -677,5 +677,21 @@
@@ -682,6 +682,22 @@
status = "disabled";
};
@ -47,4 +47,5 @@ arch/arm/boot/dts/qcom-ipq8064.dtsi | 15 +++++++++++++++
+ };
+
};
};
sfpb_mutex: sfpb-mutex {

View file

@ -117,7 +117,7 @@ Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
};
--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
@@ -693,5 +693,91 @@
@@ -698,6 +698,92 @@
status = "disabled";
};
@ -208,4 +208,5 @@ Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
+ };
+
};
};
sfpb_mutex: sfpb-mutex {

View file

@ -0,0 +1,167 @@
From fb7737e949e31d8a71acee6bbb670f32dbd2a2c0 Mon Sep 17 00:00:00 2001
From: Suman Anna <s-anna@ti.com>
Date: Wed, 4 Mar 2015 20:01:14 -0600
Subject: [PATCH] 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 <s-anna@ti.com>
Reviewed-by: Bjorn Andersson <bjorn.andersson@sonymobile.com>
[small comment clarification]
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
---
Documentation/hwspinlock.txt | 10 +++++
drivers/hwspinlock/hwspinlock_core.c | 79 ++++++++++++++++++++++++++++++++++++
include/linux/hwspinlock.h | 7 ++++
3 files changed, 96 insertions(+)
--- 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
--- a/drivers/hwspinlock/hwspinlock_core.c
+++ b/drivers/hwspinlock/hwspinlock_core.c
@@ -27,6 +27,7 @@
#include <linux/hwspinlock.h>
#include <linux/pm_runtime.h>
#include <linux/mutex.h>
+#include <linux/of.h>
#include "hwspinlock_internal.h"
@@ -257,6 +258,84 @@ void __hwspin_unlock(struct hwspinlock *
}
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;
--- 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 hwspin
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 *
{
}
+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;

View file

@ -0,0 +1,234 @@
From 19a0f61224d2d91860fa8291ab63cb104ee86bdd Mon Sep 17 00:00:00 2001
From: Bjorn Andersson <bjorn.andersson@sonymobile.com>
Date: Tue, 24 Mar 2015 10:11:05 -0700
Subject: [PATCH] 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 <galak@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@sonymobile.com>
Reviewed-by: Andy Gross <agross@codeaurora.org>
Reviewed-by: Jeffrey Hugo <jhugo@codeaurora.org>
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
---
drivers/hwspinlock/Kconfig | 12 +++
drivers/hwspinlock/Makefile | 1 +
drivers/hwspinlock/qcom_hwspinlock.c | 181 +++++++++++++++++++++++++++++++++++
3 files changed, 194 insertions(+)
create mode 100644 drivers/hwspinlock/qcom_hwspinlock.c
--- 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
--- 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
--- /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 <linux/hwspinlock.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#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");

View file

@ -0,0 +1,26 @@
From bd5717a4632cdecafe82d03de7dcb3b1876e2828 Mon Sep 17 00:00:00 2001
From: Bjorn Andersson <bjorn.andersson@sonymobile.com>
Date: Fri, 26 Jun 2015 14:47:21 -0700
Subject: [PATCH] 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 <bjorn.andersson@sonymobile.com>
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
---
drivers/hwspinlock/qcom_hwspinlock.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/hwspinlock/qcom_hwspinlock.c
+++ b/drivers/hwspinlock/qcom_hwspinlock.c
@@ -123,7 +123,7 @@ static int qcom_hwspinlock_probe(struct
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);

View file

@ -0,0 +1,33 @@
From c7c482da19a5e4ba7101198c21c2434056b0b2da Mon Sep 17 00:00:00 2001
From: Mathieu Olivari <mathieu@codeaurora.org>
Date: Thu, 13 Aug 2015 09:45:26 -0700
Subject: [PATCH 1/3] ARM: qcom: add SFPB nodes to IPQ806x dts
Add one new node to the ipq806x.dtsi file to declare & register the
hardware spinlock devices. This mechanism is required to be used by
other drivers such as SMEM.
Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
---
arch/arm/boot/dts/qcom-ipq8064.dtsi | 11 +++++++++++
1 file changed, 11 insertions(+)
--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
@@ -329,5 +329,16 @@
#reset-cells = <1>;
};
+ sfpb_mutex_block: syscon@1200600 {
+ compatible = "syscon";
+ reg = <0x01200600 0x100>;
+ };
};
+
+ sfpb_mutex: sfpb-mutex {
+ compatible = "qcom,sfpb-mutex";
+ syscon = <&sfpb_mutex_block 4 4>;
+
+ #hwlock-cells = <1>;
+ };
};

View file

@ -134,10 +134,11 @@ Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
/ {
model = "Qualcomm IPQ8064";
@@ -329,5 +331,127 @@
#reset-cells = <1>;
@@ -333,6 +335,129 @@
compatible = "syscon";
reg = <0x01200600 0x100>;
};
+
+ pcie0: pci@1b500000 {
+ compatible = "qcom,pcie-v0";
+ reg = <0x1b500000 0x1000
@ -261,4 +262,5 @@ Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
+ status = "disabled";
+ };
};
};
sfpb_mutex: sfpb-mutex {

View file

@ -1,6 +1,6 @@
--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
@@ -359,15 +359,21 @@
@@ -364,15 +364,21 @@
clocks = <&gcc PCIE_A_CLK>,
<&gcc PCIE_H_CLK>,
@ -26,7 +26,7 @@
status = "disabled";
};
@@ -400,15 +406,21 @@
@@ -405,15 +411,21 @@
clocks = <&gcc PCIE_1_A_CLK>,
<&gcc PCIE_1_H_CLK>,
@ -52,7 +52,7 @@
status = "disabled";
};
@@ -441,15 +453,21 @@
@@ -446,15 +458,21 @@
clocks = <&gcc PCIE_2_A_CLK>,
<&gcc PCIE_2_H_CLK>,

View file

@ -13,7 +13,7 @@ Signed-off-by: Andy Gross <agross@codeaurora.org>
--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
@@ -595,5 +595,25 @@
@@ -600,6 +600,26 @@
status = "disabled";
};
@ -38,4 +38,5 @@ Signed-off-by: Andy Gross <agross@codeaurora.org>
+ status = "disabled";
+ };
};
};
sfpb_mutex: sfpb-mutex {

View file

@ -26,7 +26,7 @@ arch/arm/boot/dts/qcom-ipq8064.dtsi | 15 +++++++++++++++
--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
@@ -615,5 +615,21 @@
@@ -620,6 +620,22 @@
status = "disabled";
};
@ -47,4 +47,5 @@ arch/arm/boot/dts/qcom-ipq8064.dtsi | 15 +++++++++++++++
+ status = "disabled";
+ };
};
};
sfpb_mutex: sfpb-mutex {

View file

@ -117,7 +117,7 @@ Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
};
--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
@@ -631,5 +631,91 @@
@@ -636,6 +636,92 @@
status = "disabled";
};
@ -208,4 +208,5 @@ Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
+ status = "disabled";
+ };
};
};
sfpb_mutex: sfpb-mutex {