summaryrefslogtreecommitdiff
path: root/drivers/soc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/soc')
-rw-r--r--drivers/soc/Kconfig2
-rw-r--r--drivers/soc/Makefile2
-rw-r--r--drivers/soc/canaan/Kconfig12
-rw-r--r--drivers/soc/canaan/Makefile3
-rw-r--r--drivers/soc/canaan/k210-sysctl.c78
-rw-r--r--drivers/soc/kendryte/Kconfig14
-rw-r--r--drivers/soc/kendryte/Makefile3
-rw-r--r--drivers/soc/kendryte/k210-sysctl.c260
-rw-r--r--drivers/soc/litex/Kconfig14
-rw-r--r--drivers/soc/litex/litex_soc_ctrl.c116
-rw-r--r--drivers/soc/mediatek/Makefile1
-rw-r--r--drivers/soc/mediatek/mtk-mutex.c474
-rw-r--r--drivers/soc/sifive/sifive_l2_cache.c27
-rw-r--r--drivers/soc/xilinx/Kconfig17
-rw-r--r--drivers/soc/xilinx/Makefile1
-rw-r--r--drivers/soc/xilinx/xlnx_vcu.c628
16 files changed, 649 insertions, 1003 deletions
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index f357c6c659d2..e8a30c4c5aec 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -6,6 +6,7 @@ source "drivers/soc/amlogic/Kconfig"
source "drivers/soc/aspeed/Kconfig"
source "drivers/soc/atmel/Kconfig"
source "drivers/soc/bcm/Kconfig"
+source "drivers/soc/canaan/Kconfig"
source "drivers/soc/fsl/Kconfig"
source "drivers/soc/imx/Kconfig"
source "drivers/soc/ixp4xx/Kconfig"
@@ -22,6 +23,5 @@ source "drivers/soc/ti/Kconfig"
source "drivers/soc/ux500/Kconfig"
source "drivers/soc/versatile/Kconfig"
source "drivers/soc/xilinx/Kconfig"
-source "drivers/soc/kendryte/Kconfig"
endmenu
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index 9bceb12b291d..f678e4d9e585 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_ARCH_ACTIONS) += actions/
obj-y += aspeed/
obj-$(CONFIG_ARCH_AT91) += atmel/
obj-y += bcm/
+obj-$(CONFIG_SOC_CANAAN) += canaan/
obj-$(CONFIG_ARCH_DOVE) += dove/
obj-$(CONFIG_MACH_DOVE) += dove/
obj-y += fsl/
@@ -28,4 +29,3 @@ obj-y += ti/
obj-$(CONFIG_ARCH_U8500) += ux500/
obj-$(CONFIG_PLAT_VERSATILE) += versatile/
obj-y += xilinx/
-obj-$(CONFIG_SOC_KENDRYTE) += kendryte/
diff --git a/drivers/soc/canaan/Kconfig b/drivers/soc/canaan/Kconfig
new file mode 100644
index 000000000000..8179b69518b4
--- /dev/null
+++ b/drivers/soc/canaan/Kconfig
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config SOC_K210_SYSCTL
+ bool "Canaan Kendryte K210 SoC system controller"
+ depends on RISCV && SOC_CANAAN && OF
+ default SOC_CANAAN
+ select PM
+ select SIMPLE_PM_BUS
+ select SYSCON
+ select MFD_SYSCON
+ help
+ Canaan Kendryte K210 SoC system controller driver.
diff --git a/drivers/soc/canaan/Makefile b/drivers/soc/canaan/Makefile
new file mode 100644
index 000000000000..570280ad7967
--- /dev/null
+++ b/drivers/soc/canaan/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_SOC_K210_SYSCTL) += k210-sysctl.o
diff --git a/drivers/soc/canaan/k210-sysctl.c b/drivers/soc/canaan/k210-sysctl.c
new file mode 100644
index 000000000000..27a346c406bc
--- /dev/null
+++ b/drivers/soc/canaan/k210-sysctl.c
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Christoph Hellwig.
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ */
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/clk.h>
+#include <asm/soc.h>
+
+#include <soc/canaan/k210-sysctl.h>
+
+static int k210_sysctl_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct clk *pclk;
+ int ret;
+
+ dev_info(dev, "K210 system controller\n");
+
+ /* Get power bus clock */
+ pclk = devm_clk_get(dev, NULL);
+ if (IS_ERR(pclk))
+ return dev_err_probe(dev, PTR_ERR(pclk),
+ "Get bus clock failed\n");
+
+ ret = clk_prepare_enable(pclk);
+ if (ret) {
+ dev_err(dev, "Enable bus clock failed\n");
+ return ret;
+ }
+
+ /* Populate children */
+ ret = devm_of_platform_populate(dev);
+ if (ret)
+ dev_err(dev, "Populate platform failed %d\n", ret);
+
+ return ret;
+}
+
+static const struct of_device_id k210_sysctl_of_match[] = {
+ { .compatible = "canaan,k210-sysctl", },
+ { /* sentinel */ },
+};
+
+static struct platform_driver k210_sysctl_driver = {
+ .driver = {
+ .name = "k210-sysctl",
+ .of_match_table = k210_sysctl_of_match,
+ },
+ .probe = k210_sysctl_probe,
+};
+builtin_platform_driver(k210_sysctl_driver);
+
+/*
+ * System controller registers base address and size.
+ */
+#define K210_SYSCTL_BASE_ADDR 0x50440000ULL
+#define K210_SYSCTL_BASE_SIZE 0x1000
+
+/*
+ * This needs to be called very early during initialization, given that
+ * PLL1 needs to be enabled to be able to use all SRAM.
+ */
+static void __init k210_soc_early_init(const void *fdt)
+{
+ void __iomem *sysctl_base;
+
+ sysctl_base = ioremap(K210_SYSCTL_BASE_ADDR, K210_SYSCTL_BASE_SIZE);
+ if (!sysctl_base)
+ panic("k210-sysctl: ioremap failed");
+
+ k210_clk_early_init(sysctl_base);
+
+ iounmap(sysctl_base);
+}
+SOC_EARLY_INIT_DECLARE(k210_soc, "canaan,kendryte-k210", k210_soc_early_init);
diff --git a/drivers/soc/kendryte/Kconfig b/drivers/soc/kendryte/Kconfig
deleted file mode 100644
index 49785b1b0217..000000000000
--- a/drivers/soc/kendryte/Kconfig
+++ /dev/null
@@ -1,14 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-if SOC_KENDRYTE
-
-config K210_SYSCTL
- bool "Kendryte K210 system controller"
- default y
- depends on RISCV
- help
- Enables controlling the K210 various clocks and to enable
- general purpose use of the extra 2MB of SRAM normally
- reserved for the AI engine.
-
-endif
diff --git a/drivers/soc/kendryte/Makefile b/drivers/soc/kendryte/Makefile
deleted file mode 100644
index 002d9ce95c0d..000000000000
--- a/drivers/soc/kendryte/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-obj-$(CONFIG_K210_SYSCTL) += k210-sysctl.o
diff --git a/drivers/soc/kendryte/k210-sysctl.c b/drivers/soc/kendryte/k210-sysctl.c
deleted file mode 100644
index 707019223dd8..000000000000
--- a/drivers/soc/kendryte/k210-sysctl.c
+++ /dev/null
@@ -1,260 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (c) 2019 Christoph Hellwig.
- * Copyright (c) 2019 Western Digital Corporation or its affiliates.
- */
-#include <linux/types.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
-#include <linux/bitfield.h>
-#include <asm/soc.h>
-
-#define K210_SYSCTL_CLK0_FREQ 26000000UL
-
-/* Registers base address */
-#define K210_SYSCTL_SYSCTL_BASE_ADDR 0x50440000ULL
-
-/* Registers */
-#define K210_SYSCTL_PLL0 0x08
-#define K210_SYSCTL_PLL1 0x0c
-/* clkr: 4bits, clkf1: 6bits, clkod: 4bits, bwadj: 4bits */
-#define PLL_RESET (1 << 20)
-#define PLL_PWR (1 << 21)
-#define PLL_INTFB (1 << 22)
-#define PLL_BYPASS (1 << 23)
-#define PLL_TEST (1 << 24)
-#define PLL_OUT_EN (1 << 25)
-#define PLL_TEST_EN (1 << 26)
-#define K210_SYSCTL_PLL_LOCK 0x18
-#define PLL0_LOCK1 (1 << 0)
-#define PLL0_LOCK2 (1 << 1)
-#define PLL0_SLIP_CLEAR (1 << 2)
-#define PLL0_TEST_CLK_OUT (1 << 3)
-#define PLL1_LOCK1 (1 << 8)
-#define PLL1_LOCK2 (1 << 9)
-#define PLL1_SLIP_CLEAR (1 << 10)
-#define PLL1_TEST_CLK_OUT (1 << 11)
-#define PLL2_LOCK1 (1 << 16)
-#define PLL2_LOCK2 (1 << 16)
-#define PLL2_SLIP_CLEAR (1 << 18)
-#define PLL2_TEST_CLK_OUT (1 << 19)
-#define K210_SYSCTL_CLKSEL0 0x20
-#define CLKSEL_ACLK (1 << 0)
-#define K210_SYSCTL_CLKEN_CENT 0x28
-#define CLKEN_CPU (1 << 0)
-#define CLKEN_SRAM0 (1 << 1)
-#define CLKEN_SRAM1 (1 << 2)
-#define CLKEN_APB0 (1 << 3)
-#define CLKEN_APB1 (1 << 4)
-#define CLKEN_APB2 (1 << 5)
-#define K210_SYSCTL_CLKEN_PERI 0x2c
-#define CLKEN_ROM (1 << 0)
-#define CLKEN_DMA (1 << 1)
-#define CLKEN_AI (1 << 2)
-#define CLKEN_DVP (1 << 3)
-#define CLKEN_FFT (1 << 4)
-#define CLKEN_GPIO (1 << 5)
-#define CLKEN_SPI0 (1 << 6)
-#define CLKEN_SPI1 (1 << 7)
-#define CLKEN_SPI2 (1 << 8)
-#define CLKEN_SPI3 (1 << 9)
-#define CLKEN_I2S0 (1 << 10)
-#define CLKEN_I2S1 (1 << 11)
-#define CLKEN_I2S2 (1 << 12)
-#define CLKEN_I2C0 (1 << 13)
-#define CLKEN_I2C1 (1 << 14)
-#define CLKEN_I2C2 (1 << 15)
-#define CLKEN_UART1 (1 << 16)
-#define CLKEN_UART2 (1 << 17)
-#define CLKEN_UART3 (1 << 18)
-#define CLKEN_AES (1 << 19)
-#define CLKEN_FPIO (1 << 20)
-#define CLKEN_TIMER0 (1 << 21)
-#define CLKEN_TIMER1 (1 << 22)
-#define CLKEN_TIMER2 (1 << 23)
-#define CLKEN_WDT0 (1 << 24)
-#define CLKEN_WDT1 (1 << 25)
-#define CLKEN_SHA (1 << 26)
-#define CLKEN_OTP (1 << 27)
-#define CLKEN_RTC (1 << 29)
-
-struct k210_sysctl {
- void __iomem *regs;
- struct clk_hw hw;
-};
-
-static void k210_set_bits(u32 val, void __iomem *reg)
-{
- writel(readl(reg) | val, reg);
-}
-
-static void k210_clear_bits(u32 val, void __iomem *reg)
-{
- writel(readl(reg) & ~val, reg);
-}
-
-static void k210_pll1_enable(void __iomem *regs)
-{
- u32 val;
-
- val = readl(regs + K210_SYSCTL_PLL1);
- val &= ~GENMASK(19, 0); /* clkr1 = 0 */
- val |= FIELD_PREP(GENMASK(9, 4), 0x3B); /* clkf1 = 59 */
- val |= FIELD_PREP(GENMASK(13, 10), 0x3); /* clkod1 = 3 */
- val |= FIELD_PREP(GENMASK(19, 14), 0x3B); /* bwadj1 = 59 */
- writel(val, regs + K210_SYSCTL_PLL1);
-
- k210_clear_bits(PLL_BYPASS, regs + K210_SYSCTL_PLL1);
- k210_set_bits(PLL_PWR, regs + K210_SYSCTL_PLL1);
-
- /*
- * Reset the pll. The magic NOPs come from the Kendryte reference SDK.
- */
- k210_clear_bits(PLL_RESET, regs + K210_SYSCTL_PLL1);
- k210_set_bits(PLL_RESET, regs + K210_SYSCTL_PLL1);
- nop();
- nop();
- k210_clear_bits(PLL_RESET, regs + K210_SYSCTL_PLL1);
-
- for (;;) {
- val = readl(regs + K210_SYSCTL_PLL_LOCK);
- if (val & PLL1_LOCK2)
- break;
- writel(val | PLL1_SLIP_CLEAR, regs + K210_SYSCTL_PLL_LOCK);
- }
-
- k210_set_bits(PLL_OUT_EN, regs + K210_SYSCTL_PLL1);
-}
-
-static unsigned long k210_sysctl_clk_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- struct k210_sysctl *s = container_of(hw, struct k210_sysctl, hw);
- u32 clksel0, pll0;
- u64 pll0_freq, clkr0, clkf0, clkod0;
-
- /*
- * If the clock selector is not set, use the base frequency.
- * Otherwise, use PLL0 frequency with a frequency divisor.
- */
- clksel0 = readl(s->regs + K210_SYSCTL_CLKSEL0);
- if (!(clksel0 & CLKSEL_ACLK))
- return K210_SYSCTL_CLK0_FREQ;
-
- /*
- * Get PLL0 frequency:
- * freq = base frequency * clkf0 / (clkr0 * clkod0)
- */
- pll0 = readl(s->regs + K210_SYSCTL_PLL0);
- clkr0 = 1 + FIELD_GET(GENMASK(3, 0), pll0);
- clkf0 = 1 + FIELD_GET(GENMASK(9, 4), pll0);
- clkod0 = 1 + FIELD_GET(GENMASK(13, 10), pll0);
- pll0_freq = clkf0 * K210_SYSCTL_CLK0_FREQ / (clkr0 * clkod0);
-
- /* Get the frequency divisor from the clock selector */
- return pll0_freq / (2ULL << FIELD_GET(0x00000006, clksel0));
-}
-
-static const struct clk_ops k210_sysctl_clk_ops = {
- .recalc_rate = k210_sysctl_clk_recalc_rate,
-};
-
-static const struct clk_init_data k210_clk_init_data = {
- .name = "k210-sysctl-pll1",
- .ops = &k210_sysctl_clk_ops,
-};
-
-static int k210_sysctl_probe(struct platform_device *pdev)
-{
- struct k210_sysctl *s;
- int error;
-
- pr_info("Kendryte K210 SoC sysctl\n");
-
- s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL);
- if (!s)
- return -ENOMEM;
-
- s->regs = devm_ioremap_resource(&pdev->dev,
- platform_get_resource(pdev, IORESOURCE_MEM, 0));
- if (IS_ERR(s->regs))
- return PTR_ERR(s->regs);
-
- s->hw.init = &k210_clk_init_data;
- error = devm_clk_hw_register(&pdev->dev, &s->hw);
- if (error) {
- dev_err(&pdev->dev, "failed to register clk");
- return error;
- }
-
- error = devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_simple_get,
- &s->hw);
- if (error) {
- dev_err(&pdev->dev, "adding clk provider failed\n");
- return error;
- }
-
- return 0;
-}
-
-static const struct of_device_id k210_sysctl_of_match[] = {
- { .compatible = "kendryte,k210-sysctl", },
- {}
-};
-
-static struct platform_driver k210_sysctl_driver = {
- .driver = {
- .name = "k210-sysctl",
- .of_match_table = k210_sysctl_of_match,
- },
- .probe = k210_sysctl_probe,
-};
-
-static int __init k210_sysctl_init(void)
-{
- return platform_driver_register(&k210_sysctl_driver);
-}
-core_initcall(k210_sysctl_init);
-
-/*
- * This needs to be called very early during initialization, given that
- * PLL1 needs to be enabled to be able to use all SRAM.
- */
-static void __init k210_soc_early_init(const void *fdt)
-{
- void __iomem *regs;
-
- regs = ioremap(K210_SYSCTL_SYSCTL_BASE_ADDR, 0x1000);
- if (!regs)
- panic("K210 sysctl ioremap");
-
- /* Enable PLL1 to make the KPU SRAM useable */
- k210_pll1_enable(regs);
-
- k210_set_bits(PLL_OUT_EN, regs + K210_SYSCTL_PLL0);
-
- k210_set_bits(CLKEN_CPU | CLKEN_SRAM0 | CLKEN_SRAM1,
- regs + K210_SYSCTL_CLKEN_CENT);
- k210_set_bits(CLKEN_ROM | CLKEN_TIMER0 | CLKEN_RTC,
- regs + K210_SYSCTL_CLKEN_PERI);
-
- k210_set_bits(CLKSEL_ACLK, regs + K210_SYSCTL_CLKSEL0);
-
- iounmap(regs);
-}
-SOC_EARLY_INIT_DECLARE(generic_k210, "kendryte,k210", k210_soc_early_init);
-
-#ifdef CONFIG_SOC_KENDRYTE_K210_DTB_BUILTIN
-/*
- * Generic entry for the default k210.dtb embedded DTB for boards with:
- * - Vendor ID: 0x4B5
- * - Arch ID: 0xE59889E6A5A04149 (= "Canaan AI" in UTF-8 encoded Chinese)
- * - Impl ID: 0x4D41495832303030 (= "MAIX2000")
- * These values are reported by the SiPEED MAXDUINO, SiPEED MAIX GO and
- * SiPEED Dan dock boards.
- */
-SOC_BUILTIN_DTB_DECLARE(k210, 0x4B5, 0xE59889E6A5A04149, 0x4D41495832303030);
-#endif
diff --git a/drivers/soc/litex/Kconfig b/drivers/soc/litex/Kconfig
index 7a7c38282e11..e7011d665b15 100644
--- a/drivers/soc/litex/Kconfig
+++ b/drivers/soc/litex/Kconfig
@@ -12,9 +12,21 @@ config LITEX_SOC_CONTROLLER
select LITEX
help
This option enables the SoC Controller Driver which verifies
- LiteX CSR access and provides common litex_get_reg/litex_set_reg
+ LiteX CSR access and provides common litex_[read|write]*
accessors.
All drivers that use functions from litex.h must depend on
LITEX.
+config LITEX_SUBREG_SIZE
+ int "Size of a LiteX CSR subregister, in bytes"
+ depends on LITEX
+ range 1 4
+ default 4
+ help
+ LiteX MMIO registers (referred to as Configuration and Status
+ registers, or CSRs) are spread across adjacent 8- or 32-bit
+ subregisters, located at 32-bit aligned MMIO addresses. Use
+ this to select the appropriate size (1 or 4 bytes) matching
+ your particular LiteX build.
+
endmenu
diff --git a/drivers/soc/litex/litex_soc_ctrl.c b/drivers/soc/litex/litex_soc_ctrl.c
index 9b0766384570..6268bfa7f0d6 100644
--- a/drivers/soc/litex/litex_soc_ctrl.c
+++ b/drivers/soc/litex/litex_soc_ctrl.c
@@ -15,79 +15,11 @@
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/io.h>
+#include <linux/reboot.h>
-/*
- * LiteX SoC Generator, depending on the configuration, can split a single
- * logical CSR (Control&Status Register) into a series of consecutive physical
- * registers.
- *
- * For example, in the configuration with 8-bit CSR Bus, 32-bit aligned (the
- * default one for 32-bit CPUs) a 32-bit logical CSR will be generated as four
- * 32-bit physical registers, each one containing one byte of meaningful data.
- *
- * For details see: https://github.com/enjoy-digital/litex/wiki/CSR-Bus
- *
- * The purpose of `litex_set_reg`/`litex_get_reg` is to implement the logic
- * of writing to/reading from the LiteX CSR in a single place that can be
- * then reused by all LiteX drivers.
- */
-
-/**
- * litex_set_reg() - Writes the value to the LiteX CSR (Control&Status Register)
- * @reg: Address of the CSR
- * @reg_size: The width of the CSR expressed in the number of bytes
- * @val: Value to be written to the CSR
- *
- * In the currently supported LiteX configuration (8-bit CSR Bus, 32-bit aligned),
- * a 32-bit LiteX CSR is generated as 4 consecutive 32-bit physical registers,
- * each one containing one byte of meaningful data.
- *
- * This function splits a single possibly multi-byte write into a series of
- * single-byte writes with a proper offset.
- */
-void litex_set_reg(void __iomem *reg, unsigned long reg_size,
- unsigned long val)
-{
- unsigned long shifted_data, shift, i;
-
- for (i = 0; i < reg_size; ++i) {
- shift = ((reg_size - i - 1) * LITEX_SUBREG_SIZE_BIT);
- shifted_data = val >> shift;
-
- WRITE_LITEX_SUBREGISTER(shifted_data, reg, i);
- }
-}
-EXPORT_SYMBOL_GPL(litex_set_reg);
-
-/**
- * litex_get_reg() - Reads the value of the LiteX CSR (Control&Status Register)
- * @reg: Address of the CSR
- * @reg_size: The width of the CSR expressed in the number of bytes
- *
- * Return: Value read from the CSR
- *
- * In the currently supported LiteX configuration (8-bit CSR Bus, 32-bit aligned),
- * a 32-bit LiteX CSR is generated as 4 consecutive 32-bit physical registers,
- * each one containing one byte of meaningful data.
- *
- * This function generates a series of single-byte reads with a proper offset
- * and joins their results into a single multi-byte value.
- */
-unsigned long litex_get_reg(void __iomem *reg, unsigned long reg_size)
-{
- unsigned long shifted_data, shift, i;
- unsigned long result = 0;
-
- for (i = 0; i < reg_size; ++i) {
- shifted_data = READ_LITEX_SUBREGISTER(reg, i);
-
- shift = ((reg_size - i - 1) * LITEX_SUBREG_SIZE_BIT);
- result |= (shifted_data << shift);
- }
-
- return result;
-}
-EXPORT_SYMBOL_GPL(litex_get_reg);
+/* reset register located at the base address */
+#define RESET_REG_OFF 0x00
+#define RESET_REG_VALUE 0x00000001
#define SCRATCH_REG_OFF 0x04
#define SCRATCH_REG_VALUE 0x12345678
@@ -131,15 +63,27 @@ static int litex_check_csr_access(void __iomem *reg_addr)
/* restore original value of the SCRATCH register */
litex_write32(reg_addr + SCRATCH_REG_OFF, SCRATCH_REG_VALUE);
- pr_info("LiteX SoC Controller driver initialized");
+ pr_info("LiteX SoC Controller driver initialized: subreg:%d, align:%d",
+ LITEX_SUBREG_SIZE, LITEX_SUBREG_ALIGN);
return 0;
}
struct litex_soc_ctrl_device {
void __iomem *base;
+ struct notifier_block reset_nb;
};
+static int litex_reset_handler(struct notifier_block *this, unsigned long mode,
+ void *cmd)
+{
+ struct litex_soc_ctrl_device *soc_ctrl_dev =
+ container_of(this, struct litex_soc_ctrl_device, reset_nb);
+
+ litex_write32(soc_ctrl_dev->base + RESET_REG_OFF, RESET_REG_VALUE);
+ return NOTIFY_DONE;
+}
+
#ifdef CONFIG_OF
static const struct of_device_id litex_soc_ctrl_of_match[] = {
{.compatible = "litex,soc-controller"},
@@ -151,6 +95,7 @@ MODULE_DEVICE_TABLE(of, litex_soc_ctrl_of_match);
static int litex_soc_ctrl_probe(struct platform_device *pdev)
{
struct litex_soc_ctrl_device *soc_ctrl_dev;
+ int error;
soc_ctrl_dev = devm_kzalloc(&pdev->dev, sizeof(*soc_ctrl_dev), GFP_KERNEL);
if (!soc_ctrl_dev)
@@ -160,7 +105,29 @@ static int litex_soc_ctrl_probe(struct platform_device *pdev)
if (IS_ERR(soc_ctrl_dev->base))
return PTR_ERR(soc_ctrl_dev->base);
- return litex_check_csr_access(soc_ctrl_dev->base);
+ error = litex_check_csr_access(soc_ctrl_dev->base);
+ if (error)
+ return error;
+
+ platform_set_drvdata(pdev, soc_ctrl_dev);
+
+ soc_ctrl_dev->reset_nb.notifier_call = litex_reset_handler;
+ soc_ctrl_dev->reset_nb.priority = 128;
+ error = register_restart_handler(&soc_ctrl_dev->reset_nb);
+ if (error) {
+ dev_warn(&pdev->dev, "cannot register restart handler: %d\n",
+ error);
+ }
+
+ return 0;
+}
+
+static int litex_soc_ctrl_remove(struct platform_device *pdev)
+{
+ struct litex_soc_ctrl_device *soc_ctrl_dev = platform_get_drvdata(pdev);
+
+ unregister_restart_handler(&soc_ctrl_dev->reset_nb);
+ return 0;
}
static struct platform_driver litex_soc_ctrl_driver = {
@@ -169,6 +136,7 @@ static struct platform_driver litex_soc_ctrl_driver = {
.of_match_table = of_match_ptr(litex_soc_ctrl_of_match)
},
.probe = litex_soc_ctrl_probe,
+ .remove = litex_soc_ctrl_remove,
};
module_platform_driver(litex_soc_ctrl_driver);
diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile
index b6908db534c2..90270f8114ed 100644
--- a/drivers/soc/mediatek/Makefile
+++ b/drivers/soc/mediatek/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o
obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o
obj-$(CONFIG_MTK_SCPSYS_PM_DOMAINS) += mtk-pm-domains.o
obj-$(CONFIG_MTK_MMSYS) += mtk-mmsys.o
+obj-$(CONFIG_MTK_MMSYS) += mtk-mutex.o
diff --git a/drivers/soc/mediatek/mtk-mutex.c b/drivers/soc/mediatek/mtk-mutex.c
new file mode 100644
index 000000000000..f531b119da7a
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-mutex.c
@@ -0,0 +1,474 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ */
+
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/soc/mediatek/mtk-mmsys.h>
+#include <linux/soc/mediatek/mtk-mutex.h>
+
+#define MT2701_MUTEX0_MOD0 0x2c
+#define MT2701_MUTEX0_SOF0 0x30
+
+#define DISP_REG_MUTEX_EN(n) (0x20 + 0x20 * (n))
+#define DISP_REG_MUTEX(n) (0x24 + 0x20 * (n))
+#define DISP_REG_MUTEX_RST(n) (0x28 + 0x20 * (n))
+#define DISP_REG_MUTEX_MOD(mutex_mod_reg, n) (mutex_mod_reg + 0x20 * (n))
+#define DISP_REG_MUTEX_SOF(mutex_sof_reg, n) (mutex_sof_reg + 0x20 * (n))
+#define DISP_REG_MUTEX_MOD2(n) (0x34 + 0x20 * (n))
+
+#define INT_MUTEX BIT(1)
+
+#define MT8167_MUTEX_MOD_DISP_PWM 1
+#define MT8167_MUTEX_MOD_DISP_OVL0 6
+#define MT8167_MUTEX_MOD_DISP_OVL1 7
+#define MT8167_MUTEX_MOD_DISP_RDMA0 8
+#define MT8167_MUTEX_MOD_DISP_RDMA1 9
+#define MT8167_MUTEX_MOD_DISP_WDMA0 10
+#define MT8167_MUTEX_MOD_DISP_CCORR 11
+#define MT8167_MUTEX_MOD_DISP_COLOR 12
+#define MT8167_MUTEX_MOD_DISP_AAL 13
+#define MT8167_MUTEX_MOD_DISP_GAMMA 14
+#define MT8167_MUTEX_MOD_DISP_DITHER 15
+#define MT8167_MUTEX_MOD_DISP_UFOE 16
+
+#define MT8173_MUTEX_MOD_DISP_OVL0 11
+#define MT8173_MUTEX_MOD_DISP_OVL1 12
+#define MT8173_MUTEX_MOD_DISP_RDMA0 13
+#define MT8173_MUTEX_MOD_DISP_RDMA1 14
+#define MT8173_MUTEX_MOD_DISP_RDMA2 15
+#define MT8173_MUTEX_MOD_DISP_WDMA0 16
+#define MT8173_MUTEX_MOD_DISP_WDMA1 17
+#define MT8173_MUTEX_MOD_DISP_COLOR0 18
+#define MT8173_MUTEX_MOD_DISP_COLOR1 19
+#define MT8173_MUTEX_MOD_DISP_AAL 20
+#define MT8173_MUTEX_MOD_DISP_GAMMA 21
+#define MT8173_MUTEX_MOD_DISP_UFOE 22
+#define MT8173_MUTEX_MOD_DISP_PWM0 23
+#define MT8173_MUTEX_MOD_DISP_PWM1 24
+#define MT8173_MUTEX_MOD_DISP_OD 25
+
+#define MT2712_MUTEX_MOD_DISP_PWM2 10
+#define MT2712_MUTEX_MOD_DISP_OVL0 11
+#define MT2712_MUTEX_MOD_DISP_OVL1 12
+#define MT2712_MUTEX_MOD_DISP_RDMA0 13
+#define MT2712_MUTEX_MOD_DISP_RDMA1 14
+#define MT2712_MUTEX_MOD_DISP_RDMA2 15
+#define MT2712_MUTEX_MOD_DISP_WDMA0 16
+#define MT2712_MUTEX_MOD_DISP_WDMA1 17
+#define MT2712_MUTEX_MOD_DISP_COLOR0 18
+#define MT2712_MUTEX_MOD_DISP_COLOR1 19
+#define MT2712_MUTEX_MOD_DISP_AAL0 20
+#define MT2712_MUTEX_MOD_DISP_UFOE 22
+#define MT2712_MUTEX_MOD_DISP_PWM0 23
+#define MT2712_MUTEX_MOD_DISP_PWM1 24
+#define MT2712_MUTEX_MOD_DISP_OD0 25
+#define MT2712_MUTEX_MOD2_DISP_AAL1 33
+#define MT2712_MUTEX_MOD2_DISP_OD1 34
+
+#define MT2701_MUTEX_MOD_DISP_OVL 3
+#define MT2701_MUTEX_MOD_DISP_WDMA 6
+#define MT2701_MUTEX_MOD_DISP_COLOR 7
+#define MT2701_MUTEX_MOD_DISP_BLS 9
+#define MT2701_MUTEX_MOD_DISP_RDMA0 10
+#define MT2701_MUTEX_MOD_DISP_RDMA1 12
+
+#define MT2712_MUTEX_SOF_SINGLE_MODE 0
+#define MT2712_MUTEX_SOF_DSI0 1
+#define MT2712_MUTEX_SOF_DSI1 2
+#define MT2712_MUTEX_SOF_DPI0 3
+#define MT2712_MUTEX_SOF_DPI1 4
+#define MT2712_MUTEX_SOF_DSI2 5
+#define MT2712_MUTEX_SOF_DSI3 6
+#define MT8167_MUTEX_SOF_DPI0 2
+#define MT8167_MUTEX_SOF_DPI1 3
+
+struct mtk_mutex {
+ int id;
+ bool claimed;
+};
+
+enum mtk_mutex_sof_id {
+ MUTEX_SOF_SINGLE_MODE,
+ MUTEX_SOF_DSI0,
+ MUTEX_SOF_DSI1,
+ MUTEX_SOF_DPI0,
+ MUTEX_SOF_DPI1,
+ MUTEX_SOF_DSI2,
+ MUTEX_SOF_DSI3,
+};
+
+struct mtk_mutex_data {
+ const unsigned int *mutex_mod;
+ const unsigned int *mutex_sof;
+ const unsigned int mutex_mod_reg;
+ const unsigned int mutex_sof_reg;
+ const bool no_clk;
+};
+
+struct mtk_mutex_ctx {
+ struct device *dev;
+ struct clk *clk;
+ void __iomem *regs;
+ struct mtk_mutex mutex[10];
+ const struct mtk_mutex_data *data;
+};
+
+static const unsigned int mt2701_mutex_mod[DDP_COMPONENT_ID_MAX] = {
+ [DDP_COMPONENT_BLS] = MT2701_MUTEX_MOD_DISP_BLS,
+ [DDP_COMPONENT_COLOR0] = MT2701_MUTEX_MOD_DISP_COLOR,
+ [DDP_COMPONENT_OVL0] = MT2701_MUTEX_MOD_DISP_OVL,
+ [DDP_COMPONENT_RDMA0] = MT2701_MUTEX_MOD_DISP_RDMA0,
+ [DDP_COMPONENT_RDMA1] = MT2701_MUTEX_MOD_DISP_RDMA1,
+ [DDP_COMPONENT_WDMA0] = MT2701_MUTEX_MOD_DISP_WDMA,
+};
+
+static const unsigned int mt2712_mutex_mod[DDP_COMPONENT_ID_MAX] = {
+ [DDP_COMPONENT_AAL0] = MT2712_MUTEX_MOD_DISP_AAL0,
+ [DDP_COMPONENT_AAL1] = MT2712_MUTEX_MOD2_DISP_AAL1,
+ [DDP_COMPONENT_COLOR0] = MT2712_MUTEX_MOD_DISP_COLOR0,
+ [DDP_COMPONENT_COLOR1] = MT2712_MUTEX_MOD_DISP_COLOR1,
+ [DDP_COMPONENT_OD0] = MT2712_MUTEX_MOD_DISP_OD0,
+ [DDP_COMPONENT_OD1] = MT2712_MUTEX_MOD2_DISP_OD1,
+ [DDP_COMPONENT_OVL0] = MT2712_MUTEX_MOD_DISP_OVL0,
+ [DDP_COMPONENT_OVL1] = MT2712_MUTEX_MOD_DISP_OVL1,
+ [DDP_COMPONENT_PWM0] = MT2712_MUTEX_MOD_DISP_PWM0,
+ [DDP_COMPONENT_PWM1] = MT2712_MUTEX_MOD_DISP_PWM1,
+ [DDP_COMPONENT_PWM2] = MT2712_MUTEX_MOD_DISP_PWM2,
+ [DDP_COMPONENT_RDMA0] = MT2712_MUTEX_MOD_DISP_RDMA0,
+ [DDP_COMPONENT_RDMA1] = MT2712_MUTEX_MOD_DISP_RDMA1,
+ [DDP_COMPONENT_RDMA2] = MT2712_MUTEX_MOD_DISP_RDMA2,
+ [DDP_COMPONENT_UFOE] = MT2712_MUTEX_MOD_DISP_UFOE,
+ [DDP_COMPONENT_WDMA0] = MT2712_MUTEX_MOD_DISP_WDMA0,
+ [DDP_COMPONENT_WDMA1] = MT2712_MUTEX_MOD_DISP_WDMA1,
+};
+
+static const unsigned int mt8167_mutex_mod[DDP_COMPONENT_ID_MAX] = {
+ [DDP_COMPONENT_AAL0] = MT8167_MUTEX_MOD_DISP_AAL,
+ [DDP_COMPONENT_CCORR] = MT8167_MUTEX_MOD_DISP_CCORR,
+ [DDP_COMPONENT_COLOR0] = MT8167_MUTEX_MOD_DISP_COLOR,
+ [DDP_COMPONENT_DITHER] = MT8167_MUTEX_MOD_DISP_DITHER,
+ [DDP_COMPONENT_GAMMA] = MT8167_MUTEX_MOD_DISP_GAMMA,
+ [DDP_COMPONENT_OVL0] = MT8167_MUTEX_MOD_DISP_OVL0,
+ [DDP_COMPONENT_OVL1] = MT8167_MUTEX_MOD_DISP_OVL1,
+ [DDP_COMPONENT_PWM0] = MT8167_MUTEX_MOD_DISP_PWM,
+ [DDP_COMPONENT_RDMA0] = MT8167_MUTEX_MOD_DISP_RDMA0,
+ [DDP_COMPONENT_RDMA1] = MT8167_MUTEX_MOD_DISP_RDMA1,
+ [DDP_COMPONENT_UFOE] = MT8167_MUTEX_MOD_DISP_UFOE,
+ [DDP_COMPONENT_WDMA0] = MT8167_MUTEX_MOD_DISP_WDMA0,
+};
+
+static const unsigned int mt8173_mutex_mod[DDP_COMPONENT_ID_MAX] = {
+ [DDP_COMPONENT_AAL0] = MT8173_MUTEX_MOD_DISP_AAL,
+ [DDP_COMPONENT_COLOR0] = MT8173_MUTEX_MOD_DISP_COLOR0,
+ [DDP_COMPONENT_COLOR1] = MT8173_MUTEX_MOD_DISP_COLOR1,
+ [DDP_COMPONENT_GAMMA] = MT8173_MUTEX_MOD_DISP_GAMMA,
+ [DDP_COMPONENT_OD0] = MT8173_MUTEX_MOD_DISP_OD,
+ [DDP_COMPONENT_OVL0] = MT8173_MUTEX_MOD_DISP_OVL0,
+ [DDP_COMPONENT_OVL1] = MT8173_MUTEX_MOD_DISP_OVL1,
+ [DDP_COMPONENT_PWM0] = MT8173_MUTEX_MOD_DISP_PWM0,
+ [DDP_COMPONENT_PWM1] = MT8173_MUTEX_MOD_DISP_PWM1,
+ [DDP_COMPONENT_RDMA0] = MT8173_MUTEX_MOD_DISP_RDMA0,
+ [DDP_COMPONENT_RDMA1] = MT8173_MUTEX_MOD_DISP_RDMA1,
+ [DDP_COMPONENT_RDMA2] = MT8173_MUTEX_MOD_DISP_RDMA2,
+ [DDP_COMPONENT_UFOE] = MT8173_MUTEX_MOD_DISP_UFOE,
+ [DDP_COMPONENT_WDMA0] = MT8173_MUTEX_MOD_DISP_WDMA0,
+ [DDP_COMPONENT_WDMA1] = MT8173_MUTEX_MOD_DISP_WDMA1,
+};
+
+static const unsigned int mt2712_mutex_sof[MUTEX_SOF_DSI3 + 1] = {
+ [MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE,
+ [MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0,
+ [MUTEX_SOF_DSI1] = MUTEX_SOF_DSI1,
+ [MUTEX_SOF_DPI0] = MUTEX_SOF_DPI0,
+ [MUTEX_SOF_DPI1] = MUTEX_SOF_DPI1,
+ [MUTEX_SOF_DSI2] = MUTEX_SOF_DSI2,
+ [MUTEX_SOF_DSI3] = MUTEX_SOF_DSI3,
+};
+
+static const unsigned int mt8167_mutex_sof[MUTEX_SOF_DSI3 + 1] = {
+ [MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE,
+ [MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0,
+ [MUTEX_SOF_DPI0] = MT8167_MUTEX_SOF_DPI0,
+ [MUTEX_SOF_DPI1] = MT8167_MUTEX_SOF_DPI1,
+};
+
+static const struct mtk_mutex_data mt2701_mutex_driver_data = {
+ .mutex_mod = mt2701_mutex_mod,
+ .mutex_sof = mt2712_mutex_sof,
+ .mutex_mod_reg = MT2701_MUTEX0_MOD0,
+ .mutex_sof_reg = MT2701_MUTEX0_SOF0,
+};
+
+static const struct mtk_mutex_data mt2712_mutex_driver_data = {
+ .mutex_mod = mt2712_mutex_mod,
+ .mutex_sof = mt2712_mutex_sof,
+ .mutex_mod_reg = MT2701_MUTEX0_MOD0,
+ .mutex_sof_reg = MT2701_MUTEX0_SOF0,
+};
+
+static const struct mtk_mutex_data mt8167_mutex_driver_data = {
+ .mutex_mod = mt8167_mutex_mod,
+ .mutex_sof = mt8167_mutex_sof,
+ .mutex_mod_reg = MT2701_MUTEX0_MOD0,
+ .mutex_sof_reg = MT2701_MUTEX0_SOF0,
+ .no_clk = true,
+};
+
+static const struct mtk_mutex_data mt8173_mutex_driver_data = {
+ .mutex_mod = mt8173_mutex_mod,
+ .mutex_sof = mt2712_mutex_sof,
+ .mutex_mod_reg = MT2701_MUTEX0_MOD0,
+ .mutex_sof_reg = MT2701_MUTEX0_SOF0,
+};
+
+struct mtk_mutex *mtk_mutex_get(struct device *dev)
+{
+ struct mtk_mutex_ctx *mtx = dev_get_drvdata(dev);
+ int i;
+
+ for (i = 0; i < 10; i++)
+ if (!mtx->mutex[i].claimed) {
+ mtx->mutex[i].claimed = true;
+ return &mtx->mutex[i];
+ }
+
+ return ERR_PTR(-EBUSY);
+}
+EXPORT_SYMBOL_GPL(mtk_mutex_get);
+
+void mtk_mutex_put(struct mtk_mutex *mutex)
+{
+ struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
+ mutex[mutex->id]);
+
+ WARN_ON(&mtx->mutex[mutex->id] != mutex);
+
+ mutex->claimed = false;
+}
+EXPORT_SYMBOL_GPL(mtk_mutex_put);
+
+int mtk_mutex_prepare(struct mtk_mutex *mutex)
+{
+ struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
+ mutex[mutex->id]);
+ return clk_prepare_enable(mtx->clk);
+}
+EXPORT_SYMBOL_GPL(mtk_mutex_prepare);
+
+void mtk_mutex_unprepare(struct mtk_mutex *mutex)
+{
+ struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
+ mutex[mutex->id]);
+ clk_disable_unprepare(mtx->clk);
+}
+EXPORT_SYMBOL_GPL(mtk_mutex_unprepare);
+
+void mtk_mutex_add_comp(struct mtk_mutex *mutex,
+ enum mtk_ddp_comp_id id)
+{
+ struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
+ mutex[mutex->id]);
+ unsigned int reg;
+ unsigned int sof_id;
+ unsigned int offset;
+
+ WARN_ON(&mtx->mutex[mutex->id] != mutex);
+
+ switch (id) {
+ case DDP_COMPONENT_DSI0:
+ sof_id = MUTEX_SOF_DSI0;
+ break;
+ case DDP_COMPONENT_DSI1:
+ sof_id = MUTEX_SOF_DSI0;
+ break;
+ case DDP_COMPONENT_DSI2:
+ sof_id = MUTEX_SOF_DSI2;
+ break;
+ case DDP_COMPONENT_DSI3:
+ sof_id = MUTEX_SOF_DSI3;
+ break;
+ case DDP_COMPONENT_DPI0:
+ sof_id = MUTEX_SOF_DPI0;
+ break;
+ case DDP_COMPONENT_DPI1:
+ sof_id = MUTEX_SOF_DPI1;
+ break;
+ default:
+ if (mtx->data->mutex_mod[id] < 32) {
+ offset = DISP_REG_MUTEX_MOD(mtx->data->mutex_mod_reg,
+ mutex->id);
+ reg = readl_relaxed(mtx->regs + offset);
+ reg |= 1 << mtx->data->mutex_mod[id];
+ writel_relaxed(reg, mtx->regs + offset);
+ } else {
+ offset = DISP_REG_MUTEX_MOD2(mutex->id);
+ reg = readl_relaxed(mtx->regs + offset);
+ reg |= 1 << (mtx->data->mutex_mod[id] - 32);
+ writel_relaxed(reg, mtx->regs + offset);
+ }
+ return;
+ }
+
+ writel_relaxed(mtx->data->mutex_sof[sof_id],
+ mtx->regs +
+ DISP_REG_MUTEX_SOF(mtx->data->mutex_sof_reg, mutex->id));
+}
+EXPORT_SYMBOL_GPL(mtk_mutex_add_comp);
+
+void mtk_mutex_remove_comp(struct mtk_mutex *mutex,
+ enum mtk_ddp_comp_id id)
+{
+ struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
+ mutex[mutex->id]);
+ unsigned int reg;
+ unsigned int offset;
+
+ WARN_ON(&mtx->mutex[mutex->id] != mutex);
+
+ switch (id) {
+ case DDP_COMPONENT_DSI0:
+ case DDP_COMPONENT_DSI1:
+ case DDP_COMPONENT_DSI2:
+ case DDP_COMPONENT_DSI3:
+ case DDP_COMPONENT_DPI0:
+ case DDP_COMPONENT_DPI1:
+ writel_relaxed(MUTEX_SOF_SINGLE_MODE,
+ mtx->regs +
+ DISP_REG_MUTEX_SOF(mtx->data->mutex_sof_reg,
+ mutex->id));
+ break;
+ default:
+ if (mtx->data->mutex_mod[id] < 32) {
+ offset = DISP_REG_MUTEX_MOD(mtx->data->mutex_mod_reg,
+ mutex->id);
+ reg = readl_relaxed(mtx->regs + offset);
+ reg &= ~(1 << mtx->data->mutex_mod[id]);
+ writel_relaxed(reg, mtx->regs + offset);
+ } else {
+ offset = DISP_REG_MUTEX_MOD2(mutex->id);
+ reg = readl_relaxed(mtx->regs + offset);
+ reg &= ~(1 << (mtx->data->mutex_mod[id] - 32));
+ writel_relaxed(reg, mtx->regs + offset);
+ }
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(mtk_mutex_remove_comp);
+
+void mtk_mutex_enable(struct mtk_mutex *mutex)
+{
+ struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
+ mutex[mutex->id]);
+
+ WARN_ON(&mtx->mutex[mutex->id] != mutex);
+
+ writel(1, mtx->regs + DISP_REG_MUTEX_EN(mutex->id));
+}
+EXPORT_SYMBOL_GPL(mtk_mutex_enable);
+
+void mtk_mutex_disable(struct mtk_mutex *mutex)
+{
+ struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
+ mutex[mutex->id]);
+
+ WARN_ON(&mtx->mutex[mutex->id] != mutex);
+
+ writel(0, mtx->regs + DISP_REG_MUTEX_EN(mutex->id));
+}
+EXPORT_SYMBOL_GPL(mtk_mutex_disable);
+
+void mtk_mutex_acquire(struct mtk_mutex *mutex)
+{
+ struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
+ mutex[mutex->id]);
+ u32 tmp;
+
+ writel(1, mtx->regs + DISP_REG_MUTEX_EN(mutex->id));
+ writel(1, mtx->regs + DISP_REG_MUTEX(mutex->id));
+ if (readl_poll_timeout_atomic(mtx->regs + DISP_REG_MUTEX(mutex->id),
+ tmp, tmp & INT_MUTEX, 1, 10000))
+ pr_err("could not acquire mutex %d\n", mutex->id);
+}
+EXPORT_SYMBOL_GPL(mtk_mutex_acquire);
+
+void mtk_mutex_release(struct mtk_mutex *mutex)
+{
+ struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
+ mutex[mutex->id]);
+
+ writel(0, mtx->regs + DISP_REG_MUTEX(mutex->id));
+}
+EXPORT_SYMBOL_GPL(mtk_mutex_release);
+
+static int mtk_mutex_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mtk_mutex_ctx *mtx;
+ struct resource *regs;
+ int i;
+
+ mtx = devm_kzalloc(dev, sizeof(*mtx), GFP_KERNEL);
+ if (!mtx)
+ return -ENOMEM;
+
+ for (i = 0; i < 10; i++)
+ mtx->mutex[i].id = i;
+
+ mtx->data = of_device_get_match_data(dev);
+
+ if (!mtx->data->no_clk) {
+ mtx->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(mtx->clk)) {
+ if (PTR_ERR(mtx->clk) != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get clock\n");
+ return PTR_ERR(mtx->clk);
+ }
+ }
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mtx->regs = devm_ioremap_resource(dev, regs);
+ if (IS_ERR(mtx->regs)) {
+ dev_err(dev, "Failed to map mutex registers\n");
+ return PTR_ERR(mtx->regs);
+ }
+
+ platform_set_drvdata(pdev, mtx);
+
+ return 0;
+}
+
+static int mtk_mutex_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static const struct of_device_id mutex_driver_dt_match[] = {
+ { .compatible = "mediatek,mt2701-disp-mutex",
+ .data = &mt2701_mutex_driver_data},
+ { .compatible = "mediatek,mt2712-disp-mutex",
+ .data = &mt2712_mutex_driver_data},
+ { .compatible = "mediatek,mt8167-disp-mutex",
+ .data = &mt8167_mutex_driver_data},
+ { .compatible = "mediatek,mt8173-disp-mutex",
+ .data = &mt8173_mutex_driver_data},
+ {},
+};
+MODULE_DEVICE_TABLE(of, mutex_driver_dt_match);
+
+struct platform_driver mtk_mutex_driver = {
+ .probe = mtk_mutex_probe,
+ .remove = mtk_mutex_remove,
+ .driver = {
+ .name = "mediatek-mutex",
+ .owner = THIS_MODULE,
+ .of_match_table = mutex_driver_dt_match,
+ },
+};
+
+builtin_platform_driver(mtk_mutex_driver);
diff --git a/drivers/soc/sifive/sifive_l2_cache.c b/drivers/soc/sifive/sifive_l2_cache.c
index 44d7e1951da3..59640a1d0b28 100644
--- a/drivers/soc/sifive/sifive_l2_cache.c
+++ b/drivers/soc/sifive/sifive_l2_cache.c
@@ -17,6 +17,10 @@
#define SIFIVE_L2_DIRECCFIX_HIGH 0x104
#define SIFIVE_L2_DIRECCFIX_COUNT 0x108
+#define SIFIVE_L2_DIRECCFAIL_LOW 0x120
+#define SIFIVE_L2_DIRECCFAIL_HIGH 0x124
+#define SIFIVE_L2_DIRECCFAIL_COUNT 0x128
+
#define SIFIVE_L2_DATECCFIX_LOW 0x140
#define SIFIVE_L2_DATECCFIX_HIGH 0x144
#define SIFIVE_L2_DATECCFIX_COUNT 0x148
@@ -29,7 +33,7 @@
#define SIFIVE_L2_WAYENABLE 0x08
#define SIFIVE_L2_ECCINJECTERR 0x40
-#define SIFIVE_L2_MAX_ECCINTR 3
+#define SIFIVE_L2_MAX_ECCINTR 4
static void __iomem *l2_base;
static int g_irq[SIFIVE_L2_MAX_ECCINTR];
@@ -39,6 +43,7 @@ enum {
DIR_CORR = 0,
DATA_CORR,
DATA_UNCORR,
+ DIR_UNCORR,
};
#ifdef CONFIG_DEBUG_FS
@@ -93,6 +98,7 @@ static void l2_config_read(void)
static const struct of_device_id sifive_l2_ids[] = {
{ .compatible = "sifive,fu540-c000-ccache" },
+ { .compatible = "sifive,fu740-c000-ccache" },
{ /* end of table */ },
};
@@ -155,6 +161,15 @@ static irqreturn_t l2_int_handler(int irq, void *device)
atomic_notifier_call_chain(&l2_err_chain, SIFIVE_L2_ERR_TYPE_CE,
"DirECCFix");
}
+ if (irq == g_irq[DIR_UNCORR]) {
+ add_h = readl(l2_base + SIFIVE_L2_DIRECCFAIL_HIGH);
+ add_l = readl(l2_base + SIFIVE_L2_DIRECCFAIL_LOW);
+ /* Reading this register clears the DirFail interrupt sig */
+ readl(l2_base + SIFIVE_L2_DIRECCFAIL_COUNT);
+ atomic_notifier_call_chain(&l2_err_chain, SIFIVE_L2_ERR_TYPE_UE,
+ "DirECCFail");
+ panic("L2CACHE: DirFail @ 0x%08X.%08X\n", add_h, add_l);
+ }
if (irq == g_irq[DATA_CORR]) {
add_h = readl(l2_base + SIFIVE_L2_DATECCFIX_HIGH);
add_l = readl(l2_base + SIFIVE_L2_DATECCFIX_LOW);
@@ -181,7 +196,7 @@ static int __init sifive_l2_init(void)
{
struct device_node *np;
struct resource res;
- int i, rc;
+ int i, rc, intr_num;
np = of_find_matching_node(NULL, sifive_l2_ids);
if (!np)
@@ -194,7 +209,13 @@ static int __init sifive_l2_init(void)
if (!l2_base)
return -ENOMEM;
- for (i = 0; i < SIFIVE_L2_MAX_ECCINTR; i++) {
+ intr_num = of_property_count_u32_elems(np, "interrupts");
+ if (!intr_num) {
+ pr_err("L2CACHE: no interrupts property\n");
+ return -ENODEV;
+ }
+
+ for (i = 0; i < intr_num; i++) {
g_irq[i] = irq_of_parse_and_map(np, i);
rc = request_irq(g_irq[i], l2_int_handler, 0, "l2_ecc", NULL);
if (rc) {
diff --git a/drivers/soc/xilinx/Kconfig b/drivers/soc/xilinx/Kconfig
index 0b1708dae361..53af9115dc31 100644
--- a/drivers/soc/xilinx/Kconfig
+++ b/drivers/soc/xilinx/Kconfig
@@ -1,23 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
menu "Xilinx SoC drivers"
-config XILINX_VCU
- tristate "Xilinx VCU logicoreIP Init"
- depends on HAS_IOMEM
- select REGMAP_MMIO
- help
- Provides the driver to enable and disable the isolation between the
- processing system and programmable logic part by using the logicoreIP
- register set. This driver also configures the frequency based on the
- clock information from the logicoreIP register set.
-
- If you say yes here you get support for the logicoreIP.
-
- If unsure, say N.
-
- To compile this driver as a module, choose M here: the
- module will be called xlnx_vcu.
-
config ZYNQMP_POWER
bool "Enable Xilinx Zynq MPSoC Power Management driver"
depends on PM && ZYNQMP_FIRMWARE
diff --git a/drivers/soc/xilinx/Makefile b/drivers/soc/xilinx/Makefile
index f66bfea5de17..9854e6f6086b 100644
--- a/drivers/soc/xilinx/Makefile
+++ b/drivers/soc/xilinx/Makefile
@@ -1,4 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_XILINX_VCU) += xlnx_vcu.o
obj-$(CONFIG_ZYNQMP_POWER) += zynqmp_power.o
obj-$(CONFIG_ZYNQMP_PM_DOMAINS) += zynqmp_pm_domains.o
diff --git a/drivers/soc/xilinx/xlnx_vcu.c b/drivers/soc/xilinx/xlnx_vcu.c
deleted file mode 100644
index 14daad4efc58..000000000000
--- a/drivers/soc/xilinx/xlnx_vcu.c
+++ /dev/null
@@ -1,628 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Xilinx VCU Init
- *
- * Copyright (C) 2016 - 2017 Xilinx, Inc.
- *
- * Contacts Dhaval Shah <dshah@xilinx.com>
- */
-#include <linux/clk.h>
-#include <linux/device.h>
-#include <linux/errno.h>
-#include <linux/io.h>
-#include <linux/mfd/syscon.h>
-#include <linux/mfd/syscon/xlnx-vcu.h>
-#include <linux/module.h>
-#include <linux/of_platform.h>
-#include <linux/platform_device.h>
-#include <linux/regmap.h>
-
-/* vcu slcr registers, bitmask and shift */
-#define VCU_PLL_CTRL 0x24
-#define VCU_PLL_CTRL_RESET_MASK 0x01
-#define VCU_PLL_CTRL_RESET_SHIFT 0
-#define VCU_PLL_CTRL_BYPASS_MASK 0x01
-#define VCU_PLL_CTRL_BYPASS_SHIFT 3
-#define VCU_PLL_CTRL_FBDIV_MASK 0x7f
-#define VCU_PLL_CTRL_FBDIV_SHIFT 8
-#define VCU_PLL_CTRL_POR_IN_MASK 0x01
-#define VCU_PLL_CTRL_POR_IN_SHIFT 1
-#define VCU_PLL_CTRL_PWR_POR_MASK 0x01
-#define VCU_PLL_CTRL_PWR_POR_SHIFT 2
-#define VCU_PLL_CTRL_CLKOUTDIV_MASK 0x03
-#define VCU_PLL_CTRL_CLKOUTDIV_SHIFT 16
-#define VCU_PLL_CTRL_DEFAULT 0
-#define VCU_PLL_DIV2 2
-
-#define VCU_PLL_CFG 0x28
-#define VCU_PLL_CFG_RES_MASK 0x0f
-#define VCU_PLL_CFG_RES_SHIFT 0
-#define VCU_PLL_CFG_CP_MASK 0x0f
-#define VCU_PLL_CFG_CP_SHIFT 5
-#define VCU_PLL_CFG_LFHF_MASK 0x03
-#define VCU_PLL_CFG_LFHF_SHIFT 10
-#define VCU_PLL_CFG_LOCK_CNT_MASK 0x03ff
-#define VCU_PLL_CFG_LOCK_CNT_SHIFT 13
-#define VCU_PLL_CFG_LOCK_DLY_MASK 0x7f
-#define VCU_PLL_CFG_LOCK_DLY_SHIFT 25
-#define VCU_ENC_CORE_CTRL 0x30
-#define VCU_ENC_MCU_CTRL 0x34
-#define VCU_DEC_CORE_CTRL 0x38
-#define VCU_DEC_MCU_CTRL 0x3c
-#define VCU_PLL_DIVISOR_MASK 0x3f
-#define VCU_PLL_DIVISOR_SHIFT 4
-#define VCU_SRCSEL_MASK 0x01
-#define VCU_SRCSEL_SHIFT 0
-#define VCU_SRCSEL_PLL 1
-
-#define VCU_PLL_STATUS 0x60
-#define VCU_PLL_STATUS_LOCK_STATUS_MASK 0x01
-
-#define MHZ 1000000
-#define FVCO_MIN (1500U * MHZ)
-#define FVCO_MAX (3000U * MHZ)
-#define DIVISOR_MIN 0
-#define DIVISOR_MAX 63
-#define FRAC 100
-#define LIMIT (10 * MHZ)
-
-/**
- * struct xvcu_device - Xilinx VCU init device structure
- * @dev: Platform device
- * @pll_ref: pll ref clock source
- * @aclk: axi clock source
- * @logicore_reg_ba: logicore reg base address
- * @vcu_slcr_ba: vcu_slcr Register base address
- * @coreclk: core clock frequency
- */
-struct xvcu_device {
- struct device *dev;
- struct clk *pll_ref;
- struct clk *aclk;
- struct regmap *logicore_reg_ba;
- void __iomem *vcu_slcr_ba;
- u32 coreclk;
-};
-
-static struct regmap_config vcu_settings_regmap_config = {
- .name = "regmap",
- .reg_bits = 32,
- .val_bits = 32,
- .reg_stride = 4,
- .max_register = 0xfff,
- .cache_type = REGCACHE_NONE,
-};
-
-/**
- * struct xvcu_pll_cfg - Helper data
- * @fbdiv: The integer portion of the feedback divider to the PLL
- * @cp: PLL charge pump control
- * @res: PLL loop filter resistor control
- * @lfhf: PLL loop filter high frequency capacitor control
- * @lock_dly: Lock circuit configuration settings for lock windowsize
- * @lock_cnt: Lock circuit counter setting
- */
-struct xvcu_pll_cfg {
- u32 fbdiv;
- u32 cp;
- u32 res;
- u32 lfhf;
- u32 lock_dly;
- u32 lock_cnt;
-};
-
-static const struct xvcu_pll_cfg xvcu_pll_cfg[] = {
- { 25, 3, 10, 3, 63, 1000 },
- { 26, 3, 10, 3, 63, 1000 },
- { 27, 4, 6, 3, 63, 1000 },
- { 28, 4, 6, 3, 63, 1000 },
- { 29, 4, 6, 3, 63, 1000 },
- { 30, 4, 6, 3, 63, 1000 },
- { 31, 6, 1, 3, 63, 1000 },
- { 32, 6, 1, 3, 63, 1000 },
- { 33, 4, 10, 3, 63, 1000 },
- { 34, 5, 6, 3, 63, 1000 },
- { 35, 5, 6, 3, 63, 1000 },
- { 36, 5, 6, 3, 63, 1000 },
- { 37, 5, 6, 3, 63, 1000 },
- { 38, 5, 6, 3, 63, 975 },
- { 39, 3, 12, 3, 63, 950 },
- { 40, 3, 12, 3, 63, 925 },
- { 41, 3, 12, 3, 63, 900 },
- { 42, 3, 12, 3, 63, 875 },
- { 43, 3, 12, 3, 63, 850 },
- { 44, 3, 12, 3, 63, 850 },
- { 45, 3, 12, 3, 63, 825 },
- { 46, 3, 12, 3, 63, 800 },
- { 47, 3, 12, 3, 63, 775 },
- { 48, 3, 12, 3, 63, 775 },
- { 49, 3, 12, 3, 63, 750 },
- { 50, 3, 12, 3, 63, 750 },
- { 51, 3, 2, 3, 63, 725 },
- { 52, 3, 2, 3, 63, 700 },
- { 53, 3, 2, 3, 63, 700 },
- { 54, 3, 2, 3, 63, 675 },
- { 55, 3, 2, 3, 63, 675 },
- { 56, 3, 2, 3, 63, 650 },
- { 57, 3, 2, 3, 63, 650 },
- { 58, 3, 2, 3, 63, 625 },
- { 59, 3, 2, 3, 63, 625 },
- { 60, 3, 2, 3, 63, 625 },
- { 61, 3, 2, 3, 63, 600 },
- { 62, 3, 2, 3, 63, 600 },
- { 63, 3, 2, 3, 63, 600 },
- { 64, 3, 2, 3, 63, 600 },
- { 65, 3, 2, 3, 63, 600 },
- { 66, 3, 2, 3, 63, 600 },
- { 67, 3, 2, 3, 63, 600 },
- { 68, 3, 2, 3, 63, 600 },
- { 69, 3, 2, 3, 63, 600 },
- { 70, 3, 2, 3, 63, 600 },
- { 71, 3, 2, 3, 63, 600 },
- { 72, 3, 2, 3, 63, 600 },
- { 73, 3, 2, 3, 63, 600 },
- { 74, 3, 2, 3, 63, 600 },
- { 75, 3, 2, 3, 63, 600 },
- { 76, 3, 2, 3, 63, 600 },
- { 77, 3, 2, 3, 63, 600 },
- { 78, 3, 2, 3, 63, 600 },
- { 79, 3, 2, 3, 63, 600 },
- { 80, 3, 2, 3, 63, 600 },
- { 81, 3, 2, 3, 63, 600 },
- { 82, 3, 2, 3, 63, 600 },
- { 83, 4, 2, 3, 63, 600 },
- { 84, 4, 2, 3, 63, 600 },
- { 85, 4, 2, 3, 63, 600 },
- { 86, 4, 2, 3, 63, 600 },
- { 87, 4, 2, 3, 63, 600 },
- { 88, 4, 2, 3, 63, 600 },
- { 89, 4, 2, 3, 63, 600 },
- { 90, 4, 2, 3, 63, 600 },
- { 91, 4, 2, 3, 63, 600 },
- { 92, 4, 2, 3, 63, 600 },
- { 93, 4, 2, 3, 63, 600 },
- { 94, 4, 2, 3, 63, 600 },
- { 95, 4, 2, 3, 63, 600 },
- { 96, 4, 2, 3, 63, 600 },
- { 97, 4, 2, 3, 63, 600 },
- { 98, 4, 2, 3, 63, 600 },
- { 99, 4, 2, 3, 63, 600 },
- { 100, 4, 2, 3, 63, 600 },
- { 101, 4, 2, 3, 63, 600 },
- { 102, 4, 2, 3, 63, 600 },
- { 103, 5, 2, 3, 63, 600 },
- { 104, 5, 2, 3, 63, 600 },
- { 105, 5, 2, 3, 63, 600 },
- { 106, 5, 2, 3, 63, 600 },
- { 107, 3, 4, 3, 63, 600 },
- { 108, 3, 4, 3, 63, 600 },
- { 109, 3, 4, 3, 63, 600 },
- { 110, 3, 4, 3, 63, 600 },
- { 111, 3, 4, 3, 63, 600 },
- { 112, 3, 4, 3, 63, 600 },
- { 113, 3, 4, 3, 63, 600 },
- { 114, 3, 4, 3, 63, 600 },
- { 115, 3, 4, 3, 63, 600 },
- { 116, 3, 4, 3, 63, 600 },
- { 117, 3, 4, 3, 63, 600 },
- { 118, 3, 4, 3, 63, 600 },
- { 119, 3, 4, 3, 63, 600 },
- { 120, 3, 4, 3, 63, 600 },
- { 121, 3, 4, 3, 63, 600 },
- { 122, 3, 4, 3, 63, 600 },
- { 123, 3, 4, 3, 63, 600 },
- { 124, 3, 4, 3, 63, 600 },
- { 125, 3, 4, 3, 63, 600 },
-};
-
-/**
- * xvcu_read - Read from the VCU register space
- * @iomem: vcu reg space base address
- * @offset: vcu reg offset from base
- *
- * Return: Returns 32bit value from VCU register specified
- *
- */
-static inline u32 xvcu_read(void __iomem *iomem, u32 offset)
-{
- return ioread32(iomem + offset);
-}
-
-/**
- * xvcu_write - Write to the VCU register space
- * @iomem: vcu reg space base address
- * @offset: vcu reg offset from base
- * @value: Value to write
- */
-static inline void xvcu_write(void __iomem *iomem, u32 offset, u32 value)
-{
- iowrite32(value, iomem + offset);
-}
-
-/**
- * xvcu_write_field_reg - Write to the vcu reg field
- * @iomem: vcu reg space base address
- * @offset: vcu reg offset from base
- * @field: vcu reg field to write to
- * @mask: vcu reg mask
- * @shift: vcu reg number of bits to shift the bitfield
- */
-static void xvcu_write_field_reg(void __iomem *iomem, int offset,
- u32 field, u32 mask, int shift)
-{
- u32 val = xvcu_read(iomem, offset);
-
- val &= ~(mask << shift);
- val |= (field & mask) << shift;
-
- xvcu_write(iomem, offset, val);
-}
-
-/**
- * xvcu_set_vcu_pll_info - Set the VCU PLL info
- * @xvcu: Pointer to the xvcu_device structure
- *
- * Programming the VCU PLL based on the user configuration
- * (ref clock freq, core clock freq, mcu clock freq).
- * Core clock frequency has higher priority than mcu clock frequency
- * Errors in following cases
- * - When mcu or clock clock get from logicoreIP is 0
- * - When VCU PLL DIV related bits value other than 1
- * - When proper data not found for given data
- * - When sis570_1 clocksource related operation failed
- *
- * Return: Returns status, either success or error+reason
- */
-static int xvcu_set_vcu_pll_info(struct xvcu_device *xvcu)
-{
- u32 refclk, coreclk, mcuclk, inte, deci;
- u32 divisor_mcu, divisor_core, fvco;
- u32 clkoutdiv, vcu_pll_ctrl, pll_clk;
- u32 cfg_val, mod, ctrl;
- int ret, i;
- const struct xvcu_pll_cfg *found = NULL;
-
- regmap_read(xvcu->logicore_reg_ba, VCU_PLL_CLK, &inte);
- regmap_read(xvcu->logicore_reg_ba, VCU_PLL_CLK_DEC, &deci);
- regmap_read(xvcu->logicore_reg_ba, VCU_CORE_CLK, &coreclk);
- coreclk *= MHZ;
- regmap_read(xvcu->logicore_reg_ba, VCU_MCU_CLK, &mcuclk);
- mcuclk *= MHZ;
- if (!mcuclk || !coreclk) {
- dev_err(xvcu->dev, "Invalid mcu and core clock data\n");
- return -EINVAL;
- }
-
- refclk = (inte * MHZ) + (deci * (MHZ / FRAC));
- dev_dbg(xvcu->dev, "Ref clock from logicoreIP is %uHz\n", refclk);
- dev_dbg(xvcu->dev, "Core clock from logicoreIP is %uHz\n", coreclk);
- dev_dbg(xvcu->dev, "Mcu clock from logicoreIP is %uHz\n", mcuclk);
-
- clk_disable_unprepare(xvcu->pll_ref);
- ret = clk_set_rate(xvcu->pll_ref, refclk);
- if (ret)
- dev_warn(xvcu->dev, "failed to set logicoreIP refclk rate\n");
-
- ret = clk_prepare_enable(xvcu->pll_ref);
- if (ret) {
- dev_err(xvcu->dev, "failed to enable pll_ref clock source\n");
- return ret;
- }
-
- refclk = clk_get_rate(xvcu->pll_ref);
-
- /*
- * The divide-by-2 should be always enabled (==1)
- * to meet the timing in the design.
- * Otherwise, it's an error
- */
- vcu_pll_ctrl = xvcu_read(xvcu->vcu_slcr_ba, VCU_PLL_CTRL);
- clkoutdiv = vcu_pll_ctrl >> VCU_PLL_CTRL_CLKOUTDIV_SHIFT;
- clkoutdiv = clkoutdiv & VCU_PLL_CTRL_CLKOUTDIV_MASK;
- if (clkoutdiv != 1) {
- dev_err(xvcu->dev, "clkoutdiv value is invalid\n");
- return -EINVAL;
- }
-
- for (i = ARRAY_SIZE(xvcu_pll_cfg) - 1; i >= 0; i--) {
- const struct xvcu_pll_cfg *cfg = &xvcu_pll_cfg[i];
-
- fvco = cfg->fbdiv * refclk;
- if (fvco >= FVCO_MIN && fvco <= FVCO_MAX) {
- pll_clk = fvco / VCU_PLL_DIV2;
- if (fvco % VCU_PLL_DIV2 != 0)
- pll_clk++;
- mod = pll_clk % coreclk;
- if (mod < LIMIT) {
- divisor_core = pll_clk / coreclk;
- } else if (coreclk - mod < LIMIT) {
- divisor_core = pll_clk / coreclk;
- divisor_core++;
- } else {
- continue;
- }
- if (divisor_core >= DIVISOR_MIN &&
- divisor_core <= DIVISOR_MAX) {
- found = cfg;
- divisor_mcu = pll_clk / mcuclk;
- mod = pll_clk % mcuclk;
- if (mcuclk - mod < LIMIT)
- divisor_mcu++;
- break;
- }
- }
- }
-
- if (!found) {
- dev_err(xvcu->dev, "Invalid clock combination.\n");
- return -EINVAL;
- }
-
- xvcu->coreclk = pll_clk / divisor_core;
- mcuclk = pll_clk / divisor_mcu;
- dev_dbg(xvcu->dev, "Actual Ref clock freq is %uHz\n", refclk);
- dev_dbg(xvcu->dev, "Actual Core clock freq is %uHz\n", xvcu->coreclk);
- dev_dbg(xvcu->dev, "Actual Mcu clock freq is %uHz\n", mcuclk);
-
- vcu_pll_ctrl &= ~(VCU_PLL_CTRL_FBDIV_MASK << VCU_PLL_CTRL_FBDIV_SHIFT);
- vcu_pll_ctrl |= (found->fbdiv & VCU_PLL_CTRL_FBDIV_MASK) <<
- VCU_PLL_CTRL_FBDIV_SHIFT;
- vcu_pll_ctrl &= ~(VCU_PLL_CTRL_POR_IN_MASK <<
- VCU_PLL_CTRL_POR_IN_SHIFT);
- vcu_pll_ctrl |= (VCU_PLL_CTRL_DEFAULT & VCU_PLL_CTRL_POR_IN_MASK) <<
- VCU_PLL_CTRL_POR_IN_SHIFT;
- vcu_pll_ctrl &= ~(VCU_PLL_CTRL_PWR_POR_MASK <<
- VCU_PLL_CTRL_PWR_POR_SHIFT);
- vcu_pll_ctrl |= (VCU_PLL_CTRL_DEFAULT & VCU_PLL_CTRL_PWR_POR_MASK) <<
- VCU_PLL_CTRL_PWR_POR_SHIFT;
- xvcu_write(xvcu->vcu_slcr_ba, VCU_PLL_CTRL, vcu_pll_ctrl);
-
- /* Set divisor for the core and mcu clock */
- ctrl = xvcu_read(xvcu->vcu_slcr_ba, VCU_ENC_CORE_CTRL);
- ctrl &= ~(VCU_PLL_DIVISOR_MASK << VCU_PLL_DIVISOR_SHIFT);
- ctrl |= (divisor_core & VCU_PLL_DIVISOR_MASK) <<
- VCU_PLL_DIVISOR_SHIFT;
- ctrl &= ~(VCU_SRCSEL_MASK << VCU_SRCSEL_SHIFT);
- ctrl |= (VCU_SRCSEL_PLL & VCU_SRCSEL_MASK) << VCU_SRCSEL_SHIFT;
- xvcu_write(xvcu->vcu_slcr_ba, VCU_ENC_CORE_CTRL, ctrl);
-
- ctrl = xvcu_read(xvcu->vcu_slcr_ba, VCU_DEC_CORE_CTRL);
- ctrl &= ~(VCU_PLL_DIVISOR_MASK << VCU_PLL_DIVISOR_SHIFT);
- ctrl |= (divisor_core & VCU_PLL_DIVISOR_MASK) <<
- VCU_PLL_DIVISOR_SHIFT;
- ctrl &= ~(VCU_SRCSEL_MASK << VCU_SRCSEL_SHIFT);
- ctrl |= (VCU_SRCSEL_PLL & VCU_SRCSEL_MASK) << VCU_SRCSEL_SHIFT;
- xvcu_write(xvcu->vcu_slcr_ba, VCU_DEC_CORE_CTRL, ctrl);
-
- ctrl = xvcu_read(xvcu->vcu_slcr_ba, VCU_ENC_MCU_CTRL);
- ctrl &= ~(VCU_PLL_DIVISOR_MASK << VCU_PLL_DIVISOR_SHIFT);
- ctrl |= (divisor_mcu & VCU_PLL_DIVISOR_MASK) << VCU_PLL_DIVISOR_SHIFT;
- ctrl &= ~(VCU_SRCSEL_MASK << VCU_SRCSEL_SHIFT);
- ctrl |= (VCU_SRCSEL_PLL & VCU_SRCSEL_MASK) << VCU_SRCSEL_SHIFT;
- xvcu_write(xvcu->vcu_slcr_ba, VCU_ENC_MCU_CTRL, ctrl);
-
- ctrl = xvcu_read(xvcu->vcu_slcr_ba, VCU_DEC_MCU_CTRL);
- ctrl &= ~(VCU_PLL_DIVISOR_MASK << VCU_PLL_DIVISOR_SHIFT);
- ctrl |= (divisor_mcu & VCU_PLL_DIVISOR_MASK) << VCU_PLL_DIVISOR_SHIFT;
- ctrl &= ~(VCU_SRCSEL_MASK << VCU_SRCSEL_SHIFT);
- ctrl |= (VCU_SRCSEL_PLL & VCU_SRCSEL_MASK) << VCU_SRCSEL_SHIFT;
- xvcu_write(xvcu->vcu_slcr_ba, VCU_DEC_MCU_CTRL, ctrl);
-
- /* Set RES, CP, LFHF, LOCK_CNT and LOCK_DLY cfg values */
- cfg_val = (found->res << VCU_PLL_CFG_RES_SHIFT) |
- (found->cp << VCU_PLL_CFG_CP_SHIFT) |
- (found->lfhf << VCU_PLL_CFG_LFHF_SHIFT) |
- (found->lock_cnt << VCU_PLL_CFG_LOCK_CNT_SHIFT) |
- (found->lock_dly << VCU_PLL_CFG_LOCK_DLY_SHIFT);
- xvcu_write(xvcu->vcu_slcr_ba, VCU_PLL_CFG, cfg_val);
-
- return 0;
-}
-
-/**
- * xvcu_set_pll - PLL init sequence
- * @xvcu: Pointer to the xvcu_device structure
- *
- * Call the api to set the PLL info and once that is done then
- * init the PLL sequence to make the PLL stable.
- *
- * Return: Returns status, either success or error+reason
- */
-static int xvcu_set_pll(struct xvcu_device *xvcu)
-{
- u32 lock_status;
- unsigned long timeout;
- int ret;
-
- ret = xvcu_set_vcu_pll_info(xvcu);
- if (ret) {
- dev_err(xvcu->dev, "failed to set pll info\n");
- return ret;
- }
-
- xvcu_write_field_reg(xvcu->vcu_slcr_ba, VCU_PLL_CTRL,
- 1, VCU_PLL_CTRL_BYPASS_MASK,
- VCU_PLL_CTRL_BYPASS_SHIFT);
- xvcu_write_field_reg(xvcu->vcu_slcr_ba, VCU_PLL_CTRL,
- 1, VCU_PLL_CTRL_RESET_MASK,
- VCU_PLL_CTRL_RESET_SHIFT);
- xvcu_write_field_reg(xvcu->vcu_slcr_ba, VCU_PLL_CTRL,
- 0, VCU_PLL_CTRL_RESET_MASK,
- VCU_PLL_CTRL_RESET_SHIFT);
- /*
- * Defined the timeout for the max time to wait the
- * PLL_STATUS to be locked.
- */
- timeout = jiffies + msecs_to_jiffies(2000);
- do {
- lock_status = xvcu_read(xvcu->vcu_slcr_ba, VCU_PLL_STATUS);
- if (lock_status & VCU_PLL_STATUS_LOCK_STATUS_MASK) {
- xvcu_write_field_reg(xvcu->vcu_slcr_ba, VCU_PLL_CTRL,
- 0, VCU_PLL_CTRL_BYPASS_MASK,
- VCU_PLL_CTRL_BYPASS_SHIFT);
- return 0;
- }
- } while (!time_after(jiffies, timeout));
-
- /* PLL is not locked even after the timeout of the 2sec */
- dev_err(xvcu->dev, "PLL is not locked\n");
- return -ETIMEDOUT;
-}
-
-/**
- * xvcu_probe - Probe existence of the logicoreIP
- * and initialize PLL
- *
- * @pdev: Pointer to the platform_device structure
- *
- * Return: Returns 0 on success
- * Negative error code otherwise
- */
-static int xvcu_probe(struct platform_device *pdev)
-{
- struct resource *res;
- struct xvcu_device *xvcu;
- void __iomem *regs;
- int ret;
-
- xvcu = devm_kzalloc(&pdev->dev, sizeof(*xvcu), GFP_KERNEL);
- if (!xvcu)
- return -ENOMEM;
-
- xvcu->dev = &pdev->dev;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vcu_slcr");
- if (!res) {
- dev_err(&pdev->dev, "get vcu_slcr memory resource failed.\n");
- return -ENODEV;
- }
-
- xvcu->vcu_slcr_ba = devm_ioremap(&pdev->dev, res->start,
- resource_size(res));
- if (!xvcu->vcu_slcr_ba) {
- dev_err(&pdev->dev, "vcu_slcr register mapping failed.\n");
- return -ENOMEM;
- }
-
- xvcu->logicore_reg_ba =
- syscon_regmap_lookup_by_compatible("xlnx,vcu-settings");
- if (IS_ERR(xvcu->logicore_reg_ba)) {
- dev_info(&pdev->dev,
- "could not find xlnx,vcu-settings: trying direct register access\n");
-
- res = platform_get_resource_byname(pdev,
- IORESOURCE_MEM, "logicore");
- if (!res) {
- dev_err(&pdev->dev, "get logicore memory resource failed.\n");
- return -ENODEV;
- }
-
- regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
- if (!regs) {
- dev_err(&pdev->dev, "logicore register mapping failed.\n");
- return -ENOMEM;
- }
-
- xvcu->logicore_reg_ba =
- devm_regmap_init_mmio(&pdev->dev, regs,
- &vcu_settings_regmap_config);
- if (IS_ERR(xvcu->logicore_reg_ba)) {
- dev_err(&pdev->dev, "failed to init regmap\n");
- return PTR_ERR(xvcu->logicore_reg_ba);
- }
- }
-
- xvcu->aclk = devm_clk_get(&pdev->dev, "aclk");
- if (IS_ERR(xvcu->aclk)) {
- dev_err(&pdev->dev, "Could not get aclk clock\n");
- return PTR_ERR(xvcu->aclk);
- }
-
- xvcu->pll_ref = devm_clk_get(&pdev->dev, "pll_ref");
- if (IS_ERR(xvcu->pll_ref)) {
- dev_err(&pdev->dev, "Could not get pll_ref clock\n");
- return PTR_ERR(xvcu->pll_ref);
- }
-
- ret = clk_prepare_enable(xvcu->aclk);
- if (ret) {
- dev_err(&pdev->dev, "aclk clock enable failed\n");
- return ret;
- }
-
- ret = clk_prepare_enable(xvcu->pll_ref);
- if (ret) {
- dev_err(&pdev->dev, "pll_ref clock enable failed\n");
- goto error_aclk;
- }
-
- /*
- * Do the Gasket isolation and put the VCU out of reset
- * Bit 0 : Gasket isolation
- * Bit 1 : put VCU out of reset
- */
- regmap_write(xvcu->logicore_reg_ba, VCU_GASKET_INIT, VCU_GASKET_VALUE);
-
- /* Do the PLL Settings based on the ref clk,core and mcu clk freq */
- ret = xvcu_set_pll(xvcu);
- if (ret) {
- dev_err(&pdev->dev, "Failed to set the pll\n");
- goto error_pll_ref;
- }
-
- dev_set_drvdata(&pdev->dev, xvcu);
-
- return 0;
-
-error_pll_ref:
- clk_disable_unprepare(xvcu->pll_ref);
-error_aclk:
- clk_disable_unprepare(xvcu->aclk);
- return ret;
-}
-
-/**
- * xvcu_remove - Insert gasket isolation
- * and disable the clock
- * @pdev: Pointer to the platform_device structure
- *
- * Return: Returns 0 on success
- * Negative error code otherwise
- */
-static int xvcu_remove(struct platform_device *pdev)
-{
- struct xvcu_device *xvcu;
-
- xvcu = platform_get_drvdata(pdev);
- if (!xvcu)
- return -ENODEV;
-
- /* Add the the Gasket isolation and put the VCU in reset. */
- regmap_write(xvcu->logicore_reg_ba, VCU_GASKET_INIT, 0);
-
- clk_disable_unprepare(xvcu->pll_ref);
- clk_disable_unprepare(xvcu->aclk);
-
- return 0;
-}
-
-static const struct of_device_id xvcu_of_id_table[] = {
- { .compatible = "xlnx,vcu" },
- { .compatible = "xlnx,vcu-logicoreip-1.0" },
- { }
-};
-MODULE_DEVICE_TABLE(of, xvcu_of_id_table);
-
-static struct platform_driver xvcu_driver = {
- .driver = {
- .name = "xilinx-vcu",
- .of_match_table = xvcu_of_id_table,
- },
- .probe = xvcu_probe,
- .remove = xvcu_remove,
-};
-
-module_platform_driver(xvcu_driver);
-
-MODULE_AUTHOR("Dhaval Shah <dshah@xilinx.com>");
-MODULE_DESCRIPTION("Xilinx VCU init Driver");
-MODULE_LICENSE("GPL v2");