summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2021-07-18 07:13:55 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2021-07-18 07:13:55 +0200
commit33f8f53317659cd2c61dd118bfa7150f33aa30fb (patch)
treecec893f4b273f4a78e1d84326d15e97b75a456df /drivers
parentca922d6044e49b1ed9782aa8eb28d1ed70931978 (diff)
parentb60bdac8a5870dc136c9b028771371dd123a2431 (diff)
downloadbarebox-33f8f53317659cd2c61dd118bfa7150f33aa30fb.tar.gz
barebox-33f8f53317659cd2c61dd118bfa7150f33aa30fb.tar.xz
Merge branch 'for-next/riscv'
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/starfive/Makefile3
-rw-r--r--drivers/clk/starfive/clk.h64
-rw-r--r--drivers/clk/starfive/jh7100-clkgen.c363
-rw-r--r--drivers/clocksource/timer-clint.c7
-rw-r--r--drivers/clocksource/timer-riscv.c5
-rw-r--r--drivers/gpio/Kconfig8
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/gpio-starfive-vic.c177
-rw-r--r--drivers/hw_random/Kconfig7
-rw-r--r--drivers/hw_random/Makefile1
-rw-r--r--drivers/hw_random/starfive-vic-rng.c208
-rw-r--r--drivers/mci/dw_mmc.c23
-rw-r--r--drivers/mci/mci-core.c15
-rw-r--r--drivers/misc/Kconfig10
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/starfive-pwrseq.c92
-rw-r--r--drivers/net/Kconfig8
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/designware.c64
-rw-r--r--drivers/net/designware.h29
-rw-r--r--drivers/net/designware_starfive.c110
-rw-r--r--drivers/nvmem/Kconfig8
-rw-r--r--drivers/nvmem/Makefile2
-rw-r--r--drivers/nvmem/starfive-otp.c201
-rw-r--r--drivers/pinctrl/pinctrl-single.c4
-rw-r--r--drivers/reset/Kconfig6
-rw-r--r--drivers/reset/Makefile1
-rw-r--r--drivers/reset/core.c78
-rw-r--r--drivers/reset/reset-starfive-vic.c234
-rw-r--r--drivers/soc/Makefile5
-rw-r--r--drivers/soc/sifive/Makefile1
-rw-r--r--drivers/soc/sifive/sifive_l2_cache.c136
-rw-r--r--drivers/soc/starfive/Makefile1
-rw-r--r--drivers/soc/starfive/jh7100_dma.c55
-rw-r--r--drivers/watchdog/Kconfig7
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/starfive_wdt.c106
39 files changed, 1987 insertions, 59 deletions
diff --git a/drivers/Makefile b/drivers/Makefile
index e21ac7095c..9958b748eb 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -40,7 +40,7 @@ obj-$(CONFIG_HAB) += hab/
obj-$(CONFIG_CRYPTO_HW) += crypto/
obj-$(CONFIG_AIODEV) += aiodev/
obj-y += memory/
-obj-y += soc/imx/
+obj-y += soc/
obj-y += nvme/
obj-y += ddr/
obj-y += power/
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index b0be8d1bd8..499df2fe39 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -23,3 +23,4 @@ obj-$(CONFIG_MACH_MIPS_LOONGSON)+= loongson/
obj-$(CONFIG_ARCH_LAYERSCAPE) += clk-qoric.o
obj-y += analogbits/
obj-$(CONFIG_CLK_SIFIVE) += sifive/
+obj-$(CONFIG_SOC_STARFIVE) += starfive/
diff --git a/drivers/clk/starfive/Makefile b/drivers/clk/starfive/Makefile
new file mode 100644
index 0000000000..4e9bf7f2ba
--- /dev/null
+++ b/drivers/clk/starfive/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_SOC_STARFIVE_JH71XX) += jh7100-clkgen.o
diff --git a/drivers/clk/starfive/clk.h b/drivers/clk/starfive/clk.h
new file mode 100644
index 0000000000..cfbf116dcb
--- /dev/null
+++ b/drivers/clk/starfive/clk.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2021 Ahmad Fatoum, Pengutronix
+ */
+
+#ifndef STARFIVE_CLK_H_
+#define STARFIVE_CLK_H_
+
+#include <linux/clk.h>
+
+#define STARFIVE_CLK_ENABLE_SHIFT 31
+#define STARFIVE_CLK_INVERT_SHIFT 30
+#define STARFIVE_CLK_MUX_SHIFT 24
+
+static inline struct clk *starfive_clk_underspecifid(const char *name, const char *parent)
+{
+ /*
+ * TODO With documentation available, all users of this functions can be
+ * migrated to one of the above or to a clk_fixed_factor with
+ * appropriate factor
+ */
+ return clk_fixed_factor(name, parent, 1, 1, 0);
+}
+
+static inline struct clk *starfive_clk_divider(const char *name, const char *parent,
+ void __iomem *reg, u8 width)
+{
+ return starfive_clk_underspecifid(name, parent);
+}
+
+static inline struct clk *starfive_clk_gate(const char *name, const char *parent,
+ void __iomem *reg)
+{
+ return clk_gate(name, parent, reg, STARFIVE_CLK_ENABLE_SHIFT, CLK_SET_RATE_PARENT, 0);
+}
+
+static inline struct clk *starfive_clk_divider_table(const char *name,
+ const char *parent, void __iomem *reg, u8 width,
+ const struct clk_div_table *table)
+{
+ return clk_divider_table(name, parent, CLK_SET_RATE_PARENT, reg, 0,
+ width, table, 0);
+}
+
+static inline struct clk *starfive_clk_gated_divider(const char *name,
+ const char *parent, void __iomem *reg, u8 width)
+{
+ /* TODO divider part */
+ return clk_gate(name, parent, reg, STARFIVE_CLK_ENABLE_SHIFT, CLK_SET_RATE_PARENT, 0);
+}
+
+static inline struct clk *starfive_clk_gate_dis(const char *name, const char *parent,
+ void __iomem *reg)
+{
+ return clk_gate_inverted(name, parent, reg, STARFIVE_CLK_INVERT_SHIFT, CLK_SET_RATE_PARENT);
+}
+
+static inline struct clk *starfive_clk_mux(const char *name, void __iomem *reg,
+ u8 width, const char * const *parents, u8 num_parents)
+{
+ return clk_mux(name, 0, reg, STARFIVE_CLK_MUX_SHIFT, width, parents, num_parents, 0);
+}
+
+#endif
diff --git a/drivers/clk/starfive/jh7100-clkgen.c b/drivers/clk/starfive/jh7100-clkgen.c
new file mode 100644
index 0000000000..df5353e8e6
--- /dev/null
+++ b/drivers/clk/starfive/jh7100-clkgen.c
@@ -0,0 +1,363 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2021 Ahmad Fatoum, Pengutronix
+ */
+
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <linux/clk.h>
+#include <io.h>
+#include <of.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <dt-bindings/clock/starfive-jh7100.h>
+
+#include "clk.h"
+
+
+static const char *cpundbus_root_sels[4] = {
+ [0] = "osc_sys",
+ [1] = "pll0_out",
+ [2] = "pll1_out",
+ [3] = "pll2_out",
+};
+
+static const char *dla_root_sels[4] = {
+ [0] = "osc_sys",
+ [1] = "pll1_out",
+ [2] = "pll2_out",
+ [3] = "dummy",
+};
+
+static const char *dsp_root_sels[4] = {
+ [0] = "osc_sys",
+ [1] = "pll0_out",
+ [2] = "pll1_out",
+ [3] = "pll2_out",
+};
+
+static const char *gmacusb_root_sels[4] = {
+ [0] = "osc_sys",
+ [1] = "pll0_out",
+ [2] = "pll2_out",
+ [3] = "dummy",
+};
+
+static const char *perh0_root_sels[2] = {
+ [0] = "osc_sys",
+ [1] = "pll0_out",
+};
+
+static const char *perh1_root_sels[2] = {
+ [0] = "osc_sys",
+ [1] = "pll2_out",
+};
+
+static const char *vin_root_sels[4] = {
+ [0] = "osc_sys",
+ [1] = "pll1_out",
+ [2] = "pll2_out",
+ [3] = "dummy",
+};
+
+static const char *vout_root_sels[4] = {
+ [0] = "osc_aud",
+ [1] = "pll0_out",
+ [2] = "pll2_out",
+ [3] = "dummy",
+};
+
+static const char *cdechifi4_root_sels[4] = {
+ [0] = "osc_sys",
+ [1] = "pll1_out",
+ [2] = "pll2_out",
+ [3] = "dummy",
+};
+
+static const char *cdec_root_sels[4] = {
+ [0] = "osc_sys",
+ [1] = "pll0_out",
+ [2] = "pll1_out",
+ [3] = "dummy",
+};
+
+static const char *voutbus_root_sels[4] = {
+ [0] = "osc_aud",
+ [1] = "pll0_out",
+ [2] = "pll2_out",
+ [3] = "dummy",
+};
+
+static const char *pll2_refclk_sels[2] = {
+ [0] = "osc_sys",
+ [1] = "osc_aud",
+};
+
+static const char *ddrc0_sels[4] = {
+ [0] = "ddrosc_div2",
+ [1] = "ddrpll_div2",
+ [2] = "ddrpll_div4",
+ [3] = "ddrpll_div8",
+};
+
+static const char *ddrc1_sels[4] = {
+ [0] = "ddrosc_div2",
+ [1] = "ddrpll_div2",
+ [2] = "ddrpll_div4",
+ [3] = "ddrpll_div8",
+};
+
+static const char *nne_bus_sels[2] = {
+ [0] = "cpu_axi",
+ [1] = "nnebus_src1",
+};
+
+static const char *usbphy_25m_sels[2] = {
+ [0] = "osc_sys",
+ [1] = "usbphy_plldiv25m",
+};
+
+static const char *gmac_tx_sels[4] = {
+ [0] = "gmac_gtxclk",
+ [1] = "gmac_mii_txclk",
+ [2] = "gmac_rmii_txclk",
+ [3] = "dummy",
+};
+
+static const char *gmac_rx_pre_sels[2] = {
+ [0] = "gmac_gr_mii_rxclk",
+ [1] = "gmac_rmii_rxclk",
+};
+
+static struct clk *clks[CLK_END];
+
+/* assume osc_sys as direct parent for clocks of yet unknown lineage */
+#define UNKNOWN "osc_sys"
+
+static void starfive_clkgen_init(struct device_node *np, void __iomem *base)
+{
+ clks[CLK_OSC_SYS] = of_clk_get_by_name(np, "osc_sys");
+ clks[CLK_OSC_AUD] = of_clk_get_by_name(np, "osc_aud");
+ clks[CLK_PLL0_OUT] = starfive_clk_underspecifid("pll0_out", "osc_sys");
+ clks[CLK_PLL1_OUT] = starfive_clk_underspecifid("pll1_out", "osc_sys");
+ clks[CLK_PLL2_OUT] = starfive_clk_underspecifid("pll2_out", "pll2_refclk");
+ clks[CLK_CPUNDBUS_ROOT] = starfive_clk_mux("cpundbus_root", base + 0x0, 2, cpundbus_root_sels, ARRAY_SIZE(cpundbus_root_sels));
+ clks[CLK_DLA_ROOT] = starfive_clk_mux("dla_root", base + 0x4, 2, dla_root_sels, ARRAY_SIZE(dla_root_sels));
+ clks[CLK_DSP_ROOT] = starfive_clk_mux("dsp_root", base + 0x8, 2, dsp_root_sels, ARRAY_SIZE(dsp_root_sels));
+ clks[CLK_GMACUSB_ROOT] = starfive_clk_mux("gmacusb_root", base + 0xC, 2, gmacusb_root_sels, ARRAY_SIZE(gmacusb_root_sels));
+ clks[CLK_PERH0_ROOT] = starfive_clk_mux("perh0_root", base + 0x10, 1, perh0_root_sels, ARRAY_SIZE(perh0_root_sels));
+ clks[CLK_PERH1_ROOT] = starfive_clk_mux("perh1_root", base + 0x14, 1, perh1_root_sels, ARRAY_SIZE(perh1_root_sels));
+ clks[CLK_VIN_ROOT] = starfive_clk_mux("vin_root", base + 0x18, 2, vin_root_sels, ARRAY_SIZE(vin_root_sels));
+ clks[CLK_VOUT_ROOT] = starfive_clk_mux("vout_root", base + 0x1C, 2, vout_root_sels, ARRAY_SIZE(vout_root_sels));
+ clks[CLK_AUDIO_ROOT] = starfive_clk_gated_divider("audio_root", UNKNOWN, base + 0x20, 4);
+ clks[CLK_CDECHIFI4_ROOT] = starfive_clk_mux("cdechifi4_root", base + 0x24, 2, cdechifi4_root_sels, ARRAY_SIZE(cdechifi4_root_sels));
+ clks[CLK_CDEC_ROOT] = starfive_clk_mux("cdec_root", base + 0x28, 2, cdec_root_sels, ARRAY_SIZE(cdec_root_sels));
+ clks[CLK_VOUTBUS_ROOT] = starfive_clk_mux("voutbus_root", base + 0x2C, 2, voutbus_root_sels, ARRAY_SIZE(voutbus_root_sels));
+ clks[CLK_CPUNBUS_ROOT_DIV] = starfive_clk_divider("cpunbus_root_div", "cpunbus_root", base + 0x30, 2);
+ clks[CLK_DSP_ROOT_DIV] = starfive_clk_divider("dsp_root_div", "dsp_root", base + 0x34, 3);
+ clks[CLK_PERH0_SRC] = starfive_clk_divider("perh0_src", "perh0_root", base + 0x38, 3);
+ clks[CLK_PERH1_SRC] = starfive_clk_divider("perh1_src", "perh1_root", base + 0x3C, 3);
+ clks[CLK_PLL0_TESTOUT] = starfive_clk_gated_divider("pll0_testout", "pll0_out", base + 0x40, 5);
+ clks[CLK_PLL1_TESTOUT] = starfive_clk_gated_divider("pll1_testout", "pll1_out", base + 0x44, 5);
+ clks[CLK_PLL2_TESTOUT] = starfive_clk_gated_divider("pll2_testout", "pll2_out", base + 0x48, 5);
+ clks[CLK_PLL2_REF] = starfive_clk_mux("pll2_refclk", base + 0x4C, 1, pll2_refclk_sels, ARRAY_SIZE(pll2_refclk_sels));
+ clks[CLK_CPU_CORE] = starfive_clk_divider("cpu_core", UNKNOWN, base + 0x50, 4);
+ clks[CLK_CPU_AXI] = starfive_clk_divider("cpu_axi", UNKNOWN, base + 0x54, 4);
+ clks[CLK_AHB_BUS] = starfive_clk_divider("ahb_bus", UNKNOWN, base + 0x58, 4);
+ clks[CLK_APB1_BUS] = starfive_clk_divider("apb1_bus", UNKNOWN, base + 0x5C, 4);
+ clks[CLK_APB2_BUS] = starfive_clk_divider("apb2_bus", UNKNOWN, base + 0x60, 4);
+ clks[CLK_DOM3AHB_BUS] = starfive_clk_gate("dom3ahb_bus", UNKNOWN, base + 0x64);
+ clks[CLK_DOM7AHB_BUS] = starfive_clk_gate("dom7ahb_bus", UNKNOWN, base + 0x68);
+ clks[CLK_U74_CORE0] = starfive_clk_gate("u74_core0", UNKNOWN, base + 0x6C);
+ clks[CLK_U74_CORE1] = starfive_clk_gated_divider("u74_core1", "", base + 0x70, 4);
+ clks[CLK_U74_AXI] = starfive_clk_gate("u74_axi", UNKNOWN, base + 0x74);
+ clks[CLK_U74RTC_TOGGLE] = starfive_clk_gate("u74rtc_toggle", UNKNOWN, base + 0x78);
+ clks[CLK_SGDMA2P_AXI] = starfive_clk_gate("sgdma2p_axi", UNKNOWN, base + 0x7C);
+ clks[CLK_DMA2PNOC_AXI] = starfive_clk_gate("dma2pnoc_axi", UNKNOWN, base + 0x80);
+ clks[CLK_SGDMA2P_AHB] = starfive_clk_gate("sgdma2p_ahb", UNKNOWN, base + 0x84);
+ clks[CLK_DLA_BUS] = starfive_clk_divider("dla_bus", UNKNOWN, base + 0x88, 3);
+ clks[CLK_DLA_AXI] = starfive_clk_gate("dla_axi", UNKNOWN, base + 0x8C);
+ clks[CLK_DLANOC_AXI] = starfive_clk_gate("dlanoc_axi", UNKNOWN, base + 0x90);
+ clks[CLK_DLA_APB] = starfive_clk_gate("dla_apb", UNKNOWN, base + 0x94);
+ clks[CLK_VP6_CORE] = starfive_clk_gated_divider("vp6_core", UNKNOWN, base + 0x98, 3);
+ clks[CLK_VP6BUS_SRC] = starfive_clk_divider("vp6bus_src", UNKNOWN, base + 0x9C, 3);
+ clks[CLK_VP6_AXI] = starfive_clk_gated_divider("vp6_axi", UNKNOWN, base + 0xA0, 3);
+ clks[CLK_VCDECBUS_SRC] = starfive_clk_divider("vcdecbus_src", UNKNOWN, base + 0xA4, 3);
+ clks[CLK_VDEC_BUS] = starfive_clk_divider("vdec_bus", UNKNOWN, base + 0xA8, 4);
+ clks[CLK_VDEC_AXI] = starfive_clk_gate("vdec_axi", UNKNOWN, base + 0xAC);
+ clks[CLK_VDECBRG_MAIN] = starfive_clk_gate("vdecbrg_mainclk", UNKNOWN, base + 0xB0);
+ clks[CLK_VDEC_BCLK] = starfive_clk_gated_divider("vdec_bclk", UNKNOWN, base + 0xB4, 4);
+ clks[CLK_VDEC_CCLK] = starfive_clk_gated_divider("vdec_cclk", UNKNOWN, base + 0xB8, 4);
+ clks[CLK_VDEC_APB] = starfive_clk_gate("vdec_apb", UNKNOWN, base + 0xBC);
+ clks[CLK_JPEG_AXI] = starfive_clk_gated_divider("jpeg_axi", UNKNOWN, base + 0xC0, 4);
+ clks[CLK_JPEG_CCLK] = starfive_clk_gated_divider("jpeg_cclk", UNKNOWN, base + 0xC4, 4);
+ clks[CLK_JPEG_APB] = starfive_clk_gate("jpeg_apb", UNKNOWN, base + 0xC8);
+ clks[CLK_GC300_2X] = starfive_clk_gated_divider("gc300_2x", UNKNOWN, base + 0xCC, 4);
+ clks[CLK_GC300_AHB] = starfive_clk_gate("gc300_ahb", UNKNOWN, base + 0xD0);
+ clks[CLK_JPCGC300_AXIBUS] = starfive_clk_divider("jpcgc300_axibus", UNKNOWN, base + 0xD4, 4);
+ clks[CLK_GC300_AXI] = starfive_clk_gate("gc300_axi", UNKNOWN, base + 0xD8);
+ clks[CLK_JPCGC300_MAIN] = starfive_clk_gate("jpcgc300_mainclk", UNKNOWN, base + 0xDC);
+ clks[CLK_VENC_BUS] = starfive_clk_divider("venc_bus", UNKNOWN, base + 0xE0, 4);
+ clks[CLK_VENC_AXI] = starfive_clk_gate("venc_axi", UNKNOWN, base + 0xE4);
+ clks[CLK_VENCBRG_MAIN] = starfive_clk_gate("vencbrg_mainclk", UNKNOWN, base + 0xE8);
+ clks[CLK_VENC_BCLK] = starfive_clk_gated_divider("venc_bclk", UNKNOWN, base + 0xEC, 4);
+ clks[CLK_VENC_CCLK] = starfive_clk_gated_divider("venc_cclk", UNKNOWN, base + 0xF0, 4);
+ clks[CLK_VENC_APB] = starfive_clk_gate("venc_apb", UNKNOWN, base + 0xF4);
+ clks[CLK_DDRPLL_DIV2] = starfive_clk_gated_divider("ddrpll_div2", UNKNOWN, base + 0xF8, 2);
+ clks[CLK_DDRPLL_DIV4] = starfive_clk_gated_divider("ddrpll_div4", UNKNOWN, base + 0xFC, 2);
+ clks[CLK_DDRPLL_DIV8] = starfive_clk_gated_divider("ddrpll_div8", UNKNOWN, base + 0x100, 2);
+ clks[CLK_DDROSC_DIV2] = starfive_clk_gated_divider("ddrosc_div2", UNKNOWN, base + 0x104, 2);
+ clks[CLK_DDRC0] = starfive_clk_mux("ddrc0", base + 0x108, 2, ddrc0_sels, ARRAY_SIZE(ddrc0_sels));
+ clks[CLK_DDRC1] = starfive_clk_mux("ddrc1", base + 0x10C, 2, ddrc1_sels, ARRAY_SIZE(ddrc1_sels));
+ clks[CLK_DDRPHY_APB] = starfive_clk_gate("ddrphy_apb", UNKNOWN, base + 0x110);
+ clks[CLK_NOC_ROB] = starfive_clk_divider("noc_rob", UNKNOWN, base + 0x114, 4);
+ clks[CLK_NOC_COG] = starfive_clk_divider("noc_cog", UNKNOWN, base + 0x118, 4);
+ clks[CLK_NNE_AHB] = starfive_clk_gate("nne_ahb", UNKNOWN, base + 0x11C);
+ clks[CLK_NNEBUS_SRC1] = starfive_clk_divider("nnebus_src1", UNKNOWN, base + 0x120, 3);
+ clks[CLK_NNE_BUS] = starfive_clk_mux("nne_bus", base + 0x124, 2, nne_bus_sels, ARRAY_SIZE(nne_bus_sels));
+ clks[CLK_NNE_AXI] = starfive_clk_gate("nne_axi", UNKNOWN, base + 0x128);
+ clks[CLK_NNENOC_AXI] = starfive_clk_gate("nnenoc_axi", UNKNOWN, base + 0x12C);
+ clks[CLK_DLASLV_AXI] = starfive_clk_gate("dlaslv_axi", UNKNOWN, base + 0x130);
+ clks[CLK_DSPX2C_AXI] = starfive_clk_gate("dspx2c_axi", UNKNOWN, base + 0x134);
+ clks[CLK_HIFI4_SRC] = starfive_clk_divider("hifi4_src", UNKNOWN, base + 0x138, 3);
+ clks[CLK_HIFI4_COREFREE] = starfive_clk_divider("hifi4_corefree", UNKNOWN, base + 0x13C, 4);
+ clks[CLK_HIFI4_CORE] = starfive_clk_gate("hifi4_core", UNKNOWN, base + 0x140);
+ clks[CLK_HIFI4_BUS] = starfive_clk_divider("hifi4_bus", UNKNOWN, base + 0x144, 4);
+ clks[CLK_HIFI4_AXI] = starfive_clk_gate("hifi4_axi", UNKNOWN, base + 0x148);
+ clks[CLK_HIFI4NOC_AXI] = starfive_clk_gate("hifi4noc_axi", UNKNOWN, base + 0x14C);
+ clks[CLK_SGDMA1P_BUS] = starfive_clk_divider("sgdma1p_bus", UNKNOWN, base + 0x150, 4);
+ clks[CLK_SGDMA1P_AXI] = starfive_clk_gate("sgdma1p_axi", UNKNOWN, base + 0x154);
+ clks[CLK_DMA1P_AXI] = starfive_clk_gate("dma1p_axi", UNKNOWN, base + 0x158);
+ clks[CLK_X2C_AXI] = starfive_clk_gated_divider("x2c_axi", UNKNOWN, base + 0x15C, 4);
+ clks[CLK_USB_BUS] = starfive_clk_divider("usb_bus", UNKNOWN, base + 0x160, 4);
+ clks[CLK_USB_AXI] = starfive_clk_gate("usb_axi", UNKNOWN, base + 0x164);
+ clks[CLK_USBNOC_AXI] = starfive_clk_gate("usbnoc_axi", UNKNOWN, base + 0x168);
+ clks[CLK_USBPHY_ROOTDIV] = starfive_clk_divider("usbphy_rootdiv", UNKNOWN, base + 0x16C, 3);
+ clks[CLK_USBPHY_125M] = starfive_clk_gated_divider("usbphy_125m", UNKNOWN, base + 0x170, 4);
+ clks[CLK_USBPHY_PLLDIV25M] = starfive_clk_gated_divider("usbphy_plldiv25m", UNKNOWN, base + 0x174, 6);
+ clks[CLK_USBPHY_25M] = starfive_clk_mux("usbphy_25m", base + 0x178, 1, usbphy_25m_sels, ARRAY_SIZE(usbphy_25m_sels));
+ clks[CLK_AUDIO_DIV] = starfive_clk_divider("audio_div", UNKNOWN, base + 0x17C, 18);
+ clks[CLK_AUDIO_SRC] = starfive_clk_gate("audio_src", UNKNOWN, base + 0x180);
+ clks[CLK_AUDIO_12288] = starfive_clk_gate("audio_12288", UNKNOWN, base + 0x184);
+ clks[CLK_VIN_SRC] = starfive_clk_gated_divider("vin_src", UNKNOWN, base + 0x188, 3);
+ clks[CLK_ISP0_BUS] = starfive_clk_divider("isp0_bus", UNKNOWN, base + 0x18C, 4);
+ clks[CLK_ISP0_AXI] = starfive_clk_gate("isp0_axi", UNKNOWN, base + 0x190);
+ clks[CLK_ISP0NOC_AXI] = starfive_clk_gate("isp0noc_axi", UNKNOWN, base + 0x194);
+ clks[CLK_ISPSLV_AXI] = starfive_clk_gate("ispslv_axi", UNKNOWN, base + 0x198);
+ clks[CLK_ISP1_BUS] = starfive_clk_divider("isp1_bus", UNKNOWN, base + 0x19C, 4);
+ clks[CLK_ISP1_AXI] = starfive_clk_gate("isp1_axi", UNKNOWN, base + 0x1A0);
+ clks[CLK_ISP1NOC_AXI] = starfive_clk_gate("isp1noc_axi", UNKNOWN, base + 0x1A4);
+ clks[CLK_VIN_BUS] = starfive_clk_divider("vin_bus", UNKNOWN, base + 0x1A8, 4);
+ clks[CLK_VIN_AXI] = starfive_clk_gate("vin_axi", UNKNOWN, base + 0x1AC);
+ clks[CLK_VINNOC_AXI] = starfive_clk_gate("vinnoc_axi", UNKNOWN, base + 0x1B0);
+ clks[CLK_VOUT_SRC] = starfive_clk_gated_divider("vout_src", UNKNOWN, base + 0x1B4, 3);
+ clks[CLK_DISPBUS_SRC] = starfive_clk_divider("dispbus_src", UNKNOWN, base + 0x1B8, 3);
+ clks[CLK_DISP_BUS] = starfive_clk_divider("disp_bus", UNKNOWN, base + 0x1BC, 3);
+ clks[CLK_DISP_AXI] = starfive_clk_gate("disp_axi", UNKNOWN, base + 0x1C0);
+ clks[CLK_DISPNOC_AXI] = starfive_clk_gate("dispnoc_axi", UNKNOWN, base + 0x1C4);
+ clks[CLK_SDIO0_AHB] = starfive_clk_gate("sdio0_ahb", UNKNOWN, base + 0x1C8);
+ clks[CLK_SDIO0_CCLKINT] = starfive_clk_gated_divider("sdio0_cclkint", UNKNOWN, base + 0x1CC, 5);
+ clks[CLK_SDIO0_CCLKINT_INV] = starfive_clk_gate_dis("sdio0_cclkint_inv", UNKNOWN, base + 0x1D0);
+ clks[CLK_SDIO1_AHB] = starfive_clk_gate("sdio1_ahb", UNKNOWN, base + 0x1D4);
+ clks[CLK_SDIO1_CCLKINT] = starfive_clk_gated_divider("sdio1_cclkint", UNKNOWN, base + 0x1D8, 5);
+ clks[CLK_SDIO1_CCLKINT_INV] = starfive_clk_gate_dis("sdio1_cclkint_inv", UNKNOWN, base + 0x1DC);
+ clks[CLK_GMAC_AHB] = starfive_clk_gate("gmac_ahb", UNKNOWN, base + 0x1E0);
+ clks[CLK_GMAC_ROOT_DIV] = starfive_clk_divider("gmac_root_div", UNKNOWN, base + 0x1E4, 4);
+ clks[CLK_GMAC_PTP_REF] = starfive_clk_gated_divider("gmac_ptp_refclk", UNKNOWN, base + 0x1E8, 5);
+ clks[CLK_GMAC_GTX] = starfive_clk_gated_divider("gmac_gtxclk", UNKNOWN, base + 0x1EC, 8);
+ clks[CLK_GMAC_RMII_TX] = starfive_clk_gated_divider("gmac_rmii_txclk", UNKNOWN, base + 0x1F0, 4);
+ clks[CLK_GMAC_RMII_RX] = starfive_clk_gated_divider("gmac_rmii_rxclk", UNKNOWN, base + 0x1F4, 4);
+ clks[CLK_GMAC_TX] = starfive_clk_mux("gmac_tx", base + 0x1F8, 2, gmac_tx_sels, ARRAY_SIZE(gmac_tx_sels));
+ clks[CLK_GMAC_TX_INV] = starfive_clk_gate_dis("gmac_tx_inv", UNKNOWN, base + 0x1FC);
+ clks[CLK_GMAC_RX_PRE] = starfive_clk_mux("gmac_rx_pre", base + 0x200, 1, gmac_rx_pre_sels, ARRAY_SIZE(gmac_rx_pre_sels));
+ clks[CLK_GMAC_RX_INV] = starfive_clk_gate_dis("gmac_rx_inv", UNKNOWN, base + 0x204);
+ clks[CLK_GMAC_RMII] = starfive_clk_gate("gmac_rmii", UNKNOWN, base + 0x208);
+ clks[CLK_GMAC_TOPHYREF] = starfive_clk_gated_divider("gmac_tophyref", UNKNOWN, base + 0x20C, 7);
+ clks[CLK_SPI2AHB_AHB] = starfive_clk_gate("spi2ahb_ahb", UNKNOWN, base + 0x210);
+ clks[CLK_SPI2AHB_CORE] = starfive_clk_gated_divider("spi2ahb_core", UNKNOWN, base + 0x214, 5);
+ clks[CLK_EZMASTER_AHB] = starfive_clk_gate("ezmaster_ahb", UNKNOWN, base + 0x218);
+ clks[CLK_E24_AHB] = starfive_clk_gate("e24_ahb", UNKNOWN, base + 0x21C);
+ clks[CLK_E24RTC_TOGGLE] = starfive_clk_gate("e24rtc_toggle", UNKNOWN, base + 0x220);
+ clks[CLK_QSPI_AHB] = starfive_clk_gate("qspi_ahb", UNKNOWN, base + 0x224);
+ clks[CLK_QSPI_APB] = starfive_clk_gate("qspi_apb", UNKNOWN, base + 0x228);
+ clks[CLK_QSPI_REF] = starfive_clk_gated_divider("qspi_refclk", UNKNOWN, base + 0x22C, 5);
+ clks[CLK_SEC_AHB] = starfive_clk_gate("sec_ahb", UNKNOWN, base + 0x230);
+ clks[CLK_AES] = starfive_clk_gate("aes_clk", UNKNOWN, base + 0x234);
+ clks[CLK_SHA] = starfive_clk_gate("sha_clk", UNKNOWN, base + 0x238);
+ clks[CLK_PKA] = starfive_clk_gate("pka_clk", UNKNOWN, base + 0x23C);
+ clks[CLK_TRNG_APB] = starfive_clk_gate("trng_apb", UNKNOWN, base + 0x240);
+ clks[CLK_OTP_APB] = starfive_clk_gate("otp_apb", UNKNOWN, base + 0x244);
+ clks[CLK_UART0_APB] = starfive_clk_gate("uart0_apb", UNKNOWN, base + 0x248);
+ clks[CLK_UART0_CORE] = starfive_clk_gated_divider("uart0_core", UNKNOWN, base + 0x24C, 6);
+ clks[CLK_UART1_APB] = starfive_clk_gate("uart1_apb", UNKNOWN, base + 0x250);
+ clks[CLK_UART1_CORE] = starfive_clk_gated_divider("uart1_core", UNKNOWN, base + 0x254, 6);
+ clks[CLK_SPI0_APB] = starfive_clk_gate("spi0_apb", UNKNOWN, base + 0x258);
+ clks[CLK_SPI0_CORE] = starfive_clk_gated_divider("spi0_core", UNKNOWN, base + 0x25C, 6);
+ clks[CLK_SPI1_APB] = starfive_clk_gate("spi1_apb", UNKNOWN, base + 0x260);
+ clks[CLK_SPI1_CORE] = starfive_clk_gated_divider("spi1_core", UNKNOWN, base + 0x264, 6);
+ clks[CLK_I2C0_APB] = starfive_clk_gate("i2c0_apb", UNKNOWN, base + 0x268);
+ clks[CLK_I2C0_CORE] = starfive_clk_gated_divider("i2c0_core", UNKNOWN, base + 0x26C, 6);
+ clks[CLK_I2C1_APB] = starfive_clk_gate("i2c1_apb", UNKNOWN, base + 0x270);
+ clks[CLK_I2C1_CORE] = starfive_clk_gated_divider("i2c1_core", UNKNOWN, base + 0x274, 6);
+ clks[CLK_GPIO_APB] = starfive_clk_gate("gpio_apb", UNKNOWN, base + 0x278);
+ clks[CLK_UART2_APB] = starfive_clk_gate("uart2_apb", UNKNOWN, base + 0x27C);
+ clks[CLK_UART2_CORE] = starfive_clk_gated_divider("uart2_core", UNKNOWN, base + 0x280, 6);
+ clks[CLK_UART3_APB] = starfive_clk_gate("uart3_apb", UNKNOWN, base + 0x284);
+ clks[CLK_UART3_CORE] = starfive_clk_gated_divider("uart3_core", UNKNOWN, base + 0x288, 6);
+ clks[CLK_SPI2_APB] = starfive_clk_gate("spi2_apb", UNKNOWN, base + 0x28C);
+ clks[CLK_SPI2_CORE] = starfive_clk_gated_divider("spi2_core", UNKNOWN, base + 0x290, 6);
+ clks[CLK_SPI3_APB] = starfive_clk_gate("spi3_apb", UNKNOWN, base + 0x294);
+ clks[CLK_SPI3_CORE] = starfive_clk_gated_divider("spi3_core", UNKNOWN, base + 0x298, 6);
+ clks[CLK_I2C2_APB] = starfive_clk_gate("i2c2_apb", UNKNOWN, base + 0x29C);
+ clks[CLK_I2C2_CORE] = starfive_clk_gated_divider("i2c2_core", UNKNOWN, base + 0x2A0, 6);
+ clks[CLK_I2C3_APB] = starfive_clk_gate("i2c3_apb", UNKNOWN, base + 0x2A4);
+ clks[CLK_I2C3_CORE] = starfive_clk_gated_divider("i2c3_core", UNKNOWN, base + 0x2A8, 6);
+ clks[CLK_WDTIMER_APB] = starfive_clk_gate("wdtimer_apb", UNKNOWN, base + 0x2AC);
+ clks[CLK_WDT_CORE] = starfive_clk_gated_divider("wdt_coreclk", UNKNOWN, base + 0x2B0, 6);
+ clks[CLK_TIMER0_CORE] = starfive_clk_gated_divider("timer0_coreclk", UNKNOWN, base + 0x2B4, 6);
+ clks[CLK_TIMER1_CORE] = starfive_clk_gated_divider("timer1_coreclk", UNKNOWN, base + 0x2B8, 6);
+ clks[CLK_TIMER2_CORE] = starfive_clk_gated_divider("timer2_coreclk", UNKNOWN, base + 0x2BC, 6);
+ clks[CLK_TIMER3_CORE] = starfive_clk_gated_divider("timer3_coreclk", UNKNOWN, base + 0x2C0, 6);
+ clks[CLK_TIMER4_CORE] = starfive_clk_gated_divider("timer4_coreclk", UNKNOWN, base + 0x2C4, 6);
+ clks[CLK_TIMER5_CORE] = starfive_clk_gated_divider("timer5_coreclk", UNKNOWN, base + 0x2C8, 6);
+ clks[CLK_TIMER6_CORE] = starfive_clk_gated_divider("timer6_coreclk", UNKNOWN, base + 0x2CC, 6);
+ clks[CLK_VP6INTC_APB] = starfive_clk_gate("vp6intc_apb", UNKNOWN, base + 0x2D0);
+ clks[CLK_PWM_APB] = starfive_clk_gate("pwm_apb", UNKNOWN, base + 0x2D4);
+ clks[CLK_MSI_APB] = starfive_clk_gate("msi_apb", UNKNOWN, base + 0x2D8);
+ clks[CLK_TEMP_APB] = starfive_clk_gate("temp_apb", UNKNOWN, base + 0x2DC);
+ clks[CLK_TEMP_SENSE] = starfive_clk_gated_divider("temp_sense", UNKNOWN, base + 0x2E0, 5);
+ clks[CLK_SYSERR_APB] = starfive_clk_gate("syserr_apb", UNKNOWN, base + 0x2E4);
+}
+
+static struct clk_onecell_data clk_data;
+
+static int starfive_clkgen_clk_probe(struct device_d *dev)
+{
+ struct resource *iores;
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+
+ starfive_clkgen_init(dev->device_node, IOMEM(iores->start));
+
+ clk_data.clks = clks;
+ clk_data.clk_num = ARRAY_SIZE(clks);
+ of_clk_add_provider(dev->device_node, of_clk_src_onecell_get,
+ &clk_data);
+
+ return 0;
+}
+
+static __maybe_unused struct of_device_id starfive_clkgen_clk_dt_ids[] = {
+ { .compatible = "starfive,jh7100-clkgen" },
+ { /* sentinel */ }
+};
+
+static struct driver_d starfive_clkgen_clk_driver = {
+ .probe = starfive_clkgen_clk_probe,
+ .name = "starfive-clkgen",
+ .of_compatible = starfive_clkgen_clk_dt_ids,
+};
+core_platform_driver(starfive_clkgen_clk_driver);
diff --git a/drivers/clocksource/timer-clint.c b/drivers/clocksource/timer-clint.c
index b7360010bd..412ce3e1e9 100644
--- a/drivers/clocksource/timer-clint.c
+++ b/drivers/clocksource/timer-clint.c
@@ -17,6 +17,7 @@
#include <linux/err.h>
#include <io.h>
#include <asm/timer.h>
+#include <asm/system.h>
#define CLINT_TIMER_VAL_OFF 0xbff8
@@ -63,8 +64,8 @@ static int clint_timer_init_dt(struct device_d* dev)
{
struct resource *iores;
- /* one timer is enough */
- if (clint_timer_val)
+ /* one timer is enough. Only M-Mode */
+ if (clint_timer_val || riscv_mode() != RISCV_M_MODE)
return 0;
iores = dev_request_mem_resource(dev, 0);
@@ -72,7 +73,7 @@ static int clint_timer_init_dt(struct device_d* dev)
return PTR_ERR(iores);
clint_timer_val = IOMEM(iores->start) + CLINT_TIMER_VAL_OFF;
- dev_info(dev, "running at %lu Hz\n", riscv_timebase);
+ dev_dbg(dev, "running at %lu Hz\n", riscv_timebase);
clint_clocksource.mult = clocksource_hz2mult(riscv_timebase, clint_clocksource.shift);
diff --git a/drivers/clocksource/timer-riscv.c b/drivers/clocksource/timer-riscv.c
index ef67cff475..5a517fe6b4 100644
--- a/drivers/clocksource/timer-riscv.c
+++ b/drivers/clocksource/timer-riscv.c
@@ -12,6 +12,7 @@
#include <clock.h>
#include <asm/timer.h>
#include <asm/csr.h>
+#include <asm/system.h>
static u64 notrace riscv_timer_get_count_sbi(void)
{
@@ -45,7 +46,7 @@ static u64 notrace riscv_timer_get_count_rdcycle(void)
static u64 notrace riscv_timer_get_count(void)
{
- if (IS_ENABLED(CONFIG_RISCV_SBI))
+ if (riscv_mode() == RISCV_S_MODE)
return riscv_timer_get_count_sbi();
else
return riscv_timer_get_count_rdcycle();
@@ -59,7 +60,7 @@ static struct clocksource riscv_clocksource = {
static int riscv_timer_init(struct device_d* dev)
{
- dev_info(dev, "running at %lu Hz\n", riscv_timebase);
+ dev_dbg(dev, "running at %lu Hz\n", riscv_timebase);
riscv_clocksource.mult = clocksource_hz2mult(riscv_timebase, riscv_clocksource.shift);
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index a8ee9e58b8..98a44fbbb5 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -171,6 +171,14 @@ config GPIO_SIFIVE
help
Say yes here to support the GPIO device on SiFive SoCs.
+config GPIO_STARFIVE
+ bool "StarFive GPIO support"
+ depends on SOC_STARFIVE || CROSS_COMPILE
+ depends on OF_GPIO
+ select GPIO_GENERIC
+ help
+ Say yes here to support the GPIO device on StarFive SoCs.
+
config GPIO_LIBFTDI1
bool "libftdi1 driver"
depends on SANDBOX
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 25e12105d8..638cbb19a3 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -24,3 +24,4 @@ obj-$(CONFIG_GPIO_SX150X) += gpio-sx150x.o
obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o
obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o
obj-$(CONFIG_GPIO_SIFIVE) += gpio-sifive.o
+obj-$(CONFIG_GPIO_STARFIVE) += gpio-starfive-vic.o
diff --git a/drivers/gpio/gpio-starfive-vic.c b/drivers/gpio/gpio-starfive-vic.c
new file mode 100644
index 0000000000..baa4f584d5
--- /dev/null
+++ b/drivers/gpio/gpio-starfive-vic.c
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * COPYRIGHT 2020 Shanghai StarFive Technology Co., Ltd.
+ */
+
+#include <linux/basic_mmio_gpio.h>
+#include <linux/reset.h>
+#include <linux/clk.h>
+#include <printk.h>
+#include <driver.h>
+#include <errno.h>
+#include <pinctrl.h>
+
+#define GPIO_EN 0x0
+#define GPIO_IS_LOW 0x10
+#define GPIO_IS_HIGH 0x14
+#define GPIO_IBE_LOW 0x18
+#define GPIO_IBE_HIGH 0x1c
+#define GPIO_IEV_LOW 0x20
+#define GPIO_IEV_HIGH 0x24
+#define GPIO_IE_LOW 0x28
+#define GPIO_IE_HIGH 0x2c
+#define GPIO_IC_LOW 0x30
+#define GPIO_IC_HIGH 0x34
+//read only
+#define GPIO_RIS_LOW 0x38
+#define GPIO_RIS_HIGH 0x3c
+#define GPIO_MIS_LOW 0x40
+#define GPIO_MIS_HIGH 0x44
+#define GPIO_DIN_LOW 0x48
+#define GPIO_DIN_HIGH 0x4c
+
+#define GPIO_DOUT_X_REG 0x50
+#define GPIO_DOEN_X_REG 0x54
+
+#define MAX_GPIO 64
+
+struct starfive_gpio {
+ void __iomem *base;
+ struct gpio_chip gc;
+};
+
+#define to_starfive_gpio(gc) container_of(gc, struct starfive_gpio, gc)
+
+static int starfive_direction_input(struct gpio_chip *gc, unsigned offset)
+{
+ struct starfive_gpio *chip = to_starfive_gpio(gc);
+
+ if (offset >= gc->ngpio)
+ return -EINVAL;
+
+ writel(0x1, chip->base + GPIO_DOEN_X_REG + offset * 8);
+
+ return 0;
+}
+
+static int starfive_direction_output(struct gpio_chip *gc, unsigned offset, int value)
+{
+ struct starfive_gpio *chip = to_starfive_gpio(gc);
+
+ if (offset >= gc->ngpio)
+ return -EINVAL;
+ writel(0x0, chip->base + GPIO_DOEN_X_REG + offset * 8);
+ writel(value, chip->base + GPIO_DOUT_X_REG + offset * 8);
+
+ return 0;
+}
+
+static int starfive_get_direction(struct gpio_chip *gc, unsigned offset)
+{
+ struct starfive_gpio *chip = to_starfive_gpio(gc);
+
+ if (offset >= gc->ngpio)
+ return -EINVAL;
+
+ return readl(chip->base + GPIO_DOEN_X_REG + offset * 8) & 0x1;
+}
+
+static int starfive_get_value(struct gpio_chip *gc, unsigned offset)
+{
+ struct starfive_gpio *chip = to_starfive_gpio(gc);
+ int value;
+
+ if (offset >= gc->ngpio)
+ return -EINVAL;
+
+ if(offset < 32){
+ value = readl(chip->base + GPIO_DIN_LOW);
+ return (value >> offset) & 0x1;
+ } else {
+ value = readl(chip->base + GPIO_DIN_HIGH);
+ return (value >> (offset - 32)) & 0x1;
+ }
+}
+
+static void starfive_set_value(struct gpio_chip *gc, unsigned offset, int value)
+{
+ struct starfive_gpio *chip = to_starfive_gpio(gc);
+
+ if (offset >= gc->ngpio)
+ return;
+
+ writel(value, chip->base + GPIO_DOUT_X_REG + offset * 8);
+}
+
+static struct gpio_ops starfive_gpio_ops = {
+ .direction_input = starfive_direction_input,
+ .direction_output = starfive_direction_output,
+ .get_direction = starfive_get_direction,
+ .get = starfive_get_value,
+ .set = starfive_set_value,
+};
+
+static int starfive_gpio_probe(struct device_d *dev)
+{
+ struct starfive_gpio *chip;
+ struct resource *res;
+ struct clk *clk;
+ int ret;
+
+ clk = clk_get(dev, NULL);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ clk_enable(clk);
+
+ ret = device_reset(dev);
+ if (ret)
+ return ret;
+
+ ret = pinctrl_single_probe(dev);
+ if (ret)
+ return ret;
+
+ res = dev_get_resource(dev, IORESOURCE_MEM, 0);
+ if (IS_ERR(res))
+ return PTR_ERR(res);
+
+ chip = xzalloc(sizeof(*chip));
+ chip->base = IOMEM(res->start);
+
+ chip->gc.base = -1;
+ chip->gc.ngpio = MAX_GPIO;
+ chip->gc.dev = dev;
+ chip->gc.ops = &starfive_gpio_ops;
+
+ /* Disable all GPIO interrupts */
+ iowrite32(0, chip->base + GPIO_IE_HIGH);
+ iowrite32(0, chip->base + GPIO_IE_LOW);
+
+ ret = gpiochip_add(&chip->gc);
+ if (ret) {
+ dev_err(dev, "could not add gpiochip\n");
+ gpiochip_remove(&chip->gc);
+ return ret;
+ }
+
+ writel(1, chip->base + GPIO_EN);
+
+ return 0;
+}
+
+static const struct of_device_id starfive_gpio_match[] = {
+ { .compatible = "starfive,gpio0", },
+ { },
+};
+
+static struct driver_d starfive_gpio_driver = {
+ .probe = starfive_gpio_probe,
+ .name = "starfive_gpio",
+ .of_compatible = starfive_gpio_match,
+};
+postcore_platform_driver(starfive_gpio_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Huan Feng <huan.feng@starfivetech.com>");
+MODULE_DESCRIPTION("Starfive VIC GPIO generator driver");
diff --git a/drivers/hw_random/Kconfig b/drivers/hw_random/Kconfig
index a84c03efef..764911f4d3 100644
--- a/drivers/hw_random/Kconfig
+++ b/drivers/hw_random/Kconfig
@@ -36,4 +36,11 @@ config HW_RANDOM_VIRTIO
This driver provides guest-side support for the virtual Random Number
Generator hardware.
+config HW_RANDOM_STARFIVE
+ tristate "StarFive Random Number Generator"
+ depends on SOC_STARFIVE || COMPILE_TEST
+ help
+ This driver provides barebox support for the Random Number
+ Generator hardware found on the StarFive family of SoCs.
+
endif
diff --git a/drivers/hw_random/Makefile b/drivers/hw_random/Makefile
index 4bab3967fc..4cf33d2d93 100644
--- a/drivers/hw_random/Makefile
+++ b/drivers/hw_random/Makefile
@@ -3,3 +3,4 @@ obj-$(CONFIG_HWRNG_MXC_RNGC) += mxc-rngc.o
obj-$(CONFIG_HWRNG_STM32) += stm32-rng.o
obj-$(CONFIG_HWRNG_DEV_RANDOM) += dev-random.o
obj-$(CONFIG_HW_RANDOM_VIRTIO) += virtio-rng.o
+obj-$(CONFIG_HW_RANDOM_STARFIVE) += starfive-vic-rng.o
diff --git a/drivers/hw_random/starfive-vic-rng.c b/drivers/hw_random/starfive-vic-rng.c
new file mode 100644
index 0000000000..f7b7585884
--- /dev/null
+++ b/drivers/hw_random/starfive-vic-rng.c
@@ -0,0 +1,208 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * COPYRIGHT 2020 Shanghai StarFive Technology Co., Ltd.
+ */
+#include <common.h>
+#include <linux/err.h>
+#include <io.h>
+#include <of.h>
+#include <driver.h>
+#include <linux/hw_random.h>
+#include <linux/reset.h>
+#include <linux/clk.h>
+
+#define VIC_RAND_LEN 4
+
+#define VIC_CTRL 0x00
+#define VIC_MODE 0x04
+#define VIC_SMODE 0x08
+#define VIC_STAT 0x0C
+#define VIC_IE 0x10
+#define VIC_ISTAT 0x14
+#define VIC_ALARM 0x18
+#define VIC_BUILD_ID 0x1C
+#define VIC_FEATURES 0x20
+#define VIC_RAND0 0x24
+#define VIC_NPA_DATA0 0x34
+#define VIC_SEED0 0x74
+#define VIC_IA_RDATA 0xA4
+#define VIC_IA_WDATA 0xA8
+#define VIC_IA_ADDR 0xAC
+#define VIC_IA_CMD 0xB0
+
+/* CTRL */
+#define VIC_CTRL_CMD_NOP 0
+#define VIC_CTRL_CMD_GEN_NOISE 1
+#define VIC_CTRL_CMD_GEN_NONCE 2
+#define VIC_CTRL_CMD_CREATE_STATE 3
+#define VIC_CTRL_CMD_RENEW_STATE 4
+#define VIC_CTRL_CMD_REFRESH_ADDIN 5
+#define VIC_CTRL_CMD_GEN_RANDOM 6
+#define VIC_CTRL_CMD_ADVANCE_STATE 7
+#define VIC_CTRL_CMD_KAT 8
+#define VIC_CTRL_CMD_ZEROIZE 15
+
+/* SMODE */
+#define _VIC_SMODE_SECURE_EN 1
+
+#define VIC_SMODE_SECURE_EN(x) ((x) << _VIC_SMODE_SECURE_EN)
+
+/* STAT */
+#define _VIC_STAT_BUSY 31
+
+#define VIC_STAT_BUSY (1UL << _VIC_STAT_BUSY)
+
+/* IE */
+#define _VIC_IE_GLBL 31
+#define _VIC_IE_DONE 4
+#define _VIC_IE_ALARMS 3
+#define _VIC_IE_NOISE_RDY 2
+#define _VIC_IE_KAT_COMPLETE 1
+#define _VIC_IE_ZEROIZE 0
+
+#define VIC_IE_GLBL (1UL << _VIC_IE_GLBL)
+#define VIC_IE_DONE (1UL << _VIC_IE_DONE)
+#define VIC_IE_ALARMS (1UL << _VIC_IE_ALARMS)
+#define VIC_IE_NOISE_RDY (1UL << _VIC_IE_NOISE_RDY)
+#define VIC_IE_KAT_COMPLETE (1UL << _VIC_IE_KAT_COMPLETE)
+#define VIC_IE_ZEROIZE (1UL << _VIC_IE_ZEROIZE)
+#define VIC_IE_ALL (VIC_IE_GLBL | VIC_IE_DONE | VIC_IE_ALARMS | \
+ VIC_IE_NOISE_RDY | VIC_IE_KAT_COMPLETE | VIC_IE_ZEROIZE)
+
+#define to_vic_rng(p) container_of(p, struct vic_rng, rng)
+
+struct vic_rng {
+ struct device_d *dev;
+ void __iomem *base;
+ struct hwrng rng;
+};
+
+static inline void vic_wait_till_idle(struct vic_rng *hrng)
+{
+ while(readl(hrng->base + VIC_STAT) & VIC_STAT_BUSY)
+ ;
+}
+
+static inline void vic_rng_irq_mask_clear(struct vic_rng *hrng)
+{
+ u32 data = readl(hrng->base + VIC_ISTAT);
+ writel(data, hrng->base + VIC_ISTAT);
+ writel(0, hrng->base + VIC_ALARM);
+}
+
+static int vic_trng_cmd(struct vic_rng *hrng, u32 cmd)
+{
+ vic_wait_till_idle(hrng);
+
+ switch (cmd) {
+ case VIC_CTRL_CMD_NOP:
+ case VIC_CTRL_CMD_GEN_NOISE:
+ case VIC_CTRL_CMD_GEN_NONCE:
+ case VIC_CTRL_CMD_CREATE_STATE:
+ case VIC_CTRL_CMD_RENEW_STATE:
+ case VIC_CTRL_CMD_REFRESH_ADDIN:
+ case VIC_CTRL_CMD_GEN_RANDOM:
+ case VIC_CTRL_CMD_ADVANCE_STATE:
+ case VIC_CTRL_CMD_KAT:
+ case VIC_CTRL_CMD_ZEROIZE:
+ writel(cmd, hrng->base + VIC_CTRL);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int vic_rng_init(struct hwrng *rng)
+{
+ struct vic_rng *hrng = to_vic_rng(rng);
+ struct clk *clk;
+ int ret;
+
+ clk = clk_get(rng->dev, NULL);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ clk_enable(clk);
+
+ ret = device_reset(rng->dev);
+ if (ret)
+ return ret;
+
+ // clear register: ISTAT
+ vic_rng_irq_mask_clear(hrng);
+
+ // set mission mode
+ writel(VIC_SMODE_SECURE_EN(1), hrng->base + VIC_SMODE);
+
+ vic_trng_cmd(hrng, VIC_CTRL_CMD_GEN_NOISE);
+ vic_wait_till_idle(hrng);
+
+ // set interrupt
+ writel(VIC_IE_ALL, hrng->base + VIC_IE);
+
+ // zeroize
+ vic_trng_cmd(hrng, VIC_CTRL_CMD_ZEROIZE);
+
+ vic_wait_till_idle(hrng);
+
+ return 0;
+}
+
+static int vic_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
+{
+ struct vic_rng *hrng = to_vic_rng(rng);
+
+ vic_trng_cmd(hrng, VIC_CTRL_CMD_ZEROIZE);
+ vic_trng_cmd(hrng, VIC_CTRL_CMD_GEN_NOISE);
+ vic_trng_cmd(hrng, VIC_CTRL_CMD_CREATE_STATE);
+
+ vic_wait_till_idle(hrng);
+ max = min_t(size_t, max, VIC_RAND_LEN * 4);
+
+ writel(0x0, hrng->base + VIC_MODE);
+ vic_trng_cmd(hrng, VIC_CTRL_CMD_GEN_RANDOM);
+
+ vic_wait_till_idle(hrng);
+ memcpy_fromio(buf, hrng->base + VIC_RAND0, max);
+ vic_trng_cmd(hrng, VIC_CTRL_CMD_ZEROIZE);
+
+ vic_wait_till_idle(hrng);
+ return max;
+}
+
+static int vic_rng_probe(struct device_d *dev)
+{
+ struct vic_rng *hrng;
+ struct resource *res;
+
+ hrng = xzalloc(sizeof(*hrng));
+
+ res = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(res))
+ return PTR_ERR(res);
+
+ hrng->base = IOMEM(res->start);
+ hrng->dev = dev;
+
+ hrng->rng.name = dev_name(dev);
+ hrng->rng.init = vic_rng_init;
+ hrng->rng.read = vic_rng_read;
+
+ return hwrng_register(dev, &hrng->rng);
+}
+
+static const struct of_device_id vic_rng_dt_ids[] = {
+ { .compatible = "starfive,vic-rng" },
+ { /* sentinel */ }
+};
+
+static struct driver_d vic_rng_driver = {
+ .name = "vic-rng",
+ .probe = vic_rng_probe,
+ .of_compatible = vic_rng_dt_ids,
+};
+device_platform_driver(vic_rng_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Huan Feng <huan.feng@starfivetech.com>");
+MODULE_DESCRIPTION("Starfive VIC random number generator driver");
diff --git a/drivers/mci/dw_mmc.c b/drivers/mci/dw_mmc.c
index 930b538adc..b402090ab3 100644
--- a/drivers/mci/dw_mmc.c
+++ b/drivers/mci/dw_mmc.c
@@ -17,6 +17,7 @@
#include <io.h>
#include <platform_data/dw_mmc.h>
#include <linux/bitops.h>
+#include <linux/reset.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <errno.h>
@@ -31,7 +32,7 @@ struct dwmci_host {
unsigned int fifo_size_bytes;
struct dwmci_idmac *idmac;
- unsigned long clkrate;
+ u32 clkrate;
int ciu_div;
u32 fifoth_val;
u32 pwren_value;
@@ -548,6 +549,7 @@ static int dwmci_init(struct mci_host *mci, struct device_d *dev)
static int dw_mmc_probe(struct device_d *dev)
{
+ struct reset_control *rst;
struct resource *iores;
struct dwmci_host *host;
struct dw_mmc_platform_data *pdata = dev->platform_data;
@@ -568,6 +570,15 @@ static int dw_mmc_probe(struct device_d *dev)
clk_enable(host->clk_biu);
clk_enable(host->clk_ciu);
+ rst = reset_control_get(dev, "reset");
+ if (IS_ERR(rst)) {
+ return PTR_ERR(rst);
+ } else if (rst) {
+ reset_control_assert(rst);
+ udelay(10);
+ reset_control_deassert(rst);
+ }
+
iores = dev_request_mem_resource(dev, 0);
if (IS_ERR(iores))
return PTR_ERR(iores);
@@ -606,7 +617,11 @@ static int dw_mmc_probe(struct device_d *dev)
else
host->pwren_value = 1;
- host->clkrate = clk_get_rate(host->clk_ciu);
+ if (of_device_is_compatible(dev->device_node, "starfive,jh7100-dw-mshc"))
+ of_property_read_u32(dev->device_node, "clock-frequency", &host->clkrate);
+ if (!host->clkrate)
+ host->clkrate = clk_get_rate(host->clk_ciu);
+
host->mci.f_min = host->clkrate / 510 / host->ciu_div;
if (host->mci.f_min < 200000)
host->mci.f_min = 200000;
@@ -625,6 +640,10 @@ static __maybe_unused struct of_device_id dw_mmc_compatible[] = {
}, {
.compatible = "rockchip,rk3288-dw-mshc",
}, {
+ .compatible = "snps,dw-mshc",
+ }, {
+ .compatible = "starfive,jh7100-dw-mshc",
+ }, {
/* sentinel */
}
};
diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index a094f3cbf5..92a73c8f1d 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -21,6 +21,7 @@
#include <of.h>
#include <linux/err.h>
#include <linux/sizes.h>
+#include <dma.h>
#define MAX_BUFFER_NUMBER 0xffffffff
@@ -1789,6 +1790,11 @@ static int mci_card_probe(struct mci *mci)
mci->cdevname = basprintf("disk%d", disknum);
}
+ if (!sector_buf)
+ sector_buf = dma_alloc(SECTOR_SIZE);
+
+ /* FIXME we don't check sector_buf against the device dma mask here */
+
rc = mci_startup(mci);
if (rc) {
dev_warn(&mci->dev, "Card's startup fails with %d\n", rc);
@@ -1850,15 +1856,6 @@ static int mci_set_probe(struct param_d *param, void *priv)
return 0;
}
-static int mci_init(void)
-{
- sector_buf = xmemalign(32, SECTOR_SIZE);
-
- return 0;
-}
-
-device_initcall(mci_init);
-
int mci_detect_card(struct mci_host *host)
{
int rc;
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 87674a2a29..7426dfc463 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -42,4 +42,14 @@ config ACPI_TEST
help
This is a simple Test driver to test the ACPI bus.
+config STARFIVE_PWRSEQ
+ bool "StarFive power sequencing driver"
+ depends on SOC_STARFIVE
+ help
+ This driver sets up a number of StarFive peripherals not matched
+ by more specific barebox drivers by deasserting reset lines, muxing
+ pins and/or enabling clocks. Peripherals set up by this can then
+ be accessed over /dev/mem or used from kernels which still depend
+ on bootloader for initialization.
+
endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 4d92465a1e..36743e6ae6 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_STATE_DRV) += state.o
obj-$(CONFIG_DEV_MEM) += mem.o
obj-$(CONFIG_UBOOTVAR) += ubootvar.o
obj-$(CONFIG_ACPI_TEST) += acpi-test.o
+obj-$(CONFIG_STARFIVE_PWRSEQ) += starfive-pwrseq.o
diff --git a/drivers/misc/starfive-pwrseq.c b/drivers/misc/starfive-pwrseq.c
new file mode 100644
index 0000000000..6236547bc5
--- /dev/null
+++ b/drivers/misc/starfive-pwrseq.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2021 Ahmad Fatoum, Pengutronix
+ */
+
+#include <driver.h>
+#include <init.h>
+#include <linux/reset.h>
+#include <dt-bindings/clock/starfive-jh7100.h>
+#include <linux/clk.h>
+
+struct starfive_pwrseq {
+ const char **names;
+};
+
+static int starfive_pwrseq_probe(struct device_d *dev)
+{
+ int ret;
+
+ ret = device_reset_all(dev);
+ if (ret)
+ return ret;
+
+ return of_platform_populate(dev->device_node, NULL, dev);
+}
+
+static struct of_device_id starfive_pwrseq_dt_ids[] = {
+ { .compatible = "starfive,axi-dma" },
+ { .compatible = "cm,cm521-vpu" },
+ { .compatible = "starfive,vic-sec" },
+ { .compatible = "sfc,tempsensor" },
+ { .compatible = "cm,codaj12-jpu-1" },
+ { .compatible = "cdns,xrp" },
+ { .compatible = "starfive,nne50" },
+ { .compatible = "nvidia,nvdla_os_initial" },
+ { .compatible = "starfive,spi2ahb" },
+ { /* sentinel */ }
+};
+
+static struct driver_d starfive_pwrseq_driver = {
+ .name = "starfive_pwrseq",
+ .probe = starfive_pwrseq_probe,
+ .of_compatible = starfive_pwrseq_dt_ids,
+};
+
+static const int clks[] = {
+ CLK_VDEC_AXI, CLK_VDECBRG_MAIN, CLK_VDEC_BCLK, CLK_VDEC_CCLK, CLK_VDEC_APB,
+ CLK_JPEG_AXI, CLK_JPEG_CCLK, CLK_JPEG_APB,
+ CLK_DLA_AXI, CLK_DLANOC_AXI, CLK_DLA_APB, CLK_NNENOC_AXI, CLK_DLASLV_AXI,
+ CLK_VENC_AXI, CLK_VENCBRG_MAIN, CLK_VENC_BCLK, CLK_VENC_CCLK, CLK_VENC_APB,
+ CLK_SGDMA1P_AXI,
+ CLK_DMA2PNOC_AXI, CLK_SGDMA2P_AXI, CLK_SGDMA2P_AHB,
+ CLK_SDIO0_AHB,
+ CLK_SDIO1_AHB,
+ CLK_SPI2AHB_AHB, CLK_SPI2AHB_CORE,
+ CLK_EZMASTER_AHB,
+ CLK_SEC_AHB, CLK_AES, CLK_SHA, CLK_PKA,
+ CLK_UART0_APB, CLK_UART0_CORE,
+ CLK_UART1_APB, CLK_UART1_CORE,
+ CLK_UART2_APB, CLK_UART2_CORE,
+ CLK_UART3_APB, CLK_UART3_CORE,
+ CLK_SPI0_APB, CLK_SPI0_CORE,
+ CLK_SPI1_APB, CLK_SPI1_CORE,
+ CLK_SPI2_APB, CLK_SPI2_CORE,
+ CLK_SPI3_APB, CLK_SPI3_CORE,
+ CLK_I2C0_APB, CLK_I2C0_CORE,
+ CLK_I2C1_APB, CLK_I2C1_CORE,
+ CLK_I2C2_APB, CLK_I2C2_CORE,
+ CLK_I2C3_APB, CLK_I2C3_CORE,
+ CLK_VP6INTC_APB,
+ CLK_TEMP_APB, CLK_TEMP_SENSE,
+
+ CLK_END
+};
+
+static int __init starfive_pwrseq_driver_register(void)
+{
+ struct of_phandle_args clkspec;
+ int i;
+
+ clkspec.args_count = 1;
+ clkspec.np = of_find_compatible_node(NULL, NULL, "starfive,jh7100-clkgen");
+ if (clkspec.np) {
+ for (i = 0; clks[i] != CLK_END; i++) {
+ clkspec.args[0] = clks[i];
+ clk_enable(of_clk_get_from_provider(&clkspec));
+ }
+ }
+
+ return platform_driver_register(&starfive_pwrseq_driver);
+}
+device_initcall(starfive_pwrseq_driver_register);
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 18931211b5..802169a86e 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -82,6 +82,14 @@ config DRIVER_NET_DESIGNWARE_SOCFPGA
This option enables support for the Synopsys
Designware Core Univesal MAC 10M/100M/1G ethernet IP on SoCFPGA.
+config DRIVER_NET_DESIGNWARE_STARFIVE
+ bool "Designware Universal MAC ethernet driver for StarFive platforms"
+ depends on SOC_STARFIVE || COMPILE_TEST
+ select MFD_SYSCON
+ help
+ This option enables support for the Synopsys
+ Designware Core Univesal MAC 10M/100M/1G ethernet IP on StarFive.
+
endif
config DRIVER_NET_DESIGNWARE_EQOS
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 1674d53dff..fb3e3bdee4 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_DRIVER_NET_DAVINCI_EMAC) += davinci_emac.o
obj-$(CONFIG_DRIVER_NET_DESIGNWARE) += designware.o
obj-$(CONFIG_DRIVER_NET_DESIGNWARE_GENERIC) += designware_generic.o
obj-$(CONFIG_DRIVER_NET_DESIGNWARE_SOCFPGA) += designware_socfpga.o
+obj-$(CONFIG_DRIVER_NET_DESIGNWARE_STARFIVE) += designware_starfive.o
obj-$(CONFIG_DRIVER_NET_DESIGNWARE_EQOS) += designware_eqos.o
obj-$(CONFIG_DRIVER_NET_DESIGNWARE_STM32) += designware_stm32.o
obj-$(CONFIG_DRIVER_NET_DESIGNWARE_TEGRA186) += designware_tegra186.o
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index 0ee6d3d78a..afc275e81e 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -104,15 +104,15 @@ static void tx_descs_init(struct eth_device *dev)
{
struct dw_eth_dev *priv = dev->priv;
struct eth_dma_regs *dma_p = priv->dma_regs_p;
- struct dmamacdescr *desc_table_p = &priv->tx_mac_descrtable[0];
+ struct dmamacdescr *desc_table_p = &priv->tx_mac_descrtable_cpu[0];
char *txbuffs = &priv->txbuffs[0];
struct dmamacdescr *desc_p;
u32 idx;
for (idx = 0; idx < CONFIG_TX_DESCR_NUM; idx++) {
desc_p = &desc_table_p[idx];
- desc_p->dmamac_addr = &txbuffs[idx * CONFIG_ETH_BUFSIZE];
- desc_p->dmamac_next = &desc_table_p[idx + 1];
+ desc_p->dmamac_addr = virt_to_phys(&txbuffs[idx * CONFIG_ETH_BUFSIZE]);
+ desc_p->dmamac_next = tx_dma_addr(priv, &desc_table_p[idx + 1]);
if (priv->enh_desc) {
desc_p->txrx_status &= ~(DESC_ENH_TXSTS_TXINT | DESC_ENH_TXSTS_TXLAST |
@@ -130,9 +130,9 @@ static void tx_descs_init(struct eth_device *dev)
}
/* Correcting the last pointer of the chain */
- desc_p->dmamac_next = &desc_table_p[0];
+ desc_p->dmamac_next = tx_dma_addr(priv, &desc_table_p[0]);
- writel((ulong)&desc_table_p[0], &dma_p->txdesclistaddr);
+ writel(desc_p->dmamac_next, &dma_p->txdesclistaddr);
priv->tx_currdescnum = 0;
}
@@ -140,15 +140,15 @@ static void rx_descs_init(struct eth_device *dev)
{
struct dw_eth_dev *priv = dev->priv;
struct eth_dma_regs *dma_p = priv->dma_regs_p;
- struct dmamacdescr *desc_table_p = &priv->rx_mac_descrtable[0];
+ struct dmamacdescr *desc_table_p = &priv->rx_mac_descrtable_cpu[0];
char *rxbuffs = &priv->rxbuffs[0];
struct dmamacdescr *desc_p;
u32 idx;
for (idx = 0; idx < CONFIG_RX_DESCR_NUM; idx++) {
desc_p = &desc_table_p[idx];
- desc_p->dmamac_addr = &rxbuffs[idx * CONFIG_ETH_BUFSIZE];
- desc_p->dmamac_next = &desc_table_p[idx + 1];
+ desc_p->dmamac_addr = virt_to_phys(&rxbuffs[idx * CONFIG_ETH_BUFSIZE]);
+ desc_p->dmamac_next = rx_dma_addr(priv, &desc_table_p[idx + 1]);
desc_p->dmamac_cntl = MAC_MAX_FRAME_SZ;
if (priv->enh_desc)
@@ -156,15 +156,15 @@ static void rx_descs_init(struct eth_device *dev)
else
desc_p->dmamac_cntl |= DESC_RXCTRL_RXCHAIN;
- dma_sync_single_for_cpu((unsigned long)desc_p->dmamac_addr,
+ dma_sync_single_for_cpu(desc_p->dmamac_addr,
CONFIG_ETH_BUFSIZE, DMA_FROM_DEVICE);
desc_p->txrx_status = DESC_RXSTS_OWNBYDMA;
}
/* Correcting the last pointer of the chain */
- desc_p->dmamac_next = &desc_table_p[0];
+ desc_p->dmamac_next = rx_dma_addr(priv, &desc_table_p[0]);
- writel((ulong)&desc_table_p[0], &dma_p->rxdesclistaddr);
+ writel(desc_p->dmamac_next, &dma_p->rxdesclistaddr);
priv->rx_currdescnum = 0;
}
@@ -276,7 +276,7 @@ static int dwc_ether_send(struct eth_device *dev, void *packet, int length)
struct dw_eth_dev *priv = dev->priv;
struct eth_dma_regs *dma_p = priv->dma_regs_p;
u32 owndma, desc_num = priv->tx_currdescnum;
- struct dmamacdescr *desc_p = &priv->tx_mac_descrtable[desc_num];
+ struct dmamacdescr *desc_p = &priv->tx_mac_descrtable_cpu[desc_num];
owndma = priv->enh_desc ? DESC_ENH_TXSTS_OWNBYDMA : DESC_TXSTS_OWNBYDMA;
/* Check if the descriptor is owned by CPU */
@@ -285,8 +285,8 @@ static int dwc_ether_send(struct eth_device *dev, void *packet, int length)
return -1;
}
- memcpy((void *)desc_p->dmamac_addr, packet, length);
- dma_sync_single_for_device((unsigned long)desc_p->dmamac_addr, length,
+ memcpy(dmamac_addr(desc_p), packet, length);
+ dma_sync_single_for_device(desc_p->dmamac_addr, length,
DMA_TO_DEVICE);
if (priv->enh_desc) {
@@ -314,7 +314,7 @@ static int dwc_ether_send(struct eth_device *dev, void *packet, int length)
/* Start the transmission */
writel(POLL_DATA, &dma_p->txpolldemand);
- dma_sync_single_for_cpu((unsigned long)desc_p->dmamac_addr, length,
+ dma_sync_single_for_cpu(desc_p->dmamac_addr, length,
DMA_TO_DEVICE);
return 0;
@@ -324,7 +324,7 @@ static int dwc_ether_rx(struct eth_device *dev)
{
struct dw_eth_dev *priv = dev->priv;
u32 desc_num = priv->rx_currdescnum;
- struct dmamacdescr *desc_p = &priv->rx_mac_descrtable[desc_num];
+ struct dmamacdescr *desc_p = &priv->rx_mac_descrtable_cpu[desc_num];
u32 status = desc_p->txrx_status;
int length = 0;
@@ -358,10 +358,10 @@ static int dwc_ether_rx(struct eth_device *dev)
length = (status & DESC_RXSTS_FRMLENMSK) >>
DESC_RXSTS_FRMLENSHFT;
- dma_sync_single_for_cpu((unsigned long)desc_p->dmamac_addr,
+ dma_sync_single_for_cpu(desc_p->dmamac_addr,
length, DMA_FROM_DEVICE);
- net_receive(dev, desc_p->dmamac_addr, length);
- dma_sync_single_for_device((unsigned long)desc_p->dmamac_addr,
+ net_receive(dev, dmamac_addr(desc_p), length);
+ dma_sync_single_for_device(desc_p->dmamac_addr,
length, DMA_FROM_DEVICE);
ret = length;
}
@@ -451,17 +451,20 @@ struct dw_eth_dev *dwc_drv_probe(struct device_d *dev)
int ret;
struct dw_eth_drvdata *drvdata;
+ dma_set_mask(dev, DMA_BIT_MASK(32));
+
priv = xzalloc(sizeof(struct dw_eth_dev));
ret = dev_get_drvdata(dev, (const void **)&drvdata);
if (ret)
return ERR_PTR(ret);
- if (drvdata && drvdata->enh_desc)
+ if (drvdata) {
priv->enh_desc = drvdata->enh_desc;
- else
+ priv->fix_mac_speed = drvdata->fix_mac_speed;
+ } else {
dev_warn(dev, "No drvdata specified\n");
-
+ }
if (pdata) {
priv->phy_addr = pdata->phy_addr;
@@ -481,12 +484,21 @@ struct dw_eth_dev *dwc_drv_probe(struct device_d *dev)
priv->mac_regs_p = base;
dwc_version(dev, readl(&priv->mac_regs_p->version));
priv->dma_regs_p = base + DW_DMA_BASE_OFFSET;
- priv->tx_mac_descrtable = dma_alloc_coherent(
+
+ priv->tx_mac_descrtable_cpu = dma_alloc_coherent(
CONFIG_TX_DESCR_NUM * sizeof(struct dmamacdescr),
- DMA_ADDRESS_BROKEN);
- priv->rx_mac_descrtable = dma_alloc_coherent(
+ &priv->tx_mac_descrtable_dev);
+
+ if (dma_mapping_error(dev, priv->tx_mac_descrtable_dev))
+ return ERR_PTR(-EFAULT);
+
+ priv->rx_mac_descrtable_cpu = dma_alloc_coherent(
CONFIG_RX_DESCR_NUM * sizeof(struct dmamacdescr),
- DMA_ADDRESS_BROKEN);
+ &priv->rx_mac_descrtable_dev);
+
+ if (dma_mapping_error(dev, priv->rx_mac_descrtable_dev))
+ return ERR_PTR(-EFAULT);
+
priv->txbuffs = dma_alloc(TX_TOTAL_BUFSIZE);
priv->rxbuffs = dma_alloc(RX_TOTAL_BUFSIZE);
diff --git a/drivers/net/designware.h b/drivers/net/designware.h
index 0a6a6bf1a4..8f6234aec5 100644
--- a/drivers/net/designware.h
+++ b/drivers/net/designware.h
@@ -8,6 +8,7 @@
#define __DESIGNWARE_ETH_H
#include <net.h>
+#include <linux/types.h>
struct dw_eth_dev {
struct eth_device netdev;
@@ -18,8 +19,11 @@ struct dw_eth_dev {
u32 tx_currdescnum;
u32 rx_currdescnum;
- struct dmamacdescr *tx_mac_descrtable;
- struct dmamacdescr *rx_mac_descrtable;
+ struct dmamacdescr *tx_mac_descrtable_cpu;
+ struct dmamacdescr *rx_mac_descrtable_cpu;
+
+ dma_addr_t tx_mac_descrtable_dev;
+ dma_addr_t rx_mac_descrtable_dev;
u8 *txbuffs;
u8 *rxbuffs;
@@ -35,9 +39,24 @@ struct dw_eth_dev {
struct dw_eth_drvdata {
bool enh_desc;
+ void (*fix_mac_speed)(int speed);
void *priv;
};
+static inline dma_addr_t tx_dma_addr(struct dw_eth_dev *priv,
+ struct dmamacdescr *desc)
+{
+ return priv->tx_mac_descrtable_dev
+ + ((u8 *)desc - (u8 *)priv->tx_mac_descrtable_cpu);
+}
+
+static inline dma_addr_t rx_dma_addr(struct dw_eth_dev *priv,
+ struct dmamacdescr *desc)
+{
+ return priv->rx_mac_descrtable_dev
+ + ((u8 *)desc - (u8 *)priv->rx_mac_descrtable_cpu);
+}
+
struct dw_eth_dev *dwc_drv_probe(struct device_d *dev);
void dwc_drv_remove(struct device_d *dev);
@@ -138,10 +157,12 @@ struct eth_dma_regs {
struct dmamacdescr {
u32 txrx_status;
u32 dmamac_cntl;
- void *dmamac_addr;
- struct dmamacdescr *dmamac_next;
+ u32 dmamac_addr;
+ u32 dmamac_next;
};
+#define dmamac_addr(descr) (phys_to_virt((descr)->dmamac_addr))
+
/*
* txrx_status definitions
*/
diff --git a/drivers/net/designware_starfive.c b/drivers/net/designware_starfive.c
new file mode 100644
index 0000000000..3dc9d14e11
--- /dev/null
+++ b/drivers/net/designware_starfive.c
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2021 Ahmad Fatoum, Pengutronix
+ */
+
+#include <common.h>
+#include <init.h>
+#include <linux/reset.h>
+#include <linux/clk.h>
+#include <mfd/syscon.h>
+#include <soc/starfive/sysmain.h>
+#include "designware.h"
+
+/*
+ * GMAC_GTXCLK
+ * bit name access default description
+ * [31] _gmac_gtxclk enable RW 0x0 "1:enable; 0:disable"
+ * [30] reserved - 0x0 reserved
+ * [29:8] reserved - 0x0 reserved
+ * [7:0] gmac_gtxclk ratio RW 0x4 divider value
+ *
+ * 1000M: gtxclk@125M => 500/125 = 0x4
+ * 100M: gtxclk@25M => 500/25 = 0x14
+ * 10M: gtxclk@2.5M => 500/2.5 = 0xc8
+ */
+
+#define CLKGEN_BASE 0x11800000
+#define CLKGEN_GMAC_GTXCLK_OFFSET 0x1EC
+#define CLKGEN_GMAC_GTXCLK_ADDR (CLKGEN_BASE + CLKGEN_GMAC_GTXCLK_OFFSET)
+
+
+#define CLKGEN_125M_DIV 0x4
+#define CLKGEN_25M_DIV 0x14
+#define CLKGEN_2_5M_DIV 0xc8
+
+static void dwmac_fixed_speed(int speed)
+{
+ /* TODO: move this into clk driver */
+ void __iomem *addr = IOMEM(CLKGEN_GMAC_GTXCLK_ADDR);
+ u32 value;
+
+ value = readl(addr) & (~0x000000FF);
+
+ switch (speed) {
+ case SPEED_1000: value |= CLKGEN_125M_DIV; break;
+ case SPEED_100: value |= CLKGEN_25M_DIV; break;
+ case SPEED_10: value |= CLKGEN_2_5M_DIV; break;
+ default: return;
+ }
+
+ writel(value, addr);
+}
+
+static struct dw_eth_drvdata starfive_drvdata = {
+ .enh_desc = 1,
+ .fix_mac_speed = dwmac_fixed_speed,
+};
+
+static int starfive_dwc_ether_probe(struct device_d *dev)
+{
+ struct dw_eth_dev *dwc;
+ struct regmap *regmap;
+ int ret;
+ struct clk_bulk_data clks[] = {
+ { .id = "stmmaceth" },
+ { .id = "ptp_ref" },
+ { .id = "tx" },
+ };
+
+ regmap = syscon_regmap_lookup_by_phandle(dev->device_node, "starfive,sysmain");
+ if (IS_ERR(regmap)) {
+ dev_err(dev, "Could not get starfive,sysmain node\n");
+ return PTR_ERR(regmap);
+ }
+
+ ret = clk_bulk_get(dev, ARRAY_SIZE(clks), clks);
+ if (ret)
+ return ret;
+
+ ret = clk_bulk_enable(ARRAY_SIZE(clks), clks);
+ if (ret < 0)
+ return ret;
+
+ ret = device_reset(dev);
+ if (ret)
+ return ret;
+
+ dwc = dwc_drv_probe(dev);
+ if (IS_ERR(dwc))
+ return PTR_ERR(dwc);
+
+ if (phy_interface_mode_is_rgmii(dwc->interface)) {
+ regmap_update_bits(regmap, SYSMAIN_GMAC_PHY_INTF_SEL, 0x7, 0x1);
+ regmap_write(regmap, SYSMAIN_GMAC_GTXCLK_DLYCHAIN_SEL, 0x4);
+ }
+
+ return 0;
+}
+
+static struct of_device_id starfive_dwc_ether_compatible[] = {
+ { .compatible = "starfive,stmmac", .data = &starfive_drvdata },
+ { /* sentinel */ }
+};
+
+static struct driver_d starfive_dwc_ether_driver = {
+ .name = "starfive-designware_eth",
+ .probe = starfive_dwc_ether_probe,
+ .of_compatible = starfive_dwc_ether_compatible,
+};
+device_platform_driver(starfive_dwc_ether_driver);
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index 0d7c0b7b9e..3781f7a839 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -65,4 +65,12 @@ config STM32_BSEC
This adds support for the STM32 OTP controller. Reads and writes
to will go to the shadow RAM, not the OTP fuses themselvers.
+config STARFIVE_OTP
+ tristate "Starfive OTP Supprot"
+ depends on SOC_STARFIVE
+ depends on OFDEVICE
+ help
+ This adds support for the StarFive OTP controller. Only reading
+ is currently supported.
+
endif
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index 53c02dc785..55507f5441 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -22,3 +22,5 @@ nvmem_eeprom_93xx46-y := eeprom_93xx46.o
obj-$(CONFIG_STM32_BSEC) += nvmem_bsec.o
nvmem_bsec-y := bsec.o
+
+obj-$(CONFIG_STARFIVE_OTP) += starfive-otp.o
diff --git a/drivers/nvmem/starfive-otp.c b/drivers/nvmem/starfive-otp.c
new file mode 100644
index 0000000000..f9bf05ca87
--- /dev/null
+++ b/drivers/nvmem/starfive-otp.c
@@ -0,0 +1,201 @@
+// SPDX_License-Identifier: GPL-2.0
+/*
+ * Copyright 2021 StarFive, Inc
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <malloc.h>
+#include <xfuncs.h>
+#include <errno.h>
+#include <gpiod.h>
+#include <init.h>
+#include <net.h>
+#include <io.h>
+#include <of.h>
+#include <regmap.h>
+#include <machine_id.h>
+#include <linux/reset.h>
+#include <linux/clk.h>
+#include <linux/nvmem-provider.h>
+
+// otp reg offset
+#define OTP_CFGR 0x00
+#define OTPC_IER 0x04
+#define OTPC_SRR 0x08
+#define OTP_OPRR 0x0c
+#define OTPC_CTLR 0x10
+#define OTPC_ADDRR 0x14
+#define OTPC_DINR 0x18
+#define OTPC_DOUTR 0x1c
+
+#define OTP_EMPTY_CELL_VALUE 0xffffffffUL
+
+// cfgr (offset 0x00)
+#define OTP_CFGR_PRG_CNT_MASK 0xff
+#define OTP_CFGR_PRG_CNT_SHIFT 0
+#define OTP_CFGR_DIV_1US_MASK 0xff
+#define OTP_CFGR_DIV_1US_SHIFT 8
+#define OTP_CFGR_RD_CYC_MASK 0x0f
+#define OTP_CFGR_RD_CYC_SHIFT 16
+
+// ier (offset 0x04)
+#define OTPC_IER_DONE_IE BIT(0)
+#define OTPC_IER_BUSY_OPR_IE BIT(1)
+
+// srr (offset 0x08)
+#define OTPC_SRR_DONE BIT(0)
+#define OTPC_SRR_BUSY_OPR BIT(1)
+#define OTPC_SRR_INFO_RD_LOCK BIT(29)
+#define OTPC_SRR_INFO_WR_LOCK BIT(30)
+#define OTPC_SRR_BUSY BIT(31)
+
+// oprr (offset 0x0c)
+#define OTP_OPRR_OPR_MASK 0x00000007
+#define OTP_OPRR_OPR_SHIFT 0
+
+#define OTP_OPR_STANDBY 0x0 // user mode
+#define OTP_OPR_READ 0x1 // user mode
+#define OTP_OPR_MARGIN_READ_PROG 0x2 // testing mode
+#define OTP_OPR_MARGIN_READ_INIT 0x3 // testing mode
+#define OTP_OPR_PROGRAM 0x4 // user mode
+#define OTP_OPR_DEEP_STANDBY 0x5 // user mode
+#define OTP_OPR_DEBUG 0x6 // user mode
+
+// ctlr (offset 0x10, see EG512X32TH028CW01_v1.0.pdf "Pin Description")
+#define OTPC_CTLR_PCE BIT(0)
+#define OTPC_CTLR_PTM_MASK 0x0000000e
+#define OTPC_CTLR_PTM_SHIFT 1
+#define OTPC_CTLR_PDSTB BIT(4)
+#define OTPC_CTLR_PTR BIT(5)
+#define OTPC_CTLR_PPROG BIT(6)
+#define OTPC_CTLR_PWE BIT(7)
+#define OTPC_CTLR_PCLK BIT(8)
+
+// addrr (offset 0x14)
+#define OTPC_ADDRR_PA_MASK 0x000001ff
+#define OTPC_ADDRR_PA_SHIFT 0
+
+/*
+ * data format:
+ * struct starfive_otp_data{
+ * char vendor[32];
+ * uint64_t sn;
+ * uint8_t mac_addr[6];
+ * uint8_t padding_0[2];
+ * }
+ */
+
+struct starfive_otp {
+ int power_gpio;
+ struct starfive_otp_regs __iomem *regs;
+};
+
+struct starfive_otp_regs {
+ /* TODO: add otp ememory_eg512x32 registers define */
+ u32 otp_cfg; /* timing Register */
+ u32 otpc_ie; /* interrupt Enable */
+ u32 otpc_sr; /* status Register */
+ u32 otp_opr; /* operation mode select Register */
+ u32 otpc_ctl; /* otp control port */
+ u32 otpc_addr; /* otp pa port */
+ u32 otpc_din; /* otp pdin port */
+ u32 otpc_dout; /* otp pdout */
+ u32 reserved[504];
+ u32 mem[512];
+};
+
+/*
+ * offset and size are assumed aligned to the size of the fuses (32-bit).
+ */
+static int starfive_otp_read(void *ctx, unsigned offset, unsigned *val)
+{
+ struct starfive_otp *priv = ctx;
+
+ gpio_set_active(priv->power_gpio, true);
+ mdelay(10);
+
+ //otp set to read mode
+ writel(OTP_OPR_READ, &priv->regs->otp_opr);
+ mdelay(5);
+
+ /* read all requested fuses */
+ *val = readl(&priv->regs->mem[offset / 4]);
+
+ gpio_set_active(priv->power_gpio, false);
+ mdelay(5);
+
+ return 0;
+}
+
+static int starfive_otp_write(void *ctx, unsigned offset, unsigned val)
+{
+ return -EOPNOTSUPP;
+}
+
+static struct regmap_bus starfive_otp_regmap_bus = {
+ .reg_read = starfive_otp_read,
+ .reg_write = starfive_otp_write,
+};
+
+static int starfive_otp_probe(struct device_d *dev)
+{
+ struct starfive_otp *priv;
+ struct regmap_config config = {};
+ struct resource *iores;
+ struct regmap *map;
+ struct clk *clk;
+ u32 total_fuses;
+ int ret;
+
+ clk = clk_get(dev, NULL);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ clk_enable(clk);
+
+ ret = device_reset(dev);
+ if (ret)
+ return ret;
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+
+ ret = of_property_read_u32(dev->device_node, "fuse-count", &total_fuses);
+ if (ret < 0) {
+ dev_err(dev, "missing required fuse-count property\n");
+ return ret;
+ }
+
+ config.name = "starfive-otp";
+ config.reg_bits = 32;
+ config.val_bits = 32;
+ config.reg_stride = 4;
+ config.max_register = total_fuses;
+
+ priv = xzalloc(sizeof(*priv));
+
+ priv->regs = IOMEM(iores->start);
+ priv->power_gpio = gpiod_get(dev, "power", GPIOD_OUT_LOW);
+ if (priv->power_gpio < 0)
+ return priv->power_gpio;
+
+ map = regmap_init(dev, &starfive_otp_regmap_bus, priv, &config);
+ if (IS_ERR(map))
+ return PTR_ERR(map);
+
+ return PTR_ERR_OR_ZERO(nvmem_regmap_register(map, "starfive-otp"));
+}
+
+static struct of_device_id starfive_otp_dt_ids[] = {
+ { .compatible = "starfive,fu740-otp" },
+ { /* sentinel */ }
+};
+
+static struct driver_d starfive_otp_driver = {
+ .name = "starfive_otp",
+ .probe = starfive_otp_probe,
+ .of_compatible = starfive_otp_dt_ids,
+};
+device_platform_driver(starfive_otp_driver);
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index c774660232..cf2f724d18 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -128,7 +128,7 @@ static struct pinctrl_ops pcs_ops = {
.set_state = pcs_set_state,
};
-static int pcs_probe(struct device_d *dev)
+int pinctrl_single_probe(struct device_d *dev)
{
struct resource *iores;
struct pinctrl_single *pcs;
@@ -215,7 +215,7 @@ static __maybe_unused struct of_device_id pcs_dt_ids[] = {
static struct driver_d pcs_driver = {
.name = "pinctrl-single",
- .probe = pcs_probe,
+ .probe = pinctrl_single_probe,
.of_compatible = DRV_OF_COMPAT(pcs_dt_ids),
};
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 316ece9e71..9429f107bb 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -27,4 +27,10 @@ config RESET_STM32
help
This enables the reset controller driver for STM32MP and STM32 MCUs.
+config RESET_STARFIVE
+ bool "StarFive Controller Driver" if COMPILE_TEST
+ default SOC_STARFIVE
+ help
+ This enables the reset controller driver for the StarFive JH7100.
+
endif
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 8460c4b154..ce494baae5 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -2,3 +2,4 @@ obj-$(CONFIG_RESET_CONTROLLER) += core.o
obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o
obj-$(CONFIG_RESET_IMX7) += reset-imx7.o
obj-$(CONFIG_RESET_STM32) += reset-stm32.o
+obj-$(CONFIG_RESET_STARFIVE) += reset-starfive-vic.o
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 1dd071635f..9f5a642539 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -139,30 +139,35 @@ int reset_control_deassert(struct reset_control *rstc)
EXPORT_SYMBOL_GPL(reset_control_deassert);
/**
- * of_reset_control_get - Lookup and obtain a reference to a reset controller.
+ * of_reset_control_count - Count reset lines
+ * @node: device node
+ *
+ * Returns number of resets, 0 if none specified
+ */
+static int of_reset_control_count(struct device_node *node)
+{
+ return of_count_phandle_with_args(node, "resets", "#reset-cells");
+}
+
+/**
+ * of_reset_control_get_by_index - Lookup and obtain a reference to a reset controller.
* @node: device to be reset by the controller
- * @id: reset line name
+ * @index: reset line index
*
* Returns a struct reset_control or IS_ERR() condition containing errno.
- *
- * Use of id names is optional.
*/
-struct reset_control *of_reset_control_get(struct device_node *node,
- const char *id)
+static struct reset_control *of_reset_control_get_by_index(struct device_node *node,
+ int index)
{
struct reset_control *rstc;
struct reset_controller_dev *r, *rcdev;
struct of_phandle_args args;
- int index = 0;
int rstc_id;
int ret;
if (!of_get_property(node, "resets", NULL))
return NULL;
- if (id)
- index = of_property_match_string(node,
- "reset-names", id);
ret = of_parse_phandle_with_args(node, "resets", "#reset-cells",
index, &args);
if (ret)
@@ -199,6 +204,26 @@ struct reset_control *of_reset_control_get(struct device_node *node,
return rstc;
}
+/**
+ * of_reset_control_get - Lookup and obtain a reference to a reset controller.
+ * @node: device to be reset by the controller
+ * @id: reset line name
+ *
+ * Returns a struct reset_control or IS_ERR() condition containing errno.
+ *
+ * Use of id names is optional.
+ */
+struct reset_control *of_reset_control_get(struct device_node *node,
+ const char *id)
+{
+ int index = 0;
+
+ if (id)
+ index = of_property_match_string(node, "reset-names", id);
+
+ return of_reset_control_get_by_index(node, index);
+}
+
static struct reset_control *
gpio_reset_control_get(struct device_d *dev, const char *id)
{
@@ -306,6 +331,39 @@ int device_reset(struct device_d *dev)
}
EXPORT_SYMBOL_GPL(device_reset);
+int device_reset_all(struct device_d *dev)
+{
+ struct reset_control *rstc;
+ int ret, i;
+
+ for (i = 0; i < of_reset_control_count(dev->device_node); i++) {
+ int ret;
+
+ rstc = of_reset_control_get_by_index(dev->device_node, i);
+ if (IS_ERR(rstc))
+ return PTR_ERR(rstc);
+
+ ret = reset_control_reset(rstc);
+ if (ret)
+ return ret;
+
+ reset_control_put(rstc);
+ }
+
+ if (i == 0) {
+ rstc = gpio_reset_control_get(dev, NULL);
+
+ ret = reset_control_reset(rstc);
+ if (ret)
+ return ret;
+
+ reset_control_put(rstc);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(device_reset_all);
+
int device_reset_us(struct device_d *dev, int us)
{
struct reset_control *rstc;
diff --git a/drivers/reset/reset-starfive-vic.c b/drivers/reset/reset-starfive-vic.c
new file mode 100644
index 0000000000..bcf615da0a
--- /dev/null
+++ b/drivers/reset/reset-starfive-vic.c
@@ -0,0 +1,234 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2021 Ahmad Fatoum, Pengutronix
+ *
+ * StarFive Reset Controller driver
+ */
+#define pr_fmt(fmt) "reset-starfive: " fmt
+
+#include <common.h>
+#include <init.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/reset-controller.h>
+#include <soc/starfive/rstgen.h>
+#include <dt-bindings/reset-controller/starfive-jh7100.h>
+#include <dt-bindings/clock/starfive-jh7100.h>
+
+struct starfive_rstgen {
+ void __iomem *base;
+ struct reset_controller_dev rcdev;
+ const struct starfive_rstgen_ops *ops;
+ struct device_node *clknp;
+ const int *sync_resets;
+};
+
+static struct starfive_rstgen *to_starfive_rstgen(struct reset_controller_dev *rcdev)
+{
+ return container_of(rcdev, struct starfive_rstgen, rcdev);
+}
+
+static const int jh7110_rstgen_sync_resets[RSTN_END] = {
+ [RSTN_SGDMA2P_AHB] = CLK_SGDMA2P_AHB,
+ [RSTN_SGDMA2P_AXI] = CLK_SGDMA2P_AXI,
+ [RSTN_DMA2PNOC_AXI] = CLK_DMA2PNOC_AXI,
+ [RSTN_DLA_AXI] = CLK_DLA_AXI,
+ [RSTN_DLANOC_AXI] = CLK_DLANOC_AXI,
+ [RSTN_DLA_APB] = CLK_DLA_APB,
+ [RSTN_VDECBRG_MAIN] = CLK_VDECBRG_MAIN,
+ [RSTN_VDEC_AXI] = CLK_VDEC_AXI,
+ [RSTN_VDEC_BCLK] = CLK_VDEC_BCLK,
+ [RSTN_VDEC_CCLK] = CLK_VDEC_CCLK,
+ [RSTN_VDEC_APB] = CLK_VDEC_APB,
+ [RSTN_JPEG_AXI] = CLK_JPEG_AXI,
+ [RSTN_JPEG_CCLK] = CLK_JPEG_CCLK,
+ [RSTN_JPEG_APB] = CLK_JPEG_APB,
+ [RSTN_JPCGC300_MAIN] = CLK_JPCGC300_MAIN,
+ [RSTN_GC300_2X] = CLK_GC300_2X,
+ [RSTN_GC300_AXI] = CLK_GC300_AXI,
+ [RSTN_GC300_AHB] = CLK_GC300_AHB,
+ [RSTN_VENC_AXI] = CLK_VENC_AXI,
+ [RSTN_VENCBRG_MAIN] = CLK_VENCBRG_MAIN,
+ [RSTN_VENC_BCLK] = CLK_VENC_BCLK,
+ [RSTN_VENC_CCLK] = CLK_VENC_CCLK,
+ [RSTN_VENC_APB] = CLK_VENC_APB,
+ [RSTN_DDRPHY_APB] = CLK_DDRPHY_APB,
+ [RSTN_USB_AXI] = CLK_USB_AXI,
+ [RSTN_SGDMA1P_AXI] = CLK_SGDMA1P_AXI,
+ [RSTN_DMA1P_AXI] = CLK_DMA1P_AXI,
+ [RSTN_NNE_AHB] = CLK_NNE_AHB,
+ [RSTN_NNE_AXI] = CLK_NNE_AXI,
+ [RSTN_NNENOC_AXI] = CLK_NNENOC_AXI,
+ [RSTN_DLASLV_AXI] = CLK_DLASLV_AXI,
+ [RSTN_VOUT_SRC] = CLK_VOUT_SRC,
+ [RSTN_DISP_AXI] = CLK_DISP_AXI,
+ [RSTN_DISPNOC_AXI] = CLK_DISPNOC_AXI,
+ [RSTN_SDIO0_AHB] = CLK_SDIO0_AHB,
+ [RSTN_SDIO1_AHB] = CLK_SDIO1_AHB,
+ [RSTN_GMAC_AHB] = CLK_GMAC_AHB,
+ [RSTN_SPI2AHB_AHB] = CLK_SPI2AHB_AHB,
+ [RSTN_SPI2AHB_CORE] = CLK_SPI2AHB_CORE,
+ [RSTN_EZMASTER_AHB] = CLK_EZMASTER_AHB,
+ [RSTN_SEC_AHB] = CLK_SEC_AHB,
+ [RSTN_AES] = CLK_AES,
+ [RSTN_PKA] = CLK_PKA,
+ [RSTN_SHA] = CLK_SHA,
+ [RSTN_TRNG_APB] = CLK_TRNG_APB,
+ [RSTN_OTP_APB] = CLK_OTP_APB,
+ [RSTN_UART0_APB] = CLK_UART0_APB,
+ [RSTN_UART0_CORE] = CLK_UART0_CORE,
+ [RSTN_UART1_APB] = CLK_UART1_APB,
+ [RSTN_UART1_CORE] = CLK_UART1_CORE,
+ [RSTN_SPI0_APB] = CLK_SPI0_APB,
+ [RSTN_SPI0_CORE] = CLK_SPI0_CORE,
+ [RSTN_SPI1_APB] = CLK_SPI1_APB,
+ [RSTN_SPI1_CORE] = CLK_SPI1_CORE,
+ [RSTN_I2C0_APB] = CLK_I2C0_APB,
+ [RSTN_I2C0_CORE] = CLK_I2C0_CORE,
+ [RSTN_I2C1_APB] = CLK_I2C1_APB,
+ [RSTN_I2C1_CORE] = CLK_I2C1_CORE,
+ [RSTN_GPIO_APB] = CLK_GPIO_APB,
+ [RSTN_UART2_APB] = CLK_UART2_APB,
+ [RSTN_UART2_CORE] = CLK_UART2_CORE,
+ [RSTN_UART3_APB] = CLK_UART3_APB,
+ [RSTN_UART3_CORE] = CLK_UART3_CORE,
+ [RSTN_SPI2_APB] = CLK_SPI2_APB,
+ [RSTN_SPI2_CORE] = CLK_SPI2_CORE,
+ [RSTN_SPI3_APB] = CLK_SPI3_APB,
+ [RSTN_SPI3_CORE] = CLK_SPI3_CORE,
+ [RSTN_I2C2_APB] = CLK_I2C2_APB,
+ [RSTN_I2C2_CORE] = CLK_I2C2_CORE,
+ [RSTN_I2C3_APB] = CLK_I2C3_APB,
+ [RSTN_I2C3_CORE] = CLK_I2C3_CORE,
+ [RSTN_WDTIMER_APB] = CLK_WDTIMER_APB,
+ [RSTN_WDT] = CLK_WDT_CORE,
+ [RSTN_VP6INTC_APB] = CLK_VP6INTC_APB,
+ [RSTN_TEMP_APB] = CLK_TEMP_APB,
+ [RSTN_TEMP_SENSE] = CLK_TEMP_SENSE,
+};
+
+static struct clk *starfive_reset_clk_get(struct starfive_rstgen *priv, unsigned id)
+{
+ struct of_phandle_args clkspec = {
+ .np = priv->clknp,
+ .args_count = 1,
+ };
+
+ if (!priv->sync_resets || !priv->sync_resets[id])
+ return 0;
+
+ clkspec.args[0] = priv->sync_resets[id];
+
+ pr_debug("synchronous reset=%u clk=%u\n", id, priv->sync_resets[id]);
+
+ return of_clk_get_from_provider(&clkspec);
+}
+
+static int starfive_reset_clk_enable(struct starfive_rstgen *priv, unsigned id)
+{
+ return clk_enable(starfive_reset_clk_get(priv, id));
+}
+
+static void starfive_reset_clk_disable(struct starfive_rstgen *priv, unsigned id)
+{
+ clk_disable(starfive_reset_clk_get(priv, id));
+}
+
+static int starfive_rstgen(struct starfive_rstgen *priv, unsigned id, bool assert)
+{
+ void __iomem *base = priv->base;
+
+ __starfive_rstgen(base, id, assert);
+
+ return wait_on_timeout(NSEC_PER_MSEC, __starfive_rstgen_asserted(base, id) == assert);
+}
+
+static int starfive_rstgen_assert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct starfive_rstgen *priv = to_starfive_rstgen(rcdev);
+ int ret;
+
+ starfive_reset_clk_enable(priv, id);
+ ret = starfive_rstgen(priv, id, true);
+ starfive_reset_clk_disable(priv, id);
+
+ return ret;
+}
+
+static int starfive_rstgen_deassert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct starfive_rstgen *priv = to_starfive_rstgen(rcdev);
+ int ret;
+
+ starfive_reset_clk_enable(priv, id);
+ ret = starfive_rstgen(priv, id, false);
+ starfive_reset_clk_disable(priv, id);
+
+ return ret;
+}
+
+static int starfive_reset(struct reset_controller_dev *rcdev, unsigned long id)
+{
+ struct starfive_rstgen *priv = to_starfive_rstgen(rcdev);
+ int ret;
+
+ starfive_reset_clk_enable(priv, id);
+
+ ret = starfive_rstgen(priv, id, true);
+ if (ret)
+ goto out;
+
+ udelay(2);
+
+ ret = starfive_rstgen(priv, id, false);
+
+out:
+ starfive_reset_clk_disable(priv, id);
+
+ return ret;
+}
+
+static const struct reset_control_ops starfive_rstgen_ops = {
+ .assert = starfive_rstgen_assert,
+ .deassert = starfive_rstgen_deassert,
+ .reset = starfive_reset,
+};
+
+static int starfive_rstgen_probe(struct device_d *dev)
+{
+ struct starfive_rstgen *priv;
+ struct resource *iores;
+
+ priv = xzalloc(sizeof(*priv));
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+
+ if ((priv->sync_resets = device_get_match_data(dev))) {
+ priv->clknp = of_find_compatible_node(NULL, NULL, "starfive,jh7100-clkgen");
+ if (!priv->clknp)
+ return -ENODEV;
+ }
+
+ priv->base = IOMEM(iores->start);
+ priv->rcdev.nr_resets = RSTN_END;
+ priv->rcdev.ops = &starfive_rstgen_ops;
+ priv->rcdev.of_node = dev->device_node;
+
+ return reset_controller_register(&priv->rcdev);
+}
+
+static const struct of_device_id starfive_rstgen_reset_dt_ids[] = {
+ { .compatible = "starfive,jh7100-rstgen", .data = jh7110_rstgen_sync_resets },
+ { /* sentinel */ },
+};
+
+static struct driver_d starfive_rstgen_reset_driver = {
+ .name = "starfive_rstgen",
+ .probe = starfive_rstgen_probe,
+ .of_compatible = starfive_rstgen_reset_dt_ids,
+};
+core_platform_driver(starfive_rstgen_reset_driver);
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
new file mode 100644
index 0000000000..c3499c0c7f
--- /dev/null
+++ b/drivers/soc/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-y += imx/
+obj-$(CONFIG_CPU_SIFIVE) += sifive/
+obj-$(CONFIG_SOC_STARFIVE) += starfive/
diff --git a/drivers/soc/sifive/Makefile b/drivers/soc/sifive/Makefile
new file mode 100644
index 0000000000..e8113c66f5
--- /dev/null
+++ b/drivers/soc/sifive/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SIFIVE_L2) += sifive_l2_cache.o
diff --git a/drivers/soc/sifive/sifive_l2_cache.c b/drivers/soc/sifive/sifive_l2_cache.c
new file mode 100644
index 0000000000..a1e9a10622
--- /dev/null
+++ b/drivers/soc/sifive/sifive_l2_cache.c
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SiFive L2 cache controller Driver
+ *
+ * Copyright (C) 2018-2019 SiFive, Inc.
+ *
+ */
+
+#define pr_fmt(fmt) "sifive-l2: " fmt
+
+#include <io.h>
+#include <printk.h>
+#include <stdio.h>
+#include <driver.h>
+#include <init.h>
+#include <soc/sifive/l2_cache.h>
+#include <asm/barrier.h>
+#include <linux/bitops.h>
+
+#define SIFIVE_L2_DIRECCFIX_LOW 0x100
+#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
+
+#define SIFIVE_L2_DATECCFAIL_LOW 0x160
+#define SIFIVE_L2_DATECCFAIL_HIGH 0x164
+#define SIFIVE_L2_DATECCFAIL_COUNT 0x168
+
+#define SIFIVE_L2_FLUSH64 0x200
+
+#define SIFIVE_L2_CONFIG 0x00
+#define SIFIVE_L2_WAYENABLE 0x08
+#define SIFIVE_L2_ECCINJECTERR 0x40
+
+#define SIFIVE_L2_MAX_ECCINTR 4
+
+#define MASK_NUM_WAYS GENMASK(15, 8)
+#define NUM_WAYS_SHIFT 8
+
+#define SIFIVE_L2_FLUSH64_LINE_LEN 64
+
+static void __iomem *l2_base = NULL;
+
+static void sifive_l2_config_read(struct device_d *dev)
+{
+ u32 regval, val;
+
+ printf("Cache configuration:\n");
+
+ regval = readl(l2_base + SIFIVE_L2_CONFIG);
+ val = regval & 0xFF;
+ printf(" #Banks: %d\n", val);
+ val = (regval & 0xFF00) >> 8;
+ printf(" #Ways per bank: %d\n", val);
+ val = (regval & 0xFF0000) >> 16;
+ printf(" #Sets per bank: %llu\n", 1llu << val);
+ val = (regval & 0xFF000000) >> 24;
+ printf(" #Bytes per cache block: %llu\n", 1llu << val);
+
+ regval = readl(l2_base + SIFIVE_L2_WAYENABLE);
+ printf(" #Index of the largest way enabled: %d\n", regval);
+}
+
+void sifive_l2_flush64_range(dma_addr_t start, dma_addr_t end)
+{
+ unsigned long line;
+
+ start = ALIGN_DOWN(start, 64);
+ end = ALIGN(end, 64);
+
+ if (WARN_ON(!l2_base))
+ return;
+
+ if (start == end)
+ return;
+
+ mb();
+ for (line = start; line < end; line += SIFIVE_L2_FLUSH64_LINE_LEN) {
+ writeq(line, l2_base + SIFIVE_L2_FLUSH64);
+ mb();
+ }
+}
+
+static void sifive_l2_enable_ways(void)
+{
+ u32 config;
+ u32 ways;
+
+ config = readl(l2_base + SIFIVE_L2_CONFIG);
+ ways = (config & MASK_NUM_WAYS) >> NUM_WAYS_SHIFT;
+
+ mb();
+ writel(ways - 1, l2_base + SIFIVE_L2_WAYENABLE);
+ mb();
+}
+
+static int sifive_l2_probe(struct device_d *dev)
+{
+ struct resource *iores;
+
+ if (l2_base)
+ return -EBUSY;
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+
+ l2_base = IOMEM(iores->start);
+
+ sifive_l2_enable_ways();
+
+ dev->info = sifive_l2_config_read;
+
+ return 0;
+}
+
+static const struct of_device_id sifive_l2_ids[] = {
+ { .compatible = "sifive,fu540-c000-ccache" },
+ { .compatible = "sifive,fu740-c000-ccache" },
+ { .compatible = "starfive,ccache0" },
+ { /* end of table */ },
+};
+
+static struct driver_d sifive_l2_driver = {
+ .name = "sfive-l2cache",
+ .probe = sifive_l2_probe,
+ .of_compatible = sifive_l2_ids,
+};
+postcore_platform_driver(sifive_l2_driver);
diff --git a/drivers/soc/starfive/Makefile b/drivers/soc/starfive/Makefile
new file mode 100644
index 0000000000..72504b3bef
--- /dev/null
+++ b/drivers/soc/starfive/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SOC_STARFIVE_JH7100) += jh7100_dma.o
diff --git a/drivers/soc/starfive/jh7100_dma.c b/drivers/soc/starfive/jh7100_dma.c
new file mode 100644
index 0000000000..a1dc48e73f
--- /dev/null
+++ b/drivers/soc/starfive/jh7100_dma.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Ahmad Fatoum, Pengutronix
+ */
+
+#include <common.h>
+#include <asm/dma.h>
+#include <soc/sifive/l2_cache.h>
+
+#define SDRAM_CACHED_BASE 0x80000000
+#define SDRAM_UNCACHED_BASE 0x1000000000
+
+static inline void *jh7100_alloc_coherent(size_t size, dma_addr_t *dma_handle)
+{
+ dma_addr_t cpu_base;
+ void *ret;
+
+ ret = xmemalign(PAGE_SIZE, size);
+
+ memset(ret, 0, size);
+
+ cpu_base = (dma_addr_t)ret;
+
+ if (dma_handle)
+ *dma_handle = cpu_base;
+
+ sifive_l2_flush64_range(cpu_base, cpu_base + size);
+
+ return ret - SDRAM_CACHED_BASE + SDRAM_UNCACHED_BASE;
+
+}
+
+static inline void jh7100_free_coherent(void *vaddr, dma_addr_t dma_handle, size_t size)
+{
+ free((void *)dma_handle);
+}
+
+static const struct dma_ops jh7100_dma_ops = {
+ .alloc_coherent = jh7100_alloc_coherent,
+ .free_coherent = jh7100_free_coherent,
+ .flush_range = sifive_l2_flush64_range,
+ .inv_range = sifive_l2_flush64_range,
+};
+
+static int jh7100_dma_init(void)
+{
+ /* board drivers can claim the machine compatible, so no driver here */
+ if (!of_machine_is_compatible("starfive,jh7100"))
+ return 0;
+
+ dma_set_ops(&jh7100_dma_ops);
+
+ return 0;
+}
+mmu_initcall(jh7100_dma_init);
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index b785181c59..080bc91ff7 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -141,4 +141,11 @@ config ITCO_WDT
NO_REBOOT flag which prevents the watchdog from rebooting the
machine.
+config STARFIVE_WDT
+ tristate "StarFive Watchdog Timer"
+ depends on SOC_STARFIVE && OFDEVICE
+ help
+ If you say yes here you get support for the watchdog device
+ on StarFive SoCs.
+
endif
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 0b598af402..4e784b5aaa 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -18,3 +18,4 @@ obj-$(CONFIG_STPMIC1_WATCHDOG) += stpmic1_wdt.o
obj-$(CONFIG_F71808E_WDT) += f71808e_wdt.o
obj-$(CONFIG_GPIO_WATCHDOG) += gpio_wdt.o
obj-$(CONFIG_ITCO_WDT) += itco_wdt.o
+obj-$(CONFIG_STARFIVE_WDT) += starfive_wdt.o
diff --git a/drivers/watchdog/starfive_wdt.c b/drivers/watchdog/starfive_wdt.c
new file mode 100644
index 0000000000..6779566fd6
--- /dev/null
+++ b/drivers/watchdog/starfive_wdt.c
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2018 Kalray Inc.
+ */
+
+#include <common.h>
+#include <init.h>
+#include <io.h>
+#include <of.h>
+#include <watchdog.h>
+#include <linux/reset.h>
+
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#define WDT_REG_RESET_EN 0x104
+#define WDT_REG_TIMEOUT 0x108
+#define WDT_REG_CONTROL 0x110
+#define WDT_REG_UNLOCK 0x13c
+
+#define WDT_UNLOCK_KEY 0x378f0765
+
+#define WDT_TICKS_PER_SEC 50000000
+
+struct starfive_wdt {
+ u32 clk_rate;
+ struct watchdog wdd;
+ void __iomem *base;
+ bool setup;
+};
+
+static int starfive_wdt_set_timeout(struct watchdog *wdd, unsigned int timeout)
+{
+ struct starfive_wdt *wd = container_of(wdd, struct starfive_wdt, wdd);
+
+ writel(0, wd->base + WDT_REG_CONTROL);
+
+ if (timeout > 0) {
+ timeout *= wd->clk_rate;
+ writel(timeout, wd->base + WDT_REG_TIMEOUT);
+ writel(1, wd->base + WDT_REG_CONTROL);
+ }
+
+ return 0;
+}
+
+static int starfive_wdt_drv_probe(struct device_d *dev)
+{
+ struct starfive_wdt *wd;
+ struct resource *iores;
+ struct watchdog *wdd;
+ struct clk_bulk_data clks[] = {
+ { .id = "bus" },
+ { .id = "core" },
+ };
+ int ret;
+
+ ret = clk_bulk_get(dev, ARRAY_SIZE(clks), clks);
+ if (ret)
+ return ret;
+
+ ret = clk_bulk_enable(ARRAY_SIZE(clks), clks);
+ if (ret < 0)
+ return ret;
+
+ ret = device_reset_all(dev);
+ if (ret)
+ return ret;
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+
+ wd = xzalloc(sizeof(*wd));
+ wd->base = IOMEM(iores->start);
+
+ wd->clk_rate = WDT_TICKS_PER_SEC;
+
+ writel(WDT_UNLOCK_KEY, wd->base + WDT_REG_UNLOCK);
+ wd->base = IOMEM(iores->start);
+ /* reset, not interrupt, on timer expiry */
+ writel(1, wd->base + WDT_REG_RESET_EN);
+
+ wdd = &wd->wdd;
+ wdd->name = "starfive_wdt";
+ wdd->hwdev = dev;
+ wdd->set_timeout = starfive_wdt_set_timeout;
+ wdd->timeout_max = U32_MAX / wd->clk_rate;
+
+ wdd->running = readl(wd->base + WDT_REG_CONTROL) & 1 ?
+ WDOG_HW_RUNNING : WDOG_HW_NOT_RUNNING;
+
+ return watchdog_register(wdd);
+}
+
+static struct of_device_id starfive_wdt_of_match[] = {
+ { .compatible = "starfive,wdt", },
+ { /* sentinel */ }
+};
+
+static struct driver_d starfive_wdt_driver = {
+ .name = "starfive-wdt",
+ .probe = starfive_wdt_drv_probe,
+ .of_compatible = starfive_wdt_of_match,
+};
+device_platform_driver(starfive_wdt_driver);