031-hwspinlock-qcom-Add-support-for-Qualcomm-HW-Mutex-bl.patch 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. From 19a0f61224d2d91860fa8291ab63cb104ee86bdd Mon Sep 17 00:00:00 2001
  2. From: Bjorn Andersson <bjorn.andersson@sonymobile.com>
  3. Date: Tue, 24 Mar 2015 10:11:05 -0700
  4. Subject: [PATCH] hwspinlock: qcom: Add support for Qualcomm HW Mutex block
  5. Add driver for Qualcomm Hardware Mutex block found in many Qualcomm
  6. SoCs.
  7. Based on initial effort by Kumar Gala <galak@codeaurora.org>
  8. Signed-off-by: Bjorn Andersson <bjorn.andersson@sonymobile.com>
  9. Reviewed-by: Andy Gross <agross@codeaurora.org>
  10. Reviewed-by: Jeffrey Hugo <jhugo@codeaurora.org>
  11. Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
  12. ---
  13. drivers/hwspinlock/Kconfig | 12 +++
  14. drivers/hwspinlock/Makefile | 1 +
  15. drivers/hwspinlock/qcom_hwspinlock.c | 181 +++++++++++++++++++++++++++++++++++
  16. 3 files changed, 194 insertions(+)
  17. create mode 100644 drivers/hwspinlock/qcom_hwspinlock.c
  18. --- a/drivers/hwspinlock/Kconfig
  19. +++ b/drivers/hwspinlock/Kconfig
  20. @@ -18,6 +18,18 @@ config HWSPINLOCK_OMAP
  21. If unsure, say N.
  22. +config HWSPINLOCK_QCOM
  23. + tristate "Qualcomm Hardware Spinlock device"
  24. + depends on ARCH_QCOM
  25. + select HWSPINLOCK
  26. + select MFD_SYSCON
  27. + help
  28. + Say y here to support the Qualcomm Hardware Mutex functionality, which
  29. + provides a synchronisation mechanism for the various processors on
  30. + the SoC.
  31. +
  32. + If unsure, say N.
  33. +
  34. config HSEM_U8500
  35. tristate "STE Hardware Semaphore functionality"
  36. depends on ARCH_U8500
  37. --- a/drivers/hwspinlock/Makefile
  38. +++ b/drivers/hwspinlock/Makefile
  39. @@ -4,4 +4,5 @@
  40. obj-$(CONFIG_HWSPINLOCK) += hwspinlock_core.o
  41. obj-$(CONFIG_HWSPINLOCK_OMAP) += omap_hwspinlock.o
  42. +obj-$(CONFIG_HWSPINLOCK_QCOM) += qcom_hwspinlock.o
  43. obj-$(CONFIG_HSEM_U8500) += u8500_hsem.o
  44. --- /dev/null
  45. +++ b/drivers/hwspinlock/qcom_hwspinlock.c
  46. @@ -0,0 +1,181 @@
  47. +/*
  48. + * Copyright (c) 2013, The Linux Foundation. All rights reserved.
  49. + * Copyright (c) 2015, Sony Mobile Communications AB
  50. + *
  51. + * This software is licensed under the terms of the GNU General Public
  52. + * License version 2, as published by the Free Software Foundation, and
  53. + * may be copied, distributed, and modified under those terms.
  54. + *
  55. + * This program is distributed in the hope that it will be useful,
  56. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  57. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  58. + * GNU General Public License for more details.
  59. + */
  60. +
  61. +#include <linux/hwspinlock.h>
  62. +#include <linux/io.h>
  63. +#include <linux/kernel.h>
  64. +#include <linux/mfd/syscon.h>
  65. +#include <linux/module.h>
  66. +#include <linux/of.h>
  67. +#include <linux/of_device.h>
  68. +#include <linux/platform_device.h>
  69. +#include <linux/pm_runtime.h>
  70. +#include <linux/regmap.h>
  71. +
  72. +#include "hwspinlock_internal.h"
  73. +
  74. +#define QCOM_MUTEX_APPS_PROC_ID 1
  75. +#define QCOM_MUTEX_NUM_LOCKS 32
  76. +
  77. +static int qcom_hwspinlock_trylock(struct hwspinlock *lock)
  78. +{
  79. + struct regmap_field *field = lock->priv;
  80. + u32 lock_owner;
  81. + int ret;
  82. +
  83. + ret = regmap_field_write(field, QCOM_MUTEX_APPS_PROC_ID);
  84. + if (ret)
  85. + return ret;
  86. +
  87. + ret = regmap_field_read(field, &lock_owner);
  88. + if (ret)
  89. + return ret;
  90. +
  91. + return lock_owner == QCOM_MUTEX_APPS_PROC_ID;
  92. +}
  93. +
  94. +static void qcom_hwspinlock_unlock(struct hwspinlock *lock)
  95. +{
  96. + struct regmap_field *field = lock->priv;
  97. + u32 lock_owner;
  98. + int ret;
  99. +
  100. + ret = regmap_field_read(field, &lock_owner);
  101. + if (ret) {
  102. + pr_err("%s: unable to query spinlock owner\n", __func__);
  103. + return;
  104. + }
  105. +
  106. + if (lock_owner != QCOM_MUTEX_APPS_PROC_ID) {
  107. + pr_err("%s: spinlock not owned by us (actual owner is %d)\n",
  108. + __func__, lock_owner);
  109. + }
  110. +
  111. + ret = regmap_field_write(field, 0);
  112. + if (ret)
  113. + pr_err("%s: failed to unlock spinlock\n", __func__);
  114. +}
  115. +
  116. +static const struct hwspinlock_ops qcom_hwspinlock_ops = {
  117. + .trylock = qcom_hwspinlock_trylock,
  118. + .unlock = qcom_hwspinlock_unlock,
  119. +};
  120. +
  121. +static const struct of_device_id qcom_hwspinlock_of_match[] = {
  122. + { .compatible = "qcom,sfpb-mutex" },
  123. + { .compatible = "qcom,tcsr-mutex" },
  124. + { }
  125. +};
  126. +MODULE_DEVICE_TABLE(of, qcom_hwspinlock_of_match);
  127. +
  128. +static int qcom_hwspinlock_probe(struct platform_device *pdev)
  129. +{
  130. + struct hwspinlock_device *bank;
  131. + struct device_node *syscon;
  132. + struct reg_field field;
  133. + struct regmap *regmap;
  134. + size_t array_size;
  135. + u32 stride;
  136. + u32 base;
  137. + int ret;
  138. + int i;
  139. +
  140. + syscon = of_parse_phandle(pdev->dev.of_node, "syscon", 0);
  141. + if (!syscon) {
  142. + dev_err(&pdev->dev, "no syscon property\n");
  143. + return -ENODEV;
  144. + }
  145. +
  146. + regmap = syscon_node_to_regmap(syscon);
  147. + if (IS_ERR(regmap))
  148. + return PTR_ERR(regmap);
  149. +
  150. + ret = of_property_read_u32_index(pdev->dev.of_node, "syscon", 1, &base);
  151. + if (ret < 0) {
  152. + dev_err(&pdev->dev, "no offset in syscon\n");
  153. + return -EINVAL;
  154. + }
  155. +
  156. + ret = of_property_read_u32_index(pdev->dev.of_node, "syscon", 2, &stride);
  157. + if (ret < 0) {
  158. + dev_err(&pdev->dev, "no stride syscon\n");
  159. + return -EINVAL;
  160. + }
  161. +
  162. + array_size = QCOM_MUTEX_NUM_LOCKS * sizeof(struct hwspinlock);
  163. + bank = devm_kzalloc(&pdev->dev, sizeof(*bank) + array_size, GFP_KERNEL);
  164. + if (!bank)
  165. + return -ENOMEM;
  166. +
  167. + platform_set_drvdata(pdev, bank);
  168. +
  169. + for (i = 0; i < QCOM_MUTEX_NUM_LOCKS; i++) {
  170. + field.reg = base + i * stride;
  171. + field.lsb = 0;
  172. + field.msb = 32;
  173. +
  174. + bank->lock[i].priv = devm_regmap_field_alloc(&pdev->dev,
  175. + regmap, field);
  176. + }
  177. +
  178. + pm_runtime_enable(&pdev->dev);
  179. +
  180. + ret = hwspin_lock_register(bank, &pdev->dev, &qcom_hwspinlock_ops,
  181. + 0, QCOM_MUTEX_NUM_LOCKS);
  182. + if (ret)
  183. + pm_runtime_disable(&pdev->dev);
  184. +
  185. + return ret;
  186. +}
  187. +
  188. +static int qcom_hwspinlock_remove(struct platform_device *pdev)
  189. +{
  190. + struct hwspinlock_device *bank = platform_get_drvdata(pdev);
  191. + int ret;
  192. +
  193. + ret = hwspin_lock_unregister(bank);
  194. + if (ret) {
  195. + dev_err(&pdev->dev, "%s failed: %d\n", __func__, ret);
  196. + return ret;
  197. + }
  198. +
  199. + pm_runtime_disable(&pdev->dev);
  200. +
  201. + return 0;
  202. +}
  203. +
  204. +static struct platform_driver qcom_hwspinlock_driver = {
  205. + .probe = qcom_hwspinlock_probe,
  206. + .remove = qcom_hwspinlock_remove,
  207. + .driver = {
  208. + .name = "qcom_hwspinlock",
  209. + .of_match_table = qcom_hwspinlock_of_match,
  210. + },
  211. +};
  212. +
  213. +static int __init qcom_hwspinlock_init(void)
  214. +{
  215. + return platform_driver_register(&qcom_hwspinlock_driver);
  216. +}
  217. +/* board init code might need to reserve hwspinlocks for predefined purposes */
  218. +postcore_initcall(qcom_hwspinlock_init);
  219. +
  220. +static void __exit qcom_hwspinlock_exit(void)
  221. +{
  222. + platform_driver_unregister(&qcom_hwspinlock_driver);
  223. +}
  224. +module_exit(qcom_hwspinlock_exit);
  225. +
  226. +MODULE_LICENSE("GPL v2");
  227. +MODULE_DESCRIPTION("Hardware spinlock driver for Qualcomm SoCs");