From 0df342428870e6cfa113964c94e03150b450b658 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 27 May 2021 19:57:35 +0200 Subject: [PATCH 01/55] dt-bindings: usb: cdns,usb3: Fix interrupts order Correct the order of the descriptions for the "interrupts" property to match the order of the "interrupt-names" property. Fixes: 68989fe1c39d9b32 ("dt-bindings: usb: Convert cdns-usb3.txt to YAML schema") Signed-off-by: Geert Uytterhoeven --- Documentation/devicetree/bindings/usb/cdns,usb3.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/usb/cdns,usb3.yaml b/Documentation/devicetree/bindings/usb/cdns,usb3.yaml index a407e1143cf425..8dedfa16c9929d 100644 --- a/Documentation/devicetree/bindings/usb/cdns,usb3.yaml +++ b/Documentation/devicetree/bindings/usb/cdns,usb3.yaml @@ -28,9 +28,9 @@ properties: interrupts: minItems: 3 items: - - description: OTG/DRD controller interrupt - description: XHCI host controller interrupt - description: Device controller interrupt + - description: OTG/DRD controller interrupt - description: interrupt used to wake up core, e.g when usbcmd.rs is cleared by xhci core, this interrupt is optional From e93c67f58edc4dd1d26179325366adf5bcbf738a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 27 May 2021 20:03:18 +0200 Subject: [PATCH 02/55] mmc: dw_mmc-pltfm: Remove unused As of commit 4cdc2ec1da322776 ("mmc: dw_mmc: move rockchip related code to a separate file"), dw_mmc-pltfm.c no longer uses the clock API. Signed-off-by: Geert Uytterhoeven --- drivers/mmc/host/dw_mmc-pltfm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c index 73731cd3ba2315..9901208be7973f 100644 --- a/drivers/mmc/host/dw_mmc-pltfm.c +++ b/drivers/mmc/host/dw_mmc-pltfm.c @@ -17,7 +17,6 @@ #include #include #include -#include #include "dw_mmc.h" #include "dw_mmc-pltfm.h" From 6814ff18619a3b17924d477fd77db1190c73bdf6 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Sun, 30 May 2021 23:42:44 -0700 Subject: [PATCH 03/55] dt-bindings: add StarFive Technology Co. Ltd. Add vendor prefix for StarFive Technology Co. Ltd [1]. StarFive was formed in 2018 and has now produced their first SoC, the JH7100, which contains 64-bit RISC-V cores [2]. It used in the BeagleV Starlight [3]. [1] https://starfivetech.com/site/company [2] https://github.com/beagleboard/beaglev-starlight [3] https://github.com/starfive-tech/beaglev_doc Signed-off-by: Drew Fustini --- Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index b868cefc7c5500..3dd6a42fbbad2b 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -1085,6 +1085,8 @@ patternProperties: (formerly part of MStar Semiconductor, Inc.) "^st,.*": description: STMicroelectronics + "^starfive,.*": + description: StarFive Technology Co. Ltd. "^starry,.*": description: Starry Electronic Technology (ShenZhen) Co., LTD "^startek,.*": From 1928e3b1c72869d042bf6119d7645e78532aa7f4 Mon Sep 17 00:00:00 2001 From: Matteo Croce Date: Wed, 9 Jun 2021 19:23:03 +0200 Subject: [PATCH 04/55] stmmac: prefetch right address To support XDP, a headroom is prepended to the packet data. Consider this offset when doing a prefetch. Fixes: da5ec7f22a0f ("net: stmmac: refactor stmmac_init_rx_buffers for stmmac_reinit_rx_buffers") Signed-off-by: Matteo Croce Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index c87202cbd3d6d3..91cd5073ddb261 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -5138,7 +5138,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) /* Buffer is good. Go on. */ - prefetch(page_address(buf->page)); + prefetch(page_address(buf->page) + buf->page_offset); if (buf->sec_page) prefetch(page_address(buf->sec_page)); From 29fb86f43c14fe055554d13c640ea7c2a454d466 Mon Sep 17 00:00:00 2001 From: Wong Vee Khee Date: Fri, 11 Jun 2021 17:02:38 +0800 Subject: [PATCH 05/55] net: stmmac: Fix potential integer overflow The commit d96febedfde2 ("net: stmmac: arrange Tx tail pointer update to stmmac_flush_tx_descriptors") introduced the following coverity warning:- 1. Unintentional integer overflow (OVERFLOW_BEFORE_WIDEN) overflow_before_widen: Potentially overflowing expression 'tx_q->cur_tx * desc_size' with type 'unsigned int' (32 bits, unsigned) is evaluated using 32-bit arithmetic, and then used in a context that expects an expression of type dma_addr_t (64 bits, unsigned). Fixed this by assigning tx_tail_addr to dma_addr_t type, as dma_addr_t datatype is decided by CONFIG_ARCH_DMA_ADDR_T_64_BIT. Fixes: d96febedfde2 ("net: stmmac: arrange Tx tail pointer update to stmmac_flush_tx_descriptors") Signed-off-by: Wong Vee Khee Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index b6cd43eda7acc1..8aa55612d0949c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -75,7 +75,7 @@ struct stmmac_tx_queue { unsigned int cur_tx; unsigned int dirty_tx; dma_addr_t dma_tx_phy; - u32 tx_tail_addr; + dma_addr_t tx_tail_addr; u32 mss; }; From 1fe56de5efc64cbee41e0ca33a9f1d0533c84089 Mon Sep 17 00:00:00 2001 From: Matteo Croce Date: Mon, 14 Jun 2021 04:25:04 +0200 Subject: [PATCH 06/55] stmmac: align RX buffers On RX an SKB is allocated and the received buffer is copied into it. But on some architectures, the memcpy() needs the source and destination buffers to have the same alignment to be efficient. This is not our case, because SKB data pointer is misaligned by two bytes to compensate the ethernet header. Align the RX buffer the same way as the SKB one, so the copy is faster. An iperf3 RX test gives a decent improvement on a RISC-V machine: before: [ ID] Interval Transfer Bitrate Retr [ 5] 0.00-10.00 sec 733 MBytes 615 Mbits/sec 88 sender [ 5] 0.00-10.01 sec 730 MBytes 612 Mbits/sec receiver after: [ ID] Interval Transfer Bitrate Retr [ 5] 0.00-10.00 sec 1.10 GBytes 942 Mbits/sec 0 sender [ 5] 0.00-10.00 sec 1.09 GBytes 940 Mbits/sec receiver And the memcpy() overhead during the RX drops dramatically. before: Overhead Shared O Symbol 43.35% [kernel] [k] memcpy 33.77% [kernel] [k] __asm_copy_to_user 3.64% [kernel] [k] sifive_l2_flush64_range after: Overhead Shared O Symbol 45.40% [kernel] [k] __asm_copy_to_user 28.09% [kernel] [k] memcpy 4.27% [kernel] [k] sifive_l2_flush64_range Signed-off-by: Matteo Croce Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index 8aa55612d0949c..82cee970aaadac 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -338,9 +338,9 @@ static inline bool stmmac_xdp_is_enabled(struct stmmac_priv *priv) static inline unsigned int stmmac_rx_offset(struct stmmac_priv *priv) { if (stmmac_xdp_is_enabled(priv)) - return XDP_PACKET_HEADROOM; + return XDP_PACKET_HEADROOM + NET_IP_ALIGN; - return 0; + return NET_SKB_PAD + NET_IP_ALIGN; } void stmmac_disable_rx_queue(struct stmmac_priv *priv, u32 queue); From bd8687871f1d5878b5391c08000680e2025a87e0 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Wed, 16 Jun 2021 01:49:31 -0700 Subject: [PATCH 07/55] dt-bindings: riscv: add starfive jh7100 bindings Add DT binding documentation for the StarFive JH7100 Soc [1] and the BeagleV Starlight JH7100 board [2]. [1] https://github.com/starfive-tech/beaglev_doc [2] https://github.com/beagleboard/beaglev-starlight Signed-off-by: Drew Fustini --- .../devicetree/bindings/riscv/starfive.yaml | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 Documentation/devicetree/bindings/riscv/starfive.yaml diff --git a/Documentation/devicetree/bindings/riscv/starfive.yaml b/Documentation/devicetree/bindings/riscv/starfive.yaml new file mode 100644 index 00000000000000..4deae9f5c60d7c --- /dev/null +++ b/Documentation/devicetree/bindings/riscv/starfive.yaml @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/riscv/starfive.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: StarFive SoC-based boards + +maintainers: + - Michael Zhu + - Drew Fustini + +description: + SiFive SoC-based boards + +properties: + $nodename: + const: '/' + compatible: + oneOf: + - items: + - const: beagle,beaglev-starlight-jh7100 + - const: starfive,jh7100 + + - items: + - const: starfive,jh7100 + +additionalProperties: true + +... From 40ed7badf2225ea763a9bc048c9b953799ef8112 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 1 Jun 2021 16:02:23 +0200 Subject: [PATCH 08/55] [WIP] dt-bindings: clock: starfive: Add preliminary JH7100 bindings Add preliminary Device Tree bindings for the StarFive JH7100 Clock Generator. To be verified against documentation when it becomes available. Signed-off-by: Geert Uytterhoeven --- .../clock/starfive,jh7100-clkgen.yaml | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/starfive,jh7100-clkgen.yaml diff --git a/Documentation/devicetree/bindings/clock/starfive,jh7100-clkgen.yaml b/Documentation/devicetree/bindings/clock/starfive,jh7100-clkgen.yaml new file mode 100644 index 00000000000000..9e88ac647ae2a7 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/starfive,jh7100-clkgen.yaml @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/starfive,jh7100-clkgen.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: StarFive JH7100 Clock Generator + +maintainers: + - FIXME + - Geert Uytterhoeven + +properties: + compatible: + const: starfive,jh7100-clkgen + + reg: + maxItems: 1 + + clocks: + items: + - description: Main clock source (default 25 MHz) + - description: Application-specific clock source (12-27 MHz) + + clock-names: + items: + - const: osc0 + - const: osc1 + + '#clock-cells': + const: 1 + description: + See for valid indices. + +required: + - compatible + - reg + - clocks + - clock-names + - '#clock-cells' + +additionalProperties: false + +examples: + - | + clkgen: clock-controller@11800000 { + compatible = "starfive,jh7100-clkgen"; + reg = <0x11800000 0x10000>; + clocks = <&osc0_clk>, <&osc1_clk>; + clock-names = "osc0", "osc1"; + #clock-cells = <1>; + }; From f36db575f616dcfbac99f086bbf34f9b2464ebaa Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 1 Jun 2021 15:57:52 +0200 Subject: [PATCH 09/55] [WIP] dt-bindings: clock: starfive: Add preliminary JH7100 Clock Definitions Add all clock outputs for the StarFive JH7100 Clock Generator, based on the list of fixed-frequency clocks defined in jh7100.dtsi. To be verified against documentation when it becomes available. Signed-off-by: Geert Uytterhoeven --- .../clock/starfive-jh7100-clkgen.h | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 include/dt-bindings/clock/starfive-jh7100-clkgen.h diff --git a/include/dt-bindings/clock/starfive-jh7100-clkgen.h b/include/dt-bindings/clock/starfive-jh7100-clkgen.h new file mode 100644 index 00000000000000..5f6807c82ec55a --- /dev/null +++ b/include/dt-bindings/clock/starfive-jh7100-clkgen.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */ +/* + * Copyright (C) 2021 Glider bv + */ +#ifndef __DT_BINDINGS_CLOCK_STARFIVE_JH7100_CLOCK_H__ +#define __DT_BINDINGS_CLOCK_STARFIVE_JH7100_CLOCK_H__ + +/* StarFive JH7100 clocks FIXME PRELIMINARY */ +#define JH7100_CLK_AXI 0 +#define JH7100_CLK_AHB0 1 +#define JH7100_CLK_AHB2 2 +#define JH7100_CLK_APB1 3 +#define JH7100_CLK_APB2 4 +#define JH7100_CLK_VPU 5 +#define JH7100_CLK_JPU 6 +#define JH7100_CLK_PWM 7 +#define JH7100_CLK_DWMMC_BIU 8 +#define JH7100_CLK_DWMMC_CIU 9 +#define JH7100_CLK_UART 10 +#define JH7100_CLK_HS_UART 11 +#define JH7100_CLK_I2C0 12 +#define JH7100_CLK_I2C2 13 +#define JH7100_CLK_QSPI 14 +#define JH7100_CLK_SPI 15 +#define JH7100_CLK_GMAC 16 +#define JH7100_CLK_HF 17 +#define JH7100_CLK_RTC 18 + +#endif /* __DT_BINDINGS_CLOCK_STARFIVE_JH7100_CLOCK_H__ */ From c439373dd560cc20123abf936bf7c24f089f24ef Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 1 Jun 2021 15:57:52 +0200 Subject: [PATCH 10/55] [WIP] clk: starfive: Add preliminary JH7100 Clock Generator Driver Add a preliminary driver for the StarFive JH7100 Clock Generator. For now, all clocks are implemented as fixed-factor clocks relative to osc0, based on the list of fixed-frequency clocks defined in jh7100.dtsi. To be updated when the documentation becomes available. Signed-off-by: Geert Uytterhoeven --- drivers/clk/Kconfig | 1 + drivers/clk/Makefile | 1 + drivers/clk/starfive/Kconfig | 9 ++ drivers/clk/starfive/Makefile | 3 + drivers/clk/starfive/clk-starfive-jh7100.c | 124 +++++++++++++++++++++ 5 files changed, 138 insertions(+) create mode 100644 drivers/clk/starfive/Kconfig create mode 100644 drivers/clk/starfive/Makefile create mode 100644 drivers/clk/starfive/clk-starfive-jh7100.c diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index e80918be8e9c45..61b243a14f428b 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -397,6 +397,7 @@ source "drivers/clk/samsung/Kconfig" source "drivers/clk/sifive/Kconfig" source "drivers/clk/socfpga/Kconfig" source "drivers/clk/sprd/Kconfig" +source "drivers/clk/starfive/Kconfig" source "drivers/clk/sunxi/Kconfig" source "drivers/clk/sunxi-ng/Kconfig" source "drivers/clk/tegra/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 5f06879d7fe98c..c154596d1ab5c6 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -109,6 +109,7 @@ obj-y += socfpga/ obj-$(CONFIG_PLAT_SPEAR) += spear/ obj-y += sprd/ obj-$(CONFIG_ARCH_STI) += st/ +obj-$(CONFIG_SOC_STARFIVE_VIC7100) += starfive/ obj-$(CONFIG_ARCH_SUNXI) += sunxi/ obj-$(CONFIG_SUNXI_CCU) += sunxi-ng/ obj-$(CONFIG_ARCH_TEGRA) += tegra/ diff --git a/drivers/clk/starfive/Kconfig b/drivers/clk/starfive/Kconfig new file mode 100644 index 00000000000000..0e23c9a8a66381 --- /dev/null +++ b/drivers/clk/starfive/Kconfig @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0 + +config CLK_STARFIVE_JH7100 + bool "StarFive JH7100 clock support" + depends on SOC_STARFIVE_VIC7100 || COMPILE_TEST + default y if SOC_STARFIVE_VIC7100 + help + Say yes here to support the clock controller on the StarFive JH7100 + SoC. diff --git a/drivers/clk/starfive/Makefile b/drivers/clk/starfive/Makefile new file mode 100644 index 00000000000000..09759cc735307f --- /dev/null +++ b/drivers/clk/starfive/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 +# StarFive Clock +obj-$(CONFIG_CLK_STARFIVE_JH7100) += clk-starfive-jh7100.o diff --git a/drivers/clk/starfive/clk-starfive-jh7100.c b/drivers/clk/starfive/clk-starfive-jh7100.c new file mode 100644 index 00000000000000..a768394c28f0a1 --- /dev/null +++ b/drivers/clk/starfive/clk-starfive-jh7100.c @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * StarFive JH7100 Clock Generator Driver + * This is part of the PCR (Power/Clock/Reset) Management Unit Driver + * + * FIXME PRELIMINARY + * For now, all clocks are implemented as fixed-factor clocks relative to osc0 + * + * TODO Real clock topology, clock register programming + * PLL0 used for system main logic, including CPU, bus + * PLL1 output to support DDR, DLA and DSP + * PLL2 output to support slow speed peripherals, video input and video output + * + * Copyright (C) 2021 Glider bv + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static const struct jh7100_clk { + const char *name; + unsigned int mult; + unsigned int div; +} jh7100_clks[] = { + [JH7100_CLK_AXI] = { "axi", .mult = 20, .div = 1 }, + [JH7100_CLK_AHB0] = { "ahb0", .mult = 10, .div = 1 }, + [JH7100_CLK_AHB2] = { "ahb2", .mult = 5, .div = 1 }, + [JH7100_CLK_APB1] = { "apb1", .mult = 5, .div = 1 }, + [JH7100_CLK_APB2] = { "apb2", .mult = 5, .div = 1 }, + [JH7100_CLK_VPU] = { "vpu", .mult = 16, .div = 1 }, + [JH7100_CLK_JPU] = { "jpu", .mult = 40, .div = 3 }, + [JH7100_CLK_PWM] = { "pwm", .mult = 5, .div = 1 }, + [JH7100_CLK_DWMMC_BIU] = { "dwmmc-biu", .mult = 4, .div = 1 }, + [JH7100_CLK_DWMMC_CIU] = { "dwmmc-ciu", .mult = 4, .div = 1 }, + [JH7100_CLK_UART] = { "uart", .mult = 4, .div = 1 }, + [JH7100_CLK_HS_UART] = { "hs_uart", .mult = 297, .div = 100 }, + [JH7100_CLK_I2C0] = { "i2c0", .mult = 99, .div = 50 }, + [JH7100_CLK_I2C2] = { "i2c2", .mult = 2, .div = 1 }, + [JH7100_CLK_QSPI] = { "qspi", .mult = 2, .div = 1 }, + [JH7100_CLK_SPI] = { "spi", .mult = 2, .div = 1 }, + [JH7100_CLK_GMAC] = { "gmac", .mult = 1, .div = 1 }, + [JH7100_CLK_HF] = { "hf", .mult = 1, .div = 1 }, + [JH7100_CLK_RTC] = { "rtc", .mult = 1, .div = 4 } +}; + +struct clk_starfive_jh7100_priv { + struct clk_onecell_data data; + void __iomem *base; + struct clk *clks[]; +}; + +static int __init clk_starfive_jh7100_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + unsigned int nclks = ARRAY_SIZE(jh7100_clks); + struct clk_starfive_jh7100_priv *priv; + const char *osc0_name; + struct clk_hw *hw; + struct clk *osc0; + unsigned int i; + + priv = devm_kzalloc(dev, struct_size(priv, clks, nclks), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + osc0 = devm_clk_get(dev, "osc0"); + if (IS_ERR(osc0)) + return PTR_ERR(osc0); + + osc0_name = __clk_get_name(osc0); + + for (i = 0; i < nclks; i++) { + hw = devm_clk_hw_register_fixed_factor(dev, + jh7100_clks[i].name, osc0_name, 0, jh7100_clks[i].mult, + jh7100_clks[i].div); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + priv->clks[i] = hw->clk; + } + + priv->data.clks = priv->clks; + priv->data.clk_num = nclks; + + return of_clk_add_provider(np, of_clk_src_onecell_get, &priv->data); +} + +static const struct of_device_id clk_starfive_jh7100_match[] = { + { + .compatible = "starfive,jh7100-clkgen", + }, + { /* sentinel */ } +}; +static struct platform_driver clk_starfive_jh7100_driver = { + .driver = { + .name = "clk-starfive-jh7100", + .of_match_table = clk_starfive_jh7100_match, + }, +}; + +static int __init clk_starfive_jh7100_init(void) +{ + return platform_driver_probe(&clk_starfive_jh7100_driver, + clk_starfive_jh7100_probe); +} + +subsys_initcall(clk_starfive_jh7100_init); + +MODULE_DESCRIPTION("StarFive JH7100 Clock Generator Driver"); +MODULE_AUTHOR("Geert Uytterhoeven "); +MODULE_LICENSE("GPL v2"); From f2b20a0558b1f1cb73a3262c1dd7fc55dbeca2f4 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Mon, 31 May 2021 00:07:38 -0700 Subject: [PATCH 11/55] dt-bindings: gpio: add starfive,jh7100-gpio bindings Add bindings for the GPIO controller in the StarFive JH7100 SoC [1]. [1] https://github.com/starfive-tech/beaglev_doc Signed-off-by: Drew Fustini --- .../bindings/gpio/starfive,jh7100-gpio.yaml | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpio/starfive,jh7100-gpio.yaml diff --git a/Documentation/devicetree/bindings/gpio/starfive,jh7100-gpio.yaml b/Documentation/devicetree/bindings/gpio/starfive,jh7100-gpio.yaml new file mode 100644 index 00000000000000..8c9d14d9ac3b69 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/starfive,jh7100-gpio.yaml @@ -0,0 +1,60 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpio/starfive,jh7100-gpio.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: StarFive JH7100 GPIO controller + +maintainers: + - Huan Feng + - Drew Fustini + +properties: + compatible: + items: + - const: starfive,jh7100-gpio + + reg: + maxItems: 1 + + interrupts: + description: + Interrupt mapping, one per GPIO. Maximum 32 GPIOs. + minItems: 1 + maxItems: 32 + + gpio-controller: true + + "#gpio-cells": + const: 2 + + interrupt-controller: true + + "#interrupt-cells": + const: 2 + +required: + - compatible + - reg + - interrupts + - interrupt-controller + - "#interrupt-cells" + - "#gpio-cells" + - gpio-controller + +additionalProperties: false + +examples: + - | + gpio@11910000 { + compatible = "starfive,jh7100-gpio"; + reg = <0x11910000 0x10000>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <32>; + }; + +... From b9823836811a6b4ff289f86bd010a003150eba8d Mon Sep 17 00:00:00 2001 From: Huan Feng Date: Fri, 8 Jan 2021 03:19:19 +0800 Subject: [PATCH 12/55] gpio: starfive-jh7100: Add StarFive JH7100 GPIO driver This SoC is used on the BeagleV Starlight JH7100 board [1]. [1] https://github.com/beagleboard/beaglev-starlight Signed-off-by: Emil Renner Berthing Signed-off-by: Drew Fustini --- drivers/gpio/Kconfig | 8 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-starfive-jh7100.c | 426 ++++++++++++++++++++++++++++ 3 files changed, 435 insertions(+) create mode 100644 drivers/gpio/gpio-starfive-jh7100.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 1dd0ec6727fde2..26630e4852c077 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -542,6 +542,14 @@ config GPIO_SIFIVE help Say yes here to support the GPIO device on SiFive SoCs. +config GPIO_STARFIVE_JH7100 + bool "StarFive JH7100 GPIO support" + depends on OF_GPIO + select GPIOLIB_IRQCHIP + default y if SOC_STARFIVE_VIC7100 + help + Say yes here to support the GPIO device on StarFive JH7100 SoC. + config GPIO_SIOX tristate "SIOX GPIO support" depends on SIOX diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index d7c81e1611a4d5..939922eaf5f355 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -132,6 +132,7 @@ obj-$(CONFIG_GPIO_SAMA5D2_PIOBU) += gpio-sama5d2-piobu.o obj-$(CONFIG_GPIO_SCH311X) += gpio-sch311x.o obj-$(CONFIG_GPIO_SCH) += gpio-sch.o obj-$(CONFIG_GPIO_SIFIVE) += gpio-sifive.o +obj-$(CONFIG_GPIO_STARFIVE_JH7100) += gpio-starfive-jh7100.o obj-$(CONFIG_GPIO_SIOX) += gpio-siox.o obj-$(CONFIG_GPIO_SL28CPLD) += gpio-sl28cpld.o obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o diff --git a/drivers/gpio/gpio-starfive-jh7100.c b/drivers/gpio/gpio-starfive-jh7100.c new file mode 100644 index 00000000000000..06c4399ba0356d --- /dev/null +++ b/drivers/gpio/gpio-starfive-jh7100.c @@ -0,0 +1,426 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * GPIO driver for StarFive JH7100 SoC + * + * Copyright (C) 2020 Shanghai StarFive Technology Co., Ltd. + */ + +#include +#include +#include +#include +#include + +#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 { + raw_spinlock_t lock; + void __iomem *base; + struct gpio_chip gc; + unsigned long enabled; + unsigned int trigger[MAX_GPIO]; + unsigned int irq_parent[MAX_GPIO]; +}; + +static int starfive_direction_input(struct gpio_chip *gc, unsigned int offset) +{ + struct starfive_gpio *chip = gpiochip_get_data(gc); + unsigned long flags; + + if (offset >= gc->ngpio) + return -EINVAL; + + raw_spin_lock_irqsave(&chip->lock, flags); + writel_relaxed(0x1, chip->base + GPIO_DOEN_X_REG + offset * 8); + raw_spin_unlock_irqrestore(&chip->lock, flags); + + return 0; +} + +static int starfive_direction_output(struct gpio_chip *gc, unsigned int offset, int value) +{ + struct starfive_gpio *chip = gpiochip_get_data(gc); + unsigned long flags; + + if (offset >= gc->ngpio) + return -EINVAL; + + raw_spin_lock_irqsave(&chip->lock, flags); + writel_relaxed(0x0, chip->base + GPIO_DOEN_X_REG + offset * 8); + writel_relaxed(value, chip->base + GPIO_DOUT_X_REG + offset * 8); + raw_spin_unlock_irqrestore(&chip->lock, flags); + + return 0; +} + +static int starfive_get_direction(struct gpio_chip *gc, unsigned int offset) +{ + struct starfive_gpio *chip = gpiochip_get_data(gc); + + if (offset >= gc->ngpio) + return -EINVAL; + + return readl_relaxed(chip->base + GPIO_DOEN_X_REG + offset * 8) & 0x1; +} + +static int starfive_get_value(struct gpio_chip *gc, unsigned int offset) +{ + struct starfive_gpio *chip = gpiochip_get_data(gc); + int value; + + if (offset >= gc->ngpio) + return -EINVAL; + + if (offset < 32) { + value = readl_relaxed(chip->base + GPIO_DIN_LOW); + value = (value >> offset) & 0x1; + } else { + value = readl_relaxed(chip->base + GPIO_DIN_HIGH); + value = (value >> (offset - 32)) & 0x1; + } + + return value; +} + +static void starfive_set_value(struct gpio_chip *gc, unsigned int offset, int value) +{ + struct starfive_gpio *chip = gpiochip_get_data(gc); + unsigned long flags; + + if (offset >= gc->ngpio) + return; + + raw_spin_lock_irqsave(&chip->lock, flags); + writel_relaxed(value, chip->base + GPIO_DOUT_X_REG + offset * 8); + raw_spin_unlock_irqrestore(&chip->lock, flags); +} + +static void starfive_set_ie(struct starfive_gpio *chip, int offset) +{ + unsigned long flags; + int old_value, new_value; + int reg_offset, index; + + if (offset < 32) { + reg_offset = 0; + index = offset; + } else { + reg_offset = 4; + index = offset - 32; + } + raw_spin_lock_irqsave(&chip->lock, flags); + old_value = readl_relaxed(chip->base + GPIO_IE_LOW + reg_offset); + new_value = old_value | (1 << index); + writel_relaxed(new_value, chip->base + GPIO_IE_LOW + reg_offset); + raw_spin_unlock_irqrestore(&chip->lock, flags); +} + +static int starfive_irq_set_type(struct irq_data *d, unsigned int trigger) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct starfive_gpio *chip = gpiochip_get_data(gc); + int offset = irqd_to_hwirq(d); + unsigned int reg_is, reg_ibe, reg_iev; + int reg_offset, index; + + if (offset < 0 || offset >= gc->ngpio) + return -EINVAL; + + if (offset < 32) { + reg_offset = 0; + index = offset; + } else { + reg_offset = 4; + index = offset - 32; + } + switch (trigger) { + case IRQ_TYPE_LEVEL_HIGH: + reg_is = readl_relaxed(chip->base + GPIO_IS_LOW + reg_offset); + reg_ibe = readl_relaxed(chip->base + GPIO_IBE_LOW + reg_offset); + reg_iev = readl_relaxed(chip->base + GPIO_IEV_LOW + reg_offset); + reg_is &= ~(1 << index); + reg_ibe &= ~(1 << index); + reg_iev |= (1 << index); + writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset); + writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset); + writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset); + break; + case IRQ_TYPE_LEVEL_LOW: + reg_is = readl_relaxed(chip->base + GPIO_IS_LOW + reg_offset); + reg_ibe = readl_relaxed(chip->base + GPIO_IBE_LOW + reg_offset); + reg_iev = readl_relaxed(chip->base + GPIO_IEV_LOW + reg_offset); + reg_is &= ~(1 << index); + reg_ibe &= ~(1 << index); + reg_iev &= (1 << index); + writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset); + writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset); + writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset); + break; + case IRQ_TYPE_EDGE_BOTH: + reg_is = readl_relaxed(chip->base + GPIO_IS_LOW + reg_offset); + reg_ibe = readl_relaxed(chip->base + GPIO_IBE_LOW + reg_offset); + //reg_iev = readl_relaxed(chip->base + GPIO_IEV_LOW + reg_offset); + reg_is |= ~(1 << index); + reg_ibe |= ~(1 << index); + //reg_iev |= (1 << index); + writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset); + writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset); + //writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset); + break; + case IRQ_TYPE_EDGE_RISING: + reg_is = readl_relaxed(chip->base + GPIO_IS_LOW + reg_offset); + reg_ibe = readl_relaxed(chip->base + GPIO_IBE_LOW + reg_offset); + reg_iev = readl_relaxed(chip->base + GPIO_IEV_LOW + reg_offset); + reg_is |= ~(1 << index); + reg_ibe &= ~(1 << index); + reg_iev |= (1 << index); + writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset); + writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset); + writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset); + break; + case IRQ_TYPE_EDGE_FALLING: + reg_is = readl_relaxed(chip->base + GPIO_IS_LOW + reg_offset); + reg_ibe = readl_relaxed(chip->base + GPIO_IBE_LOW + reg_offset); + reg_iev = readl_relaxed(chip->base + GPIO_IEV_LOW + reg_offset); + reg_is |= ~(1 << index); + reg_ibe &= ~(1 << index); + reg_iev &= (1 << index); + writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset); + writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset); + writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset); + break; + } + + chip->trigger[offset] = trigger; + starfive_set_ie(chip, offset); + return 0; +} + +/* chained_irq_{enter,exit} already mask the parent */ +static void starfive_irq_mask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct starfive_gpio *chip = gpiochip_get_data(gc); + unsigned int value; + int offset = irqd_to_hwirq(d); + int reg_offset, index; + + if (offset < 0 || offset >= gc->ngpio) + return; + + if (offset < 32) { + reg_offset = 0; + index = offset; + } else { + reg_offset = 4; + index = offset - 32; + } + + value = readl_relaxed(chip->base + GPIO_IE_LOW + reg_offset); + value &= ~(0x1 << index); + writel_relaxed(value, chip->base + GPIO_IE_LOW + reg_offset); +} + +static void starfive_irq_unmask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct starfive_gpio *chip = gpiochip_get_data(gc); + unsigned int value; + int offset = irqd_to_hwirq(d); + int reg_offset, index; + + if (offset < 0 || offset >= gc->ngpio) + return; + + if (offset < 32) { + reg_offset = 0; + index = offset; + } else { + reg_offset = 4; + index = offset - 32; + } + + value = readl_relaxed(chip->base + GPIO_IE_LOW + reg_offset); + value |= (0x1 << index); + writel_relaxed(value, chip->base + GPIO_IE_LOW + reg_offset); +} + +static void starfive_irq_enable(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct starfive_gpio *chip = gpiochip_get_data(gc); + int offset = irqd_to_hwirq(d); + + starfive_irq_unmask(d); + assign_bit(offset, &chip->enabled, 1); +} + +static void starfive_irq_disable(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct starfive_gpio *chip = gpiochip_get_data(gc); + int offset = irqd_to_hwirq(d) % MAX_GPIO; // must not fail + + assign_bit(offset, &chip->enabled, 0); + starfive_set_ie(chip, offset); +} + +static struct irq_chip starfive_irqchip = { + .name = "starfive-jh7100-gpio", + .irq_set_type = starfive_irq_set_type, + .irq_mask = starfive_irq_mask, + .irq_unmask = starfive_irq_unmask, + .irq_enable = starfive_irq_enable, + .irq_disable = starfive_irq_disable, +}; + +static irqreturn_t starfive_irq_handler(int irq, void *gc) +{ + int offset; + int reg_offset, index; + unsigned int value; + unsigned long flags; + struct starfive_gpio *chip = gc; + + for (offset = 0; offset < 64; offset++) { + if (offset < 32) { + reg_offset = 0; + index = offset; + } else { + reg_offset = 4; + index = offset - 32; + } + + raw_spin_lock_irqsave(&chip->lock, flags); + value = readl_relaxed(chip->base + GPIO_MIS_LOW + reg_offset); + if (value & BIT(index)) + writel_relaxed(BIT(index), chip->base + GPIO_IC_LOW + + reg_offset); + + /* generic_handle_irq(irq_find_mapping(chip->gc.irq.domain, offset)); */ + raw_spin_unlock_irqrestore(&chip->lock, flags); + } + + return IRQ_HANDLED; +} + +static int starfive_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct starfive_gpio *chip; + struct gpio_irq_chip *girq; + struct resource *res; + int irq, ret, ngpio; + + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + chip->base = devm_ioremap_resource(dev, res); + if (IS_ERR(chip->base)) { + dev_err(dev, "failed to allocate device memory\n"); + return PTR_ERR(chip->base); + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "Cannot get IRQ resource\n"); + return irq; + } + + raw_spin_lock_init(&chip->lock); + chip->gc.direction_input = starfive_direction_input; + chip->gc.direction_output = starfive_direction_output; + chip->gc.get_direction = starfive_get_direction; + chip->gc.get = starfive_get_value; + chip->gc.set = starfive_set_value; + chip->gc.base = 0; + chip->gc.ngpio = 64; + chip->gc.label = dev_name(dev); + chip->gc.parent = dev; + chip->gc.owner = THIS_MODULE; + + girq = &chip->gc.irq; + girq->chip = &starfive_irqchip; + girq->parent_handler = NULL; + girq->num_parents = 0; + girq->parents = NULL; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_simple_irq; + + ret = gpiochip_add_data(&chip->gc, chip); + if (ret) { + dev_err(dev, "gpiochip_add_data ret=%d!\n", ret); + return ret; + } + + /* Disable all GPIO interrupts before enabling parent interrupts */ + iowrite32(0, chip->base + GPIO_IE_HIGH); + iowrite32(0, chip->base + GPIO_IE_LOW); + chip->enabled = 0; + + ret = devm_request_irq(dev, irq, starfive_irq_handler, IRQF_SHARED, + dev_name(dev), chip); + if (ret) { + dev_err(dev, "IRQ handler registering failed (%d)\n", ret); + return ret; + } + + writel_relaxed(1, chip->base + GPIO_EN); + + dev_info(dev, "StarFive GPIO chip registered %d GPIOs\n", ngpio); + + return 0; +} + +static const struct of_device_id starfive_gpio_match[] = { + { .compatible = "starfive,jh7100-gpio", }, + { /* sentinel */ }, +}; + +static struct platform_driver starfive_gpio_driver = { + .probe = starfive_gpio_probe, + .driver = { + .name = "gpio_starfive_jh7100", + .of_match_table = of_match_ptr(starfive_gpio_match), + }, +}; + +static int __init starfive_gpio_init(void) +{ + return platform_driver_register(&starfive_gpio_driver); +} +subsys_initcall(starfive_gpio_init); + +static void __exit starfive_gpio_exit(void) +{ + platform_driver_unregister(&starfive_gpio_driver); +} +module_exit(starfive_gpio_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Huan Feng "); +MODULE_DESCRIPTION("StarFive JH7100 GPIO driver"); From d6f652086f0480ca3972d62a160bd16b8b2e7dea Mon Sep 17 00:00:00 2001 From: Huan Feng Date: Fri, 8 Jan 2021 03:19:19 +0800 Subject: [PATCH 13/55] gpio: starfive-jh7100: Add legacy header and code Signed-off-by: Emil Renner Berthing --- drivers/gpio/gpio-starfive-jh7100.c | 120 +++++++++ include/linux/gpio-starfive-vic.h | 384 ++++++++++++++++++++++++++++ 2 files changed, 504 insertions(+) create mode 100644 include/linux/gpio-starfive-vic.h diff --git a/drivers/gpio/gpio-starfive-jh7100.c b/drivers/gpio/gpio-starfive-jh7100.c index 06c4399ba0356d..039b020d721f07 100644 --- a/drivers/gpio/gpio-starfive-jh7100.c +++ b/drivers/gpio/gpio-starfive-jh7100.c @@ -44,6 +44,10 @@ struct starfive_gpio { unsigned int irq_parent[MAX_GPIO]; }; +static DEFINE_SPINLOCK(sfg_lock); + +static void __iomem *gpio_base; + static int starfive_direction_input(struct gpio_chip *gc, unsigned int offset) { struct starfive_gpio *chip = gpiochip_get_data(gc); @@ -326,6 +330,121 @@ static irqreturn_t starfive_irq_handler(int irq, void *gc) return IRQ_HANDLED; } +void sf_vic_gpio_dout_reverse(int gpio, int en) +{ + unsigned int value; + int offset; + + if (!gpio_base) + return; + + offset = gpio * 8 + GPIO_DOUT_X_REG; + + spin_lock(&sfg_lock); + value = ioread32(gpio_base + offset); + value &= ~(0x1 << 31); + value |= (en & 0x1) << 31; + iowrite32(value, gpio_base + offset); + spin_unlock(&sfg_lock); +} +EXPORT_SYMBOL_GPL(sf_vic_gpio_dout_reverse); + +void sf_vic_gpio_dout_value(int gpio, int v) +{ + unsigned int value; + int offset; + + if (!gpio_base) + return; + + offset = gpio * 8 + GPIO_DOUT_X_REG; + spin_lock(&sfg_lock); + value = ioread32(gpio_base + offset); + value &= ~(0xFF); + value |= (v&0xFF); + iowrite32(value, gpio_base + offset); + spin_unlock(&sfg_lock); +} +EXPORT_SYMBOL_GPL(sf_vic_gpio_dout_value); + +void sf_vic_gpio_dout_low(int gpio) +{ + sf_vic_gpio_dout_value(gpio, 0); +} +EXPORT_SYMBOL_GPL(sf_vic_gpio_dout_low); + +void sf_vic_gpio_dout_high(int gpio) +{ + sf_vic_gpio_dout_value(gpio, 1); +} +EXPORT_SYMBOL_GPL(sf_vic_gpio_dout_high); + +void sf_vic_gpio_doen_reverse(int gpio, int en) +{ + unsigned int value; + int offset; + + if (!gpio_base) + return; + + offset = gpio * 8 + GPIO_DOEN_X_REG; + + spin_lock(&sfg_lock); + value = ioread32(gpio_base + offset); + value &= ~(0x1 << 31); + value |= (en & 0x1) << 31; + iowrite32(value, gpio_base + offset); + spin_unlock(&sfg_lock); +} +EXPORT_SYMBOL_GPL(sf_vic_gpio_doen_reverse); + +void sf_vic_gpio_doen_value(int gpio, int v) +{ + unsigned int value; + int offset; + + if (!gpio_base) + return; + + offset = gpio * 8 + GPIO_DOEN_X_REG; + + spin_lock(&sfg_lock); + value = ioread32(gpio_base + offset); + value &= ~(0xFF); + value |= (v&0xFF); + iowrite32(value, gpio_base + offset); + spin_unlock(&sfg_lock); +} +EXPORT_SYMBOL_GPL(sf_vic_gpio_doen_value); + +void sf_vic_gpio_doen_low(int gpio) +{ + sf_vic_gpio_doen_value(gpio, 0); +} +EXPORT_SYMBOL_GPL(sf_vic_gpio_doen_low); + +void sf_vic_gpio_doen_high(int gpio) +{ + sf_vic_gpio_doen_value(gpio, 1); +} +EXPORT_SYMBOL_GPL(sf_vic_gpio_doen_high); + +void sf_vic_gpio_manual(int offset, int v) +{ + unsigned int value; + + if (!gpio_base) + return; + + spin_lock(&sfg_lock); + value = ioread32(gpio_base + offset); + value &= ~(0xFF); + value |= (v&0xFF); + iowrite32(value, gpio_base + offset); + spin_unlock(&sfg_lock); +} +EXPORT_SYMBOL_GPL(sf_vic_gpio_manual); + static int starfive_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -344,6 +463,7 @@ static int starfive_gpio_probe(struct platform_device *pdev) dev_err(dev, "failed to allocate device memory\n"); return PTR_ERR(chip->base); } + gpio_base = chip->base; irq = platform_get_irq(pdev, 0); if (irq < 0) { diff --git a/include/linux/gpio-starfive-vic.h b/include/linux/gpio-starfive-vic.h new file mode 100644 index 00000000000000..0afcaf1876fbe5 --- /dev/null +++ b/include/linux/gpio-starfive-vic.h @@ -0,0 +1,384 @@ +#ifndef __GPIO_STARFIVE_VIC_H +#define __GPIO_STARFIVE_VIC_H + +extern void sf_vic_gpio_dout_reverse(int gpio, int en); +/* + * #define SET_GPIO_0_dout_cpu_jtag_tdo { \ + * uint32_t _ezchip_macro_read_value_=MA_INW(gpio_0_dout_REG_ADDR); \ + * _ezchip_macro_read_value_ &= ~(0xFF); \ + * _ezchip_macro_read_value_ |= (0x3&0xFF); \ + * MA_OUTW(gpio_0_dout_REG_ADDR,_ezchip_macro_read_value_); \ + * } + * in this example gpio is: 0, and v is: 0x3 + */ +extern void sf_vic_gpio_dout_value(int gpio, int v); +extern void sf_vic_gpio_dout_low(int gpio); +extern void sf_vic_gpio_dout_high(int gpio); + +extern void sf_vic_gpio_doen_reverse(int gpio, int en); +/* + * the same as sf_vic_gpio_dout_value + */ +extern void sf_vic_gpio_doen_value(int gpio, int v); +extern void sf_vic_gpio_doen_low(int gpio); +extern void sf_vic_gpio_doen_high(int gpio); + +/* + *#define SET_GPIO_uart2_pad_sin(gpio) { \ + * uint32_t _ezchip_macro_read_value_=MA_INW(gpio_uart2_pad_sin_REG_ADDR); \ + * _ezchip_macro_read_value_ &= ~(0xFF); \ + * _ezchip_macro_read_value_ |= ((gpio+2)&0xFF); \ + * MA_OUTW(gpio_uart2_pad_sin_REG_ADDR,_ezchip_macro_read_value_); \ + *} + * in this example offset is: 0x370, the offset of gpio_uart2_pad_sin_REG_ADDR + * and v is: gpio + 2 + */ +extern void sf_vic_gpio_manual(int offset, int v); + +#define SET_GPIO_dout_reverse_(gpionum, en) sf_vic_gpio_dout_reverse(gpionum, en) +#define SET_GPIO_dout_LOW(gpionum) sf_vic_gpio_dout_value(gpionum, 0x0) +#define SET_GPIO_dout_HIGH(gpionum) sf_vic_gpio_dout_value(gpionum, 0x1) +#define SET_GPIO_dout_clk_gmac_tophyref(gpionum) sf_vic_gpio_dout_value(gpionum, 0x2) +#define SET_GPIO_dout_cpu_jtag_tdo(gpionum) sf_vic_gpio_dout_value(gpionum, 0x3) +#define SET_GPIO_dout_cpu_jtag_tdo_oen(gpionum) sf_vic_gpio_dout_value(gpionum, 0x4) +#define SET_GPIO_dout_dmic_clk_out(gpionum) sf_vic_gpio_dout_value(gpionum, 0x5) +#define SET_GPIO_dout_dsp_JTDOEn_pad(gpionum) sf_vic_gpio_dout_value(gpionum, 0x6) +#define SET_GPIO_dout_dsp_JTDO_pad(gpionum) sf_vic_gpio_dout_value(gpionum, 0x7) +#define SET_GPIO_dout_i2c0_pad_sck_oe(gpionum) sf_vic_gpio_dout_value(gpionum, 0x8) +#define SET_GPIO_dout_i2c0_pad_sda_oe(gpionum) sf_vic_gpio_dout_value(gpionum, 0x9) +#define SET_GPIO_dout_i2c1_pad_sck_oe(gpionum) sf_vic_gpio_dout_value(gpionum, 0xa) +#define SET_GPIO_dout_i2c1_pad_sda_oe(gpionum) sf_vic_gpio_dout_value(gpionum, 0xb) +#define SET_GPIO_dout_i2c2_pad_sck_oe(gpionum) sf_vic_gpio_dout_value(gpionum, 0xc) +#define SET_GPIO_dout_i2c2_pad_sda_oe(gpionum) sf_vic_gpio_dout_value(gpionum, 0xd) +#define SET_GPIO_dout_i2c3_pad_sck_oe(gpionum) sf_vic_gpio_dout_value(gpionum, 0xe) +#define SET_GPIO_dout_i2c3_pad_sda_oe(gpionum) sf_vic_gpio_dout_value(gpionum, 0xf) +#define SET_GPIO_dout_i2srx_bclk_out(gpionum) sf_vic_gpio_dout_value(gpionum, 0x10) +#define SET_GPIO_dout_i2srx_bclk_out_oen(gpionum) sf_vic_gpio_dout_value(gpionum, 0x11) +#define SET_GPIO_dout_i2srx_lrck_out(gpionum) sf_vic_gpio_dout_value(gpionum, 0x12) +#define SET_GPIO_dout_i2srx_lrck_out_oen(gpionum) sf_vic_gpio_dout_value(gpionum, 0x13) +#define SET_GPIO_dout_i2srx_mclk_out(gpionum) sf_vic_gpio_dout_value(gpionum, 0x14) +#define SET_GPIO_dout_i2stx_bclk_out(gpionum) sf_vic_gpio_dout_value(gpionum, 0x15) +#define SET_GPIO_dout_i2stx_bclk_out_oen(gpionum) sf_vic_gpio_dout_value(gpionum, 0x16) +#define SET_GPIO_dout_i2stx_lrck_out(gpionum) sf_vic_gpio_dout_value(gpionum, 0x17) +#define SET_GPIO_dout_i2stx_lrckout_oen(gpionum) sf_vic_gpio_dout_value(gpionum, 0x18) +#define SET_GPIO_dout_i2stx_mclk_out(gpionum) sf_vic_gpio_dout_value(gpionum, 0x19) +#define SET_GPIO_dout_i2stx_sdout0(gpionum) sf_vic_gpio_dout_value(gpionum, 0x1a) +#define SET_GPIO_dout_i2stx_sdout1(gpionum) sf_vic_gpio_dout_value(gpionum, 0x1b) +#define SET_GPIO_dout_lcd_pad_csm_n(gpionum) sf_vic_gpio_dout_value(gpionum, 0x1c) +#define SET_GPIO_dout_pwm_pad_oe_n_bit0(gpionum) sf_vic_gpio_dout_value(gpionum, 0x1d) +#define SET_GPIO_dout_pwm_pad_oe_n_bit1(gpionum) sf_vic_gpio_dout_value(gpionum, 0x1e) +#define SET_GPIO_dout_pwm_pad_oe_n_bit2(gpionum) sf_vic_gpio_dout_value(gpionum, 0x1f) +#define SET_GPIO_dout_pwm_pad_oe_n_bit3(gpionum) sf_vic_gpio_dout_value(gpionum, 0x20) +#define SET_GPIO_dout_pwm_pad_oe_n_bit4(gpionum) sf_vic_gpio_dout_value(gpionum, 0x21) +#define SET_GPIO_dout_pwm_pad_oe_n_bit5(gpionum) sf_vic_gpio_dout_value(gpionum, 0x22) +#define SET_GPIO_dout_pwm_pad_oe_n_bit6(gpionum) sf_vic_gpio_dout_value(gpionum, 0x23) +#define SET_GPIO_dout_pwm_pad_oe_n_bit7(gpionum) sf_vic_gpio_dout_value(gpionum, 0x24) +#define SET_GPIO_dout_pwm_pad_out_bit0(gpionum) sf_vic_gpio_dout_value(gpionum, 0x25) +#define SET_GPIO_dout_pwm_pad_out_bit1(gpionum) sf_vic_gpio_dout_value(gpionum, 0x26) +#define SET_GPIO_dout_pwm_pad_out_bit2(gpionum) sf_vic_gpio_dout_value(gpionum, 0x27) +#define SET_GPIO_dout_pwm_pad_out_bit3(gpionum) sf_vic_gpio_dout_value(gpionum, 0x28) +#define SET_GPIO_dout_pwm_pad_out_bit4(gpionum) sf_vic_gpio_dout_value(gpionum, 0x29) +#define SET_GPIO_dout_pwm_pad_out_bit5(gpionum) sf_vic_gpio_dout_value(gpionum, 0x2a) +#define SET_GPIO_dout_pwm_pad_out_bit6(gpionum) sf_vic_gpio_dout_value(gpionum, 0x2b) +#define SET_GPIO_dout_pwm_pad_out_bit7(gpionum) sf_vic_gpio_dout_value(gpionum, 0x2c) +#define SET_GPIO_dout_pwmdac_left_out(gpionum) sf_vic_gpio_dout_value(gpionum, 0x2d) +#define SET_GPIO_dout_pwmdac_right_out(gpionum) sf_vic_gpio_dout_value(gpionum, 0x2e) +#define SET_GPIO_dout_qspi_csn1_out(gpionum) sf_vic_gpio_dout_value(gpionum, 0x2f) +#define SET_GPIO_dout_qspi_csn2_out(gpionum) sf_vic_gpio_dout_value(gpionum, 0x30) +#define SET_GPIO_dout_qspi_csn3_out(gpionum) sf_vic_gpio_dout_value(gpionum, 0x31) +#define SET_GPIO_dout_register23_SCFG_cmsensor_rst0(gpionum) sf_vic_gpio_dout_value(gpionum, 0x32) +#define SET_GPIO_dout_register23_SCFG_cmsensor_rst1(gpionum) sf_vic_gpio_dout_value(gpionum, 0x33) +#define SET_GPIO_dout_register32_SCFG_gmac_phy_rstn(gpionum) sf_vic_gpio_dout_value(gpionum, 0x34) +#define SET_GPIO_dout_sdio0_pad_card_power_en(gpionum) sf_vic_gpio_dout_value(gpionum, 0x35) +#define SET_GPIO_dout_sdio0_pad_cclk_out(gpionum) sf_vic_gpio_dout_value(gpionum, 0x36) +#define SET_GPIO_dout_sdio0_pad_ccmd_oe(gpionum) sf_vic_gpio_dout_value(gpionum, 0x37) +#define SET_GPIO_dout_sdio0_pad_ccmd_out(gpionum) sf_vic_gpio_dout_value(gpionum, 0x38) +#define SET_GPIO_dout_sdio0_pad_cdata_oe_bit0(gpionum) sf_vic_gpio_dout_value(gpionum, 0x39) +#define SET_GPIO_dout_sdio0_pad_cdata_oe_bit1(gpionum) sf_vic_gpio_dout_value(gpionum, 0x3a) +#define SET_GPIO_dout_sdio0_pad_cdata_oe_bit2(gpionum) sf_vic_gpio_dout_value(gpionum, 0x3b) +#define SET_GPIO_dout_sdio0_pad_cdata_oe_bit3(gpionum) sf_vic_gpio_dout_value(gpionum, 0x3c) +#define SET_GPIO_dout_sdio0_pad_cdata_oe_bit4(gpionum) sf_vic_gpio_dout_value(gpionum, 0x3d) +#define SET_GPIO_dout_sdio0_pad_cdata_oe_bit5(gpionum) sf_vic_gpio_dout_value(gpionum, 0x3e) +#define SET_GPIO_dout_sdio0_pad_cdata_oe_bit6(gpionum) sf_vic_gpio_dout_value(gpionum, 0x3f) +#define SET_GPIO_dout_sdio0_pad_cdata_oe_bit7(gpionum) sf_vic_gpio_dout_value(gpionum, 0x40) +#define SET_GPIO_dout_sdio0_pad_cdata_out_bit0(gpionum) sf_vic_gpio_dout_value(gpionum, 0x41) +#define SET_GPIO_dout_sdio0_pad_cdata_out_bit1(gpionum) sf_vic_gpio_dout_value(gpionum, 0x42) +#define SET_GPIO_dout_sdio0_pad_cdata_out_bit2(gpionum) sf_vic_gpio_dout_value(gpionum, 0x43) +#define SET_GPIO_dout_sdio0_pad_cdata_out_bit3(gpionum) sf_vic_gpio_dout_value(gpionum, 0x44) +#define SET_GPIO_dout_sdio0_pad_cdata_out_bit4(gpionum) sf_vic_gpio_dout_value(gpionum, 0x45) +#define SET_GPIO_dout_sdio0_pad_cdata_out_bit5(gpionum) sf_vic_gpio_dout_value(gpionum, 0x46) +#define SET_GPIO_dout_sdio0_pad_cdata_out_bit6(gpionum) sf_vic_gpio_dout_value(gpionum, 0x47) +#define SET_GPIO_dout_sdio0_pad_cdata_out_bit7(gpionum) sf_vic_gpio_dout_value(gpionum, 0x48) +#define SET_GPIO_dout_sdio0_pad_rst_n(gpionum) sf_vic_gpio_dout_value(gpionum, 0x49) +#define SET_GPIO_dout_sdio1_pad_card_power_en(gpionum) sf_vic_gpio_dout_value(gpionum, 0x4a) +#define SET_GPIO_dout_sdio1_pad_cclk_out(gpionum) sf_vic_gpio_dout_value(gpionum, 0x4b) +#define SET_GPIO_dout_sdio1_pad_ccmd_oe(gpionum) sf_vic_gpio_dout_value(gpionum, 0x4c) +#define SET_GPIO_dout_sdio1_pad_ccmd_out(gpionum) sf_vic_gpio_dout_value(gpionum, 0x4d) +#define SET_GPIO_dout_sdio1_pad_cdata_oe_bit0(gpionum) sf_vic_gpio_dout_value(gpionum, 0x4e) +#define SET_GPIO_dout_sdio1_pad_cdata_oe_bit1(gpionum) sf_vic_gpio_dout_value(gpionum, 0x4f) +#define SET_GPIO_dout_sdio1_pad_cdata_oe_bit2(gpionum) sf_vic_gpio_dout_value(gpionum, 0x50) +#define SET_GPIO_dout_sdio1_pad_cdata_oe_bit3(gpionum) sf_vic_gpio_dout_value(gpionum, 0x51) +#define SET_GPIO_dout_sdio1_pad_cdata_oe_bit4(gpionum) sf_vic_gpio_dout_value(gpionum, 0x52) +#define SET_GPIO_dout_sdio1_pad_cdata_oe_bit5(gpionum) sf_vic_gpio_dout_value(gpionum, 0x53) +#define SET_GPIO_dout_sdio1_pad_cdata_oe_bit6(gpionum) sf_vic_gpio_dout_value(gpionum, 0x54) +#define SET_GPIO_dout_sdio1_pad_cdata_oe_bit7(gpionum) sf_vic_gpio_dout_value(gpionum, 0x55) +#define SET_GPIO_dout_sdio1_pad_cdata_out_bit0(gpionum) sf_vic_gpio_dout_value(gpionum, 0x56) +#define SET_GPIO_dout_sdio1_pad_cdata_out_bit1(gpionum) sf_vic_gpio_dout_value(gpionum, 0x57) +#define SET_GPIO_dout_sdio1_pad_cdata_out_bit2(gpionum) sf_vic_gpio_dout_value(gpionum, 0x58) +#define SET_GPIO_dout_sdio1_pad_cdata_out_bit3(gpionum) sf_vic_gpio_dout_value(gpionum, 0x59) +#define SET_GPIO_dout_sdio1_pad_cdata_out_bit4(gpionum) sf_vic_gpio_dout_value(gpionum, 0x5a) +#define SET_GPIO_dout_sdio1_pad_cdata_out_bit5(gpionum) sf_vic_gpio_dout_value(gpionum, 0x5b) +#define SET_GPIO_dout_sdio1_pad_cdata_out_bit6(gpionum) sf_vic_gpio_dout_value(gpionum, 0x5c) +#define SET_GPIO_dout_sdio1_pad_cdata_out_bit7(gpionum) sf_vic_gpio_dout_value(gpionum, 0x5d) +#define SET_GPIO_dout_sdio1_pad_rst_n(gpionum) sf_vic_gpio_dout_value(gpionum, 0x5e) +#define SET_GPIO_dout_spdif_tx_sdout(gpionum) sf_vic_gpio_dout_value(gpionum, 0x5f) +#define SET_GPIO_dout_spdif_tx_sdout_oen(gpionum) sf_vic_gpio_dout_value(gpionum, 0x60) +#define SET_GPIO_dout_spi0_pad_oe_n(gpionum) sf_vic_gpio_dout_value(gpionum, 0x61) +#define SET_GPIO_dout_spi0_pad_sck_out(gpionum) sf_vic_gpio_dout_value(gpionum, 0x62) +#define SET_GPIO_dout_spi0_pad_ss_0_n(gpionum) sf_vic_gpio_dout_value(gpionum, 0x63) +#define SET_GPIO_dout_spi0_pad_ss_1_n(gpionum) sf_vic_gpio_dout_value(gpionum, 0x64) +#define SET_GPIO_dout_spi0_pad_txd(gpionum) sf_vic_gpio_dout_value(gpionum, 0x65) +#define SET_GPIO_dout_spi1_pad_oe_n(gpionum) sf_vic_gpio_dout_value(gpionum, 0x66) +#define SET_GPIO_dout_spi1_pad_sck_out(gpionum) sf_vic_gpio_dout_value(gpionum, 0x67) +#define SET_GPIO_dout_spi1_pad_ss_0_n(gpionum) sf_vic_gpio_dout_value(gpionum, 0x68) +#define SET_GPIO_dout_spi1_pad_ss_1_n(gpionum) sf_vic_gpio_dout_value(gpionum, 0x69) +#define SET_GPIO_dout_spi1_pad_txd(gpionum) sf_vic_gpio_dout_value(gpionum, 0x6a) +#define SET_GPIO_dout_spi2_pad_oe_n(gpionum) sf_vic_gpio_dout_value(gpionum, 0x6b) +#define SET_GPIO_dout_spi2_pad_sck_out(gpionum) sf_vic_gpio_dout_value(gpionum, 0x6c) +#define SET_GPIO_dout_spi2_pad_ss_0_n(gpionum) sf_vic_gpio_dout_value(gpionum, 0x6d) +#define SET_GPIO_dout_spi2_pad_ss_1_n(gpionum) sf_vic_gpio_dout_value(gpionum, 0x6e) +#define SET_GPIO_dout_spi2_pad_txd(gpionum) sf_vic_gpio_dout_value(gpionum, 0x6f) +#define SET_GPIO_dout_spi2ahb_pad_oe_n_bit0(gpionum) sf_vic_gpio_dout_value(gpionum, 0x70) +#define SET_GPIO_dout_spi2ahb_pad_oe_n_bit1(gpionum) sf_vic_gpio_dout_value(gpionum, 0x71) +#define SET_GPIO_dout_spi2ahb_pad_oe_n_bit2(gpionum) sf_vic_gpio_dout_value(gpionum, 0x72) +#define SET_GPIO_dout_spi2ahb_pad_oe_n_bit3(gpionum) sf_vic_gpio_dout_value(gpionum, 0x73) +#define SET_GPIO_dout_spi2ahb_pad_txd_bit0(gpionum) sf_vic_gpio_dout_value(gpionum, 0x74) +#define SET_GPIO_dout_spi2ahb_pad_txd_bit1(gpionum) sf_vic_gpio_dout_value(gpionum, 0x75) +#define SET_GPIO_dout_spi2ahb_pad_txd_bit2(gpionum) sf_vic_gpio_dout_value(gpionum, 0x76) +#define SET_GPIO_dout_spi2ahb_pad_txd_bit3(gpionum) sf_vic_gpio_dout_value(gpionum, 0x77) +#define SET_GPIO_dout_spi3_pad_oe_n(gpionum) sf_vic_gpio_dout_value(gpionum, 0x78) +#define SET_GPIO_dout_spi3_pad_sck_out(gpionum) sf_vic_gpio_dout_value(gpionum, 0x79) +#define SET_GPIO_dout_spi3_pad_ss_0_n(gpionum) sf_vic_gpio_dout_value(gpionum, 0x7a) +#define SET_GPIO_dout_spi3_pad_ss_1_n(gpionum) sf_vic_gpio_dout_value(gpionum, 0x7b) +#define SET_GPIO_dout_spi3_pad_txd(gpionum) sf_vic_gpio_dout_value(gpionum, 0x7c) +#define SET_GPIO_dout_uart0_pad_dtrn(gpionum) sf_vic_gpio_dout_value(gpionum, 0x7d) +#define SET_GPIO_dout_uart0_pad_rtsn(gpionum) sf_vic_gpio_dout_value(gpionum, 0x7e) +#define SET_GPIO_dout_uart0_pad_sout(gpionum) sf_vic_gpio_dout_value(gpionum, 0x7f) +#define SET_GPIO_dout_uart1_pad_sout(gpionum) sf_vic_gpio_dout_value(gpionum, 0x80) +#define SET_GPIO_dout_uart2_pad_dtr_n(gpionum) sf_vic_gpio_dout_value(gpionum, 0x81) +#define SET_GPIO_dout_uart2_pad_rts_n(gpionum) sf_vic_gpio_dout_value(gpionum, 0x82) +#define SET_GPIO_dout_uart2_pad_sout(gpionum) sf_vic_gpio_dout_value(gpionum, 0x83) +#define SET_GPIO_dout_uart3_pad_sout(gpionum) sf_vic_gpio_dout_value(gpionum, 0x84) +#define SET_GPIO_dout_usb_drv_bus(gpionum) sf_vic_gpio_dout_value(gpionum, 0x85) +#define SET_GPIO_doen_reverse_(gpionum, en) sf_vic_gpio_doen_reverse(gpionum, en) +#define SET_GPIO_doen_LOW(gpionum) sf_vic_gpio_doen_value(gpionum, 0x0) +#define SET_GPIO_doen_HIGH(gpionum) sf_vic_gpio_doen_value(gpionum, 0x1) +#define SET_GPIO_doen_clk_gmac_tophyref(gpionum) sf_vic_gpio_doen_value(gpionum, 0x2) +#define SET_GPIO_doen_cpu_jtag_tdo(gpionum) sf_vic_gpio_doen_value(gpionum, 0x3) +#define SET_GPIO_doen_cpu_jtag_tdo_oen(gpionum) sf_vic_gpio_doen_value(gpionum, 0x4) +#define SET_GPIO_doen_dmic_clk_out(gpionum) sf_vic_gpio_doen_value(gpionum, 0x5) +#define SET_GPIO_doen_dsp_JTDOEn_pad(gpionum) sf_vic_gpio_doen_value(gpionum, 0x6) +#define SET_GPIO_doen_dsp_JTDO_pad(gpionum) sf_vic_gpio_doen_value(gpionum, 0x7) +#define SET_GPIO_doen_i2c0_pad_sck_oe(gpionum) sf_vic_gpio_doen_value(gpionum, 0x8) +#define SET_GPIO_doen_i2c0_pad_sda_oe(gpionum) sf_vic_gpio_doen_value(gpionum, 0x9) +#define SET_GPIO_doen_i2c1_pad_sck_oe(gpionum) sf_vic_gpio_doen_value(gpionum, 0xa) +#define SET_GPIO_doen_i2c1_pad_sda_oe(gpionum) sf_vic_gpio_doen_value(gpionum, 0xb) +#define SET_GPIO_doen_i2c2_pad_sck_oe(gpionum) sf_vic_gpio_doen_value(gpionum, 0xc) +#define SET_GPIO_doen_i2c2_pad_sda_oe(gpionum) sf_vic_gpio_doen_value(gpionum, 0xd) +#define SET_GPIO_doen_i2c3_pad_sck_oe(gpionum) sf_vic_gpio_doen_value(gpionum, 0xe) +#define SET_GPIO_doen_i2c3_pad_sda_oe(gpionum) sf_vic_gpio_doen_value(gpionum, 0xf) +#define SET_GPIO_doen_i2srx_bclk_out(gpionum) sf_vic_gpio_doen_value(gpionum, 0x10) +#define SET_GPIO_doen_i2srx_bclk_out_oen(gpionum) sf_vic_gpio_doen_value(gpionum, 0x11) +#define SET_GPIO_doen_i2srx_lrck_out(gpionum) sf_vic_gpio_doen_value(gpionum, 0x12) +#define SET_GPIO_doen_i2srx_lrck_out_oen(gpionum) sf_vic_gpio_doen_value(gpionum, 0x13) +#define SET_GPIO_doen_i2srx_mclk_out(gpionum) sf_vic_gpio_doen_value(gpionum, 0x14) +#define SET_GPIO_doen_i2stx_bclk_out(gpionum) sf_vic_gpio_doen_value(gpionum, 0x15) +#define SET_GPIO_doen_i2stx_bclk_out_oen(gpionum) sf_vic_gpio_doen_value(gpionum, 0x16) +#define SET_GPIO_doen_i2stx_lrck_out(gpionum) sf_vic_gpio_doen_value(gpionum, 0x17) +#define SET_GPIO_doen_i2stx_lrckout_oen(gpionum) sf_vic_gpio_doen_value(gpionum, 0x18) +#define SET_GPIO_doen_i2stx_mclk_out(gpionum) sf_vic_gpio_doen_value(gpionum, 0x19) +#define SET_GPIO_doen_i2stx_sdout0(gpionum) sf_vic_gpio_doen_value(gpionum, 0x1a) +#define SET_GPIO_doen_i2stx_sdout1(gpionum) sf_vic_gpio_doen_value(gpionum, 0x1b) +#define SET_GPIO_doen_lcd_pad_csm_n(gpionum) sf_vic_gpio_doen_value(gpionum, 0x1c) +#define SET_GPIO_doen_pwm_pad_oe_n_bit0(gpionum) sf_vic_gpio_doen_value(gpionum, 0x1d) +#define SET_GPIO_doen_pwm_pad_oe_n_bit1(gpionum) sf_vic_gpio_doen_value(gpionum, 0x1e) +#define SET_GPIO_doen_pwm_pad_oe_n_bit2(gpionum) sf_vic_gpio_doen_value(gpionum, 0x1f) +#define SET_GPIO_doen_pwm_pad_oe_n_bit3(gpionum) sf_vic_gpio_doen_value(gpionum, 0x20) +#define SET_GPIO_doen_pwm_pad_oe_n_bit4(gpionum) sf_vic_gpio_doen_value(gpionum, 0x21) +#define SET_GPIO_doen_pwm_pad_oe_n_bit5(gpionum) sf_vic_gpio_doen_value(gpionum, 0x22) +#define SET_GPIO_doen_pwm_pad_oe_n_bit6(gpionum) sf_vic_gpio_doen_value(gpionum, 0x23) +#define SET_GPIO_doen_pwm_pad_oe_n_bit7(gpionum) sf_vic_gpio_doen_value(gpionum, 0x24) +#define SET_GPIO_doen_pwm_pad_out_bit0(gpionum) sf_vic_gpio_doen_value(gpionum, 0x25) +#define SET_GPIO_doen_pwm_pad_out_bit1(gpionum) sf_vic_gpio_doen_value(gpionum, 0x26) +#define SET_GPIO_doen_pwm_pad_out_bit2(gpionum) sf_vic_gpio_doen_value(gpionum, 0x27) +#define SET_GPIO_doen_pwm_pad_out_bit3(gpionum) sf_vic_gpio_doen_value(gpionum, 0x28) +#define SET_GPIO_doen_pwm_pad_out_bit4(gpionum) sf_vic_gpio_doen_value(gpionum, 0x29) +#define SET_GPIO_doen_pwm_pad_out_bit5(gpionum) sf_vic_gpio_doen_value(gpionum, 0x2a) +#define SET_GPIO_doen_pwm_pad_out_bit6(gpionum) sf_vic_gpio_doen_value(gpionum, 0x2b) +#define SET_GPIO_doen_pwm_pad_out_bit7(gpionum) sf_vic_gpio_doen_value(gpionum, 0x2c) +#define SET_GPIO_doen_pwmdac_left_out(gpionum) sf_vic_gpio_doen_value(gpionum, 0x2d) +#define SET_GPIO_doen_pwmdac_right_out(gpionum) sf_vic_gpio_doen_value(gpionum, 0x2e) +#define SET_GPIO_doen_qspi_csn1_out(gpionum) sf_vic_gpio_doen_value(gpionum, 0x2f) +#define SET_GPIO_doen_qspi_csn2_out(gpionum) sf_vic_gpio_doen_value(gpionum, 0x30) +#define SET_GPIO_doen_qspi_csn3_out(gpionum) sf_vic_gpio_doen_value(gpionum, 0x31) +#define SET_GPIO_doen_register23_SCFG_cmsensor_rst0(gpionum) sf_vic_gpio_doen_value(gpionum, 0x32) +#define SET_GPIO_doen_register23_SCFG_cmsensor_rst1(gpionum) sf_vic_gpio_doen_value(gpionum, 0x33) +#define SET_GPIO_doen_register32_SCFG_gmac_phy_rstn(gpionum) sf_vic_gpio_doen_value(gpionum, 0x34) +#define SET_GPIO_doen_sdio0_pad_card_power_en(gpionum) sf_vic_gpio_doen_value(gpionum, 0x35) +#define SET_GPIO_doen_sdio0_pad_cclk_out(gpionum) sf_vic_gpio_doen_value(gpionum, 0x36) +#define SET_GPIO_doen_sdio0_pad_ccmd_oe(gpionum) sf_vic_gpio_doen_value(gpionum, 0x37) +#define SET_GPIO_doen_sdio0_pad_ccmd_out(gpionum) sf_vic_gpio_doen_value(gpionum, 0x38) +#define SET_GPIO_doen_sdio0_pad_cdata_oe_bit0(gpionum) sf_vic_gpio_doen_value(gpionum, 0x39) +#define SET_GPIO_doen_sdio0_pad_cdata_oe_bit1(gpionum) sf_vic_gpio_doen_value(gpionum, 0x3a) +#define SET_GPIO_doen_sdio0_pad_cdata_oe_bit2(gpionum) sf_vic_gpio_doen_value(gpionum, 0x3b) +#define SET_GPIO_doen_sdio0_pad_cdata_oe_bit3(gpionum) sf_vic_gpio_doen_value(gpionum, 0x3c) +#define SET_GPIO_doen_sdio0_pad_cdata_oe_bit4(gpionum) sf_vic_gpio_doen_value(gpionum, 0x3d) +#define SET_GPIO_doen_sdio0_pad_cdata_oe_bit5(gpionum) sf_vic_gpio_doen_value(gpionum, 0x3e) +#define SET_GPIO_doen_sdio0_pad_cdata_oe_bit6(gpionum) sf_vic_gpio_doen_value(gpionum, 0x3f) +#define SET_GPIO_doen_sdio0_pad_cdata_oe_bit7(gpionum) sf_vic_gpio_doen_value(gpionum, 0x40) +#define SET_GPIO_doen_sdio0_pad_cdata_out_bit0(gpionum) sf_vic_gpio_doen_value(gpionum, 0x41) +#define SET_GPIO_doen_sdio0_pad_cdata_out_bit1(gpionum) sf_vic_gpio_doen_value(gpionum, 0x42) +#define SET_GPIO_doen_sdio0_pad_cdata_out_bit2(gpionum) sf_vic_gpio_doen_value(gpionum, 0x43) +#define SET_GPIO_doen_sdio0_pad_cdata_out_bit3(gpionum) sf_vic_gpio_doen_value(gpionum, 0x44) +#define SET_GPIO_doen_sdio0_pad_cdata_out_bit4(gpionum) sf_vic_gpio_doen_value(gpionum, 0x45) +#define SET_GPIO_doen_sdio0_pad_cdata_out_bit5(gpionum) sf_vic_gpio_doen_value(gpionum, 0x46) +#define SET_GPIO_doen_sdio0_pad_cdata_out_bit6(gpionum) sf_vic_gpio_doen_value(gpionum, 0x47) +#define SET_GPIO_doen_sdio0_pad_cdata_out_bit7(gpionum) sf_vic_gpio_doen_value(gpionum, 0x48) +#define SET_GPIO_doen_sdio0_pad_rst_n(gpionum) sf_vic_gpio_doen_value(gpionum, 0x49) +#define SET_GPIO_doen_sdio1_pad_card_power_en(gpionum) sf_vic_gpio_doen_value(gpionum, 0x4a) +#define SET_GPIO_doen_sdio1_pad_cclk_out(gpionum) sf_vic_gpio_doen_value(gpionum, 0x4b) +#define SET_GPIO_doen_sdio1_pad_ccmd_oe(gpionum) sf_vic_gpio_doen_value(gpionum, 0x4c) +#define SET_GPIO_doen_sdio1_pad_ccmd_out(gpionum) sf_vic_gpio_doen_value(gpionum, 0x4d) +#define SET_GPIO_doen_sdio1_pad_cdata_oe_bit0(gpionum) sf_vic_gpio_doen_value(gpionum, 0x4e) +#define SET_GPIO_doen_sdio1_pad_cdata_oe_bit1(gpionum) sf_vic_gpio_doen_value(gpionum, 0x4f) +#define SET_GPIO_doen_sdio1_pad_cdata_oe_bit2(gpionum) sf_vic_gpio_doen_value(gpionum, 0x50) +#define SET_GPIO_doen_sdio1_pad_cdata_oe_bit3(gpionum) sf_vic_gpio_doen_value(gpionum, 0x51) +#define SET_GPIO_doen_sdio1_pad_cdata_oe_bit4(gpionum) sf_vic_gpio_doen_value(gpionum, 0x52) +#define SET_GPIO_doen_sdio1_pad_cdata_oe_bit5(gpionum) sf_vic_gpio_doen_value(gpionum, 0x53) +#define SET_GPIO_doen_sdio1_pad_cdata_oe_bit6(gpionum) sf_vic_gpio_doen_value(gpionum, 0x54) +#define SET_GPIO_doen_sdio1_pad_cdata_oe_bit7(gpionum) sf_vic_gpio_doen_value(gpionum, 0x55) +#define SET_GPIO_doen_sdio1_pad_cdata_out_bit0(gpionum) sf_vic_gpio_doen_value(gpionum, 0x56) +#define SET_GPIO_doen_sdio1_pad_cdata_out_bit1(gpionum) sf_vic_gpio_doen_value(gpionum, 0x57) +#define SET_GPIO_doen_sdio1_pad_cdata_out_bit2(gpionum) sf_vic_gpio_doen_value(gpionum, 0x58) +#define SET_GPIO_doen_sdio1_pad_cdata_out_bit3(gpionum) sf_vic_gpio_doen_value(gpionum, 0x59) +#define SET_GPIO_doen_sdio1_pad_cdata_out_bit4(gpionum) sf_vic_gpio_doen_value(gpionum, 0x5a) +#define SET_GPIO_doen_sdio1_pad_cdata_out_bit5(gpionum) sf_vic_gpio_doen_value(gpionum, 0x5b) +#define SET_GPIO_doen_sdio1_pad_cdata_out_bit6(gpionum) sf_vic_gpio_doen_value(gpionum, 0x5c) +#define SET_GPIO_doen_sdio1_pad_cdata_out_bit7(gpionum) sf_vic_gpio_doen_value(gpionum, 0x5d) +#define SET_GPIO_doen_sdio1_pad_rst_n(gpionum) sf_vic_gpio_doen_value(gpionum, 0x5e) +#define SET_GPIO_doen_spdif_tx_sdout(gpionum) sf_vic_gpio_doen_value(gpionum, 0x5f) +#define SET_GPIO_doen_spdif_tx_sdout_oen(gpionum) sf_vic_gpio_doen_value(gpionum, 0x60) +#define SET_GPIO_doen_spi0_pad_oe_n(gpionum) sf_vic_gpio_doen_value(gpionum, 0x61) +#define SET_GPIO_doen_spi0_pad_sck_out(gpionum) sf_vic_gpio_doen_value(gpionum, 0x62) +#define SET_GPIO_doen_spi0_pad_ss_0_n(gpionum) sf_vic_gpio_doen_value(gpionum, 0x63) +#define SET_GPIO_doen_spi0_pad_ss_1_n(gpionum) sf_vic_gpio_doen_value(gpionum, 0x64) +#define SET_GPIO_doen_spi0_pad_txd(gpionum) sf_vic_gpio_doen_value(gpionum, 0x65) +#define SET_GPIO_doen_spi1_pad_oe_n(gpionum) sf_vic_gpio_doen_value(gpionum, 0x66) +#define SET_GPIO_doen_spi1_pad_sck_out(gpionum) sf_vic_gpio_doen_value(gpionum, 0x67) +#define SET_GPIO_doen_spi1_pad_ss_0_n(gpionum) sf_vic_gpio_doen_value(gpionum, 0x68) +#define SET_GPIO_doen_spi1_pad_ss_1_n(gpionum) sf_vic_gpio_doen_value(gpionum, 0x69) +#define SET_GPIO_doen_spi1_pad_txd(gpionum) sf_vic_gpio_doen_value(gpionum, 0x6a) +#define SET_GPIO_doen_spi2_pad_oe_n(gpionum) sf_vic_gpio_doen_value(gpionum, 0x6b) +#define SET_GPIO_doen_spi2_pad_sck_out(gpionum) sf_vic_gpio_doen_value(gpionum, 0x6c) +#define SET_GPIO_doen_spi2_pad_ss_0_n(gpionum) sf_vic_gpio_doen_value(gpionum, 0x6d) +#define SET_GPIO_doen_spi2_pad_ss_1_n(gpionum) sf_vic_gpio_doen_value(gpionum, 0x6e) +#define SET_GPIO_doen_spi2_pad_txd(gpionum) sf_vic_gpio_doen_value(gpionum, 0x6f) +#define SET_GPIO_doen_spi2ahb_pad_oe_n_bit0(gpionum) sf_vic_gpio_doen_value(gpionum, 0x70) +#define SET_GPIO_doen_spi2ahb_pad_oe_n_bit1(gpionum) sf_vic_gpio_doen_value(gpionum, 0x71) +#define SET_GPIO_doen_spi2ahb_pad_oe_n_bit2(gpionum) sf_vic_gpio_doen_value(gpionum, 0x72) +#define SET_GPIO_doen_spi2ahb_pad_oe_n_bit3(gpionum) sf_vic_gpio_doen_value(gpionum, 0x73) +#define SET_GPIO_doen_spi2ahb_pad_txd_bit0(gpionum) sf_vic_gpio_doen_value(gpionum, 0x74) +#define SET_GPIO_doen_spi2ahb_pad_txd_bit1(gpionum) sf_vic_gpio_doen_value(gpionum, 0x75) +#define SET_GPIO_doen_spi2ahb_pad_txd_bit2(gpionum) sf_vic_gpio_doen_value(gpionum, 0x76) +#define SET_GPIO_doen_spi2ahb_pad_txd_bit3(gpionum) sf_vic_gpio_doen_value(gpionum, 0x77) +#define SET_GPIO_doen_spi3_pad_oe_n(gpionum) sf_vic_gpio_doen_value(gpionum, 0x78) +#define SET_GPIO_doen_spi3_pad_sck_out(gpionum) sf_vic_gpio_doen_value(gpionum, 0x79) +#define SET_GPIO_doen_spi3_pad_ss_0_n(gpionum) sf_vic_gpio_doen_value(gpionum, 0x7a) +#define SET_GPIO_doen_spi3_pad_ss_1_n(gpionum) sf_vic_gpio_doen_value(gpionum, 0x7b) +#define SET_GPIO_doen_spi3_pad_txd(gpionum) sf_vic_gpio_doen_value(gpionum, 0x7c) +#define SET_GPIO_doen_uart0_pad_dtrn(gpionum) sf_vic_gpio_doen_value(gpionum, 0x7d) +#define SET_GPIO_doen_uart0_pad_rtsn(gpionum) sf_vic_gpio_doen_value(gpionum, 0x7e) +#define SET_GPIO_doen_uart0_pad_sout(gpionum) sf_vic_gpio_doen_value(gpionum, 0x7f) +#define SET_GPIO_doen_uart1_pad_sout(gpionum) sf_vic_gpio_doen_value(gpionum, 0x80) +#define SET_GPIO_doen_uart2_pad_dtr_n(gpionum) sf_vic_gpio_doen_value(gpionum, 0x81) +#define SET_GPIO_doen_uart2_pad_rts_n(gpionum) sf_vic_gpio_doen_value(gpionum, 0x82) +#define SET_GPIO_doen_uart2_pad_sout(gpionum) sf_vic_gpio_doen_value(gpionum, 0x83) +#define SET_GPIO_doen_uart3_pad_sout(gpionum) sf_vic_gpio_doen_value(gpionum, 0x84) +#define SET_GPIO_doen_usb_drv_bus(gpionum) sf_vic_gpio_doen_value(gpionum, 0x85) +#define SET_GPIO_cpu_jtag_tck(gpionum) sf_vic_gpio_manual(0x250, gpionum + 2) +#define SET_GPIO_cpu_jtag_tdi(gpionum) sf_vic_gpio_manual(0x254, gpionum + 2) +#define SET_GPIO_cpu_jtag_tms(gpionum) sf_vic_gpio_manual(0x258, gpionum + 2) +#define SET_GPIO_cpu_jtag_trst(gpionum) sf_vic_gpio_manual(0x25c, gpionum + 2) +#define SET_GPIO_dmic_sdin_bit0(gpionum) sf_vic_gpio_manual(0x260, gpionum + 2) +#define SET_GPIO_dmic_sdin_bit1(gpionum) sf_vic_gpio_manual(0x264, gpionum + 2) +#define SET_GPIO_dsp_JTCK_pad(gpionum) sf_vic_gpio_manual(0x268, gpionum + 2) +#define SET_GPIO_dsp_JTDI_pad(gpionum) sf_vic_gpio_manual(0x26c, gpionum + 2) +#define SET_GPIO_dsp_JTMS_pad(gpionum) sf_vic_gpio_manual(0x270, gpionum + 2) +#define SET_GPIO_dsp_TRST_pad(gpionum) sf_vic_gpio_manual(0x274, gpionum + 2) +#define SET_GPIO_i2c0_pad_sck_in(gpionum) sf_vic_gpio_manual(0x278, gpionum + 2) +#define SET_GPIO_i2c0_pad_sda_in(gpionum) sf_vic_gpio_manual(0x27c, gpionum + 2) +#define SET_GPIO_i2c1_pad_sck_in(gpionum) sf_vic_gpio_manual(0x280, gpionum + 2) +#define SET_GPIO_i2c1_pad_sda_in(gpionum) sf_vic_gpio_manual(0x284, gpionum + 2) +#define SET_GPIO_i2c2_pad_sck_in(gpionum) sf_vic_gpio_manual(0x288, gpionum + 2) +#define SET_GPIO_i2c2_pad_sda_in(gpionum) sf_vic_gpio_manual(0x28c, gpionum + 2) +#define SET_GPIO_i2c3_pad_sck_in(gpionum) sf_vic_gpio_manual(0x290, gpionum + 2) +#define SET_GPIO_i2c3_pad_sda_in(gpionum) sf_vic_gpio_manual(0x294, gpionum + 2) +#define SET_GPIO_i2srx_bclk_in(gpionum) sf_vic_gpio_manual(0x298, gpionum + 2) +#define SET_GPIO_i2srx_lrck_in(gpionum) sf_vic_gpio_manual(0x29c, gpionum + 2) +#define SET_GPIO_i2srx_sdin_bit0(gpionum) sf_vic_gpio_manual(0x2a0, gpionum + 2) +#define SET_GPIO_i2srx_sdin_bit1(gpionum) sf_vic_gpio_manual(0x2a4, gpionum + 2) +#define SET_GPIO_i2srx_sdin_bit2(gpionum) sf_vic_gpio_manual(0x2a8, gpionum + 2) +#define SET_GPIO_i2stx_bclk_in(gpionum) sf_vic_gpio_manual(0x2ac, gpionum + 2) +#define SET_GPIO_i2stx_lrck_in(gpionum) sf_vic_gpio_manual(0x2b0, gpionum + 2) +#define SET_GPIO_sdio0_pad_card_detect_n(gpionum) sf_vic_gpio_manual(0x2b4, gpionum + 2) +#define SET_GPIO_sdio0_pad_card_write_prt(gpionum) sf_vic_gpio_manual(0x2b8, gpionum + 2) +#define SET_GPIO_sdio0_pad_ccmd_in(gpionum) sf_vic_gpio_manual(0x2bc, gpionum + 2) +#define SET_GPIO_sdio0_pad_cdata_in_bit0(gpionum) sf_vic_gpio_manual(0x2c0, gpionum + 2) +#define SET_GPIO_sdio0_pad_cdata_in_bit1(gpionum) sf_vic_gpio_manual(0x2c4, gpionum + 2) +#define SET_GPIO_sdio0_pad_cdata_in_bit2(gpionum) sf_vic_gpio_manual(0x2c8, gpionum + 2) +#define SET_GPIO_sdio0_pad_cdata_in_bit3(gpionum) sf_vic_gpio_manual(0x2cc, gpionum + 2) +#define SET_GPIO_sdio0_pad_cdata_in_bit4(gpionum) sf_vic_gpio_manual(0x2d0, gpionum + 2) +#define SET_GPIO_sdio0_pad_cdata_in_bit5(gpionum) sf_vic_gpio_manual(0x2d4, gpionum + 2) +#define SET_GPIO_sdio0_pad_cdata_in_bit6(gpionum) sf_vic_gpio_manual(0x2d8, gpionum + 2) +#define SET_GPIO_sdio0_pad_cdata_in_bit7(gpionum) sf_vic_gpio_manual(0x2dc, gpionum + 2) +#define SET_GPIO_sdio1_pad_card_detect_n(gpionum) sf_vic_gpio_manual(0x2e0, gpionum + 2) +#define SET_GPIO_sdio1_pad_card_write_prt(gpionum) sf_vic_gpio_manual(0x2e4, gpionum + 2) +#define SET_GPIO_sdio1_pad_ccmd_in(gpionum) sf_vic_gpio_manual(0x2e8, gpionum + 2) +#define SET_GPIO_sdio1_pad_cdata_in_bit0(gpionum) sf_vic_gpio_manual(0x2ec, gpionum + 2) +#define SET_GPIO_sdio1_pad_cdata_in_bit1(gpionum) sf_vic_gpio_manual(0x2f0, gpionum + 2) +#define SET_GPIO_sdio1_pad_cdata_in_bit2(gpionum) sf_vic_gpio_manual(0x2f4, gpionum + 2) +#define SET_GPIO_sdio1_pad_cdata_in_bit3(gpionum) sf_vic_gpio_manual(0x2f8, gpionum + 2) +#define SET_GPIO_sdio1_pad_cdata_in_bit4(gpionum) sf_vic_gpio_manual(0x2fc, gpionum + 2) +#define SET_GPIO_sdio1_pad_cdata_in_bit5(gpionum) sf_vic_gpio_manual(0x300, gpionum + 2) +#define SET_GPIO_sdio1_pad_cdata_in_bit6(gpionum) sf_vic_gpio_manual(0x304, gpionum + 2) +#define SET_GPIO_sdio1_pad_cdata_in_bit7(gpionum) sf_vic_gpio_manual(0x308, gpionum + 2) +#define SET_GPIO_spdif_rx_sdin(gpionum) sf_vic_gpio_manual(0x30c, gpionum + 2) +#define SET_GPIO_spi0_pad_rxd(gpionum) sf_vic_gpio_manual(0x310, gpionum + 2) +#define SET_GPIO_spi0_pad_ss_in_n(gpionum) sf_vic_gpio_manual(0x314, gpionum + 2) +#define SET_GPIO_spi1_pad_rxd(gpionum) sf_vic_gpio_manual(0x318, gpionum + 2) +#define SET_GPIO_spi1_pad_ss_in_n(gpionum) sf_vic_gpio_manual(0x31c, gpionum + 2) +#define SET_GPIO_spi2_pad_rxd(gpionum) sf_vic_gpio_manual(0x320, gpionum + 2) +#define SET_GPIO_spi2_pad_ss_in_n(gpionum) sf_vic_gpio_manual(0x324, gpionum + 2) +#define SET_GPIO_spi2ahb_pad_rxd_bit0(gpionum) sf_vic_gpio_manual(0x328, gpionum + 2) +#define SET_GPIO_spi2ahb_pad_rxd_bit1(gpionum) sf_vic_gpio_manual(0x32c, gpionum + 2) +#define SET_GPIO_spi2ahb_pad_rxd_bit2(gpionum) sf_vic_gpio_manual(0x330, gpionum + 2) +#define SET_GPIO_spi2ahb_pad_rxd_bit3(gpionum) sf_vic_gpio_manual(0x334, gpionum + 2) +#define SET_GPIO_spi2ahb_pad_ss_n(gpionum) sf_vic_gpio_manual(0x338, gpionum + 2) +#define SET_GPIO_spi2ahb_slv_sclkin(gpionum) sf_vic_gpio_manual(0x33c, gpionum + 2) +#define SET_GPIO_spi3_pad_rxd(gpionum) sf_vic_gpio_manual(0x340, gpionum + 2) +#define SET_GPIO_spi3_pad_ss_in_n(gpionum) sf_vic_gpio_manual(0x344, gpionum + 2) +#define SET_GPIO_uart0_pad_ctsn(gpionum) sf_vic_gpio_manual(0x348, gpionum + 2) +#define SET_GPIO_uart0_pad_dcdn(gpionum) sf_vic_gpio_manual(0x34c, gpionum + 2) +#define SET_GPIO_uart0_pad_dsrn(gpionum) sf_vic_gpio_manual(0x350, gpionum + 2) +#define SET_GPIO_uart0_pad_rin(gpionum) sf_vic_gpio_manual(0x354, gpionum + 2) +#define SET_GPIO_uart0_pad_sin(gpionum) sf_vic_gpio_manual(0x358, gpionum + 2) +#define SET_GPIO_uart1_pad_sin(gpionum) sf_vic_gpio_manual(0x35c, gpionum + 2) +#define SET_GPIO_uart2_pad_cts_n(gpionum) sf_vic_gpio_manual(0x360, gpionum + 2) +#define SET_GPIO_uart2_pad_dcd_n(gpionum) sf_vic_gpio_manual(0x364, gpionum + 2) +#define SET_GPIO_uart2_pad_dsr_n(gpionum) sf_vic_gpio_manual(0x368, gpionum + 2) +#define SET_GPIO_uart2_pad_ri_n(gpionum) sf_vic_gpio_manual(0x36c, gpionum + 2) +#define SET_GPIO_uart2_pad_sin(gpionum) sf_vic_gpio_manual(0x370, gpionum + 2) +#define SET_GPIO_uart3_pad_sin(gpionum) sf_vic_gpio_manual(0x374, gpionum + 2) +#define SET_GPIO_usb_over_current(gpionum) sf_vic_gpio_manual(0x378, gpionum + 2) + +#endif /* __GPIO_PXA_H */ From e10da274022a67aaf24b5eaa5cbc0e80389972ae Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 27 May 2021 20:13:43 +0200 Subject: [PATCH 14/55] [WIP] dt-bindings: dma: dw-axi-dmac: Increase DMA channel limit to 16 The first DMAC instance in the StarFive JH7100 SoC supports 16 DMA channels. FIXME Given there are more changes to the driver than just increasing DMAC_MAX_CHANNELS, we probably need a new compatible value, too. Signed-off-by: Geert Uytterhoeven --- Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml b/Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml index 79e241498e2532..09d3e9ee3939e1 100644 --- a/Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml +++ b/Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml @@ -51,7 +51,7 @@ properties: dma-channels: minimum: 1 - maximum: 8 + maximum: 16 snps,dma-masters: description: | @@ -71,14 +71,14 @@ properties: Channel priority specifier associated with the DMA channels. $ref: /schemas/types.yaml#/definitions/uint32-array minItems: 1 - maxItems: 8 + maxItems: 16 snps,block-size: description: | Channel block size specifier associated with the DMA channels. $ref: /schemas/types.yaml#/definitions/uint32-array minItems: 1 - maxItems: 8 + maxItems: 16 snps,axi-max-burst-len: description: | From 621179b83efb8be976a92d32f8faeabc531157cf Mon Sep 17 00:00:00 2001 From: Huan Feng Date: Fri, 8 Jan 2021 03:35:42 +0800 Subject: [PATCH 15/55] drivers/hw_random: Add StarFive JH7100 Random Number Generator driver --- drivers/char/hw_random/Kconfig | 13 ++ drivers/char/hw_random/Makefile | 1 + drivers/char/hw_random/starfive-vic-rng.c | 256 ++++++++++++++++++++++ drivers/char/hw_random/starfive-vic-rng.h | 167 ++++++++++++++ 4 files changed, 437 insertions(+) create mode 100644 drivers/char/hw_random/starfive-vic-rng.c create mode 100644 drivers/char/hw_random/starfive-vic-rng.h diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 1fe006f3f12fab..b21b7d33357e24 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -335,6 +335,19 @@ config HW_RANDOM_POWERNV If unsure, say Y. +config HW_RANDOM_STARFIVE_VIC + tristate "Starfive VIC Random Number Generator support" + depends on HW_RANDOM + default y if SOC_STARFIVE_VIC7100 + help + This driver provides kernel-side support for the Random Number + Generator hardware found on Starfive VIC SoC. + + To compile this driver as a module, choose M here: the + module will be called starfive-vic-rng. + + If unsure, say Y. + config HW_RANDOM_HISI tristate "Hisilicon Random Number Generator support" depends on HW_RANDOM && ARCH_HISI diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index 8933fada74f2fb..9b959cfc1b3086 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon-rng.o obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o +obj-$(CONFIG_HW_RANDOM_STARFIVE_VIC) += starfive-vic-rng.o obj-$(CONFIG_HW_RANDOM_HISI) += hisi-rng.o obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o diff --git a/drivers/char/hw_random/starfive-vic-rng.c b/drivers/char/hw_random/starfive-vic-rng.c new file mode 100644 index 00000000000000..6142b6a7ace6be --- /dev/null +++ b/drivers/char/hw_random/starfive-vic-rng.c @@ -0,0 +1,256 @@ +/* + ****************************************************************************** + * @file starfive-vic-rng.c + * @author StarFive Technology + * @version V1.0 + * @date 08/13/2020 + * @brief + ****************************************************************************** + * @copy + * + * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + * COPYRIGHT 2020 Shanghai StarFive Technology Co., Ltd. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "starfive-vic-rng.h" + +#define to_vic_rng(p) container_of(p, struct vic_rng, rng) + +struct vic_rng { + struct device *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) +{ + // clear register: ISTAT + 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) { + int res = 0; + // wait till idle + 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); + break; + default: + res = -1; + break; + } + + return res; +} + +static int vic_rng_init(struct hwrng *rng) +{ + struct vic_rng *hrng = to_vic_rng(rng); + + // wait till idle + + // 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 irqreturn_t vic_rng_irq(int irq, void *priv) +{ + u32 status, val; + struct vic_rng *hrng = (struct vic_rng *)priv; + + /* + * clearing the interrupt will also clear the error register + * read error and status before clearing + */ + status = readl(hrng->base + VIC_ISTAT); + + if (status & VIC_ISTAT_ALARMS) { + writel(VIC_ISTAT_ALARMS, hrng->base + VIC_ISTAT); + val = readl(hrng->base + VIC_ALARM); + if (val & VIC_ALARM_ILLEGAL_CMD_SEQ) { + writel(VIC_ALARM_ILLEGAL_CMD_SEQ, hrng->base + VIC_ALARM); + //dev_info(hrng->dev, "ILLEGAL CMD SEQ: LAST_CMD=0x%x\r\n", + //VIC_STAT_LAST_CMD(readl(hrng->base + VIC_STAT))); + } else { + dev_info(hrng->dev, "Failed test: %x\r\n", val); + } + } + + if (status & VIC_ISTAT_ZEROIZE) { + writel(VIC_ISTAT_ZEROIZE, hrng->base + VIC_ISTAT); + //dev_info(hrng->dev, "zeroized\r\n"); + } + + if (status & VIC_ISTAT_KAT_COMPLETE) { + writel(VIC_ISTAT_KAT_COMPLETE, hrng->base + VIC_ISTAT); + //dev_info(hrng->dev, "kat_completed\r\n"); + } + + if (status & VIC_ISTAT_NOISE_RDY) { + writel(VIC_ISTAT_NOISE_RDY, hrng->base + VIC_ISTAT); + //dev_info(hrng->dev, "noise_rdy\r\n"); + } + + if (status & VIC_ISTAT_DONE) { + writel(VIC_ISTAT_DONE, hrng->base + VIC_ISTAT); + //dev_info(hrng->dev, "done\r\n"); + /* + if (VIC_STAT_LAST_CMD(readl(hrng->base + VIC_STAT)) == + VIC_CTRL_CMD_GEN_RANDOM) { + dev_info(hrng->dev, "Need Update Buffer\r\n"); + } + */ + } + vic_rng_irq_mask_clear(hrng); + + return IRQ_HANDLED; +} + +static void vic_rng_cleanup(struct hwrng *rng) +{ + struct vic_rng *hrng = to_vic_rng(rng); + + writel(0, hrng->base + VIC_CTRL); +} + +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 platform_device *pdev) +{ + int ret; + int irq; + struct vic_rng *rng; + struct resource *res; + + rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL); + if (!rng){ + return -ENOMEM; + } + + platform_set_drvdata(pdev, rng); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + rng->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(rng->base)){ + return PTR_ERR(rng->base); + } + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + dev_err(&pdev->dev, "Couldn't get irq %d\n", irq); + return irq; + } + + ret = devm_request_irq(&pdev->dev, irq, vic_rng_irq, 0, pdev->name, + (void *)rng); + if (ret) { + dev_err(&pdev->dev, "Can't get interrupt working.\n"); + return ret; + } + + rng->rng.name = pdev->name; + rng->rng.init = vic_rng_init; + rng->rng.cleanup = vic_rng_cleanup; + rng->rng.read = vic_rng_read; + + rng->dev = &pdev->dev; + + ret = devm_hwrng_register(&pdev->dev, &rng->rng); + if (ret) { + dev_err(&pdev->dev, "failed to register hwrng\n"); + return ret; + } + + dev_info(&pdev->dev, "Initialized\n"); + + return 0; +} + +static const struct of_device_id vic_rng_dt_ids[] = { + { .compatible = "starfive,vic-rng" }, + { } +}; +MODULE_DEVICE_TABLE(of, vic_rng_dt_ids); + +static struct platform_driver vic_rng_driver = { + .probe = vic_rng_probe, + .driver = { + .name = "vic-rng", + .of_match_table = of_match_ptr(vic_rng_dt_ids), + }, +}; + +module_platform_driver(vic_rng_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Huan Feng "); +MODULE_DESCRIPTION("Starfive VIC random number generator driver"); diff --git a/drivers/char/hw_random/starfive-vic-rng.h b/drivers/char/hw_random/starfive-vic-rng.h new file mode 100644 index 00000000000000..b3bbabde0cfb13 --- /dev/null +++ b/drivers/char/hw_random/starfive-vic-rng.h @@ -0,0 +1,167 @@ +/* + ****************************************************************************** + * @file starfive-vic-rng.h + * @author StarFive Technology + * @version V1.0 + * @date 08/13/2020 + * @brief + ****************************************************************************** + * @copy + * + * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + * COPYRIGHT 2020 Shanghai StarFive Technology Co., Ltd. + */ + +#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 + +/* MODE */ +#define _VIC_MODE_ADDIN_PRESENT 4 +#define _VIC_MODE_PRED_RESIST 3 +#define _VIC_MODE_KAT_SEL 2 +#define _VIC_MODE_KAT_VEC 1 +#define _VIC_MODE_SEC_ALG 0 + +#define VIC_MODE_ADDIN_PRESENT (1UL << _VIC_MODE_ADDIN_PRESENT) +#define VIC_MODE_PRED_RESIST (1UL << _VIC_MODE_PRED_RESIST) +#define VIC_MODE_KAT_SEL (1UL << _VIC_MODE_KAT_SEL) +#define VIC_MODE_KAT_VEC (1UL << _VIC_MODE_KAT_VEC) +#define VIC_MODE_SEC_ALG (1UL << _VIC_MODE_SEC_ALG) + +/* SMODE */ +#define _VIC_SMODE_MAX_REJECTS 2 +#define _VIC_SMODE_SECURE_EN 1 +#define _VIC_SMODE_NONCE 0 + +#define VIC_SMODE_MAX_REJECTS(x) ((x) << _VIC_SMODE_MAX_REJECTS) +#define VIC_SMODE_SECURE_EN(x) ((x) << _VIC_SMODE_SECURE_EN) +#define VIC_SMODE_NONCE (1UL << _VIC_SMODE_NONCE) + +/* STAT */ +#define _VIC_STAT_BUSY 31 +#define _VIC_STAT_DRBG_STATE 7 +#define _VIC_STAT_SECURE 6 +#define _VIC_STAT_NONCE_MODE 5 +#define _VIC_STAT_SEC_ALG 4 +#define _VIC_STAT_LAST_CMD 0 + +#define VIC_STAT_BUSY (1UL << _VIC_STAT_BUSY) +#define VIC_STAT_DRBG_STATE (1UL << _VIC_STAT_DRBG_STATE) +#define VIC_STAT_SECURE (1UL << _VIC_STAT_SECURE) +#define VIC_STAT_NONCE_MODE (1UL << _VIC_STAT_NONCE_MODE) +#define VIC_STAT_SEC_ALG (1UL << _VIC_STAT_SEC_ALG) +#define VIC_STAT_LAST_CMD(x) (((x) >> _VIC_STAT_LAST_CMD) & 0xF) + +/* 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) + +/* ISTAT */ +#define _VIC_ISTAT_DONE 4 +#define _VIC_ISTAT_ALARMS 3 +#define _VIC_ISTAT_NOISE_RDY 2 +#define _VIC_ISTAT_KAT_COMPLETE 1 +#define _VIC_ISTAT_ZEROIZE 0 + +#define VIC_ISTAT_DONE (1UL << _VIC_ISTAT_DONE) +#define VIC_ISTAT_ALARMS (1UL << _VIC_ISTAT_ALARMS) +#define VIC_ISTAT_NOISE_RDY (1UL << _VIC_ISTAT_NOISE_RDY) +#define VIC_ISTAT_KAT_COMPLETE (1UL << _VIC_ISTAT_KAT_COMPLETE) +#define VIC_ISTAT_ZEROIZE (1UL << _VIC_ISTAT_ZEROIZE) + +/* ALARMS */ +#define VIC_ALARM_ILLEGAL_CMD_SEQ (1UL << 4) +#define VIC_ALARM_FAILED_TEST_ID_OK 0 +#define VIC_ALARM_FAILED_TEST_ID_KAT_STAT 1 +#define VIC_ALARM_FAILED_TEST_ID_KAT 2 +#define VIC_ALARM_FAILED_TEST_ID_MONOBIT 3 +#define VIC_ALARM_FAILED_TEST_ID_RUN 4 +#define VIC_ALARM_FAILED_TEST_ID_LONGRUN 5 +#define VIC_ALARM_FAILED_TEST_ID_AUTOCORRELATION 6 +#define VIC_ALARM_FAILED_TEST_ID_POKER 7 +#define VIC_ALARM_FAILED_TEST_ID_REPETITION_COUNT 8 +#define VIC_ALARM_FAILED_TEST_ID_ADAPATIVE_PROPORTION 9 + +/* BUILD_ID */ +#define VIC_BUILD_ID_STEPPING(x) (((x) >> 28) & 0xF) +#define VIC_BUILD_ID_EPN(x) ((x) & 0xFFFF) + +/* FEATURES */ +#define VIC_FEATURES_AES_256(x) (((x) >> 9) & 1) +#define VIC_FEATURES_EXTRA_PS_PRESENT(x) (((x) >> 8) & 1) +#define VIC_FEATURES_DIAG_LEVEL_NS(x) (((x) >> 7) & 1) +#define VIC_FEATURES_DIAG_LEVEL_CLP800(x) (((x) >> 4) & 7) +#define VIC_FEATURES_DIAG_LEVEL_ST_HLT(x) (((x) >> 1) & 7) +#define VIC_FEATURES_SECURE_RST_STATE(x) ((x) & 1) + +/* IA_CMD */ +#define VIC_IA_CMD_GO (1UL << 31) +#define VIC_IA_CMD_WR (1) + +#define _VIC_SMODE_MAX_REJECTS_MASK 255UL +#define _VIC_SMODE_SECURE_EN_MASK 1UL +#define _VIC_SMODE_NONCE_MASK 1UL +#define _VIC_MODE_SEC_ALG_MASK 1UL +#define _VIC_MODE_ADDIN_PRESENT_MASK 1UL +#define _VIC_MODE_PRED_RESIST_MASK 1UL + +#define VIC_SMODE_SET_MAX_REJECTS(y, x) (((y) & ~(_VIC_SMODE_MAX_REJECTS_MASK << _VIC_SMODE_MAX_REJECTS)) | ((x) << _VIC_SMODE_MAX_REJECTS)) +#define VIC_SMODE_SET_SECURE_EN(y, x) (((y) & ~(_VIC_SMODE_SECURE_EN_MASK << _VIC_SMODE_SECURE_EN)) | ((x) << _VIC_SMODE_SECURE_EN)) +#define VIC_SMODE_SET_NONCE(y, x) (((y) & ~(_VIC_SMODE_NONCE_MASK << _VIC_SMODE_NONCE)) | ((x) << _VIC_SMODE_NONCE)) +#define VIC_SMODE_GET_MAX_REJECTS(x) (((x) >> _VIC_SMODE_MAX_REJECTS) & _VIC_SMODE_MAX_REJECTS_MASK) +#define VIC_SMODE_GET_SECURE_EN(x) (((x) >> _VIC_SMODE_SECURE_EN) & _VIC_SMODE_SECURE_EN_MASK) +#define VIC_SMODE_GET_NONCE(x) (((x) >> _VIC_SMODE_NONCE) & _VIC_SMODE_NONCE_MASK) + +#define VIC_MODE_SET_SEC_ALG(y, x) (((y) & ~(_VIC_MODE_SEC_ALG_MASK << _VIC_MODE_SEC_ALG)) | ((x) << _VIC_MODE_SEC_ALG)) +#define VIC_MODE_SET_PRED_RESIST(y, x) (((y) & ~(_VIC_MODE_PRED_RESIST_MASK << _VIC_MODE_PRED_RESIST)) | ((x) << _VIC_MODE_PRED_RESIST)) +#define VIC_MODE_SET_ADDIN_PRESENT(y, x) (((y) & ~(_VIC_MODE_ADDIN_PRESENT_MASK << _VIC_MODE_ADDIN_PRESENT)) | ((x) << _VIC_MODE_ADDIN_PRESENT)) +#define VIC_MODE_GET_SEC_ALG(x) (((x) >> _VIC_MODE_SEC_ALG) & _VIC_MODE_SEC_ALG_MASK) +#define VIC_MODE_GET_PRED_RESIST(x) (((x) >> _VIC_MODE_PRED_RESIST) & _VIC_MODE_PRED_RESIST_MASK) +#define VIC_MODE_GET_ADDIN_PRESENT(x) (((x) >> _VIC_MODE_ADDIN_PRESENT) & _VIC_MODE_ADDIN_PRESENT_MASK) + +#define VIC_RAND_LEN 4 From 8bb85681d1d69ee39a806e00944ccb120c7f3232 Mon Sep 17 00:00:00 2001 From: Emil Renner Berthing Date: Sun, 6 Jun 2021 22:15:22 +0200 Subject: [PATCH 16/55] dt-bindings: hwmon: add starfive,jh7100-temp bindings Add bindings for the temperature sensor on the StarFive JH7100 SoC. Signed-off-by: Emil Renner Berthing --- .../bindings/hwmon/starfive,jh7100-temp.yaml | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 Documentation/devicetree/bindings/hwmon/starfive,jh7100-temp.yaml diff --git a/Documentation/devicetree/bindings/hwmon/starfive,jh7100-temp.yaml b/Documentation/devicetree/bindings/hwmon/starfive,jh7100-temp.yaml new file mode 100644 index 00000000000000..5ca52c08d142e5 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/starfive,jh7100-temp.yaml @@ -0,0 +1,43 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwmon/starfive,jh7100-temp.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: StarFive JH7100 Temperature Sensor + +maintainers: + - Emil Renner Berthing + +description: | + StarFive Technology Co. JH7100 embedded temperature sensor + +properties: + compatible: + enum: + - starfive,jh7100-temp + + reg: + maxItems: 1 + + '#thermal-sensor-cells': + const: 0 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + +additionalProperties: false + +examples: + - | + tmon: tmon@124a0000 { + compatible = "starfive,jh7100-temp"; + reg = <0x124a0000 0x10000>; + #thermal-sensor-cells = <0>; + interrupts = <122>; + }; From ab937407e62a4c030c9de403524a8c37682463fb Mon Sep 17 00:00:00 2001 From: Emil Renner Berthing Date: Sun, 6 Jun 2021 22:31:18 +0200 Subject: [PATCH 17/55] hwmon: (sfctemp) Add StarFive JH7100 temperature sensor Register definitions based on sfctemp driver in the StarFive 5.10 kernel by Samin Guo . Signed-off-by: Emil Renner Berthing --- Documentation/hwmon/index.rst | 1 + Documentation/hwmon/sfctemp.rst | 32 ++++ MAINTAINERS | 8 + drivers/hwmon/Kconfig | 10 ++ drivers/hwmon/Makefile | 1 + drivers/hwmon/sfctemp.c | 284 ++++++++++++++++++++++++++++++++ 6 files changed, 336 insertions(+) create mode 100644 Documentation/hwmon/sfctemp.rst create mode 100644 drivers/hwmon/sfctemp.c diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index 9ed60fa84cbec6..f23308e97d2e6f 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -161,6 +161,7 @@ Hardware Monitoring Kernel Drivers sch5627 sch5636 scpi-hwmon + sfctemp sht15 sht21 sht3x diff --git a/Documentation/hwmon/sfctemp.rst b/Documentation/hwmon/sfctemp.rst new file mode 100644 index 00000000000000..465edce2fea5e2 --- /dev/null +++ b/Documentation/hwmon/sfctemp.rst @@ -0,0 +1,32 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Kernel driver sfctemp +===================== + +Supported chips: + - StarFive JH7100 + +Authors: + - Emil Renner Berthing + +Description +----------- + +This driver adds support for reading the built-in temperature sensor on the +JH7100 RISC-V SoC by StarFive Technology Co. Ltd. + +``sysfs`` interface +------------------- + +The temperature sensor can be enabled, disabled and queried via the standard +hwmon interface in sysfs under ``/sys/class/hwmon/hwmonX`` for some value of +``X``: + +================ ==== ============================================= +Name Perm Description +================ ==== ============================================= +temp1_enable RW Enable or disable temperature sensor. + Automatically enabled by the driver, + but may be disabled to save power. +temp1_input RO Temperature reading in milli-degrees Celsius. +================ ==== ============================================= diff --git a/MAINTAINERS b/MAINTAINERS index 8c5ee008301a65..a7d25a67227092 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16535,6 +16535,14 @@ L: netdev@vger.kernel.org S: Supported F: drivers/net/ethernet/sfc/ +SFCTEMP HWMON DRIVER +M: Emil Renner Berthing +L: linux-hwmon@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/hwmon/starfive,jh7100-temp.yaml +F: Documentation/hwmon/sfctemp.rst +F: drivers/hwmon/sfctemp.c + SFF/SFP/SFP+ MODULE SUPPORT M: Russell King L: netdev@vger.kernel.org diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 87624902ea8090..7da8fd8beb06e7 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1751,6 +1751,16 @@ config SENSORS_STTS751 This driver can also be built as a module. If so, the module will be called stts751. +config SENSORS_SFCTEMP + tristate "Starfive JH7100 temperature sensor" + depends on OF && (RISCV || COMPILE_TEST) + help + If you say yes here you get support for temperature sensor + on the Starfive JH7100 SoC. + + This driver can also be built as a module. If so, the module + will be called sfctemp. + config SENSORS_SMM665 tristate "Summit Microelectronics SMM665" depends on I2C diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 59e78bc212cf3c..3723eb580bf3e7 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -167,6 +167,7 @@ obj-$(CONFIG_SENSORS_SBTSI) += sbtsi_temp.o obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o obj-$(CONFIG_SENSORS_SCH5627) += sch5627.o obj-$(CONFIG_SENSORS_SCH5636) += sch5636.o +obj-$(CONFIG_SENSORS_SFCTEMP) += sfctemp.o obj-$(CONFIG_SENSORS_SL28CPLD) += sl28cpld-hwmon.o obj-$(CONFIG_SENSORS_SHT15) += sht15.o obj-$(CONFIG_SENSORS_SHT21) += sht21.o diff --git a/drivers/hwmon/sfctemp.c b/drivers/hwmon/sfctemp.c new file mode 100644 index 00000000000000..b60ef599299c9c --- /dev/null +++ b/drivers/hwmon/sfctemp.c @@ -0,0 +1,284 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 Emil Renner Berthing + * Copyright (C) 2021 Samin Guo + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* TempSensor reset. The RSTN can be de-asserted once the analog core has + * powered up. Trst(min 100ns) + * 0:reset 1:de-assert + */ +#define SFCTEMP_RSTN BIT(0) + +/* TempSensor analog core power down. The analog core will be powered up + * Tpu(min 50us) after PD is de-asserted. RSTN should be held low until the + * analog core is powered up. + * 0:power up 1:power down + */ +#define SFCTEMP_PD BIT(1) + +/* TempSensor start conversion enable. + * 0:disable 1:enable + */ +#define SFCTEMP_RUN BIT(2) + +/* TempSensor conversion value output. + * Temp(c)=DOUT*Y/4094 - K + */ +#define SFCTEMP_DOUT_POS 16 +#define SFCTEMP_DOUT_MSK GENMASK(27, 16) + +/* DOUT to Celcius conversion constants */ +#define SFCTEMP_Y1000 237500L +#define SFCTEMP_Z 4094L +#define SFCTEMP_K1000 81100L + +struct sfctemp { + /* serialize access to hardware register and enabled below */ + struct mutex lock; + struct completion conversion_done; + void __iomem *regs; + bool enabled; +}; + +static irqreturn_t sfctemp_isr(int irq, void *data) +{ + struct sfctemp *sfctemp = data; + + complete(&sfctemp->conversion_done); + return IRQ_HANDLED; +} + +static void sfctemp_power_up(struct sfctemp *sfctemp) +{ + /* make sure we're powered down first */ + writel(SFCTEMP_PD, sfctemp->regs); + udelay(1); + + writel(0, sfctemp->regs); + /* wait t_pu(50us) + t_rst(100ns) */ + usleep_range(60, 200); + + /* de-assert reset */ + writel(SFCTEMP_RSTN, sfctemp->regs); + udelay(1); /* wait t_su(500ps) */ +} + +static void sfctemp_power_down(struct sfctemp *sfctemp) +{ + writel(SFCTEMP_PD, sfctemp->regs); +} + +static void sfctemp_run_single(struct sfctemp *sfctemp) +{ + writel(SFCTEMP_RSTN | SFCTEMP_RUN, sfctemp->regs); + udelay(1); + writel(SFCTEMP_RSTN, sfctemp->regs); +} + +static int sfctemp_enable(struct sfctemp *sfctemp) +{ + mutex_lock(&sfctemp->lock); + if (sfctemp->enabled) + goto done; + + sfctemp_power_up(sfctemp); + sfctemp->enabled = true; +done: + mutex_unlock(&sfctemp->lock); + return 0; +} + +static int sfctemp_disable(struct sfctemp *sfctemp) +{ + mutex_lock(&sfctemp->lock); + if (!sfctemp->enabled) + goto done; + + sfctemp_power_down(sfctemp); + sfctemp->enabled = false; +done: + mutex_unlock(&sfctemp->lock); + return 0; +} + +static void sfctemp_disable_action(void *data) +{ + sfctemp_disable(data); +} + +static int sfctemp_convert(struct sfctemp *sfctemp, long *val) +{ + int ret; + + mutex_lock(&sfctemp->lock); + if (!sfctemp->enabled) { + ret = -ENODATA; + goto out; + } + + sfctemp_run_single(sfctemp); + + ret = wait_for_completion_interruptible_timeout(&sfctemp->conversion_done, + msecs_to_jiffies(10)); + if (ret < 0) + goto out; + + /* calculate temperature in milli Celcius */ + *val = (long)((readl(sfctemp->regs) & SFCTEMP_DOUT_MSK) >> SFCTEMP_DOUT_POS) + * SFCTEMP_Y1000 / SFCTEMP_Z - SFCTEMP_K1000; + + ret = 0; +out: + mutex_unlock(&sfctemp->lock); + return ret; +} + +static umode_t sfctemp_is_visible(const void *data, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + switch (type) { + case hwmon_temp: + switch (attr) { + case hwmon_temp_enable: + return 0644; + case hwmon_temp_input: + return 0444; + } + return 0; + default: + return 0; + } +} + +static int sfctemp_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + struct sfctemp *sfctemp = dev_get_drvdata(dev); + + switch (type) { + case hwmon_temp: + switch (attr) { + case hwmon_temp_enable: + *val = sfctemp->enabled; + return 0; + case hwmon_temp_input: + return sfctemp_convert(sfctemp, val); + } + return -EINVAL; + default: + return -EINVAL; + } +} + +static int sfctemp_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long val) +{ + struct sfctemp *sfctemp = dev_get_drvdata(dev); + + switch (type) { + case hwmon_temp: + switch (attr) { + case hwmon_temp_enable: + if (val == 0) + return sfctemp_disable(sfctemp); + if (val == 1) + return sfctemp_enable(sfctemp); + break; + } + return -EINVAL; + default: + return -EINVAL; + } +} + +static const struct hwmon_channel_info *sfctemp_info[] = { + HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), + HWMON_CHANNEL_INFO(temp, HWMON_T_ENABLE | HWMON_T_INPUT), + NULL +}; + +static const struct hwmon_ops sfctemp_hwmon_ops = { + .is_visible = sfctemp_is_visible, + .read = sfctemp_read, + .write = sfctemp_write, +}; + +static const struct hwmon_chip_info sfctemp_chip_info = { + .ops = &sfctemp_hwmon_ops, + .info = sfctemp_info, +}; + +static int sfctemp_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device *hwmon_dev; + struct resource *mem; + struct sfctemp *sfctemp; + int ret; + + sfctemp = devm_kzalloc(dev, sizeof(*sfctemp), GFP_KERNEL); + if (!sfctemp) + return -ENOMEM; + + dev_set_drvdata(dev, sfctemp); + mutex_init(&sfctemp->lock); + init_completion(&sfctemp->conversion_done); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + sfctemp->regs = devm_ioremap_resource(dev, mem); + if (IS_ERR(sfctemp->regs)) + return PTR_ERR(sfctemp->regs); + + ret = platform_get_irq(pdev, 0); + if (ret < 0) + return ret; + + ret = devm_request_irq(dev, ret, sfctemp_isr, + IRQF_SHARED, pdev->name, sfctemp); + if (ret) { + dev_err(dev, "request irq failed: %d\n", ret); + return ret; + } + + ret = devm_add_action(dev, sfctemp_disable_action, sfctemp); + if (ret) + return ret; + + ret = sfctemp_enable(sfctemp); + if (ret) + return ret; + + hwmon_dev = devm_hwmon_device_register_with_info(dev, pdev->name, sfctemp, + &sfctemp_chip_info, NULL); + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +static const struct of_device_id sfctemp_of_match[] = { + { .compatible = "starfive,jh7100-temp" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, sfctemp_of_match); + +static struct platform_driver sfctemp_driver = { + .driver = { + .name = "sfctemp", + .of_match_table = of_match_ptr(sfctemp_of_match), + }, + .probe = sfctemp_probe, +}; +module_platform_driver(sfctemp_driver); + +MODULE_AUTHOR("Emil Renner Berthing"); +MODULE_DESCRIPTION("StarFive JH7100 temperature sensor driver"); +MODULE_LICENSE("GPL"); From 419729648a6a8689380fc520c55a18a0c78e0e18 Mon Sep 17 00:00:00 2001 From: Tom Date: Fri, 8 Jan 2021 02:54:51 +0800 Subject: [PATCH 18/55] sifive/sifive_l2_cache: Add sifive_l2_flush64_range function --- drivers/soc/sifive/Kconfig | 15 ++++++++++ drivers/soc/sifive/sifive_l2_cache.c | 41 +++++++++++++++++++++++++++- include/soc/sifive/sifive_l2_cache.h | 4 +++ 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/drivers/soc/sifive/Kconfig b/drivers/soc/sifive/Kconfig index 58cf8c40d08d53..4d0fdab56e81a6 100644 --- a/drivers/soc/sifive/Kconfig +++ b/drivers/soc/sifive/Kconfig @@ -7,4 +7,19 @@ config SIFIVE_L2 help Support for the L2 cache controller on SiFive platforms. +config SIFIVE_L2_FLUSH + bool "Support Level 2 Cache Controller Flush operation of SiFive Soc" + +if SIFIVE_L2_FLUSH + +config SIFIVE_L2_FLUSH_START + hex "Level 2 Cache Flush operation start" + default 0x80000000 + +config SIFIVE_L2_FLUSH_SIZE + hex "Level 2 Cache Flush operation size" + default 0x800000000 + +endif # SIFIVE_L2_FLUSH + endif diff --git a/drivers/soc/sifive/sifive_l2_cache.c b/drivers/soc/sifive/sifive_l2_cache.c index 59640a1d0b28a1..0b9e9e852ee44d 100644 --- a/drivers/soc/sifive/sifive_l2_cache.c +++ b/drivers/soc/sifive/sifive_l2_cache.c @@ -29,13 +29,17 @@ #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 -static void __iomem *l2_base; +#define SIFIVE_L2_FLUSH64_LINE_LEN 64 + +static void __iomem *l2_base = NULL; static int g_irq[SIFIVE_L2_MAX_ECCINTR]; static struct riscv_cacheinfo_ops l2_cache_ops; @@ -116,6 +120,41 @@ int unregister_sifive_l2_error_notifier(struct notifier_block *nb) } EXPORT_SYMBOL_GPL(unregister_sifive_l2_error_notifier); +#ifdef CONFIG_SIFIVE_L2_FLUSH +void sifive_l2_flush64_range(unsigned long start, unsigned long len) +{ + unsigned long line; + + if(!l2_base) { + pr_warn("L2CACHE: base addr invalid, skipping flush\n"); + return; + } + + /* TODO: if (len == 0), skipping flush or going on? */ + if(!len) { + pr_debug("L2CACHE: flush64 range @ 0x%lx(len:0)\n", start); + return; + } + + /* make sure the address is in the range */ + if(start < CONFIG_SIFIVE_L2_FLUSH_START || + (start + len) > (CONFIG_SIFIVE_L2_FLUSH_START + + CONFIG_SIFIVE_L2_FLUSH_SIZE)) { + pr_warn("L2CACHE: flush64 out of range: %lx(%lx), skip flush\n", + start, len); + return; + } + + mb(); /* sync */ + for (line = start; line < start + len; + line += SIFIVE_L2_FLUSH64_LINE_LEN) { + writeq(line, l2_base + SIFIVE_L2_FLUSH64); + mb(); + } +} +EXPORT_SYMBOL_GPL(sifive_l2_flush64_range); +#endif + static int l2_largest_wayenabled(void) { return readl(l2_base + SIFIVE_L2_WAYENABLE) & 0xFF; diff --git a/include/soc/sifive/sifive_l2_cache.h b/include/soc/sifive/sifive_l2_cache.h index 92ade10ed67e94..dd3e56787d3167 100644 --- a/include/soc/sifive/sifive_l2_cache.h +++ b/include/soc/sifive/sifive_l2_cache.h @@ -7,6 +7,10 @@ #ifndef __SOC_SIFIVE_L2_CACHE_H #define __SOC_SIFIVE_L2_CACHE_H +#ifdef CONFIG_SIFIVE_L2_FLUSH +extern void sifive_l2_flush64_range(unsigned long start, unsigned long len); +#endif + extern int register_sifive_l2_error_notifier(struct notifier_block *nb); extern int unregister_sifive_l2_error_notifier(struct notifier_block *nb); From e2bf10b58e483d699e1ab74137db811ba617bd41 Mon Sep 17 00:00:00 2001 From: Tom Date: Mon, 15 Feb 2021 23:59:46 +0800 Subject: [PATCH 19/55] sifive/sifive_l2_cache: Add Starfive support --- drivers/soc/sifive/sifive_l2_cache.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soc/sifive/sifive_l2_cache.c b/drivers/soc/sifive/sifive_l2_cache.c index 0b9e9e852ee44d..5f2b295fc5efdf 100644 --- a/drivers/soc/sifive/sifive_l2_cache.c +++ b/drivers/soc/sifive/sifive_l2_cache.c @@ -103,6 +103,7 @@ static void l2_config_read(void) static const struct of_device_id sifive_l2_ids[] = { { .compatible = "sifive,fu540-c000-ccache" }, { .compatible = "sifive,fu740-c000-ccache" }, + { .compatible = "starfive,ccache0" }, { /* end of table */ }, }; From 2248a3c0514d2c2967c68e05606efe690b89f6e1 Mon Sep 17 00:00:00 2001 From: Tom Date: Sat, 13 Feb 2021 22:25:17 +0800 Subject: [PATCH 20/55] sifive/sifive_l2_cache: Add disabling IRQ option (workaround) --- drivers/irqchip/irq-sifive-plic.c | 41 ++++++++++++++++++++++++++++ drivers/soc/sifive/Kconfig | 4 +++ drivers/soc/sifive/sifive_l2_cache.c | 8 ++++++ 3 files changed, 53 insertions(+) diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c index 97d4d04b0a80eb..63a8dea3fae5da 100644 --- a/drivers/irqchip/irq-sifive-plic.c +++ b/drivers/irqchip/irq-sifive-plic.c @@ -273,6 +273,44 @@ static int plic_starting_cpu(unsigned int cpu) return 0; } +#if IS_ENABLED(CONFIG_SIFIVE_L2_IRQ_DISABLE) +#ifdef CONFIG_SOC_STARFIVE_VIC7100 +#define SIFIVE_L2_MAX_ECCINTR 4 +#else +#define SIFIVE_L2_MAX_ECCINTR 3 +#endif +static const struct of_device_id sifive_l2_ids[] = { + { .compatible = "sifive,fu540-c000-ccache" }, + { .compatible = "starfive,ccache0" }, + { /* end of table */ }, +}; + +static void sifive_l2_irq_disable(struct plic_handler *handler) +{ + int i, irq; + struct of_phandle_args oirq; + + struct device_node *np = of_find_matching_node(NULL, sifive_l2_ids); + if (!np) { + pr_err("Can't get L2 cache device node.\n"); + return; + } + + for (i = 0; i < SIFIVE_L2_MAX_ECCINTR; i++) { + if (!of_irq_parse_one(np, i, &oirq)) { + irq = *oirq.args; + if (irq) { + pr_info("disable L2 cache irq %d in plic\n", irq); + plic_toggle(handler, irq, 0); + continue; + } + } + pr_err("Can't get L2 cache irq(#%d).\n", i); + } +} +#endif + + static int __init plic_init(struct device_node *node, struct device_node *parent) { @@ -366,6 +404,9 @@ static int __init plic_init(struct device_node *node, done: for (hwirq = 1; hwirq <= nr_irqs; hwirq++) plic_toggle(handler, hwirq, 0); +#if IS_ENABLED(CONFIG_SIFIVE_L2_IRQ_DISABLE) + sifive_l2_irq_disable(handler); +#endif nr_handlers++; } diff --git a/drivers/soc/sifive/Kconfig b/drivers/soc/sifive/Kconfig index 4d0fdab56e81a6..4cccaad9e943b8 100644 --- a/drivers/soc/sifive/Kconfig +++ b/drivers/soc/sifive/Kconfig @@ -22,4 +22,8 @@ config SIFIVE_L2_FLUSH_SIZE endif # SIFIVE_L2_FLUSH +config SIFIVE_L2_IRQ_DISABLE + bool "Disable Level 2 Cache Controller interrupts" + default y if SOC_STARFIVE_VIC7100 + endif diff --git a/drivers/soc/sifive/sifive_l2_cache.c b/drivers/soc/sifive/sifive_l2_cache.c index 5f2b295fc5efdf..be4e141f5a0ea9 100644 --- a/drivers/soc/sifive/sifive_l2_cache.c +++ b/drivers/soc/sifive/sifive_l2_cache.c @@ -40,7 +40,9 @@ #define SIFIVE_L2_FLUSH64_LINE_LEN 64 static void __iomem *l2_base = NULL; +#if !IS_ENABLED(CONFIG_SIFIVE_L2_IRQ_DISABLE) static int g_irq[SIFIVE_L2_MAX_ECCINTR]; +#endif static struct riscv_cacheinfo_ops l2_cache_ops; enum { @@ -188,6 +190,7 @@ static const struct attribute_group *l2_get_priv_group(struct cacheinfo *this_le return NULL; } +#if !IS_ENABLED(CONFIG_SIFIVE_L2_IRQ_DISABLE) static irqreturn_t l2_int_handler(int irq, void *device) { unsigned int add_h, add_l; @@ -231,12 +234,15 @@ static irqreturn_t l2_int_handler(int irq, void *device) return IRQ_HANDLED; } +#endif static int __init sifive_l2_init(void) { struct device_node *np; struct resource res; +#if !IS_ENABLED(CONFIG_SIFIVE_L2_IRQ_DISABLE) int i, rc, intr_num; +#endif np = of_find_matching_node(NULL, sifive_l2_ids); if (!np) @@ -249,6 +255,7 @@ static int __init sifive_l2_init(void) if (!l2_base) return -ENOMEM; +#if !IS_ENABLED(CONFIG_SIFIVE_L2_IRQ_DISABLE) intr_num = of_property_count_u32_elems(np, "interrupts"); if (!intr_num) { pr_err("L2CACHE: no interrupts property\n"); @@ -263,6 +270,7 @@ static int __init sifive_l2_init(void) return rc; } } +#endif l2_config_read(); From 25e1b8a889b4b654d1fcf3994e1367e0cd0bb0bb Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 May 2021 08:35:33 +0200 Subject: [PATCH 21/55] sifive/sifive_l2_cache: Print a backtrace on out-of-range flushes This makes it easier to find out which driver passes a wrong address range. Signed-off-by: Geert Uytterhoeven --- drivers/soc/sifive/sifive_l2_cache.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soc/sifive/sifive_l2_cache.c b/drivers/soc/sifive/sifive_l2_cache.c index be4e141f5a0ea9..626b664547e51e 100644 --- a/drivers/soc/sifive/sifive_l2_cache.c +++ b/drivers/soc/sifive/sifive_l2_cache.c @@ -143,8 +143,8 @@ void sifive_l2_flush64_range(unsigned long start, unsigned long len) if(start < CONFIG_SIFIVE_L2_FLUSH_START || (start + len) > (CONFIG_SIFIVE_L2_FLUSH_START + CONFIG_SIFIVE_L2_FLUSH_SIZE)) { - pr_warn("L2CACHE: flush64 out of range: %lx(%lx), skip flush\n", - start, len); + WARN(1, "L2CACHE: flush64 out of range: %lx(%lx), skip flush\n", + start, len); return; } From c60e27588fa3f572f0a8854e28d44d4c14f5143d Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Sat, 12 Jun 2021 16:52:26 -0700 Subject: [PATCH 22/55] sifive/sifive_l2_cache: Align the address to cache line [Emil: fix suggested by Geert Uytterhoeven ] Signed-off-by: Atish Patra Signed-off-by: Emil Renner Berthing --- drivers/soc/sifive/sifive_l2_cache.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/soc/sifive/sifive_l2_cache.c b/drivers/soc/sifive/sifive_l2_cache.c index 626b664547e51e..fb39be6c730a94 100644 --- a/drivers/soc/sifive/sifive_l2_cache.c +++ b/drivers/soc/sifive/sifive_l2_cache.c @@ -139,6 +139,9 @@ void sifive_l2_flush64_range(unsigned long start, unsigned long len) return; } + len = len + (start % SIFIVE_L2_FLUSH64_LINE_LEN); + start = ALIGN_DOWN(start, SIFIVE_L2_FLUSH64_LINE_LEN); + /* make sure the address is in the range */ if(start < CONFIG_SIFIVE_L2_FLUSH_START || (start + len) > (CONFIG_SIFIVE_L2_FLUSH_START + From a16330d57432c67bbd58c6cf973bcbd9135b34a4 Mon Sep 17 00:00:00 2001 From: Chenjieqin Date: Fri, 8 Jan 2021 03:56:54 +0800 Subject: [PATCH 23/55] drivers/pwm: Add SiFive PWM PTC driver --- drivers/pwm/Kconfig | 10 ++ drivers/pwm/Makefile | 1 + drivers/pwm/pwm-sifive-ptc.c | 290 +++++++++++++++++++++++++++++++++++ 3 files changed, 301 insertions(+) create mode 100644 drivers/pwm/pwm-sifive-ptc.c diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index c76adedd58c9f0..e25c22b3ff1955 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -491,6 +491,16 @@ config PWM_SIFIVE To compile this driver as a module, choose M here: the module will be called pwm-sifive. +config PWM_SIFIVE_PTC + tristate "SiFive PWM PTC support" + depends on OF + depends on COMMON_CLK + help + Generic PWM framework driver for SiFive SoCs. + + To compile this driver as a module, choose M here: the module + will be called pwm-sifive-ptc. + config PWM_SL28CPLD tristate "Kontron sl28cpld PWM support" depends on MFD_SL28CPLD || COMPILE_TEST diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 708840b7fba8d8..3ad7903fd7fe21 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -45,6 +45,7 @@ obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o +obj-$(CONFIG_PWM_SIFIVE_PTC) += pwm-sifive-ptc.o obj-$(CONFIG_PWM_SL28CPLD) += pwm-sl28cpld.o obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o obj-$(CONFIG_PWM_SPRD) += pwm-sprd.o diff --git a/drivers/pwm/pwm-sifive-ptc.c b/drivers/pwm/pwm-sifive-ptc.c new file mode 100644 index 00000000000000..e510181b32bb20 --- /dev/null +++ b/drivers/pwm/pwm-sifive-ptc.c @@ -0,0 +1,290 @@ +/* + * Copyright (C) 2018 SiFive, Inc + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2, as published by + * the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define PTC_DEBUG 0 + +/* max channel of pwm */ +#define MAX_PWM 8 + +/* PTC Register offsets */ +#define REG_RPTC_CNTR 0x0 +#define REG_RPTC_HRC 0x4 +#define REG_RPTC_LRC 0x8 +#define REG_RPTC_CTRL 0xC + +/* Bit for PWM clock */ +#define BIT_PWM_CLOCK_EN 31 + +/* Bit for clock gen soft reset */ +#define BIT_CLK_GEN_SOFT_RESET 13 + +#define NS_1 1000000000 + +/* Access PTC register (cntr hrc lrc and ctrl) ,need to replace PWM_BASE_ADDR */ +#define REG_PTC_BASE_ADDR_SUB(base, N) ((base) + ((N>3)?((N-4)*0x10+(1<<15)):(N*0x10))) +#define REG_PTC_RPTC_CNTR(base,N) (REG_PTC_BASE_ADDR_SUB(base,N)) +#define REG_PTC_RPTC_HRC(base,N) (REG_PTC_BASE_ADDR_SUB(base,N) + 0x4) +#define REG_PTC_RPTC_LRC(base,N) (REG_PTC_BASE_ADDR_SUB(base,N) + 0x8) +#define REG_PTC_RPTC_CTRL(base,N) (REG_PTC_BASE_ADDR_SUB(base,N) + 0xC) + +/* pwm ptc device */ +struct sifive_pwm_ptc_device { + struct pwm_chip chip; + struct clk *clk; + void __iomem *regs; + int irq; + /* apb clock frequency , from dts */ + unsigned int approx_period; +}; + +static inline struct sifive_pwm_ptc_device *chip_to_sifive_ptc(struct pwm_chip *c) +{ + return container_of(c, struct sifive_pwm_ptc_device, chip); +} + + +static void sifive_pwm_ptc_get_state(struct pwm_chip *chip, struct pwm_device *dev, struct pwm_state *state) +{ + struct sifive_pwm_ptc_device *pwm = chip_to_sifive_ptc(chip); + uint32_t data_lrc; + uint32_t data_hrc; + uint32_t pwm_clk_ns = 0; + + /* get lrc and hrc data from registe*/ + data_lrc = ioread32(REG_PTC_RPTC_LRC(pwm->regs, dev->hwpwm)); + data_hrc = ioread32(REG_PTC_RPTC_HRC(pwm->regs, dev->hwpwm)); + + /* how many ns does apb clock elapse */ + pwm_clk_ns = NS_1 / pwm->approx_period; + + /* pwm period(ns) */ + state->period = data_lrc*pwm_clk_ns; + + /* duty cycle(ns) ,means high level eclapse ns if it is normal polarity */ + state->duty_cycle = data_hrc*pwm_clk_ns; + + /* polarity,we don't use it now because it is not in dts */ + state->polarity = PWM_POLARITY_NORMAL; + + /* enabled or not */ + state->enabled = 1; +#ifdef PTC_DEBUG + printk("sifive_pwm_ptc_get_state in,no:%d....\r\n",dev->hwpwm); + printk("data_hrc:0x%x 0x%x \n", data_hrc, data_lrc); + printk("period:%llu\r\n",state->period); + printk("duty_cycle:%llu\r\n",state->duty_cycle); + printk("polarity:%d\r\n",state->polarity); + printk("enabled:%d\r\n",state->enabled); +#endif +} + + +static int sifive_pwm_ptc_apply(struct pwm_chip *chip, struct pwm_device *dev, struct pwm_state *state) +{ + struct sifive_pwm_ptc_device *pwm = chip_to_sifive_ptc(chip); + uint32_t pwm_clk_ns = 0; + uint32_t data_hrc = 0; + uint32_t data_lrc = 0; + uint32_t period_data = 0; + uint32_t duty_data = 0; + void __iomem* reg_addr; + +#if PTC_DEBUG + printk("sifive_pwm_ptc_apply in,no:%d....\r\n",dev->hwpwm); + printk("set parameter......\r\n"); + printk("period:%d\r\n",state->period); + printk("duty_cycle:%d\r\n",state->duty_cycle); + printk("polarity:%d\r\n",state->polarity); + printk("enabled:%d\r\n",state->enabled); +#endif + /* duty_cycle should be less or equal than period */ + if(state->duty_cycle > state->period) + state->duty_cycle = state->period; + + /* calculate pwm real period (ns) */ + pwm_clk_ns = NS_1 / pwm->approx_period; + +#if PTC_DEBUG + printk("approx_period,:%d,pwm_clk_ns:%d\r\n",pwm->approx_period,pwm_clk_ns); +#endif + + /* calculate period count */ + period_data = state->period / pwm_clk_ns; + + if (!state->enabled) + /* if is unenable,just set duty_dat to 0 , means low level always */ + duty_data = 0; + else + /* calculate duty count*/ + duty_data = state->duty_cycle / pwm_clk_ns; + +#if PTC_DEBUG + printk("period_data:%d,duty_data:%d\r\n",period_data,duty_data); +#endif + + if(state->polarity == PWM_POLARITY_NORMAL) + /* calculate data_hrc */ + data_hrc = period_data - duty_data; + else + /* calculate data_hrc */ + data_hrc = duty_data; + + data_lrc = period_data; + + /* set hrc */ + reg_addr = REG_PTC_RPTC_HRC(pwm->regs, dev->hwpwm); +#if PTC_DEBUG + printk("[sifive_pwm_ptc_config]reg_addr:0x%lx,data:%d....\n",reg_addr,data_hrc); +#endif + iowrite32(data_hrc, reg_addr); + +#if PTC_DEBUG + printk("[sifive_pwm_ptc_config]hrc ok....\n"); +#endif + + /* set lrc */ + reg_addr = REG_PTC_RPTC_LRC(pwm->regs, dev->hwpwm); +#if PTC_DEBUG + printk("[sifive_pwm_ptc_config]reg_addr:0x%lx,data:%d....\n",reg_addr,data_lrc); +#endif + + iowrite32(data_lrc, reg_addr); + +#if PTC_DEBUG + printk("[sifive_pwm_ptc_config]lrc ok....\n"); +#endif + + return 0; +} + + + +static const struct pwm_ops sifive_pwm_ptc_ops = { + .get_state = sifive_pwm_ptc_get_state, + .apply = (void *)sifive_pwm_ptc_apply, + .owner = THIS_MODULE, +}; + + + + +static int sifive_pwm_ptc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = pdev->dev.of_node; + struct sifive_pwm_ptc_device *pwm; + struct pwm_chip *chip; + struct resource *res; + int ret; + +#if PTC_DEBUG + printk("sifive_pwm_ptc_probe in....\r\n"); +#endif + pwm = devm_kzalloc(dev, sizeof(*pwm), GFP_KERNEL); + if (!pwm) { + dev_err(dev, "Out of memory\n"); + return -ENOMEM; + } + + chip = &pwm->chip; + chip->dev = dev; + chip->ops = &sifive_pwm_ptc_ops; + + /* how many parameters can be transfered to ptc,need to fix */ + chip->of_pwm_n_cells = 3; + chip->base = -1; + + /* get pwm channels count, max value is 8 */ + ret = of_property_read_u32(node, "starfive,npwm", &chip->npwm); + if (ret < 0 || chip->npwm > MAX_PWM) + chip->npwm = MAX_PWM; + +#if PTC_DEBUG + printk("[sifive_pwm_ptc_probe] npwm:0x%lx....\r\n",chip->npwm); +#endif + /* get apb clock frequency */ + ret = of_property_read_u32(node, "sifive,approx-period", &pwm->approx_period); + +#if PTC_DEBUG + printk("[sifive_pwm_ptc_probe] approx_period:%d....\r\n",pwm->approx_period); +#endif + /* get IO base address*/ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + +#if PTC_DEBUG + printk("[sifive_pwm_ptc_probe] res start:0x%lx,end:0x%lx....\r\n",res->start,res->end); +#endif + pwm->regs = devm_ioremap_resource(dev, res); + if (IS_ERR(pwm->regs)) + { + dev_err(dev, "Unable to map IO resources\n"); + return PTR_ERR(pwm->regs); + } + +#if PTC_DEBUG + printk("[sifive_pwm_ptc_probe] regs:0x%lx....\r\n",pwm->regs); +#endif + + pwm->clk = devm_clk_get(dev, NULL); + if (IS_ERR(pwm->clk)) { + dev_err(dev, "Unable to find controller clock\n"); + return PTR_ERR(pwm->clk); + } + + /* after add,it will display as /sys/class/pwm/pwmchip0,0 is chip->base + * after execute echo 0 > export in , pwm0 can be seen */ + ret = pwmchip_add(chip); + if (ret < 0) { + dev_err(dev, "cannot register PTC: %d\n", ret); + return ret; + } + + platform_set_drvdata(pdev, pwm); + +#if PTC_DEBUG + printk("SiFive PWM PTC chip registered %d PWMs\n", chip->npwm); +#endif + + return 0; +} + +static int sifive_pwm_ptc_remove(struct platform_device *dev) +{ + struct sifive_pwm_ptc_device *pwm = platform_get_drvdata(dev); + struct pwm_chip *chip = &pwm->chip; + + return pwmchip_remove(chip); +} + +static const struct of_device_id sifive_pwm_ptc_of_match[] = { + { .compatible = "sifive,pwm0" }, + { .compatible = "starfive,pwm0" }, + { }, +}; +MODULE_DEVICE_TABLE(of, sifive_pwm_ptc_of_match); + +static struct platform_driver sifive_pwm_ptc_driver = { + .probe = sifive_pwm_ptc_probe, + .remove = sifive_pwm_ptc_remove, + .driver = { + .name = "pwm-sifive-ptc", + .of_match_table = of_match_ptr(sifive_pwm_ptc_of_match), + }, +}; +module_platform_driver(sifive_pwm_ptc_driver); + +MODULE_DESCRIPTION("SiFive PWM PTC driver"); +MODULE_LICENSE("GPL v2"); From 432dfc3db799e9c454abcac17232a7d9f5d635cb Mon Sep 17 00:00:00 2001 From: "yiming.li" Date: Tue, 16 Mar 2021 01:45:19 +0800 Subject: [PATCH 24/55] drivers/pwm/pwm-sifive-ptc: Clear PWM CNTR Clear CNTR of PWM after setting period & duty_cycle --- drivers/pwm/pwm-sifive-ptc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/pwm/pwm-sifive-ptc.c b/drivers/pwm/pwm-sifive-ptc.c index e510181b32bb20..9f149a064ed866 100644 --- a/drivers/pwm/pwm-sifive-ptc.c +++ b/drivers/pwm/pwm-sifive-ptc.c @@ -167,6 +167,10 @@ static int sifive_pwm_ptc_apply(struct pwm_chip *chip, struct pwm_device *dev, s printk("[sifive_pwm_ptc_config]lrc ok....\n"); #endif + /* Clear REG_RPTC_CNTR after setting period & duty_cycle*/ + reg_addr = REG_PTC_RPTC_CNTR(pwm->regs, dev->hwpwm); + iowrite32(0, reg_addr); + return 0; } From 629d2d1bc300c688aafdd5e596e24e26e627119f Mon Sep 17 00:00:00 2001 From: Tom Date: Fri, 8 Jan 2021 02:57:50 +0800 Subject: [PATCH 25/55] drivers/dma: Add dw-axi-dmac-starfive driver for VIC7100 --- drivers/dma/Kconfig | 7 + drivers/dma/Makefile | 1 + drivers/dma/dw-axi-dmac-starfive/Makefile | 2 + .../dw-axi-dmac-starfive-misc.c | 322 ++++++++++++++++++ .../starfive_dmaengine_memcpy.c | 287 ++++++++++++++++ .../dma/dw-axi-dmac/dw-axi-dmac-platform.c | 103 +++++- drivers/dma/dw-axi-dmac/dw-axi-dmac.h | 36 +- 7 files changed, 738 insertions(+), 20 deletions(-) create mode 100644 drivers/dma/dw-axi-dmac-starfive/Makefile create mode 100644 drivers/dma/dw-axi-dmac-starfive/dw-axi-dmac-starfive-misc.c create mode 100644 drivers/dma/dw-axi-dmac-starfive/starfive_dmaengine_memcpy.c diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 39b5b46e880f29..025d8a9dcfb58b 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -181,6 +181,13 @@ config DW_AXI_DMAC NOTE: This driver wasn't tested on 64 bit platform because of lack 64 bit platform with Synopsys DW AXI DMAC. +config DW_AXI_DMAC_STARFIVE + tristate "Synopsys DesignWare AXI DMA support for StarFive SOC" + depends on SOC_STARFIVE_VIC7100 + help + Enable support for Synopsys DesignWare AXI DMA controller. + NOTE: It's for StarFive SOC. + config EP93XX_DMA bool "Cirrus Logic EP93xx DMA support" depends on ARCH_EP93XX || COMPILE_TEST diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index aa69094e35470c..7d332af8b96c6f 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o obj-$(CONFIG_DMA_SUN4I) += sun4i-dma.o obj-$(CONFIG_DMA_SUN6I) += sun6i-dma.o obj-$(CONFIG_DW_AXI_DMAC) += dw-axi-dmac/ +obj-$(CONFIG_DW_AXI_DMAC_STARFIVE) += dw-axi-dmac-starfive/ obj-$(CONFIG_DW_DMAC_CORE) += dw/ obj-$(CONFIG_DW_EDMA) += dw-edma/ obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o diff --git a/drivers/dma/dw-axi-dmac-starfive/Makefile b/drivers/dma/dw-axi-dmac-starfive/Makefile new file mode 100644 index 00000000000000..c30fd928982f9e --- /dev/null +++ b/drivers/dma/dw-axi-dmac-starfive/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_DW_AXI_DMAC_STARFIVE) += starfive_dmaengine_memcpy.o dw-axi-dmac-starfive-misc.o \ No newline at end of file diff --git a/drivers/dma/dw-axi-dmac-starfive/dw-axi-dmac-starfive-misc.c b/drivers/dma/dw-axi-dmac-starfive/dw-axi-dmac-starfive-misc.c new file mode 100644 index 00000000000000..a1189bbe1e5bae --- /dev/null +++ b/drivers/dma/dw-axi-dmac-starfive/dw-axi-dmac-starfive-misc.c @@ -0,0 +1,322 @@ +/* + * Copyright 2020 StarFive, Inc + * + * DW AXI dma driver for StarFive SoC VIC7100. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DRIVER_NAME "dwaxidma" +#define AXIDMA_IOC_MAGIC 'A' +#define AXIDMA_IOCGETCHN _IO(AXIDMA_IOC_MAGIC, 0) +#define AXIDMA_IOCCFGANDSTART _IO(AXIDMA_IOC_MAGIC, 1) +#define AXIDMA_IOCGETSTATUS _IO(AXIDMA_IOC_MAGIC, 2) +#define AXIDMA_IOCRELEASECHN _IO(AXIDMA_IOC_MAGIC, 3) + +#define AXI_DMA_MAX_CHANS 20 + +#define DMA_CHN_UNUSED 0 +#define DMA_CHN_USED 1 +#define DMA_STATUS_UNFINISHED 0 +#define DMA_STATUS_FINISHED 1 + +/* for DEBUG*/ +//#define DW_DMA_CHECK_RESULTS +//#define DW_DMA_PRINT_MEM +//#define DW_DMA_FLUSH_DESC + +struct axidma_chncfg { + unsigned long src_addr; /*dma addr*/ + unsigned long dst_addr; /*dma addr*/ + unsigned long virt_src; /*mmap src addr*/ + unsigned long virt_dst; /*mmap dst addr*/ + unsigned long phys; /*desc phys addr*/ + unsigned int len; /*transport lenth*/ + int mem_fd; /*fd*/ + unsigned char chn_num; /*dma channels number*/ + unsigned char status; /*dma transport status*/ +}; + +struct axidma_chns { + struct dma_chan *dma_chan; + unsigned char used; + unsigned char status; + unsigned char reserve[2]; +}; + +struct axidma_chns channels[AXI_DMA_MAX_CHANS]; +#ifdef DW_DMA_PRINT_MEM +void print_in_line_u64(u8 *p_name, u64 *p_buf, u32 len) +{ + u32 i, j; + u32 line; + u32* ptmp; + u32 len_tmp; + u32 rest = len / 4; + + printk("%s: 0x%#llx, 0x%x\n", + p_name, dw_virt_to_phys((void *)p_buf), len); + + if(len >= 0x1000) + len_tmp = 0x1000 / 32; //print 128 size of memory. + else + len_tmp = len / 8; //print real 100% size of memory. + + rest = len / 4; //one line print 8 u32 + + for (i = 0; i < len_tmp; i += 4, rest -= line) { + if (!(i % 4)) + printk(KERN_CONT KERN_INFO" %#llx: ", + dw_virt_to_phys((void *)(p_buf + i))); + + ptmp = (u32*)(p_buf + i); + line = (rest > 8) ? 8 : rest; + + for (j = 0; j < line; j++) + printk(KERN_CONT KERN_INFO "%08x ", *(ptmp + j)); + + printk(KERN_CONT KERN_INFO"\n"); + } +} +#endif + +static int axidma_open(struct inode *inode, struct file *file) +{ + /*Open: do nothing*/ + return 0; +} + +static int axidma_release(struct inode *inode, struct file *file) +{ + /* Release: do nothing */ + return 0; +} + +static ssize_t axidma_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) +{ + /* Write: do nothing */ + return 0; +} + +static void dma_complete_func(void *status) +{ + *(char *)status = DMA_STATUS_FINISHED; +} + +static long axidma_unlocked_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int i, ret; + dma_cap_mask_t mask; + dma_cookie_t cookie; + struct dma_device *dma_dev; + struct axidma_chncfg chncfg; + struct dma_async_tx_descriptor *tx; + +#ifdef DW_DMA_FLUSH_DESC + void *des_chncfg = &chncfg; + chncfg.phys = dw_virt_to_phys(des_chncfg); +#endif + memset(&chncfg, 0, sizeof(struct axidma_chncfg)); + + switch(cmd) { + case AXIDMA_IOCGETCHN: + for(i = 0; i < AXI_DMA_MAX_CHANS; i++) { + if(DMA_CHN_UNUSED == channels[i].used) + break; + } + if(AXI_DMA_MAX_CHANS == i) { + printk("Get dma chn failed, because no idle channel\n"); + goto error; + } else { + channels[i].used = DMA_CHN_USED; + channels[i].status = DMA_STATUS_UNFINISHED; + chncfg.status = DMA_STATUS_UNFINISHED; + chncfg.chn_num = i; + } + dma_cap_zero(mask); + dma_cap_set(DMA_MEMCPY, mask); + channels[i].dma_chan = dma_request_channel(mask, NULL, NULL); + if(!channels[i].dma_chan) { + printk("dma request channel failed\n"); + channels[i].used = DMA_CHN_UNUSED; + goto error; + } + ret = copy_to_user((void __user *)arg, &chncfg, + sizeof(struct axidma_chncfg)); + if(ret) { + printk("Copy to user failed\n"); + goto error; + } + break; + case AXIDMA_IOCCFGANDSTART: +#ifdef DW_DMA_CHECK_RESULTS + void *src,*dst; +#endif + ret = copy_from_user(&chncfg, (void __user *)arg, + sizeof(struct axidma_chncfg)); + if(ret) { + printk("Copy from user failed\n"); + goto error; + } + + if((chncfg.chn_num >= AXI_DMA_MAX_CHANS) || + (!channels[chncfg.chn_num].dma_chan)) { + printk("chn_num[%d] is invalid\n", chncfg.chn_num); + goto error; + } + dma_dev = channels[chncfg.chn_num].dma_chan->device; +#ifdef DW_DMA_FLUSH_DESC + starfive_flush_dcache(chncfg.phys,sizeof(chncfg)); +#endif +#ifdef DW_DMA_CHECK_RESULTS + src = dw_phys_to_virt(chncfg.src_addr); + dst = dw_phys_to_virt(chncfg.dst_addr); +#endif + starfive_flush_dcache(chncfg.src_addr, chncfg.len); + + tx = dma_dev->device_prep_dma_memcpy( + channels[chncfg.chn_num].dma_chan, + chncfg.dst_addr, chncfg.src_addr, chncfg.len, + DMA_CTRL_ACK | DMA_PREP_INTERRUPT); + if(!tx){ + printk("Failed to prepare DMA memcpy\n"); + goto error; + } + channels[chncfg.chn_num].status = DMA_STATUS_UNFINISHED; + tx->callback_param = &channels[chncfg.chn_num].status; + tx->callback = dma_complete_func; + cookie = tx->tx_submit(tx); + if(dma_submit_error(cookie)) { + printk("Failed to dma tx_submit\n"); + goto error; + } + dma_async_issue_pending(channels[chncfg.chn_num].dma_chan); + /*flush dcache*/ + starfive_flush_dcache(chncfg.dst_addr, chncfg.len); +#ifdef DW_DMA_PRINT_MEM + print_in_line_u64((u8 *)"src", (u64 *)src, chncfg.len); + print_in_line_u64((u8 *)"dst", (u64 *)dst, chncfg.len); +#endif +#ifdef DW_DMA_CHECK_RESULTS + if(memcmp(src, dst, chncfg.len)) + printk("check data faild.\n"); + else + printk("check data ok.\n"); +#endif + break; + + case AXIDMA_IOCGETSTATUS: + ret = copy_from_user(&chncfg, (void __user *)arg, + sizeof(struct axidma_chncfg)); + if(ret) { + printk("Copy from user failed\n"); + goto error; + } + + if(chncfg.chn_num >= AXI_DMA_MAX_CHANS) { + printk("chn_num[%d] is invalid\n", chncfg.chn_num); + goto error; + } + + chncfg.status = channels[chncfg.chn_num].status; + + ret = copy_to_user((void __user *)arg, &chncfg, + sizeof(struct axidma_chncfg)); + if(ret) { + printk("Copy to user failed\n"); + goto error; + } + break; + + case AXIDMA_IOCRELEASECHN: + ret = copy_from_user(&chncfg, (void __user *)arg, + sizeof(struct axidma_chncfg)); + if(ret) { + printk("Copy from user failed\n"); + goto error; + } + + if((chncfg.chn_num >= AXI_DMA_MAX_CHANS) || + (!channels[chncfg.chn_num].dma_chan)) { + printk("chn_num[%d] is invalid\n", chncfg.chn_num); + goto error; + } + + dma_release_channel(channels[chncfg.chn_num].dma_chan); + channels[chncfg.chn_num].used = DMA_CHN_UNUSED; + channels[chncfg.chn_num].status = DMA_STATUS_UNFINISHED; + break; + + default: + printk("Don't support cmd [%d]\n", cmd); + break; + } + return 0; + +error: + return -EFAULT; +} + +/* + * Kernel Interfaces + */ +static struct file_operations axidma_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = axidma_write, + .unlocked_ioctl = axidma_unlocked_ioctl, + .open = axidma_open, + .release = axidma_release, +}; + +static struct miscdevice axidma_miscdev = { + .minor = MISC_DYNAMIC_MINOR, + .name = DRIVER_NAME, + .fops = &axidma_fops, +}; + +static int __init axidma_init(void) +{ + int ret = misc_register(&axidma_miscdev); + if(ret) { + printk (KERN_ERR "cannot register miscdev (err=%d)\n", ret); + return ret; + } + + memset(&channels, 0, sizeof(channels)); + + return 0; +} + +static void __exit axidma_exit(void) +{ + misc_deregister(&axidma_miscdev); +} + +module_init(axidma_init); +module_exit(axidma_exit); + +MODULE_AUTHOR("samin.guo"); +MODULE_DESCRIPTION("DW Axi Dmac Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/dma/dw-axi-dmac-starfive/starfive_dmaengine_memcpy.c b/drivers/dma/dw-axi-dmac-starfive/starfive_dmaengine_memcpy.c new file mode 100644 index 00000000000000..aee72c10d77fa7 --- /dev/null +++ b/drivers/dma/dw-axi-dmac-starfive/starfive_dmaengine_memcpy.c @@ -0,0 +1,287 @@ +/* + * Copyright 2020 StarFive, Inc + * + * API for dma mem2mem. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static volatile int dma_finished = 0; +static DECLARE_WAIT_QUEUE_HEAD(wq); + +u64 dw_virt_to_phys(void *vaddr) +{ + u64 pfn_offset = ((u64)vaddr) & 0xfff; + + return _dw_virt_to_phys((u64 *)vaddr) + pfn_offset; +} +EXPORT_SYMBOL(dw_virt_to_phys); + +void *dw_phys_to_virt(u64 phys) +{ + u64 pfn_offset = phys & 0xfff; + + return (void *)(_dw_phys_to_virt(phys) + pfn_offset); +} +EXPORT_SYMBOL(dw_phys_to_virt); + +static void tx_callback(void *dma_async_param) +{ + dma_finished = 1; + wake_up_interruptible(&wq); +} + +static int _dma_async_alloc_buf(struct device *dma_dev, + void **src, void **dst, size_t size, + dma_addr_t *src_dma, dma_addr_t *dst_dma) +{ + *src = dma_alloc_coherent(dma_dev, size, src_dma, GFP_KERNEL); + if(!(*src)) { + DMA_DEBUG("src alloc err.\n"); + goto _FAILED_ALLOC_SRC; + } + + *dst = dma_alloc_coherent(dma_dev, size, dst_dma, GFP_KERNEL); + if(!(*dst)) { + DMA_DEBUG("dst alloc err.\n"); + goto _FAILED_ALLOC_DST; + } + + return 0; + +_FAILED_ALLOC_DST: + dma_free_coherent(dma_dev, size, *src, *src_dma); + +_FAILED_ALLOC_SRC: + dma_free_coherent(dma_dev, size, *dst, *dst_dma); + + return -1; +} + +static int _dma_async_prebuf(void *src, void *dst, size_t size) +{ + memset((u8 *)src, 0xff, size); + memset((u8 *)dst, 0x00, size); + return 0; +} + +static int _dma_async_check_data(void *src, void *dst, size_t size) +{ + return memcmp(src, dst, size); +} + +static void _dma_async_release(struct dma_chan *chan) +{ + dma_release_channel(chan); +} + +static struct dma_chan *_dma_get_channel(enum dma_transaction_type tx_type) +{ + dma_cap_mask_t dma_mask; + + dma_cap_zero(dma_mask); + dma_cap_set(tx_type, dma_mask); + + return dma_request_channel(dma_mask, NULL, NULL); +} + +static struct dma_async_tx_descriptor *_dma_async_get_desc( + struct dma_chan *chan, + dma_addr_t src_dma, dma_addr_t dst_dma, + size_t size) +{ + dma_finished = 0; + return dmaengine_prep_dma_memcpy(chan, dst_dma, src_dma, size, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); +} + +static void _dma_async_do_start(struct dma_async_tx_descriptor *desc, + struct dma_chan *chan) +{ + dma_cookie_t dma_cookie = dmaengine_submit(desc); + if (dma_submit_error(dma_cookie)) + DMA_DEBUG("Failed to do DMA tx_submit\n"); + + dma_async_issue_pending(chan); + wait_event_interruptible(wq, dma_finished); +} + +int dw_dma_async_do_memcpy(void *src, void *dst, size_t size) +{ + int ret; + struct device *dma_dev; + struct dma_chan *chan; + dma_addr_t src_dma, dst_dma; + struct dma_async_tx_descriptor *desc; + + const struct iommu_ops *iommu; + u64 dma_addr = 0, dma_size = 0; + + dma_dev = kzalloc(sizeof(*dma_dev), GFP_KERNEL); + if(!dma_dev){ + dev_err(dma_dev, "kmalloc error.\n"); + return -ENOMEM; + } + + dma_dev->bus = NULL; + dma_dev->coherent_dma_mask = 0xffffffff; + + iort_dma_setup(dma_dev, &dma_addr, &dma_size); + iommu = iort_iommu_configure_id(dma_dev, NULL); + if (PTR_ERR(iommu) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + arch_setup_dma_ops(dma_dev, dst_dma, dma_size, iommu, true); + + if(_dma_async_alloc_buf(dma_dev, &src, &dst, size, &src_dma, &dst_dma)) { + dev_err(dma_dev, "Err alloc.\n"); + return -ENOMEM; + } + + DMA_DEBUG("src=%#llx, dst=%#llx\n", (u64)src, (u64)dst); + DMA_DEBUG("dma_src=%#x dma_dst=%#x\n", (u32)src_dma, (u32)dst_dma); + + _dma_async_prebuf(src, dst, size); + + chan = _dma_get_channel(DMA_MEMCPY); + if(!chan ){ + DMA_PRINTK("Err get chan.\n"); + return -EBUSY; + } + DMA_DEBUG("get chan ok.\n"); + + desc = _dma_async_get_desc(chan, src_dma, dst_dma, size); + if(!desc){ + DMA_PRINTK("Err get desc.\n"); + dma_release_channel(chan); + return -ENOMEM; + } + DMA_DEBUG("get desc ok.\n"); + + desc->callback = tx_callback; + + starfive_flush_dcache(src_dma, size); + starfive_flush_dcache(dst_dma, size); + + _dma_async_do_start(desc, chan); + _dma_async_release(chan); + + ret = _dma_async_check_data(src, dst, size); + + dma_free_coherent(dma_dev, size, src, src_dma); + dma_free_coherent(dma_dev, size, dst, dst_dma); + + return ret; +} +EXPORT_SYMBOL(dw_dma_async_do_memcpy); + +/* +* phys addr for dma. +*/ +int dw_dma_memcpy_raw(dma_addr_t src_dma, dma_addr_t dst_dma, size_t size) +{ + struct dma_chan *chan; + struct device *dma_dev; + struct dma_async_tx_descriptor *desc; + + const struct iommu_ops *iommu; + u64 dma_addr = 0, dma_size = 0; + + dma_dev = kzalloc(sizeof(*dma_dev), GFP_KERNEL); + if(!dma_dev){ + DMA_PRINTK("kmalloc error.\n"); + return -ENOMEM; + } + + dma_dev->bus = NULL; + dma_dev->coherent_dma_mask = 0xffffffff; + + iort_dma_setup(dma_dev, &dma_addr, &dma_size); + iommu = iort_iommu_configure_id(dma_dev, NULL); + if (PTR_ERR(iommu) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + arch_setup_dma_ops(dma_dev, dst_dma, dma_size, iommu, true); + + chan = _dma_get_channel(DMA_MEMCPY); + if(!chan){ + DMA_PRINTK("Error get chan.\n"); + return -EBUSY; + } + DMA_DEBUG("get chan ok.\n"); + + DMA_DEBUG("src_dma=%#llx, dst_dma=%#llx \n", src_dma, dst_dma); + desc = _dma_async_get_desc(chan, src_dma, dst_dma, size); + if(!desc){ + DMA_PRINTK("Error get desc.\n"); + dma_release_channel(chan); + return -ENOMEM; + } + DMA_DEBUG("get desc ok.\n"); + + desc->callback = tx_callback; + + starfive_flush_dcache(src_dma, size); + starfive_flush_dcache(dst_dma, size); + + _dma_async_do_start(desc, chan); + _dma_async_release(chan); + + return 0; +} +EXPORT_SYMBOL(dw_dma_memcpy_raw); + +/* +*virtl addr for cpu. +*/ +int dw_dma_memcpy(void *src, void *dst, size_t size) +{ + dma_addr_t src_dma, dst_dma; + + src_dma = dw_virt_to_phys(src); + dst_dma = dw_virt_to_phys(dst); + + dw_dma_memcpy_raw(src_dma, dst_dma, size); + return 0; +} +EXPORT_SYMBOL(dw_dma_memcpy); + +int dw_dma_mem2mem_test(void) +{ + int ret; + void *src = NULL; + void *dst = NULL; + size_t size = 256; + + ret = dw_dma_async_do_memcpy(src, dst, size); + if(ret){ + DMA_PRINTK("memcpy failed.\n"); + } else { + DMA_PRINTK("memcpy ok.\n"); + } + + return ret; +} diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c index d9e4ac3edb4ea1..fd1939eb821ec8 100644 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c @@ -32,6 +32,8 @@ #include "../dmaengine.h" #include "../virt-dma.h" +#include + /* * The set of bus widths supported by the DMA controller. DW AXI DMAC supports * master data bus width up to 512 bits (for both AXI master interfaces), but @@ -148,24 +150,43 @@ static inline u32 axi_chan_irq_read(struct axi_dma_chan *chan) return axi_chan_ioread32(chan, CH_INTSTATUS); } +static inline bool axi_chan_get_nr8(struct axi_dma_chan *chan) +{ + return chan->chip->flag->nr_chan_8; +} + static inline void axi_chan_disable(struct axi_dma_chan *chan) { u32 val; - val = axi_dma_ioread32(chan->chip, DMAC_CHEN); - val &= ~(BIT(chan->id) << DMAC_CHAN_EN_SHIFT); - val |= BIT(chan->id) << DMAC_CHAN_EN_WE_SHIFT; - axi_dma_iowrite32(chan->chip, DMAC_CHEN, val); + if(axi_chan_get_nr8(chan)) { + val = axi_dma_ioread32(chan->chip, DMAC_CHEN_8); + val &= ~(BIT(chan->id) << DMAC_CHAN_EN_SHIFT_8); + val |= BIT(chan->id) << DMAC_CHAN_EN_WE_SHIFT_8; + axi_dma_iowrite32(chan->chip, DMAC_CHEN_8, val); + } else { + val = axi_dma_ioread32(chan->chip, DMAC_CHEN); + val &= ~(BIT(chan->id) << DMAC_CHAN_EN_SHIFT); + val |= BIT(chan->id) << DMAC_CHAN_EN_WE_SHIFT; + axi_dma_iowrite32(chan->chip, DMAC_CHEN, val); + } } static inline void axi_chan_enable(struct axi_dma_chan *chan) { u32 val; - val = axi_dma_ioread32(chan->chip, DMAC_CHEN); - val |= BIT(chan->id) << DMAC_CHAN_EN_SHIFT | - BIT(chan->id) << DMAC_CHAN_EN_WE_SHIFT; - axi_dma_iowrite32(chan->chip, DMAC_CHEN, val); + if(axi_chan_get_nr8(chan)) { + val = axi_dma_ioread32(chan->chip, DMAC_CHEN_8); + val |= BIT(chan->id) << DMAC_CHAN_EN_SHIFT_8 | + BIT(chan->id) << DMAC_CHAN_EN_WE_SHIFT_8; + axi_dma_iowrite32(chan->chip, DMAC_CHEN_8, val); + } else { + val = axi_dma_ioread32(chan->chip, DMAC_CHEN); + val |= BIT(chan->id) << DMAC_CHAN_EN_SHIFT | + BIT(chan->id) << DMAC_CHAN_EN_WE_SHIFT; + axi_dma_iowrite32(chan->chip, DMAC_CHEN, val); + } } static inline bool axi_chan_is_hw_enable(struct axi_dma_chan *chan) @@ -335,6 +356,7 @@ static void dw_axi_dma_set_byte_halfword(struct axi_dma_chan *chan, bool set) static void axi_chan_block_xfer_start(struct axi_dma_chan *chan, struct axi_dma_desc *first) { + struct axi_dma_desc *desc; u32 priority = chan->chip->dw->hdata->priority[chan->id]; u32 reg, irq_mask; u8 lms = 0; /* Select AXI0 master for LLI fetching */ @@ -384,6 +406,23 @@ static void axi_chan_block_xfer_start(struct axi_dma_chan *chan, irq_mask |= DWAXIDMAC_IRQ_SUSPENDED; axi_chan_irq_set(chan, irq_mask); + /*flush all the desc */ +#ifdef CONFIG_SOC_STARFIVE_VIC7100 + if(chan->chip->flag->need_flush) { + /*flush fisrt desc*/ + starfive_flush_dcache(first->vd.tx.phys, sizeof(*first)); + + list_for_each_entry(desc, &first->xfer_list, xfer_list) { + starfive_flush_dcache(desc->vd.tx.phys, sizeof(*desc)); + + dev_dbg(chan->chip->dev, + "sar:%#llx dar:%#llx llp:%#llx ctl:0x%x:%08x\n", + desc->lli.sar, desc->lli.dar, desc->lli.llp, + desc->lli.ctl_hi, desc->lli.ctl_lo); + } + } +#endif + axi_chan_enable(chan); } @@ -1070,8 +1109,10 @@ static irqreturn_t dw_axi_dma_interrupt(int irq, void *dev_id) if (status & DWAXIDMAC_IRQ_ALL_ERR) axi_chan_handle_err(chan, status); - else if (status & DWAXIDMAC_IRQ_DMA_TRF) + else if (status & DWAXIDMAC_IRQ_DMA_TRF) { axi_chan_block_xfer_complete(chan); + dev_dbg(chip->dev, "axi_chan_block_xfer_complete.\n"); + } } /* Re-enable interrupts */ @@ -1126,10 +1167,17 @@ static int dma_chan_pause(struct dma_chan *dchan) spin_lock_irqsave(&chan->vc.lock, flags); - val = axi_dma_ioread32(chan->chip, DMAC_CHEN); - val |= BIT(chan->id) << DMAC_CHAN_SUSP_SHIFT | - BIT(chan->id) << DMAC_CHAN_SUSP_WE_SHIFT; - axi_dma_iowrite32(chan->chip, DMAC_CHEN, val); + if(axi_chan_get_nr8(chan)){ + val = axi_dma_ioread32(chan->chip, DMAC_CHSUSP_8); + val |= BIT(chan->id) << DMAC_CHAN_SUSP_SHIFT_8 | + BIT(chan->id) << DMAC_CHAN_SUSP_WE_SHIFT_8; + axi_dma_iowrite32(chan->chip, DMAC_CHSUSP_8, val); + } else { + val = axi_dma_ioread32(chan->chip, DMAC_CHSUSP); + val |= BIT(chan->id) << DMAC_CHAN_SUSP_SHIFT | + BIT(chan->id) << DMAC_CHAN_SUSP_WE_SHIFT; + axi_dma_iowrite32(chan->chip, DMAC_CHSUSP, val); + } do { if (axi_chan_irq_read(chan) & DWAXIDMAC_IRQ_SUSPENDED) @@ -1152,11 +1200,17 @@ static inline void axi_chan_resume(struct axi_dma_chan *chan) { u32 val; - val = axi_dma_ioread32(chan->chip, DMAC_CHEN); - val &= ~(BIT(chan->id) << DMAC_CHAN_SUSP_SHIFT); - val |= (BIT(chan->id) << DMAC_CHAN_SUSP_WE_SHIFT); - axi_dma_iowrite32(chan->chip, DMAC_CHEN, val); - + if(axi_chan_get_nr8(chan)){ + val = axi_dma_ioread32(chan->chip, DMAC_CHSUSP_8); + val &= ~(BIT(chan->id) << DMAC_CHAN_SUSP_SHIFT_8); + val |= (BIT(chan->id) << DMAC_CHAN_SUSP_WE_SHIFT_8); + axi_dma_iowrite32(chan->chip, DMAC_CHSUSP_8, val); + } else { + val = axi_dma_ioread32(chan->chip, DMAC_CHSUSP); + val &= ~(BIT(chan->id) << DMAC_CHAN_SUSP_SHIFT); + val |= (BIT(chan->id) << DMAC_CHAN_SUSP_WE_SHIFT); + axi_dma_iowrite32(chan->chip, DMAC_CHSUSP, val); + } chan->is_paused = false; } @@ -1248,6 +1302,13 @@ static int parse_device_properties(struct axi_dma_chip *chip) chip->dw->hdata->nr_channels = tmp; + if(chip->dw->hdata->nr_channels > 8){ + chip->flag->nr_chan_8 = true; +#ifdef CONFIG_SOC_STARFIVE_VIC7100 + chip->flag->need_flush = true; +#endif + } + ret = device_property_read_u32(dev, "snps,dma-masters", &tmp); if (ret) return ret; @@ -1309,6 +1370,7 @@ static int dw_probe(struct platform_device *pdev) struct resource *mem; struct dw_axi_dma *dw; struct dw_axi_dma_hcfg *hdata; + struct dw_dma_flag *flag; u32 i; int ret; @@ -1324,9 +1386,14 @@ static int dw_probe(struct platform_device *pdev) if (!hdata) return -ENOMEM; + flag = devm_kzalloc(&pdev->dev, sizeof(*flag), GFP_KERNEL); + if (!flag) + return -ENOMEM; + chip->dw = dw; chip->dev = &pdev->dev; chip->dw->hdata = hdata; + chip->flag = flag; chip->irq = platform_get_irq(pdev, 0); if (chip->irq < 0) diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h index b69897887c7654..0e454a926a82c8 100644 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h @@ -5,6 +5,8 @@ * Synopsys DesignWare AXI DMA Controller driver. * * Author: Eugeniy Paltsev + * Samin.guo + * add support for (channels > 8). 2020. */ #ifndef _AXI_DMA_PLATFORM_H @@ -18,10 +20,17 @@ #include "../virt-dma.h" -#define DMAC_MAX_CHANNELS 8 +#define DMAC_MAX_CHANNELS 16 #define DMAC_MAX_MASTERS 2 #define DMAC_MAX_BLK_SIZE 0x200000 +struct dw_dma_flag { + bool nr_chan_8; +#ifdef CONFIG_SOC_STARFIVE_VIC7100 + bool need_flush; +#endif +}; + struct dw_axi_dma_hcfg { u32 nr_channels; u32 nr_masters; @@ -68,6 +77,7 @@ struct axi_dma_chip { struct clk *core_clk; struct clk *cfgr_clk; struct dw_axi_dma *dw; + struct dw_dma_flag *flag; }; /* LLI == Linked List Item */ @@ -139,6 +149,15 @@ static inline struct axi_dma_chan *dchan_to_axi_dma_chan(struct dma_chan *dchan) #define DMAC_CHEN 0x018 /* R/W DMAC Channel Enable */ #define DMAC_CHEN_L 0x018 /* R/W DMAC Channel Enable 00-31 */ #define DMAC_CHEN_H 0x01C /* R/W DMAC Channel Enable 32-63 */ +#define DMAC_CHSUSP 0x018 /* R/W DMAC Channel suspend */ +#define DMAC_CHABORT 0x018 /* R/W DMAC Channel Abort */ + +#define DMAC_CHEN_8 0x018 /* R/W DMAC Channel Enable */ +#define DMAC_CHEN_L_8 0x018 /* R/W DMAC Channel Enable */ +#define DMAC_CHEN_H_8 0x01C /* R/W DMAC Channel Enable */ +#define DMAC_CHSUSP_8 0x020 /* R/W DMAC Channel Suspend */ +#define DMAC_CHABORT_8 0x028 /* R/W DMAC Channel Abort */ + #define DMAC_INTSTATUS 0x030 /* R DMAC Interrupt Status */ #define DMAC_COMMON_INTCLEAR 0x038 /* W DMAC Interrupt Clear */ #define DMAC_COMMON_INTSTATUS_ENA 0x040 /* R DMAC Interrupt Status Enable */ @@ -199,6 +218,19 @@ static inline struct axi_dma_chan *dchan_to_axi_dma_chan(struct dma_chan *dchan) #define DMAC_CHAN_SUSP_SHIFT 16 #define DMAC_CHAN_SUSP_WE_SHIFT 24 +#define DMAC_CHAN_ABORT_SHIFT 32 +#define DMAC_CHAN_ABORT_WE_SHIFT 40 + + +#define DMAC_CHAN_EN_SHIFT_8 0 +#define DMAC_CHAN_EN_WE_SHIFT_8 16 + +#define DMAC_CHAN_SUSP_SHIFT_8 0 +#define DMAC_CHAN_SUSP_WE_SHIFT_8 16 + +#define DMAC_CHAN_ABORT_SHIFT_8 0 +#define DMAC_CHAN_ABORT_WE_SHIFT_8 16 + /* CH_CTL_H */ #define CH_CTL_H_ARLEN_EN BIT(6) #define CH_CTL_H_ARLEN_POS 7 @@ -255,7 +287,7 @@ enum { #define CH_CTL_L_SRC_MAST BIT(0) /* CH_CFG_H */ -#define CH_CFG_H_PRIORITY_POS 17 +#define CH_CFG_H_PRIORITY_POS 15 #define CH_CFG_H_HS_SEL_DST_POS 4 #define CH_CFG_H_HS_SEL_SRC_POS 3 enum { From 49b49e89f519288afdc5b0476b8b4fe0ee2f0adb Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Fri, 30 Apr 2021 18:06:40 -0700 Subject: [PATCH 26/55] drivers/dma: Fix VIC7100 dw-axi-dmac-platform driver addition Descriptor management was simplified with commit: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=ef6fb2d6f1abd56cc067c694253ea362159b5ac3 Code added to dw-axi-dmac-platform driver due to VIC7100 Cache Coherency issues needed follow those changes. Signed-off-by: Michael Scott --- .../dma/dw-axi-dmac/dw-axi-dmac-platform.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c index fd1939eb821ec8..76a6585088463d 100644 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c @@ -356,7 +356,6 @@ static void dw_axi_dma_set_byte_halfword(struct axi_dma_chan *chan, bool set) static void axi_chan_block_xfer_start(struct axi_dma_chan *chan, struct axi_dma_desc *first) { - struct axi_dma_desc *desc; u32 priority = chan->chip->dw->hdata->priority[chan->id]; u32 reg, irq_mask; u8 lms = 0; /* Select AXI0 master for LLI fetching */ @@ -406,19 +405,23 @@ static void axi_chan_block_xfer_start(struct axi_dma_chan *chan, irq_mask |= DWAXIDMAC_IRQ_SUSPENDED; axi_chan_irq_set(chan, irq_mask); - /*flush all the desc */ + /* flush all the desc */ #ifdef CONFIG_SOC_STARFIVE_VIC7100 if(chan->chip->flag->need_flush) { - /*flush fisrt desc*/ - starfive_flush_dcache(first->vd.tx.phys, sizeof(*first)); + int count = atomic_read(&chan->descs_allocated); + int i; - list_for_each_entry(desc, &first->xfer_list, xfer_list) { - starfive_flush_dcache(desc->vd.tx.phys, sizeof(*desc)); + for (i = 0; i < count; i++) { + starfive_flush_dcache(first->hw_desc[i].llp, + sizeof(*first->hw_desc[i].lli)); dev_dbg(chan->chip->dev, "sar:%#llx dar:%#llx llp:%#llx ctl:0x%x:%08x\n", - desc->lli.sar, desc->lli.dar, desc->lli.llp, - desc->lli.ctl_hi, desc->lli.ctl_lo); + first->hw_desc[i].lli->sar, + first->hw_desc[i].lli->dar, + first->hw_desc[i].lli->llp, + first->hw_desc[i].lli->ctl_hi, + first->hw_desc[i].lli->ctl_lo); } } #endif From a9a34f7a8cf43da103d8c79684e402c086f279e4 Mon Sep 17 00:00:00 2001 From: Tom Date: Fri, 8 Jan 2021 03:25:24 +0800 Subject: [PATCH 27/55] drivers/i2c: Improve Synopsys DesignWare I2C adapter driver for StarFive VIC7100 --- drivers/i2c/busses/i2c-designware-platdrv.c | 27 +++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 4b37f28ec0c6c1..904694a19e5124 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -39,6 +39,21 @@ static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev) return clk_get_rate(dev->clk)/1000; } +#ifdef CONFIG_SOC_STARFIVE_VIC7100 +static u32 starfive_i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev) +{ + u32 val; + + if(!device_property_read_u32(dev->dev, "clocks", &val)) { + dev_info(dev->dev, "Using 'clocks' : %u / 1000", val); + return (val / 1000); + } else { + dev_info(dev->dev, "Using the static setting value: 49500"); + return 49500; + } +} +#endif + #ifdef CONFIG_ACPI static const struct acpi_device_id dw_i2c_acpi_match[] = { { "INT33C2", 0 }, @@ -271,6 +286,18 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) if (!dev->sda_hold_time && t->sda_hold_ns) dev->sda_hold_time = div_u64(clk_khz * t->sda_hold_ns + 500000, 1000000); +#ifdef CONFIG_SOC_STARFIVE_VIC7100 + } else { + u64 clk_khz; + + dev->get_clk_rate_khz = starfive_i2c_dw_get_clk_rate_khz; + clk_khz = dev->get_clk_rate_khz(dev); + + if (!dev->sda_hold_time && t->sda_hold_ns) + dev->sda_hold_time = + div_u64(clk_khz * t->sda_hold_ns + 500000, + 1000000); +#endif } adap = &dev->adapter; From e726d0a6852f2e78d0aee5dad82a4709ad37391f Mon Sep 17 00:00:00 2001 From: Tom Date: Sat, 13 Mar 2021 15:22:38 +0800 Subject: [PATCH 28/55] drivers/i2c: Add GPIO configuration for VIC7100. [FIXME] why we can not do it in U-boot? [geert: Rebase to v5.13-rc1] --- drivers/i2c/busses/i2c-designware-core.h | 2 + drivers/i2c/busses/i2c-designware-master.c | 44 +++++++++++++++++++++ drivers/i2c/busses/i2c-designware-platdrv.c | 4 ++ 3 files changed, 50 insertions(+) diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 6a53f75abf7c79..c8e2c59bc29d50 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -286,6 +286,8 @@ struct dw_i2c_dev { int (*init)(struct dw_i2c_dev *dev); int (*set_sda_hold_time)(struct dw_i2c_dev *dev); int mode; + int scl_gpio; + int sda_gpio; struct i2c_bus_recovery_info rinfo; bool suspended; }; diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index 9b08bb5df38d29..85d2cddfcdf6c8 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "i2c-designware-core.h" @@ -164,6 +165,48 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) return 0; } +static void i2c_dw_configure_gpio(struct dw_i2c_dev *dev) +{ +#ifdef CONFIG_SOC_STARFIVE_VIC7100_I2C_GPIO + if((dev->scl_gpio > 0) && (dev->sda_gpio > 0)) { + SET_GPIO_dout_LOW(dev->scl_gpio); + SET_GPIO_dout_LOW(dev->sda_gpio); + SET_GPIO_doen_reverse_(dev->scl_gpio,1); + SET_GPIO_doen_reverse_(dev->sda_gpio,1); + switch(dev->adapter.nr) { + case 0: + SET_GPIO_doen_i2c0_pad_sck_oe(dev->scl_gpio); + SET_GPIO_doen_i2c0_pad_sda_oe(dev->sda_gpio); + SET_GPIO_i2c0_pad_sck_in(dev->scl_gpio); + SET_GPIO_i2c0_pad_sda_in(dev->sda_gpio); + break; + case 1: + SET_GPIO_doen_i2c1_pad_sck_oe(dev->scl_gpio); + SET_GPIO_doen_i2c1_pad_sda_oe(dev->sda_gpio); + SET_GPIO_i2c1_pad_sck_in(dev->scl_gpio); + SET_GPIO_i2c1_pad_sda_in(dev->sda_gpio); + break; + case 2: + SET_GPIO_doen_i2c2_pad_sck_oe(dev->scl_gpio); + SET_GPIO_doen_i2c2_pad_sda_oe(dev->sda_gpio); + SET_GPIO_i2c2_pad_sck_in(dev->scl_gpio); + SET_GPIO_i2c2_pad_sda_in(dev->sda_gpio); + break; + case 3: + SET_GPIO_doen_i2c3_pad_sck_oe(dev->scl_gpio); + SET_GPIO_doen_i2c3_pad_sda_oe(dev->sda_gpio); + SET_GPIO_i2c3_pad_sck_in(dev->scl_gpio); + SET_GPIO_i2c3_pad_sda_in(dev->sda_gpio); + break; + default: + dev_err(dev->dev, "i2c adapter number is invalid\n"); + } + } else + dev_err(dev->dev, "scl/sda gpio number is invalid !\n"); +#endif + return; +} + /** * i2c_dw_init_master() - Initialize the designware I2C master hardware * @dev: device private data @@ -927,6 +970,7 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev) dev_err(dev->dev, "failure adding adapter: %d\n", ret); pm_runtime_put_noidle(dev->dev); + i2c_dw_configure_gpio(dev); return ret; } EXPORT_SYMBOL_GPL(i2c_dw_probe_master); diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 904694a19e5124..d6ecae1f94f8c5 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -220,6 +221,7 @@ static const struct dmi_system_id dw_i2c_hwmon_class_dmi[] = { static int dw_i2c_plat_probe(struct platform_device *pdev) { + struct device_node *np = pdev->dev.of_node; struct i2c_adapter *adap; struct dw_i2c_dev *dev; struct i2c_timings *t; @@ -236,6 +238,8 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) dev->flags = (uintptr_t)device_get_match_data(&pdev->dev); dev->dev = &pdev->dev; dev->irq = irq; + dev->scl_gpio = of_get_named_gpio(np, "scl-gpio", 0); + dev->sda_gpio = of_get_named_gpio(np, "sda-gpio", 0); platform_set_drvdata(pdev, dev); ret = dw_i2c_plat_request_regs(dev); From b74ce040aca8dc6b476594e55a8eeef9d6cf0f41 Mon Sep 17 00:00:00 2001 From: Tom Date: Tue, 6 Apr 2021 13:30:26 +0800 Subject: [PATCH 29/55] net: stmmac: Configure gtxclk based on speed --- .../ethernet/stmicro/stmmac/dwmac-generic.c | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c index fbfda55b4c5263..8b6b1bfad35e64 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c @@ -16,6 +16,50 @@ #include "stmmac.h" #include "stmmac_platform.h" +/* + * GMAC_GTXCLK 为 gmac 的时钟分频寄存器,低8位为分频值 + * bit name access default descript + * [31] clk_gmac_gtxclk enable RW 0x0 "1:enable; 0:disable" + * [30] reserved - 0x0 reserved + * [29:8] reserved - 0x0 reserved + * [7:0] clk_gmac_gtxclk divide ratio RW 0x4 divide value + * + * gmac 的 root 时钟为500M, gtxclk 需求的时钟如下: + * 1000M: gtxclk为125M,分频值为500/125 = 0x4 + * 100M: gtxclk为25M, 分频值为500/25 = 0x14 + * 10M: gtxclk为2.5M,分频值为500/2.5 = 0xc8 + */ +#ifdef CONFIG_SOC_STARFIVE_VIC7100 +#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(void *priv, unsigned int speed) +{ + u32 value; + void *addr = ioremap(CLKGEN_GMAC_GTXCLK_ADDR, sizeof(value)); + if (!addr) { + pr_err("%s can't remap CLKGEN_GMAC_GTXCLK_ADDR\n", __func__); + return; + } + + 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: iounmap(addr); return; + } + writel(value, addr); /*set gmac gtxclk*/ + iounmap(addr); +} +#endif + static int dwmac_generic_probe(struct platform_device *pdev) { struct plat_stmmacenet_data *plat_dat; @@ -52,6 +96,9 @@ static int dwmac_generic_probe(struct platform_device *pdev) if (ret) goto err_remove_config_dt; } +#ifdef CONFIG_SOC_STARFIVE_VIC7100 + plat_dat->fix_mac_speed = dwmac_fixed_speed; +#endif ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); if (ret) From d250145b06045040de555514709db546b289e7ac Mon Sep 17 00:00:00 2001 From: Matteo Croce Date: Fri, 21 May 2021 03:26:38 +0200 Subject: [PATCH 30/55] net: stmmac: use GFP_DMA32 Signed-off-by: Matteo Croce --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 91cd5073ddb261..025d339c81c005 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1431,14 +1431,16 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p, struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i]; if (!buf->page) { - buf->page = page_pool_dev_alloc_pages(rx_q->page_pool); + buf->page = page_pool_alloc_pages(rx_q->page_pool, + GFP_ATOMIC | __GFP_NOWARN | GFP_DMA32); if (!buf->page) return -ENOMEM; buf->page_offset = stmmac_rx_offset(priv); } if (priv->sph && !buf->sec_page) { - buf->sec_page = page_pool_dev_alloc_pages(rx_q->page_pool); + buf->sec_page = page_pool_alloc_pages(rx_q->page_pool, + GFP_ATOMIC | __GFP_NOWARN | GFP_DMA32); if (!buf->sec_page) return -ENOMEM; @@ -4452,13 +4454,15 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue) p = rx_q->dma_rx + entry; if (!buf->page) { - buf->page = page_pool_dev_alloc_pages(rx_q->page_pool); + buf->page = page_pool_alloc_pages(rx_q->page_pool, + GFP_ATOMIC | __GFP_NOWARN | GFP_DMA32); if (!buf->page) break; } if (priv->sph && !buf->sec_page) { - buf->sec_page = page_pool_dev_alloc_pages(rx_q->page_pool); + buf->sec_page = page_pool_alloc_pages(rx_q->page_pool, + GFP_ATOMIC | __GFP_NOWARN | GFP_DMA32); if (!buf->sec_page) break; From 8c98fff709612532c26f996091302151d778a59d Mon Sep 17 00:00:00 2001 From: Tom Date: Fri, 8 Jan 2021 02:59:40 +0800 Subject: [PATCH 31/55] riscv/starfive: Add VIC7100 support --- arch/riscv/Kconfig.socs | 50 ++++++++++++++++++++++++++++++++++ include/soc/starfive/vic7100.h | 36 ++++++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 include/soc/starfive/vic7100.h diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs index 30676ebb16ebd7..1a87b14e25fd7f 100644 --- a/arch/riscv/Kconfig.socs +++ b/arch/riscv/Kconfig.socs @@ -19,6 +19,56 @@ config SOC_SIFIVE help This enables support for SiFive SoC platform hardware. +config SOC_STARFIVE_VIC7100 + bool "StarFive VIC7100 SoC" + select SOC_SIFIVE + select OF_RESERVED_MEM + select SIFIVE_L2 + select SIFIVE_L2_FLUSH + select DW_AXI_DMAC_STARFIVE + select GPIO_STARFIVE_VIC + select HW_RANDOM_STARFIVE_VIC + help + This enables support for StarFive VIC7100 SoC Platform Hardware. + +menu "StarFive VIC7100 SoC Debug Option" + depends on SOC_STARFIVE_VIC7100 + +config FPGA_GMAC_FLUSH_DDR + bool "VIC7100 SOC GMAC description and packet buffer flush" + depends on SOC_STARFIVE_VIC7100 + depends on STMMAC_ETH + default y if SOC_STARFIVE_VIC7100 + help + enable VIC7100 GMAC description and packet buffer flush + +config MMC_DW_FLUSH_DDR + bool "VIC7100 SOC DW MMC buffer flush" + depends on SOC_STARFIVE_VIC7100 + depends on MMC_DW + default y if SOC_STARFIVE_VIC7100 + help + enable VIC7100 DW MMC description and data buffer flush + +config USB_CDNS3_HOST_FLUSH_DMA + bool "Cadence USB3 host controller flush dma memery" + depends on USB + depends on USB_CDNS3 + depends on SOC_STARFIVE_VIC7100 + default y if SOC_STARFIVE_VIC7100 + help + enable VIC7100 DW USB CDNS3 driver data buffer flush + +config SOC_STARFIVE_VIC7100_I2C_GPIO + bool "VIC7100 SOC I2C GPIO init" + depends on I2C_DESIGNWARE_CORE + depends on SOC_STARFIVE_VIC7100 + default y if SOC_STARFIVE_VIC7100 + help + enable VIC7100 DW I2C GPIO init in Synopsys DesignWare master driver + +endmenu + config SOC_VIRT bool "QEMU Virt Machine" select CLINT_TIMER if RISCV_M_MODE diff --git a/include/soc/starfive/vic7100.h b/include/soc/starfive/vic7100.h new file mode 100644 index 00000000000000..a850f4cd11bf75 --- /dev/null +++ b/include/soc/starfive/vic7100.h @@ -0,0 +1,36 @@ +#ifndef STARFIVE_VIC7100_H +#define STARFIVE_VIC7100_H +#include +#include + +/*cache.c*/ +#define starfive_flush_dcache(start, len) \ + sifive_l2_flush64_range(start, len) + +/*dma*/ +#define CONFIG_DW_DEBUG + +#define DMA_PRINTK(fmt,...) \ + printk("[DW_DMA] %s():%d \n" fmt, __func__, __LINE__, ##__VA_ARGS__) + +#ifdef CONFIG_DW_DEBUG +#define DMA_DEBUG(fmt,...) \ + printk("[DW_DMA_DEBUG] %s():%d \n" fmt, __func__, __LINE__, ##__VA_ARGS__) +#else +#define DMA_BEBUG(fmt,...) +#endif + +#define _dw_virt_to_phys(vaddr) (pfn_to_phys(virt_to_pfn(vaddr))) +#define _dw_phys_to_virt(paddr) (page_to_virt(phys_to_page(paddr))) + +void *dw_phys_to_virt(u64 phys); +u64 dw_virt_to_phys(void *vaddr); + +int dw_dma_async_do_memcpy(void *src, void *dst, size_t size); +int dw_dma_memcpy_raw(dma_addr_t src_dma, dma_addr_t dst_dma, size_t size); +int dw_dma_memcpy(void *src, void *dst, size_t size); + +int dw_dma_mem2mem_arry(void); +int dw_dma_mem2mem_test(void); + +#endif /*STARFIVE_VIC7100_H*/ \ No newline at end of file From b31094cc0ab16848b56fe413eeb36054473329ff Mon Sep 17 00:00:00 2001 From: "jack.zhu" Date: Mon, 11 Jan 2021 04:06:22 +0800 Subject: [PATCH 32/55] drivers/video/fbdev and drivers/media/platform: starfive drivers added 1, add ov5640&sc2235 drivers, update stf_isp 2, add MIPI/CSI/DSI drivers for VIC7100 --- drivers/media/platform/Kconfig | 1 + drivers/media/platform/Makefile | 2 + drivers/media/platform/starfive/Kconfig | 32 + drivers/media/platform/starfive/Makefile | 10 + drivers/media/platform/starfive/imx219_mipi.c | 424 +++ drivers/media/platform/starfive/ov5640_dvp.c | 455 ++++ drivers/media/platform/starfive/sc2235.c | 423 +++ drivers/media/platform/starfive/stf_csi.c | 210 ++ drivers/media/platform/starfive/stf_csi.h | 135 + drivers/media/platform/starfive/stf_event.c | 39 + drivers/media/platform/starfive/stf_isp.c | 441 ++++ drivers/media/platform/starfive/stf_isp.h | 16 + drivers/media/platform/starfive/stf_vin.c | 935 +++++++ drivers/video/fbdev/Kconfig | 10 + drivers/video/fbdev/Makefile | 1 + drivers/video/fbdev/starfive/Kconfig | 35 + drivers/video/fbdev/starfive/Makefile | 11 + drivers/video/fbdev/starfive/adv7513.c | 267 ++ drivers/video/fbdev/starfive/adv7513.h | 22 + drivers/video/fbdev/starfive/seeed5inch.c | 241 ++ .../video/fbdev/starfive/starfive_comm_regs.h | 93 + .../fbdev/starfive/starfive_display_dev.c | 135 + .../fbdev/starfive/starfive_display_dev.h | 274 ++ .../video/fbdev/starfive/starfive_displayer.c | 912 +++++++ drivers/video/fbdev/starfive/starfive_fb.c | 1245 +++++++++ drivers/video/fbdev/starfive/starfive_fb.h | 138 + drivers/video/fbdev/starfive/starfive_lcdc.c | 364 +++ drivers/video/fbdev/starfive/starfive_lcdc.h | 152 ++ .../video/fbdev/starfive/starfive_mipi_tx.c | 665 +++++ .../video/fbdev/starfive/starfive_mipi_tx.h | 203 ++ drivers/video/fbdev/starfive/starfive_vpp.c | 588 +++++ drivers/video/fbdev/starfive/starfive_vpp.h | 194 ++ drivers/video/fbdev/starfive/tda998x.c | 2279 +++++++++++++++++ include/dt-bindings/starfive_fb.h | 47 + include/video/stf-vin.h | 307 +++ 35 files changed, 11306 insertions(+) create mode 100644 drivers/media/platform/starfive/Kconfig create mode 100644 drivers/media/platform/starfive/Makefile create mode 100644 drivers/media/platform/starfive/imx219_mipi.c create mode 100644 drivers/media/platform/starfive/ov5640_dvp.c create mode 100644 drivers/media/platform/starfive/sc2235.c create mode 100644 drivers/media/platform/starfive/stf_csi.c create mode 100644 drivers/media/platform/starfive/stf_csi.h create mode 100644 drivers/media/platform/starfive/stf_event.c create mode 100644 drivers/media/platform/starfive/stf_isp.c create mode 100644 drivers/media/platform/starfive/stf_isp.h create mode 100644 drivers/media/platform/starfive/stf_vin.c create mode 100644 drivers/video/fbdev/starfive/Kconfig create mode 100644 drivers/video/fbdev/starfive/Makefile create mode 100644 drivers/video/fbdev/starfive/adv7513.c create mode 100644 drivers/video/fbdev/starfive/adv7513.h create mode 100644 drivers/video/fbdev/starfive/seeed5inch.c create mode 100644 drivers/video/fbdev/starfive/starfive_comm_regs.h create mode 100644 drivers/video/fbdev/starfive/starfive_display_dev.c create mode 100644 drivers/video/fbdev/starfive/starfive_display_dev.h create mode 100644 drivers/video/fbdev/starfive/starfive_displayer.c create mode 100644 drivers/video/fbdev/starfive/starfive_fb.c create mode 100644 drivers/video/fbdev/starfive/starfive_fb.h create mode 100644 drivers/video/fbdev/starfive/starfive_lcdc.c create mode 100644 drivers/video/fbdev/starfive/starfive_lcdc.h create mode 100644 drivers/video/fbdev/starfive/starfive_mipi_tx.c create mode 100644 drivers/video/fbdev/starfive/starfive_mipi_tx.h create mode 100644 drivers/video/fbdev/starfive/starfive_vpp.c create mode 100644 drivers/video/fbdev/starfive/starfive_vpp.h create mode 100644 drivers/video/fbdev/starfive/tda998x.c create mode 100644 include/dt-bindings/starfive_fb.h create mode 100644 include/video/stf-vin.h diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 157c924686e4b6..3cd87484d8abd1 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -171,6 +171,7 @@ source "drivers/media/platform/xilinx/Kconfig" source "drivers/media/platform/rcar-vin/Kconfig" source "drivers/media/platform/atmel/Kconfig" source "drivers/media/platform/sunxi/Kconfig" +source "drivers/media/platform/starfive/Kconfig" config VIDEO_TI_CAL tristate "TI CAL (Camera Adaptation Layer) driver" diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index eedc14aafb32c2..23141e53e53ef8 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -43,6 +43,8 @@ obj-$(CONFIG_VIDEO_STI_DELTA) += sti/delta/ obj-y += stm32/ +obj-y += starfive/ + obj-y += davinci/ obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o diff --git a/drivers/media/platform/starfive/Kconfig b/drivers/media/platform/starfive/Kconfig new file mode 100644 index 00000000000000..a79d7e1802d85d --- /dev/null +++ b/drivers/media/platform/starfive/Kconfig @@ -0,0 +1,32 @@ +# +# VIN sensor driver configuration +# +config VIDEO_STARFIVE_VIN + bool "starfive VIC video input support" + depends on OF + help + To compile this driver as a module, choose M here: the module + will be called stf-vin. + +choice + prompt "Image Sensor for VIC board" + default VIDEO_STARFIVE_VIN_SENSOR_IMX219 + depends on VIDEO_STARFIVE_VIN + optional + +config VIDEO_STARFIVE_VIN_SENSOR_OV5640 + bool "OmniVision OV5640 5mp MIPI Camera Module" + help + Say Y here if you want to have support for VIN sensor OV5640 + +config VIDEO_STARFIVE_VIN_SENSOR_IMX219 + bool "Sony IMX219 CMOS Image Sensor" + help + Say Y here if you want to have support for VIN sensor IMX219 + +config VIDEO_STARFIVE_VIN_SENSOR_SC2235 + bool "SmartSens Technology SC2235 CMOS Image Sensor" + help + Say Y here if you want to have support for VIN sensor SC2235 + +endchoice diff --git a/drivers/media/platform/starfive/Makefile b/drivers/media/platform/starfive/Makefile new file mode 100644 index 00000000000000..4585213935e653 --- /dev/null +++ b/drivers/media/platform/starfive/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for RTC class/drivers. +# + +obj-$(CONFIG_VIDEO_STARFIVE_VIN_SENSOR_OV5640) += ov5640_dvp.o +obj-$(CONFIG_VIDEO_STARFIVE_VIN_SENSOR_SC2235) += sc2235.o +obj-$(CONFIG_VIDEO_STARFIVE_VIN_SENSOR_IMX219) += imx219_mipi.o +obj-$(CONFIG_VIDEO_STARFIVE_VIN) += video_stf_vin.o +video_stf_vin-objs += stf_vin.o stf_event.o stf_isp.o stf_csi.o diff --git a/drivers/media/platform/starfive/imx219_mipi.c b/drivers/media/platform/starfive/imx219_mipi.c new file mode 100644 index 00000000000000..a99e83f0a17a32 --- /dev/null +++ b/drivers/media/platform/starfive/imx219_mipi.c @@ -0,0 +1,424 @@ +/* + * Copyright (C) 2011-2013 StarFive Technology Co., Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include