hwspinlock: add stm32 hardware spinlock support
authorBenjamin Gaignard <benjamin.gaignard@linaro.org>
Tue, 27 Nov 2018 12:49:52 +0000 (13:49 +0100)
committerTom Rini <trini@konsulko.com>
Fri, 7 Dec 2018 04:26:33 +0000 (23:26 -0500)
Implement hardware spinlock support for STM32MP1.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Patrice Chotard <patrice.chotard@st.com>
arch/arm/dts/stm32mp157c-ed1.dts
arch/arm/dts/stm32mp157c.dtsi
configs/stm32mp15_basic_defconfig
drivers/hwspinlock/Kconfig
drivers/hwspinlock/Makefile
drivers/hwspinlock/stm32_hwspinlock.c [new file with mode: 0644]

index f8b7701167118f42508e303d4895d8c1947240f8..fc277dd7d20a6a626fcec9017b569a9a258887a2 100644 (file)
        usb33d-supply = <&usb33>;
 };
 
+&hwspinlock {
+       status = "okay";
+};
+
 &usbphyc_port0 {
        phy-supply = <&vdd_usb>;
        vdda1v1-supply = <&reg11>;
index 33c5981869b30281a025c2112d77365af2965843..37cadfa30c90ff6d11875e06b549ced37855a81a 100644 (file)
                        status = "disabled";
                };
 
+               hwspinlock: hwspinlock@4c000000 {
+                       compatible = "st,stm32-hwspinlock";
+                       #hwlock-cells = <1>;
+                       reg = <0x4c000000 0x400>;
+                       clocks = <&rcc HSEM>;
+                       clock-names = "hwspinlock";
+                       status = "disabled";
+               };
+
                rcc: rcc@50000000 {
                        compatible = "st,stm32mp1-rcc", "syscon";
                        reg = <0x50000000 0x1000>;
index 3bf75380890b9d65794e95a2e375280f9e9fe93c..c8409fd04e6501d7b669c08e9b571b27f64fb8f2 100644 (file)
@@ -32,6 +32,8 @@ CONFIG_CMD_EXT4_WRITE=y
 # CONFIG_SPL_DOS_PARTITION is not set
 CONFIG_DEFAULT_DEVICE_TREE="stm32mp157c-ev1"
 CONFIG_STM32_ADC=y
+CONFIG_DM_HWSPINLOCK=y
+CONFIG_HWSPINLOCK_STM32=y
 CONFIG_DM_I2C=y
 CONFIG_SYS_I2C_STM32F7=y
 CONFIG_LED=y
index de367fd2a9ac0274fd3bb88b770b46bb6fa2be42..96d4f5d6ca33841894c5868c1e43625a80e078f9 100644 (file)
@@ -13,4 +13,12 @@ config HWSPINLOCK_SANDBOX
          can be probed and support all the methods of HWSPINLOCK, but does not
          really do anything.
 
+config HWSPINLOCK_STM32
+       bool "Enable Hardware Spinlock support for STM32"
+       depends on ARCH_STM32MP && DM_HWSPINLOCK
+       help
+         Enable hardware spinlock support in STM32MP. Hardware spinlocks are
+         hardware mutex which provide a synchronisation mechanism for the
+         various processors on the SoC.
+
 endmenu
index 2704d6814f007d2f144ea2bb361865ef7cb22a31..289b12a256662b4996a20a5427cdf18cd440b9b0 100644 (file)
@@ -4,3 +4,4 @@
 
 obj-$(CONFIG_DM_HWSPINLOCK) += hwspinlock-uclass.o
 obj-$(CONFIG_HWSPINLOCK_SANDBOX) += sandbox_hwspinlock.o
+obj-$(CONFIG_HWSPINLOCK_STM32) += stm32_hwspinlock.o
diff --git a/drivers/hwspinlock/stm32_hwspinlock.c b/drivers/hwspinlock/stm32_hwspinlock.c
new file mode 100644 (file)
index 0000000..a32bde4
--- /dev/null
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <hwspinlock.h>
+#include <asm/io.h>
+
+#define STM32_MUTEX_COREID     BIT(8)
+#define STM32_MUTEX_LOCK_BIT   BIT(31)
+#define STM32_MUTEX_NUM_LOCKS  32
+
+struct stm32mp1_hws_priv {
+       fdt_addr_t base;
+};
+
+static int stm32mp1_lock(struct udevice *dev, int index)
+{
+       struct stm32mp1_hws_priv *priv = dev_get_priv(dev);
+       u32 status;
+
+       if (index >= STM32_MUTEX_NUM_LOCKS)
+               return -EINVAL;
+
+       status = readl(priv->base + index * sizeof(u32));
+       if (status == (STM32_MUTEX_LOCK_BIT | STM32_MUTEX_COREID))
+               return -EBUSY;
+
+       writel(STM32_MUTEX_LOCK_BIT | STM32_MUTEX_COREID,
+              priv->base + index * sizeof(u32));
+
+       status = readl(priv->base + index * sizeof(u32));
+       if (status != (STM32_MUTEX_LOCK_BIT | STM32_MUTEX_COREID))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int stm32mp1_unlock(struct udevice *dev, int index)
+{
+       struct stm32mp1_hws_priv *priv = dev_get_priv(dev);
+
+       if (index >= STM32_MUTEX_NUM_LOCKS)
+               return -EINVAL;
+
+       writel(STM32_MUTEX_COREID, priv->base + index * sizeof(u32));
+
+       return 0;
+}
+
+static int stm32mp1_hwspinlock_probe(struct udevice *dev)
+{
+       struct stm32mp1_hws_priv *priv = dev_get_priv(dev);
+       struct clk clk;
+       int ret;
+
+       priv->base = dev_read_addr(dev);
+       if (priv->base == FDT_ADDR_T_NONE)
+               return -EINVAL;
+
+       ret = clk_get_by_index(dev, 0, &clk);
+       if (ret)
+               return ret;
+
+       ret = clk_enable(&clk);
+       if (ret)
+               clk_free(&clk);
+
+       return ret;
+}
+
+static const struct hwspinlock_ops stm32mp1_hwspinlock_ops = {
+       .lock = stm32mp1_lock,
+       .unlock = stm32mp1_unlock,
+};
+
+static const struct udevice_id stm32mp1_hwspinlock_ids[] = {
+       { .compatible = "st,stm32-hwspinlock" },
+       {}
+};
+
+U_BOOT_DRIVER(hwspinlock_stm32mp1) = {
+       .name = "hwspinlock_stm32mp1",
+       .id = UCLASS_HWSPINLOCK,
+       .of_match = stm32mp1_hwspinlock_ids,
+       .ops = &stm32mp1_hwspinlock_ops,
+       .probe = stm32mp1_hwspinlock_probe,
+       .priv_auto_alloc_size = sizeof(struct stm32mp1_hws_priv),
+};