diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2021-07-18 07:13:55 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2021-07-18 07:13:55 +0200 |
commit | 33f8f53317659cd2c61dd118bfa7150f33aa30fb (patch) | |
tree | cec893f4b273f4a78e1d84326d15e97b75a456df /drivers | |
parent | ca922d6044e49b1ed9782aa8eb28d1ed70931978 (diff) | |
parent | b60bdac8a5870dc136c9b028771371dd123a2431 (diff) | |
download | barebox-33f8f53317659cd2c61dd118bfa7150f33aa30fb.tar.gz barebox-33f8f53317659cd2c61dd118bfa7150f33aa30fb.tar.xz |
Merge branch 'for-next/riscv'
Diffstat (limited to 'drivers')
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); |