[board]:Init board config for JH7110
authoryanhong.wang <yanhong.wang@starfivetech.com>
Thu, 18 Nov 2021 06:06:27 +0000 (14:06 +0800)
committeryanhong.wang <yanhong.wang@starfivetech.com>
Thu, 18 Nov 2021 06:06:27 +0000 (14:06 +0800)
20 files changed:
arch/riscv/Kconfig.socs
arch/riscv/boot/dts/Makefile
arch/riscv/boot/dts/starfive/Makefile [new file with mode: 0644]
arch/riscv/boot/dts/starfive/starfive_jh7110.dts [new file with mode: 0644]
arch/riscv/boot/dts/starfive/starfive_jh7110_audio.dtsi [new file with mode: 0644]
arch/riscv/boot/dts/starfive/starfive_jh7110_clk.dtsi [new file with mode: 0644]
arch/riscv/configs/starfive_jh7110_defconfig [new file with mode: 0644]
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-starfive-jh7110.c [new file with mode: 0644]
drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c
drivers/net/ethernet/stmicro/stmmac/hwif.c
drivers/net/phy/marvell.c
drivers/net/phy/micrel.c
drivers/net/phy/phy_device.c
drivers/soc/sifive/Kconfig
drivers/soc/sifive/sifive_l2_cache.c
include/soc/sifive/sifive_l2_cache.h
include/soc/starfive/vic7100.h [new file with mode: 0644]
usr/gen_initramfs_list.sh [new file with mode: 0755]

index 30676eb..31428dc 100644 (file)
@@ -19,6 +19,82 @@ config SOC_SIFIVE
        help
          This enables support for SiFive SoC platform hardware.
 
+config SOC_STARFIVE
+       bool "StarFive Socs"
+       select SOC_SIFIVE
+       select OF_RESERVED_MEM
+       select SIFIVE_L2
+       select SIFIVE_L2_FLUSH
+       select DW_AXI_DMAC_STARFIVE
+       help
+         StarFive JH SOC platform
+
+choice
+       prompt "StarFive JH SOCs"
+       help
+         choice StarFive JH SOC platform
+
+       config SOC_STARFIVE_VIC7100
+               bool "VIC7100"
+               select HW_RANDOM_STARFIVE_VIC
+               depends on SOC_STARFIVE
+               help
+                 This enables support for StarFive VIC7100 SoC Platform Hardware.
+
+       config SOC_STARFIVE_JH7110
+               bool "JH7110"
+               select HW_RANDOM_STARFIVE_TRNG
+               depends on SOC_STARFIVE
+               help
+                 This enables support for StarFive JH7110 SoC Platform Hardware.
+endchoice
+
+menu "StarFive JH SoC Debug Option"
+       depends on SOC_STARFIVE
+
+choice
+       prompt "JH SOC GMAC Speed"
+       depends on SOC_STARFIVE
+       default FPGA_GMAC_SPEED_AUTO
+       help
+         choice VIC7100 GMAC speed.
+         (GMAC only works well on 10M/duple, for FPGA board.)
+
+       config FPGA_GMAC_SPEED10
+               bool "GMAC works on 10M mode"
+       config FPGA_GMAC_SPEED100
+               bool "GMAC works on 100M mode"
+       config FPGA_GMAC_SPEED_AUTO
+               bool "GMAC works on auto mode"
+endchoice
+
+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
+
+endmenu
+
 config SOC_VIRT
        bool "QEMU Virt Machine"
        select CLINT_TIMER if RISCV_M_MODE
index fe996b8..5c9fcae 100644 (file)
@@ -2,5 +2,6 @@
 subdir-y += sifive
 subdir-$(CONFIG_SOC_CANAAN_K210_DTB_BUILTIN) += canaan
 subdir-y += microchip
+subdir-y += starfive
 
 obj-$(CONFIG_BUILTIN_DTB) := $(addsuffix /, $(subdir-y))
diff --git a/arch/riscv/boot/dts/starfive/Makefile b/arch/riscv/boot/dts/starfive/Makefile
new file mode 100644 (file)
index 0000000..1024655
--- /dev/null
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+dtb-$(CONFIG_SOC_STARFIVE_JH7110) += starfive_jh7110.dtb
diff --git a/arch/riscv/boot/dts/starfive/starfive_jh7110.dts b/arch/riscv/boot/dts/starfive/starfive_jh7110.dts
new file mode 100644 (file)
index 0000000..21a9ce7
--- /dev/null
@@ -0,0 +1,432 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/dts-v1/;
+#include "starfive_jh7110_clk.dtsi"
+
+/ {
+       #address-cells = <2>;
+       #size-cells = <2>;
+       compatible = "sifive,freedom-u74-arty";
+       model = "sifive,freedom-u74-arty";
+
+       chosen {
+                       linux,initrd-start = <0x0 0x46100000>;
+                       linux,initrd-end = <0x0 0x4c000000>;
+                       stdout-path = "/soc/serial@10000000:115200";
+                       #bootargs = "debug console=ttyS0 rootwait";
+       };
+       aliases {
+               spi0="/soc/spi@13010000";
+               gpio0="/soc/gpio@13040000";
+               ethernet0="/soc/gmac0@16030000";
+               mmc0="/soc/sdio0@16010000";
+               mmc1="/soc/sdio1@16020000";
+       };
+       cpus: cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               timebase-frequency = <2000000>;
+               compatible = "starfive,fu74-g000";
+               cpu@0 {
+                       clock-frequency = <0>;
+                       compatible = "starfive,rocket0", "riscv";
+                       d-cache-block-size = <64>;
+                       d-cache-sets = <64>;
+                       d-cache-size = <32768>;
+                       d-tlb-sets = <1>;
+                       d-tlb-size = <40>;
+                       device_type = "cpu";
+                       i-cache-block-size = <64>;
+                       i-cache-sets = <64>;
+                       i-cache-size = <32768>;
+                       i-tlb-sets = <1>;
+                       i-tlb-size = <40>;
+                       mmu-type = "riscv,sv39";
+                       next-level-cache = <&cachectrl>;
+                       reg = <0>;
+                       riscv,isa = "rv64imac";
+                       status = "disabled";
+                       tlb-split;
+                       cpu0intctrl: interrupt-controller {
+                               #interrupt-cells = <1>;
+                               compatible = "riscv,cpu-intc";
+                               interrupt-controller;
+                       };
+               };
+               cpu@1 {
+                       clock-frequency = <0>;
+                       compatible = "starfive,rocket0", "riscv";
+                       d-cache-block-size = <64>;
+                       d-cache-sets = <64>;
+                       d-cache-size = <32768>;
+                       d-tlb-sets = <1>;
+                       d-tlb-size = <40>;
+                       device_type = "cpu";
+                       i-cache-block-size = <64>;
+                       i-cache-sets = <64>;
+                       i-cache-size = <32768>;
+                       i-tlb-sets = <1>;
+                       i-tlb-size = <40>;
+                       mmu-type = "riscv,sv39";
+                       next-level-cache = <&cachectrl>;
+                       reg = <1>;
+                       riscv,isa = "rv64imafdc";
+                       status = "okay";
+                       tlb-split;
+                       cpu1intctrl: interrupt-controller {
+                               #interrupt-cells = <1>;
+                               compatible = "riscv,cpu-intc";
+                               interrupt-controller;
+                       };
+               };
+               cpu@2 {
+                       clock-frequency = <0>;
+                       compatible = "starfive,rocket0", "riscv";
+                       d-cache-block-size = <64>;
+                       d-cache-sets = <64>;
+                       d-cache-size = <32768>;
+                       d-tlb-sets = <1>;
+                       d-tlb-size = <40>;
+                       device_type = "cpu";
+                       i-cache-block-size = <64>;
+                       i-cache-sets = <64>;
+                       i-cache-size = <32768>;
+                       i-tlb-sets = <1>;
+                       i-tlb-size = <40>;
+                       mmu-type = "riscv,sv39";
+                       next-level-cache = <&cachectrl>;
+                       reg = <2>;
+                       riscv,isa = "rv64imafdc";
+                       status = "okay";
+                       tlb-split;
+                       cpu2intctrl: interrupt-controller {
+                               #interrupt-cells = <1>;
+                               compatible = "riscv,cpu-intc";
+                               interrupt-controller;
+                       };
+               };
+               cpu@3 {
+                       clock-frequency = <0>;
+                       compatible = "starfive,rocket0", "riscv";
+                       d-cache-block-size = <64>;
+                       d-cache-sets = <64>;
+                       d-cache-size = <32768>;
+                       d-tlb-sets = <1>;
+                       d-tlb-size = <40>;
+                       device_type = "cpu";
+                       i-cache-block-size = <64>;
+                       i-cache-sets = <64>;
+                       i-cache-size = <32768>;
+                       i-tlb-sets = <1>;
+                       i-tlb-size = <40>;
+                       mmu-type = "riscv,sv39";
+                       next-level-cache = <&cachectrl>;
+                       reg = <3>;
+                       riscv,isa = "rv64imafdc";
+                       status = "okay";
+                       tlb-split;
+                       cpu3intctrl: interrupt-controller {
+                               #interrupt-cells = <1>;
+                               compatible = "riscv,cpu-intc";
+                               interrupt-controller;
+                       };
+               };
+               cpu@4 {
+                       clock-frequency = <0>;
+                       compatible = "starfive,rocket0", "riscv";
+                       d-cache-block-size = <64>;
+                       d-cache-sets = <64>;
+                       d-cache-size = <32768>;
+                       d-tlb-sets = <1>;
+                       d-tlb-size = <40>;
+                       device_type = "cpu";
+                       i-cache-block-size = <64>;
+                       i-cache-sets = <64>;
+                       i-cache-size = <32768>;
+                       i-tlb-sets = <1>;
+                       i-tlb-size = <40>;
+                       mmu-type = "riscv,sv39";
+                       next-level-cache = <&cachectrl>;
+                       reg = <4>;
+                       riscv,isa = "rv64imafdc";
+                       status = "okay";
+                       tlb-split;
+                       cpu4intctrl: interrupt-controller {
+                               #interrupt-cells = <1>;
+                               compatible = "riscv,cpu-intc";
+                               interrupt-controller;
+                       };
+               };
+       };
+       memory@80000000 {
+               device_type = "memory";
+               reg = <0x0 0x40000000 0x1 0x0>;
+       };
+       reserved-memory {
+                #address-cells = <2>;
+                #size-cells = <2>;
+                ranges;
+
+                linux,cma {
+                        compatible = "shared-dma-pool";
+                        reusable;
+                        size = <0x0 0x20000000>;
+                        alignment = <0x0 0x1000>;
+                        alloc-ranges = <0x0 0xa0000000 0x0 0x20000000>;
+                        linux,cma-default;
+                };
+        };
+
+       soc: soc {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               #clock-cells = <1>;
+               compatible = "starfive,freedom-u74-arty", "simple-bus", "arm,amba-bus";
+               ranges;
+
+               cachectrl: cache-controller@2010000 {
+                       cache-block-size = <64>;
+                       cache-level = <2>;
+                       cache-sets = <2048>;
+                       cache-size = <2097152>;
+                       cache-unified;
+                       compatible = "sifive,fu540-c000-ccache", "starfive,ccache0", "cache";
+                       interrupt-parent = <&plic>;
+                       interrupts = <1 3 4 2>;
+                       /*next-level-cache = <&L40 &L36>;*/
+                       reg = <0x0 0x2010000 0x0 0x4000 0x0 0x8000000 0x0 0x2000000>;
+                       reg-names = "control", "sideband";
+               };
+               clint: clint@2000000 {
+                       #interrupt-cells = <1>;
+                       compatible = "riscv,clint0";
+                       /*interrupts-extended = <&cpu0intctrl 3 &cpu0intctrl 7 &cpu1intctrl 3 &cpu1intctrl 7 >;*/
+                       interrupts-extended = <&cpu0intctrl 3 &cpu0intctrl 7 &cpu1intctrl 3 &cpu1intctrl 7 &cpu2intctrl 3 &cpu2intctrl 7 &cpu3intctrl 3 &cpu3intctrl 7 &cpu4intctrl 3 &cpu4intctrl 7>;
+                       reg = <0x0 0x2000000 0x0 0x10000>;
+                       reg-names = "control";
+               };
+               plic: plic@c000000 {
+                       #interrupt-cells = <1>;
+                       compatible = "riscv,plic0";
+                       interrupt-controller;
+                       /*interrupts-extended = <&cpu0intctrl 11 &cpu0intctrl 9 &cpu1intctrl 11 &cpu1intctrl 9 >;*/
+                       interrupts-extended = <&cpu0intctrl 11 &cpu1intctrl 11 &cpu1intctrl 9 &cpu2intctrl 11 &cpu2intctrl 9 &cpu3intctrl 11 &cpu3intctrl 9 &cpu4intctrl 11 &cpu4intctrl 9>;
+                       reg = <0x0 0xc000000 0x0 0x4000000>;
+                       reg-names = "control";
+                       riscv,max-priority = <7>;
+                       riscv,ndev = <136>;
+               };
+
+               uart0: serial@10000000 {
+                       compatible = "snps,dw-apb-uart";
+                       interrupt-parent = <&plic>;
+                       interrupts = <32>;
+                       reg = <0x0 0x10000000 0x0 0x10000>;
+                       reg-io-width = <4>;
+                       reg-shift = <2>;
+                       clocks = <&oscclk>, <&apb0clk>;
+                       clock-names = "baudclk", "apb_pclk";
+                       status = "okay";
+               };
+               uart1: serial@10010000 {
+                       compatible = "snps,dw-apb-uart";
+                       interrupt-parent = <&plic>;
+                       interrupts = <33>;
+                       reg = <0x0 0x10010000 0x0 0x10000>;
+                       reg-io-width = <4>;
+                       reg-shift = <2>;
+                       clocks = <&oscclk>, <&apb0clk>;
+                       clock-names = "baudclk", "apb_pclk";
+                       status = "okay";
+               };
+               uart2: serial@10020000 {
+                       compatible = "snps,dw-apb-uart";
+                       interrupt-parent = <&plic>;
+                       interrupts = <34>;
+                       reg = <0x0 0x10020000 0x0 0x10000>;
+                       reg-io-width = <4>;
+                       reg-shift = <2>;
+                       clocks = <&oscclk>, <&apb0clk>;
+                       clock-names = "baudclk", "apb_pclk";
+                       status = "okay";
+               };
+               uart3: serial@12000000 {
+                       compatible = "snps,dw-apb-uart";
+                       interrupt-parent = <&plic>;
+                       interrupts = <45>;
+                       reg = <0x0 0x12000000 0x0 0x10000>;
+                       reg-io-width = <4>;
+                       reg-shift = <2>;
+                       clocks = <&uartclk>, <&apb0clk>;
+                       clock-names = "baudclk", "apb_pclk";
+                       status = "okay";
+               };
+               uart4: serial@12010000 {
+                       compatible = "snps,dw-apb-uart";
+                       interrupt-parent = <&plic>;
+                       interrupts = <46>;
+                       reg = <0x0 0x12010000 0x0 0x10000>;
+                       reg-io-width = <4>;
+                       reg-shift = <2>;
+                       clocks = <&uartclk>, <&apb0clk>;
+                       clock-names = "baudclk", "apb_pclk";
+                       status = "okay";
+               };
+               uart5: serial@12020000 {
+                       compatible = "snps,dw-apb-uart";
+                       interrupt-parent = <&plic>;
+                       interrupts = <47>;
+                       reg = <0x0 0x12020000 0x0 0x10000>;
+                       reg-io-width = <4>;
+                       reg-shift = <2>;
+                       clocks = <&uartclk>, <&apb0clk>;
+                       clock-names = "baudclk", "apb_pclk";
+                       status = "okay";
+               };
+               gpio: gpio@13040000 {
+                       compatible = "starfive,gpio7110";
+                       interrupt-parent = <&plic>;
+                       interrupts = <91>;
+                       reg = <0x0 0x13040000 0x0 0x10000>;
+                       reg-names = "control";
+                       interrupt-controller;
+                       #gpio-cells = <2>;
+                       ngpios = <64>;
+                       status = "okay";
+               };
+               
+               /*emmc*/
+               sdio0:sdio0@16010000{
+                       compatible = "snps,dw-mshc";
+                       reg = <0x0 0x16010000 0x0 0x10000>;
+                       interrupts = <74>;
+                       interrupt-parent = <&plic>;
+                       clocks = <&dwmmc_biuclk>,<&dwmmc_ciuclk>;
+                       clock-names = "biu","ciu";
+                       clock-frequency = <4000000>;
+                       max-frequency = <1000000>;
+                       fifo-depth = <32>;
+                       card-detect-delay = <300>;
+                       fifo-watermark-aligned;
+                       data-addr = <0>;
+                       bus-width = <8>;
+                       cap-sd-highspeed;
+                       /*broken-cd;*/
+                       cap-sdio-irq;
+                       cap-mmc-hw-reset;
+                       non-removable;
+                       enable-sdio-wakeup;
+                       keep-power-in-suspend;
+                       /*cap-power-off-card;*/
+                       cap-mmc-highspeed;
+                       /*fixed-emmc-driver-type;*/
+                       post-power-on-delay-ms = <200>;
+
+               };
+               /*SD*/
+               sdio1:sdio1@16020000{
+                       compatible = "snps,dw-mshc";
+                       reg = <0x0 0x16020000 0x0 0x10000>;
+                       interrupts = <75>;
+                       interrupt-parent = <&plic>;
+                       clocks = <&dwmmc_biuclk>,<&dwmmc_ciuclk>;
+                       clock-names = "biu","ciu";
+                       clock-frequency = <4000000>;
+                       max-frequency = <1000000>;
+                       fifo-depth = <32>;
+                       card-detect-delay = <300>;
+                       fifo-watermark-aligned;
+                       data-addr = <0>;
+                       bus-width = <4>;
+                       cap-sd-highspeed;
+                       /*broken-cd;*/
+                       cap-sdio-irq;
+                       cap-mmc-hw-reset;
+                       non-removable;
+                       enable-sdio-wakeup;
+                       keep-power-in-suspend;
+                       /*cap-power-off-card;*/
+                       cap-mmc-highspeed;
+                       /*fixed-emmc-driver-type;*/
+                       post-power-on-delay-ms = <200>;
+               };
+               jpu: jpu@11900000 {
+                   compatible = "cm,codaj12-jpu";
+                   reg = <0x0 0x13090000 0x0 0x300>;
+                   interrupt-parent = <&plic>;
+                   interrupts = <14>;
+                   clocks = <&jpuclk>;
+                   clock-names = "jpege";
+                   status = "okay";
+               };
+
+               vpu_dec: vpu_dec@130A0000 {
+                   compatible = "c&m,cm511-vpu";
+                   reg = <0 0x130A0000 0 0x10000>;
+                   interrupt-parent = <&plic>;
+                   interrupts = <13>;
+                   clocks = <&vdec_rootclk>;
+                   clock-names = "vcodec";
+                   status = "okay";
+               };
+               vpu_enc:vpu_enc@130B0000 {
+                       compatible = "cnm,cnm420l-vpu";
+                       reg = <0x0 0x130B0000 0x0 0x10000>;
+                       interrupt-parent = <&plic>;
+                       interrupts = <15>;
+                       clocks = <&venc_rootclk>;
+                       clock-names = "vcodec";
+                       reg-names = "control";
+               };
+               rst: reset-controller {
+                       compatible = "starfive,jh7110-reset";
+                       #reset-cells = <1>;
+                       reset-controller;
+               };
+
+               /*gmac device configuration*/
+               stmmac_axi_setup: stmmac-axi-config {
+                       snps,wr_osr_lmt = <0xf>;
+                       snps,rd_osr_lmt = <0xf>;
+                       snps,blen = <256 128 64 32 0 0 0>;
+               };
+               gmac0:gmac0@16030000{
+                       compatible = "snps,dwc-qos-ethernet-5.10a";
+                       reg = <0x0 0x16030000 0x0 0x10000>;
+                       interrupt-parent = <&plic>;
+                       interrupts = <7>;
+                       phy-reset-gpios = <&gpio 63 0>;
+                       max-frame-size = <9000>;
+                       phy-mode = "rgmii-id";
+                       snps,multicast-filter-bins = <256>;
+                       snps,perfect-filter-entries = <128>;
+                       rx-fifo-depth = <262144>;
+                       tx-fifo-depth = <131072>;
+                       clock-names = "stmmaceth","phy_ref_clk", "apb_pclk","ptp_ref";
+                       clocks = <&gmac_bus_clk>, <&gmac_rxtx_clk>, <&gmac_bus_clk>,<&gmac_ptp_clk>;
+                       snps,fixed-burst;
+                       snps,no-pbl-x8;
+                       /*snps,force_sf_dma_mode;*/
+                       snps,force_thresh_dma_mode;
+                       snps,axi-config = <&stmmac_axi_setup>;
+                       snps,tso;
+                       snps,en-tx-lpi-clockgating;
+                       snps,en-lpi;
+                       snps,write-requests = <2>;
+                       snps,read-requests = <16>;
+                       snps,burst-map = <0x7>;
+                       snps,txpbl = <16>;
+                       snps,rxpbl = <16>;
+               };
+
+               gpu:gpu@18000000{
+                               compatible = "img-gpu";
+                               interrupt-parent = <&plic>;
+                               interrupts = <87>;
+                               reg = <0x0 0x18000000 0x0 0x100000 0x0 0x130C000 0x0 0x10000>;
+                               clocks = <&gpu_core_clk>, <&gpu_sys_clk>;
+                               clock-names = "gpu_core_clk","gpu_sys_clk";
+                               current-clock = <8000000>;
+                               status = "okay";
+               };
+       };
+};
diff --git a/arch/riscv/boot/dts/starfive/starfive_jh7110_audio.dtsi b/arch/riscv/boot/dts/starfive/starfive_jh7110_audio.dtsi
new file mode 100644 (file)
index 0000000..3c55119
--- /dev/null
@@ -0,0 +1,88 @@
+&soc{
+       sound_pwmdac:snd-card_pwmdac{
+                       compatible = "simple-audio-card";
+                       simple-audio-card,name = "Starfive-Pwmdac-Sound-Card";
+                       simple-audio-card,bitclock-master = <&pwmdac_dailink_master>;
+                       simple-audio-card,frame-master = <&pwmdac_dailink_master>;
+                       simple-audio-card,format = "left_j";
+                       pwmdac_dailink_master:simple-audio-card,cpu {
+                               sound-dai = <&pwmdac>;
+                       };
+
+                       simple-audio-card,codec {
+                               sound-dai = <&pwmdac_codec>;
+                       };
+               };
+       
+       sound_wm8960:snd-card-wm8960{
+               compatible = "simple-audio-card";
+               simple-audio-card,name = "Starfive-wm8960-Sound-Card"; 
+               /* i2s + wm8960 */
+               simple-audio-card,dai-link@0 {
+                       reg = <0>;
+                       status = "okay";
+                       format = "i2s";
+                       bitclock-master = <&sndcodec0>;
+                       frame-master = <&sndcodec0>;
+
+                       widgets =
+                                       "Microphone", "Mic Jack",
+                                       "Line", "Line In",
+                                       "Line", "Line Out",
+                                       "Speaker", "Speaker",
+                                       "Headphone", "Headphone Jack";
+                       routing =
+                                       "Headphone Jack", "HP_L",
+                                       "Headphone Jack", "HP_R",
+                                       "Speaker", "SPK_LP",
+                                       "Speaker", "SPK_LN",
+                                       "LINPUT1", "Mic Jack",
+                                       "LINPUT3", "Mic Jack",
+                                       "RINPUT1", "Mic Jack",
+                                       "RINPUT2", "Mic Jack";
+                       cpu0 {
+                               sound-dai = <&i2stx_4ch1>;
+                       };
+                       cpu1 {
+                               sound-dai = <&i2srx_3ch>;
+                       };
+                       
+                       sndcodec0:codec {
+                               sound-dai = <&wm8960>;
+                               clocks = <&audioclk>;
+                               clock-names = "mclk";
+                       };
+               };
+       };
+       
+       sound_spdif:snd-card-spdif{
+               compatible = "simple-audio-card";
+               simple-audio-card,name = "SF-SPDIF-Sound-Card";
+               simple-audio-card,bitclock-master = <&spdif_dailink_master>;
+               simple-audio-card,frame-master = <&spdif_dailink_master>;
+               simple-audio-card,format = "left_j";
+               spdif_dailink_master:simple-audio-card,cpu {
+                       sound-dai = <&spdif0>;
+               };
+
+               simple-audio-card,codec {
+                       sound-dai = <&spdif_transmitter>;
+               };
+       };
+               
+       sound_pdm:snd-card-pdm{
+               compatible = "simple-audio-card";
+               simple-audio-card,format = "i2s";
+               simple-audio-card,name = "SF-PDM-Sound-Card";
+               simple-audio-card,bitclock-master = <&pdm_dailink_master>;
+               simple-audio-card,frame-master = <&pdm_dailink_master>;
+               status = "okay";
+               simple-audio-card,cpu {
+                       sound-dai = <&i2srx_3ch>;
+               };
+               
+               pdm_dailink_master:simple-audio-card,codec {
+                       sound-dai = <&pdm>;
+               };
+       };
+};
\ No newline at end of file
diff --git a/arch/riscv/boot/dts/starfive/starfive_jh7110_clk.dtsi b/arch/riscv/boot/dts/starfive/starfive_jh7110_clk.dtsi
new file mode 100644 (file)
index 0000000..b0c1f4d
--- /dev/null
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/ {
+       oscclk:oscclk{
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <24000000>;
+               clock-output-names = "oscclk";
+       };
+       pll0clk:pll0clk{
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <1000000000>;
+               clock-output-names = "pll0clk";
+       };
+       pll1clk:pll1clk{
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <1066000000>;
+               clock-output-names = "pll1clk";
+       };
+       pll2clk:pll2clk{
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <1228800000>;
+               clock-output-names = "pll2clk";
+       };
+       rtcclk: rtcclk {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <4000000>;
+               clock-output-names = "rtcclk";
+       };
+       perh_rootclk: perh_rootclk {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <500000000>;
+       };
+       ahb0clk: ahb0clk {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <204800000>;
+       };
+       ahb1clk: ahb1clk {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <204800000>;
+       };
+       apb0clk: apb0clk {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <512000000>;
+       };
+       apb2clk: apb2clk {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <49500000>;
+       };
+       apb12clk: apb12clk {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <49500000>;
+       };
+       jpuclk: jpuclk {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <204800000>;
+       };
+       vdec_rootclk: vdec_rootclk {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <400000000>;
+       };
+       venc_rootclk: venc_rootclk {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <245760000>;
+       };
+       gmac_bus_clk: gmac_bus_clk {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <4000000>;
+       };
+       gmac_rxtx_clk: gmac_rxtx_clk {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <2500000>;
+       };
+       gmac_ptp_clk: gmac_ptp_clk {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <2500000>;
+       };
+       qspi_clk: qspi-clk@0 {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <50000000>;
+       };
+       uartclk: uartclk {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <51200000>;
+       };
+       dwmmc_biuclk: dwmmc_biuclk {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <4000000>;
+       };
+       dwmmc_ciuclk: dwmmc_ciuclk {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <4000000>;
+       };
+       stg_axiahb_clk: stg_axiahb_clk {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <204800000>;
+       };
+       stg_apbclk: stg_apbclk {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <51200000>;
+       };
+
+       gpu_core_clk: gpu_core_clk {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <24000000>;
+       };
+       gpu_sys_clk: gpu_sys_clk {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <24000000>;
+       };
+       pwmclk: pwmclk {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
+            clock-frequency = <125000000>;
+       };
+       audioclk: audioclk {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
+            clock-frequency = <12288000>;
+       };
+       canclk: canclk {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
+            clock-frequency = <24000000>;
+       };
+};
diff --git a/arch/riscv/configs/starfive_jh7110_defconfig b/arch/riscv/configs/starfive_jh7110_defconfig
new file mode 100644 (file)
index 0000000..cdedbdd
--- /dev/null
@@ -0,0 +1,235 @@
+CONFIG_DEFAULT_HOSTNAME="StarFive"
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_USELIB=y
+CONFIG_NO_HZ_IDLE=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BPF_SYSCALL=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_CFS_BANDWIDTH=y
+CONFIG_CGROUP_BPF=y
+CONFIG_NAMESPACES=y
+CONFIG_USER_NS=y
+CONFIG_CHECKPOINT_RESTORE=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_EXPERT=y
+CONFIG_SOC_STARFIVE=y
+CONFIG_SOC_STARFIVE_JH7110=y
+CONFIG_FPGA_GMAC_SPEED10=y
+CONFIG_SMP=y
+CONFIG_HZ_100=y
+# CONFIG_SECCOMP is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_PAGE_REPORTING=y
+CONFIG_CMA=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_IPV6 is not set
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_ACCT=y
+CONFIG_NETFILTER_NETLINK_QUEUE=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_TABLES=y
+CONFIG_NFT_CT=y
+CONFIG_NFT_COMPAT=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_TABLES_IPV4=y
+CONFIG_NFT_DUP_IPV4=y
+CONFIG_NFT_FIB_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_NETLINK_DIAG=y
+CONFIG_BT=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+CONFIG_CFG80211=y
+CONFIG_NET_9P=y
+CONFIG_NET_9P_VIRTIO=y
+CONFIG_PCI=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_VIRTIO_BLK=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_SCSI_VIRTIO=y
+CONFIG_NETDEVICES=y
+CONFIG_VIRTIO_NET=y
+# CONFIG_NET_VENDOR_ALACRITECH is not set
+# CONFIG_NET_VENDOR_AMAZON is not set
+# CONFIG_NET_VENDOR_AQUANTIA is not set
+# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CADENCE is not set
+# CONFIG_NET_VENDOR_CAVIUM is not set
+# CONFIG_NET_VENDOR_CORTINA is not set
+# CONFIG_NET_VENDOR_EZCHIP is not set
+# CONFIG_NET_VENDOR_GOOGLE is not set
+# CONFIG_NET_VENDOR_HUAWEI is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MELLANOX is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_NET_VENDOR_MICROSEMI is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_NETRONOME is not set
+# CONFIG_NET_VENDOR_NI is not set
+# CONFIG_NET_VENDOR_PENSANDO is not set
+# CONFIG_NET_VENDOR_QUALCOMM is not set
+CONFIG_R8169=y
+# CONFIG_NET_VENDOR_RENESAS is not set
+# CONFIG_NET_VENDOR_ROCKER is not set
+# CONFIG_NET_VENDOR_SAMSUNG is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SOLARFLARE is not set
+# CONFIG_NET_VENDOR_SOCIONEXT is not set
+CONFIG_STMMAC_ETH=y
+CONFIG_STMMAC_SELFTESTS=y
+CONFIG_DWMAC_DWC_QOS_ETH=y
+# CONFIG_NET_VENDOR_SYNOPSYS is not set
+# CONFIG_NET_VENDOR_VIA is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+# CONFIG_NET_VENDOR_XILINX is not set
+CONFIG_MARVELL_PHY=y
+CONFIG_MICREL_PHY=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_SERIO_LIBPS2=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=6
+CONFIG_SERIAL_8250_RUNTIME_UARTS=6
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_DW=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SERIAL_EARLYCON_RISCV_SBI=y
+CONFIG_HVC_RISCV_SBI=y
+CONFIG_TTY_PRINTK=y
+CONFIG_VIRTIO_CONSOLE=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_VIRTIO=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_DESIGNWARE_PLATFORM=y
+CONFIG_SPI=y
+CONFIG_SPI_SIFIVE=y
+CONFIG_SPI_SPIDEV=y
+# CONFIG_PTP_1588_CLOCK is not set
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_STARFIVE_JH7110=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_SYSCON=y
+CONFIG_POWER_RESET_SYSCON_POWEROFF=y
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_FB=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+CONFIG_USB=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_UAS=y
+CONFIG_USB_CDNS_SUPPORT=y
+CONFIG_USB_CDNS3=y
+CONFIG_USB_CDNS3_HOST=y
+CONFIG_MMC=y
+CONFIG_MMC_DEBUG=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_OF_DWCMSHC=y
+CONFIG_MMC_SPI=y
+CONFIG_MMC_DW=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_GOLDFISH=y
+CONFIG_DMADEVICES=y
+CONFIG_DW_AXI_DMAC=y
+CONFIG_DMATEST=m
+CONFIG_SYNC_FILE=y
+# CONFIG_VIRTIO_MENU is not set
+# CONFIG_VHOST_MENU is not set
+CONFIG_GOLDFISH=y
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_RPMSG_CHAR=y
+CONFIG_RPMSG_VIRTIO=y
+CONFIG_PWM=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_AUTOFS4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_CUSE=y
+CONFIG_VIRTIO_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_UTF8=y
+CONFIG_EXFAT_FS=y
+CONFIG_NTFS_FS=y
+CONFIG_NTFS_RW=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_HUGETLBFS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_V4_1=y
+CONFIG_NFS_V4_2=y
+CONFIG_ROOT_NFS=y
+CONFIG_CRYPTO_USER=y
+# CONFIG_CRYPTO_AES is not set
+CONFIG_CRYPTO_USER_API_HASH=y
+CONFIG_CRYPTO_USER_API_SKCIPHER=y
+CONFIG_CRYPTO_USER_API_RNG=y
+CONFIG_CRYPTO_USER_API_AEAD=y
+CONFIG_CRYPTO_DEV_VIRTIO=y
+CONFIG_DMA_CMA=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_FS=y
+CONFIG_SOFTLOCKUP_DETECTOR=y
+CONFIG_WQ_WATCHDOG=y
+CONFIG_DEBUG_TIMEKEEPING=y
+CONFIG_DEBUG_RT_MUTEXES=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_RWSEMS=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_STACKTRACE=y
+CONFIG_DEBUG_LIST=y
+CONFIG_DEBUG_PLIST=y
+CONFIG_DEBUG_SG=y
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_EQS_DEBUG=y
+# CONFIG_FTRACE is not set
+# CONFIG_RUNTIME_TESTING_MENU is not set
+CONFIG_MEMTEST=y
index fae5141..1dc803d 100644 (file)
@@ -549,6 +549,13 @@ config GPIO_SIFIVE
        select REGMAP_MMIO
        help
          Say yes here to support the GPIO device on SiFive SoCs.
+config GPIO_STARFIVE_JH7110
+       bool "Starfive JH7110 GPIO support"
+       depends on SOC_STARFIVE_JH7110
+       depends on OF_GPIO
+       select GPIOLIB_IRQCHIP
+       help
+         Say yes here to support the GPIO device on Starfive VIC7110 SoCs.
 
 config GPIO_SIOX
        tristate "SIOX GPIO support"
index fbcda63..8e44616 100644 (file)
@@ -133,6 +133,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_JH7110)     += gpio-starfive-jh7110.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-jh7110.c b/drivers/gpio/gpio-starfive-jh7110.c
new file mode 100644 (file)
index 0000000..2ca62b0
--- /dev/null
@@ -0,0 +1,792 @@
+/*
+ ******************************************************************************
+ * @file  gpio-starfive-vic7110.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 <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/of_irq.h>
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <linux/spinlock.h>
+
+#define GPIO_EN                0xe0
+#define GPIO_IS_LOW    0xe4
+#define GPIO_IS_HIGH   0xe8
+#define GPIO_IBE_LOW   0xf4
+#define GPIO_IBE_HIGH  0xf8
+#define GPIO_IEV_LOW   0xfc
+#define GPIO_IEV_HIGH  0x100
+#define GPIO_IE_LOW    0x104
+#define GPIO_IE_HIGH   0x108
+#define GPIO_IC_LOW    0xec
+#define GPIO_IC_HIGH   0xf0
+//read only
+#define GPIO_RIS_LOW   0x10c
+#define GPIO_RIS_HIGH  0x110
+#define GPIO_MIS_LOW   0x114
+#define GPIO_MIS_HIGH  0x118
+#define GPIO_DIN_LOW   0x11C
+#define GPIO_DIN_HIGH  0x120
+
+#define GPIO_DOUT_X_REG        0x0
+#define GPIO_DOEN_X_REG        0x40
+
+#define GPIO_INPUT_ENABLE_X_REG        0x124
+
+#define MAX_GPIO        64
+
+#define PROC_VIC "vic_gpio7110"
+
+struct sfvic7110_gpio {
+       raw_spinlock_t          lock;
+       void __iomem            *base;
+       struct gpio_chip        gc;
+       unsigned long           enabled;
+       unsigned                trigger[MAX_GPIO];
+       unsigned int            irq_parent[MAX_GPIO];
+       struct sfvic7110_gpio   *self_ptr[MAX_GPIO];
+};
+
+/* lock for procfs read access */
+static DEFINE_MUTEX(read_lock);
+
+/* lock for procfs write access */
+static DEFINE_MUTEX(write_lock);
+
+static DEFINE_SPINLOCK(sfg_lock);
+
+static void __iomem *gpio_base = NULL;
+
+static int sfvic7110_direction_input(struct gpio_chip *gc, unsigned offset)
+{
+       struct sfvic7110_gpio *chip = gpiochip_get_data(gc);
+       unsigned long flags;
+       unsigned int v;
+
+       if (offset >= gc->ngpio)
+               return -EINVAL;
+
+       raw_spin_lock_irqsave(&chip->lock, flags);
+       v = readl_relaxed(chip->base + GPIO_DOEN_X_REG + (offset & ~0x3));
+       v &= ~(0x3f << ((offset & 0x3) * 8));
+       v |= 1 << ((offset & 0x3) * 8);
+       writel_relaxed(v, chip->base + GPIO_DOEN_X_REG + (offset & ~0x3));
+       raw_spin_unlock_irqrestore(&chip->lock, flags);
+
+       return 0;
+}
+
+static int sfvic7110_direction_output(struct gpio_chip *gc, unsigned offset, int value)
+{
+       struct sfvic7110_gpio *chip = gpiochip_get_data(gc);
+       unsigned long flags;
+       unsigned int v;
+
+       if (offset >= gc->ngpio)
+               return -EINVAL;
+       raw_spin_lock_irqsave(&chip->lock, flags);
+       v = readl_relaxed(chip->base + GPIO_DOEN_X_REG + (offset & ~0x3));
+       v &= ~(0x3f << ((offset & 0x3) * 8));
+       writel_relaxed(v, chip->base + GPIO_DOEN_X_REG + (offset & ~0x3));
+
+       v = readl_relaxed(chip->base + GPIO_DOUT_X_REG + (offset & ~0x3));
+       v &= ~(0x3f << ((offset & 0x3) * 8));
+       v |= value << ((offset & 0x3) * 8);
+       writel_relaxed(v, chip->base + GPIO_DOUT_X_REG + (offset & ~0x3));
+       raw_spin_unlock_irqrestore(&chip->lock, flags);
+
+       return 0;
+}
+
+static int sfvic7110_get_direction(struct gpio_chip *gc, unsigned offset)
+{
+       struct sfvic7110_gpio *chip = gpiochip_get_data(gc);
+       unsigned int v;
+
+       if (offset >= gc->ngpio)
+               return -EINVAL;
+
+       v = readl_relaxed(chip->base + GPIO_DOEN_X_REG + (offset & ~0x3));
+       return !!(v & (0x3f << ((offset & 0x3) * 8)));
+}
+
+static int sfvic7110_get_value(struct gpio_chip *gc, unsigned offset)
+{
+       struct sfvic7110_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);
+               return (value >> offset) & 0x1;
+       } else {
+               value = readl_relaxed(chip->base + GPIO_DIN_HIGH);
+               return (value >> (offset - 32)) & 0x1;
+       }
+}
+
+static void sfvic7110_set_value(struct gpio_chip *gc, unsigned offset, int value)
+{
+       struct sfvic7110_gpio *chip = gpiochip_get_data(gc);
+       unsigned long flags;
+       unsigned int v;
+
+       if (offset >= gc->ngpio)
+               return;
+
+       raw_spin_lock_irqsave(&chip->lock, flags);
+       v = readl_relaxed(chip->base + GPIO_DOUT_X_REG + (offset & ~0x3));
+       v &= ~(0x3f << ((offset & 0x3) * 8));
+       v |= value << ((offset & 0x3) * 8);
+       writel_relaxed(v, chip->base + GPIO_DOUT_X_REG + (offset & ~0x3));
+       raw_spin_unlock_irqrestore(&chip->lock, flags);
+}
+
+static void sfvic7110_set_ie(struct sfvic7110_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 sfvic7110_irq_set_type(struct irq_data *d, unsigned trigger)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct sfvic7110_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  &= (~(0x1<< index));
+               reg_ibe &= (~(0x1<< index));
+               reg_iev |= (0x1<< 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  &= (~(0x1<< index));
+               reg_ibe &= (~(0x1<< index));
+               reg_iev &= (0x1<< 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  |= (~(0x1<< index));
+               reg_ibe |= (~(0x1<< index));
+               //reg_iev |= (0x1<< 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  |= (~(0x1<< index));
+               reg_ibe &= (~(0x1<< index));
+               reg_iev |= (0x1<< 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  |= (~(0x1<< index));
+               reg_ibe &= (~(0x1<< index));
+               reg_iev &= (0x1<< 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;
+       sfvic7110_set_ie(chip, offset);
+       return 0;
+}
+
+/* chained_irq_{enter,exit} already mask the parent */
+static void sfvic7110_irq_mask(struct irq_data *d)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct sfvic7110_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 sfvic7110_irq_unmask(struct irq_data *d)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct sfvic7110_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 sfvic7110_irq_enable(struct irq_data *d)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct sfvic7110_gpio *chip = gpiochip_get_data(gc);
+       int offset = irqd_to_hwirq(d);
+
+       sfvic7110_irq_unmask(d);
+       assign_bit(offset, &chip->enabled, 1);
+}
+
+static void sfvic7110_irq_disable(struct irq_data *d)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct sfvic7110_gpio *chip = gpiochip_get_data(gc);
+       int offset = irqd_to_hwirq(d) % MAX_GPIO; // must not fail
+
+       assign_bit(offset, &chip->enabled, 0);
+       sfvic7110_set_ie(chip, offset);
+}
+
+static struct irq_chip sfvic7110_irqchip = {
+       .name           = "sfvic7110-gpio",
+       .irq_set_type   = sfvic7110_irq_set_type,
+       .irq_mask       = sfvic7110_irq_mask,
+       .irq_unmask     = sfvic7110_irq_unmask,
+       .irq_enable     = sfvic7110_irq_enable,
+       .irq_disable    = sfvic7110_irq_disable,
+};
+
+
+static int starfive_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
+                                            unsigned int child,
+                                            unsigned int child_type,
+                                            unsigned int *parent,
+                                            unsigned int *parent_type)
+{
+       struct sfvic7110_gpio *chip = gpiochip_get_data(gc);
+       struct irq_data *d = irq_get_irq_data(chip->irq_parent[child]);
+
+       *parent_type = IRQ_TYPE_NONE;
+       *parent = irqd_to_hwirq(d);
+
+       return 0;
+}
+
+static irqreturn_t sfvic7110_irq_handler(int irq, void *gc)
+{
+       int offset;
+       // = self_ptr - &chip->self_ptr[0];
+       int reg_offset, index;
+       unsigned int value;
+       unsigned long flags;
+       struct sfvic7110_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;
+}
+
+void sf_vic_gpio_dout_reverse(int gpio,int en)
+{
+       unsigned int value;
+       int offset;
+
+       if(!gpio_base)
+               return;
+
+       offset = GPIO_DOUT_X_REG + (gpio & ~0x3);
+
+       spin_lock(&sfg_lock);
+       value = ioread32(gpio_base + offset);
+       value &= ~(0x3f << ((offset & 0x3) * 8));
+       value |= (en & 0x1) << ((offset & 0x3) * 8);
+       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_DOUT_X_REG + (gpio & ~0x3);
+
+       spin_lock(&sfg_lock);
+       value = ioread32(gpio_base + offset);
+       value &= ~(0x3f << ((offset & 0x3) * 8));
+       value |= (v & 0x3f) << ((offset & 0x3) * 8);
+       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_DOEN_X_REG + (gpio & ~0x3);
+
+       spin_lock(&sfg_lock);
+       value = ioread32(gpio_base + offset);
+       value &= ~(0x3f << ((offset & 0x3) * 8));
+       value |= (en & 0x1) << ((offset & 0x3) * 8);
+       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_DOEN_X_REG + (gpio & ~0x3);
+
+       spin_lock(&sfg_lock);
+       value = ioread32(gpio_base + offset);
+       value &= ~(0x3f << ((offset & 0x3) * 8));
+       value |= (v & 0x3f) << ((offset & 0x3) * 8);
+       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 str_to_num(char *str)
+{
+       char *p = str;
+       int value = 0;
+
+       if((*p == '0') && (*(p + 1) == 'x' || *(p + 1) == 'X')) {
+               p = p + 2;
+               while(((*p >= '0') && (*p <= '9')) ||
+                     ((*p >= 'a') && (*p <= 'f')) ||
+                     ((*p >= 'A') && (*p <= 'F'))) {
+                       if((*p >= '0') && (*p <= '9'))
+                               value = value * 16 + (*p - '0');
+                       if((*p >= 'a') && (*p <= 'f'))
+                               value = value * 16 + 10 + (*p - 'a');
+                       if((*p >= 'A') && (*p <= 'F'))
+                               value = value * 16 + 10 + (*p - 'A');
+                       p = p + 1;
+               }
+       } else {
+               while((*p >= '0') && (*p <= '9')) {
+                       value = value * 10 + (*p - '0');
+                       p = p + 1;
+               }
+       }
+
+       if(*p != '\0')
+               return -EFAULT;
+
+       return value;
+}
+
+static ssize_t vic_gpio_proc_write(struct file *file, const char __user *buf,
+                                               size_t count, loff_t *ppos)
+{
+       int ret;
+       char message[64], cmd[8],gnum[8],v[8];
+       int gpionum, value;
+
+       if (mutex_lock_interruptible(&write_lock))
+               return -ERESTARTSYS;
+
+       ret = copy_from_user(message, buf, count);
+       mutex_unlock(&write_lock);
+       if(ret)
+               return -EFAULT;
+       sscanf(message, "%s %s %s", cmd, gnum, v);
+       gpionum = str_to_num(gnum);
+       if(gpionum < 0)
+               return -EFAULT;
+       value = str_to_num(v);
+       if(value < 0)
+               return -EFAULT;
+
+       if(!strcmp(cmd,"dout")) {
+               if(gpionum < 0 || gpionum > 63){
+                       printk(KERN_ERR "vic-gpio: dout gpionum (0-63)  value (0/1) invalid: gpionum = %d value = %d\n",
+                              gpionum,value);
+                       return -EFAULT;
+               }
+               sf_vic_gpio_dout_value(gpionum, value);
+       }else if(!strcmp(cmd,"doen")) {
+               if(gpionum < 0 || gpionum > 63){
+                       printk(KERN_ERR "vic-gpio: doen gpionum (0-63)  value (0/1) invalid: gpionum = %d value = %d\n",
+                              gpionum,value);
+                       return -EFAULT;
+               }
+               sf_vic_gpio_doen_value(gpionum,value);
+       }else if(!strcmp(cmd,"utrv")) {
+               if(gpionum < 0 || gpionum > 63){
+                       printk(KERN_ERR "vic-gpio: utrv gpionum (0-63) is invalid: %d\n",gpionum);
+                       return -EFAULT;
+               }
+               sf_vic_gpio_doen_reverse(gpionum,value);
+       }else if(!strcmp(cmd,"enrv")) {
+               if(gpionum < 0 || gpionum > 63){
+                       printk(KERN_ERR "vic-gpio: enrv gpionum (0-63) is invalid: %d\n",gpionum);
+                       return -EFAULT;
+               }
+               sf_vic_gpio_doen_reverse(gpionum, value);
+       }else if(!strcmp(cmd,"manu")) {
+               if(gpionum < 0x250 || gpionum > 0x378 || (gpionum & 0x3)){
+                       printk(KERN_ERR "vic-gpio: manu offset (0x250-0x378 & mod 4) is invalid: %d\n",gpionum);
+                       return -EFAULT;
+               }
+               sf_vic_gpio_manual(gpionum, value);
+       }else {
+               printk(KERN_ERR "vic-gpio: cmd (dout  doen utrv enrv manu) invalid: %s\n",cmd);
+       }
+
+       return count;
+}
+
+static ssize_t vic_gpio_proc_read(struct file *file, char __user *buf,
+                                 size_t count, loff_t *ppos)
+{
+       int ret;
+       unsigned int copied;
+       char message[256];
+
+       sprintf(message, "Usage: echo 'cmd gpionum value' >/proc/vic_gpio\n\t"
+               "cmd: dout  doen utrv enrv or manu\n\t"
+               "gpionum: gpionum or address offset for manu\n\t"
+               "value: 0/1 for utrv/enrv, value for dout/doen/manual\n");
+       copied = strlen(message);
+
+       if(*ppos >= copied)
+               return 0;
+
+       if (mutex_lock_interruptible(&read_lock))
+               return -ERESTARTSYS;
+
+       ret = copy_to_user(buf, message, copied);
+       if(ret) {
+               mutex_unlock(&read_lock);
+       }
+       *ppos += copied;
+
+       mutex_unlock(&read_lock);
+
+       return copied;
+}
+
+static const struct file_operations vic_gpio_fops = {
+       .owner  = THIS_MODULE,
+       .read   = vic_gpio_proc_read,
+       .write  = vic_gpio_proc_write,
+       .llseek = noop_llseek,
+};
+
+static int sfvic7110_gpio_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct sfvic7110_gpio *chip;
+       struct resource *res;
+       int irq, ret, ngpio;
+       int loop;
+       struct gpio_irq_chip *girq;
+       struct device_node *node = pdev->dev.of_node;
+       struct device_node *irq_parent;
+       struct irq_domain *parent;
+
+       chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+       if (!chip) {
+               dev_err(dev, "out of memory\n");
+               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);
+       }
+       gpio_base = chip->base ;
+
+       ngpio = 64;
+
+       raw_spin_lock_init(&chip->lock);
+       chip->gc.direction_input = sfvic7110_direction_input;
+       chip->gc.direction_output = sfvic7110_direction_output;
+       chip->gc.get_direction = sfvic7110_get_direction;
+       chip->gc.get = sfvic7110_get_value;
+       chip->gc.set = sfvic7110_set_value;
+       chip->gc.base = 0;
+       chip->gc.ngpio = ngpio;
+       chip->gc.label = dev_name(dev);
+       chip->gc.parent = dev;
+       chip->gc.owner = THIS_MODULE;
+
+       irq_parent = of_irq_find_parent(node);
+       if (!irq_parent) {
+               dev_err(dev, "no IRQ parent node\n");
+               return -ENODEV;
+       }
+       parent = irq_find_host(irq_parent);
+       if (!parent) {
+               dev_err(dev, "no IRQ parent domain\n");
+               return -ENODEV;
+       }
+
+       girq = &chip->gc.irq;
+       girq->chip = &sfvic7110_irqchip;
+       girq->fwnode = of_node_to_fwnode(node);
+       girq->parent_domain = parent;
+       girq->child_to_parent_hwirq = starfive_gpio_child_to_parent_hwirq;
+       girq->handler = handle_simple_irq;
+       girq->default_type = IRQ_TYPE_NONE;
+
+       /* 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;
+       
+       platform_set_drvdata(pdev, chip);
+       ret = gpiochip_add_data(&chip->gc, chip);
+       if (ret){
+               dev_err(dev, "gpiochip_add_data ret=%d!\n", ret);
+               return ret;
+       }
+       
+#if 0
+       /* 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 = gpiochip_gpiochip_add(&chip->gc, &sfvic7110_irqchip, 0,
+                                  handle_simple_irq, IRQ_TYPE_NONE);
+       if (ret) {
+               dev_err(dev, "could not add irqchip\n");
+               gpiochip_remove(&chip->gc);
+               return ret;
+       }
+#endif
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(dev, "Cannot get IRQ resource\n");
+               return irq;
+       }
+
+       chip->irq_parent[0] = irq;
+       
+       ret = devm_request_irq(dev, irq, sfvic7110_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);
+
+       for(loop = 0; loop < MAX_GPIO; loop++) {
+               unsigned int v;
+               v = readl_relaxed(chip->base + GPIO_INPUT_ENABLE_X_REG + (loop << 2));
+               v |= 0x1;
+               writel_relaxed(v, chip->base + GPIO_INPUT_ENABLE_X_REG + (loop << 2));
+       }
+
+       if (proc_create(PROC_VIC, 0, NULL, (void *)&vic_gpio_fops) == NULL) {
+               return -ENOMEM;
+       }
+       dev_info(dev, "SiFive GPIO chip registered %d GPIOs\n", ngpio);
+
+       return 0;
+}
+
+static const struct of_device_id sfvic7110_gpio_match[] = {
+       { .compatible = "starfive,gpio7110", },
+       { },
+};
+
+static struct platform_driver sfvic7110_gpio_driver = {
+       .probe  = sfvic7110_gpio_probe,
+       .driver = {
+               .name           = "sfvic7110_gpio",
+               .of_match_table = of_match_ptr(sfvic7110_gpio_match),
+       },
+};
+
+static int __init sfvic7110_gpio_init(void)
+{
+       return platform_driver_register(&sfvic7110_gpio_driver);
+}
+subsys_initcall(sfvic7110_gpio_init);
+
+static void __exit sfvic7110_gpio_exit(void)
+{
+       platform_driver_unregister(&sfvic7110_gpio_driver);
+}
+module_exit(sfvic7110_gpio_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Huan Feng <huan.feng@starfivetech.com>");
+MODULE_DESCRIPTION("Starfive VIC GPIO generator driver");
index bc91fd8..3730c5d 100644 (file)
@@ -493,6 +493,7 @@ static int dwc_eth_dwmac_remove(struct platform_device *pdev)
 
 static const struct of_device_id dwc_eth_dwmac_match[] = {
        { .compatible = "snps,dwc-qos-ethernet-4.10", .data = &dwc_qos_data },
+       { .compatible = "snps,dwc-qos-ethernet-5.10a", .data = &dwc_qos_data },
        { .compatible = "nvidia,tegra186-eqos", .data = &tegra_eqos_data },
        { }
 };
index bb7114f..ab7dbb6 100644 (file)
@@ -215,6 +215,24 @@ static const struct stmmac_hwif_entry {
                .quirks = NULL,
        }, {
                .gmac = false,
+               .gmac4 = true,
+               .xgmac = false,
+               .min_id = DWMAC_CORE_5_20,
+               .regs = {
+                       .ptp_off = PTP_GMAC4_OFFSET,
+                       .mmc_off = MMC_GMAC4_OFFSET,
+               },
+               .desc = &dwmac4_desc_ops,
+               .dma = &dwmac410_dma_ops,
+               .mac = &dwmac510_ops,
+               .hwtimestamp = &stmmac_ptp,
+               .mode = &dwmac4_ring_mode_ops,
+               .tc = &dwmac510_tc_ops,
+               .mmc = &dwmac_mmc_ops,
+               .setup = dwmac4_setup,
+               .quirks = NULL,
+       }, {
+               .gmac = false,
                .gmac4 = false,
                .xgmac = true,
                .min_id = DWXGMAC_CORE_2_10,
index 4fcfca4..d650fb2 100644 (file)
@@ -551,9 +551,20 @@ static int m88e1121_config_aneg_rgmii_delays(struct phy_device *phydev)
        else
                mscr = 0;
 
+#if defined(CONFIG_FPGA_GMAC_SPEED10)
+       return phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE,
+                               MII_88E1121_PHY_MSCR_REG,
+                               MII_88E1121_PHY_MSCR_DELAY_MASK|BIT(6)|BIT(13),
+                               mscr);
+#elif defined(CONFIG_FPGA_GMAC_SPEED100)
+       return phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE,
+                               MII_88E1121_PHY_MSCR_REG,
+                               MII_88E1121_PHY_MSCR_DELAY_MASK|BIT(13), mscr);
+#else
        return phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE,
                                MII_88E1121_PHY_MSCR_REG,
                                MII_88E1121_PHY_MSCR_DELAY_MASK, mscr);
+#endif
 }
 
 static int m88e1121_config_aneg(struct phy_device *phydev)
index 5c928f8..dc4965c 100644 (file)
@@ -894,6 +894,48 @@ static int ksz9031_config_init(struct phy_device *phydev)
                                goto err_force_master;
                }
        }
+#if defined(CONFIG_FPGA_GMAC_SPEED10)
+       /* set to 10M
+       bit [6, 13]
+               [1,1] = Reserved
+               [1,0] = 1000 Mbps
+               [0,1] = 100 Mbps
+               [0,0] = 10 Mbps
+       */
+       result = phy_read(phydev, MII_BMCR);
+       result &=~(BIT(6)|BIT(13));
+       result = phy_write(phydev, MII_BMCR, result);
+       if (result < 0)
+               goto err_force_master;
+
+       /* remove Auto-Negotiation advertisements for 1000 Mbps full-/half-duplex*/
+       result = phy_read(phydev, MII_CTRL1000);
+       result &=~(BIT(8)|BIT(9));
+       result = phy_write(phydev, MII_CTRL1000, result);
+       if (result < 0)
+               goto err_force_master;
+#elif defined(CONFIG_FPGA_GMAC_SPEED100)
+       /* set to 100M
+       bit     [6, 13]
+               [1,1] = Reserved
+               [1,0] = 1000 Mbps
+               [0,1] = 100 Mbps
+               [0,0] = 10 Mbps
+       */
+       result = phy_read(phydev, MII_BMCR);
+       result &=~BIT(6);
+       result |=BIT(13);
+       result = phy_write(phydev, MII_BMCR, result);
+       if (result < 0)
+               goto err_force_master;
+
+       /* remove Auto-Negotiation advertisements for 1000 Mbps full-/half-duplex*/
+       result = phy_read(phydev, MII_CTRL1000);
+       result &=~(BIT(8)|BIT(9));
+       result = phy_write(phydev, MII_CTRL1000, result);
+       if (result < 0)
+               goto err_force_master;
+#endif
 
        return ksz9031_center_flp_timing(phydev);
 
index 4f9990b..a711be5 100644 (file)
@@ -589,13 +589,24 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, u32 phy_id,
        mdiodev->device_free = phy_mdio_device_free;
        mdiodev->device_remove = phy_mdio_device_remove;
 
+#if defined(CONFIG_FPGA_GMAC_SPEED10)
+       dev->speed = SPEED_10;
+       dev->duplex = DUPLEX_FULL;
+       dev->interface = PHY_INTERFACE_MODE_RGMII;
+#elif defined(CONFIG_FPGA_GMAC_SPEED100)
+       dev->speed = SPEED_100;
+       dev->duplex = DUPLEX_FULL;
+       dev->interface = PHY_INTERFACE_MODE_RGMII;
+#else
        dev->speed = SPEED_UNKNOWN;
        dev->duplex = DUPLEX_UNKNOWN;
+       dev->interface = PHY_INTERFACE_MODE_GMII;
+#endif
        dev->pause = 0;
        dev->asym_pause = 0;
        dev->link = 0;
        dev->port = PORT_TP;
-       dev->interface = PHY_INTERFACE_MODE_GMII;
+//     dev->interface = PHY_INTERFACE_MODE_GMII;
 
        dev->autoneg = AUTONEG_ENABLE;
 
@@ -1910,6 +1921,13 @@ static int genphy_config_advert(struct phy_device *phydev)
        if (err > 0)
                changed = 1;
 
+#if defined(CONFIG_FPGA_GMAC_SPEED10)
+       err = phy_write(phydev, MII_ADVERTISE, 0x61);
+       //Auto-Negotiation Advertisement 10M
+#elif defined(CONFIG_FPGA_GMAC_SPEED100)
+       err = phy_write(phydev, MII_ADVERTISE, 0x181);
+       //Auto-Negotiation Advertisement 100M
+#endif
        bmsr = phy_read(phydev, MII_BMSR);
        if (bmsr < 0)
                return bmsr;
@@ -1923,9 +1941,19 @@ static int genphy_config_advert(struct phy_device *phydev)
 
        adv = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising);
 
+#if defined(CONFIG_FPGA_GMAC_SPEED10)
+       err = phy_modify_changed(phydev, MII_CTRL1000,
+                                ADVERTISE_1000FULL | ADVERTISE_1000HALF,
+                                0);
+#elif defined(CONFIG_FPGA_GMAC_SPEED100)
+       err = phy_modify_changed(phydev, MII_CTRL1000,
+                                ADVERTISE_1000FULL | ADVERTISE_1000HALF,
+                                0);
+#else
        err = phy_modify_changed(phydev, MII_CTRL1000,
                                 ADVERTISE_1000FULL | ADVERTISE_1000HALF,
                                 adv);
+#endif
        if (err < 0)
                return err;
        if (err > 0)
index 58cf8c4..7d67517 100644 (file)
@@ -7,4 +7,20 @@ 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
+       default 0x40000000 if SOC_STARFIVE_JH7110
+
+config SIFIVE_L2_FLUSH_SIZE
+       hex "Level 2 Cache Flush operation size"
+       default 0x800000000
+       default 0x400000000 if SOC_STARFIVE_JH7110
+
+endif # SIFIVE_L2_FLUSH
 endif
index 59640a1..bf824d5 100644 (file)
 #define SIFIVE_L2_DATECCFAIL_HIGH 0x164
 #define SIFIVE_L2_DATECCFAIL_COUNT 0x168
 
+#define SIFIVE_L2_FLUSH64 0x200
+
 #define SIFIVE_L2_CONFIG 0x00
 #define SIFIVE_L2_WAYENABLE 0x08
 #define SIFIVE_L2_ECCINJECTERR 0x40
 
 #define SIFIVE_L2_MAX_ECCINTR 4
 
+#define SIFIVE_L2_FLUSH64_LINE_LEN 64
 static void __iomem *l2_base;
 static int g_irq[SIFIVE_L2_MAX_ECCINTR];
 static struct riscv_cacheinfo_ops l2_cache_ops;
@@ -116,6 +119,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;
index 92ade10..04dcac1 100644 (file)
@@ -13,4 +13,8 @@ extern int unregister_sifive_l2_error_notifier(struct notifier_block *nb);
 #define SIFIVE_L2_ERR_TYPE_CE 0
 #define SIFIVE_L2_ERR_TYPE_UE 1
 
+#ifdef CONFIG_SIFIVE_L2_FLUSH
+void sifive_l2_flush64_range(unsigned long start, unsigned long len);
+#endif
+
 #endif /* __SOC_SIFIVE_L2_CACHE_H */
diff --git a/include/soc/starfive/vic7100.h b/include/soc/starfive/vic7100.h
new file mode 100644 (file)
index 0000000..4e8ca79
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef STARFIVE_VIC7100_H
+#define STARFIVE_VIC7100_H
+#include <asm/io.h>
+#include <soc/sifive/sifive_l2_cache.h>
+
+/*cache.c*/
+#define starfive_flush_dcache(start, len) \
+       sifive_l2_flush64_range(start, len)
+
+void *dw_phys_to_virt(dma_addr_t phys);
+dma_addr_t dw_virt_to_phys(void *vaddr);
+
+int async_memcpy_single(dma_addr_t dst_dma, dma_addr_t src_dma, size_t size);
+int async_memcpy_single_virt(void *dst, void *src, size_t size);
+int async_memcpy_test(size_t size);
+
+#endif /*STARFIVE_VIC7100_H*/
diff --git a/usr/gen_initramfs_list.sh b/usr/gen_initramfs_list.sh
new file mode 100755 (executable)
index 0000000..0aad760
--- /dev/null
@@ -0,0 +1,328 @@
+#!/bin/sh
+# Copyright (C) Martin Schlemmer <azarah@nosferatu.za.org>
+# Copyright (C) 2006 Sam Ravnborg <sam@ravnborg.org>
+#
+# Released under the terms of the GNU GPL
+#
+# Generate a cpio packed initramfs. It uses gen_init_cpio to generate
+# the cpio archive, and then compresses it.
+# The script may also be used to generate the inputfile used for gen_init_cpio
+# This script assumes that gen_init_cpio is located in usr/ directory
+
+# error out on errors
+set -e
+
+usage() {
+cat << EOF
+Usage:
+$0 [-o <file>] [-u <uid>] [-g <gid>] {-d | <cpio_source>} ...
+       -o <file>      Create compressed initramfs file named <file> using
+                      gen_init_cpio and compressor depending on the extension
+       -u <uid>       User ID to map to user ID 0 (root).
+                      <uid> is only meaningful if <cpio_source> is a
+                      directory.  "squash" forces all files to uid 0.
+       -g <gid>       Group ID to map to group ID 0 (root).
+                      <gid> is only meaningful if <cpio_source> is a
+                      directory.  "squash" forces all files to gid 0.
+       <cpio_source>  File list or directory for cpio archive.
+                      If <cpio_source> is a .cpio file it will be used
+                      as direct input to initramfs.
+       -d             Output the default cpio list.
+
+All options except -o and -l may be repeated and are interpreted
+sequentially and immediately.  -u and -g states are preserved across
+<cpio_source> options so an explicit "-u 0 -g 0" is required
+to reset the root/group mapping.
+EOF
+}
+
+# awk style field access
+# $1 - field number; rest is argument string
+field() {
+       shift $1 ; echo $1
+}
+
+list_default_initramfs() {
+       # echo usr/kinit/kinit
+       :
+}
+
+default_initramfs() {
+       cat <<-EOF >> ${output}
+               # This is a very simple, default initramfs
+
+               dir /dev 0755 0 0
+               nod /dev/console 0600 0 0 c 5 1
+               dir /root 0700 0 0
+               # file /kinit usr/kinit/kinit 0755 0 0
+               # slink /init kinit 0755 0 0
+       EOF
+}
+
+filetype() {
+       local argv1="$1"
+
+       # symlink test must come before file test
+       if [ -L "${argv1}" ]; then
+               echo "slink"
+       elif [ -f "${argv1}" ]; then
+               echo "file"
+       elif [ -d "${argv1}" ]; then
+               echo "dir"
+       elif [ -b "${argv1}" -o -c "${argv1}" ]; then
+               echo "nod"
+       elif [ -p "${argv1}" ]; then
+               echo "pipe"
+       elif [ -S "${argv1}" ]; then
+               echo "sock"
+       else
+               echo "invalid"
+       fi
+       return 0
+}
+
+list_print_mtime() {
+       :
+}
+
+print_mtime() {
+       local my_mtime="0"
+
+       if [ -e "$1" ]; then
+               my_mtime=$(find "$1" -printf "%T@\n" | sort -r | head -n 1)
+       fi
+
+       echo "# Last modified: ${my_mtime}" >> ${output}
+       echo "" >> ${output}
+}
+
+list_parse() {
+       if [ -L "$1" ]; then
+               return
+       fi
+       echo "$1" | sed 's/:/\\:/g; s/$/ \\/'
+}
+
+# for each file print a line in following format
+# <filetype> <name> <path to file> <octal mode> <uid> <gid>
+# for links, devices etc the format differs. See gen_init_cpio for details
+parse() {
+       local location="$1"
+       local name="/${location#${srcdir}}"
+       # change '//' into '/'
+       name=$(echo "$name" | sed -e 's://*:/:g')
+       local mode="$2"
+       local uid="$3"
+       local gid="$4"
+       local ftype=$(filetype "${location}")
+       # remap uid/gid to 0 if necessary
+       [ "$root_uid" = "squash" ] && uid=0 || [ "$uid" -eq "$root_uid" ] && uid=0
+       [ "$root_gid" = "squash" ] && gid=0 || [ "$gid" -eq "$root_gid" ] && gid=0
+       local str="${mode} ${uid} ${gid}"
+
+       [ "${ftype}" = "invalid" ] && return 0
+       [ "${location}" = "${srcdir}" ] && return 0
+
+       case "${ftype}" in
+               "file")
+                       str="${ftype} ${name} ${location} ${str}"
+                       ;;
+               "nod")
+                       local dev=`LC_ALL=C ls -l "${location}"`
+                       local maj=`field 5 ${dev}`
+                       local min=`field 6 ${dev}`
+                       maj=${maj%,}
+
+                       [ -b "${location}" ] && dev="b" || dev="c"
+
+                       str="${ftype} ${name} ${str} ${dev} ${maj} ${min}"
+                       ;;
+               "slink")
+                       local target=`readlink "${location}"`
+                       str="${ftype} ${name} ${target} ${str}"
+                       ;;
+               *)
+                       str="${ftype} ${name} ${str}"
+                       ;;
+       esac
+
+       echo "${str}" >> ${output}
+
+       return 0
+}
+
+unknown_option() {
+       printf "ERROR: unknown option \"$arg\"\n" >&2
+       printf "If the filename validly begins with '-', " >&2
+       printf "then it must be prefixed\n" >&2
+       printf "by './' so that it won't be interpreted as an option." >&2
+       printf "\n" >&2
+       usage >&2
+       exit 1
+}
+
+list_header() {
+       :
+}
+
+header() {
+       printf "\n#####################\n# $1\n" >> ${output}
+}
+
+# process one directory (incl sub-directories)
+dir_filelist() {
+       ${dep_list}header "$1"
+
+       srcdir=$(echo "$1" | sed -e 's://*:/:g')
+       dirlist=$(find "${srcdir}" -printf "%p %m %U %G\n" | LANG=C sort)
+
+       # If $dirlist is only one line, then the directory is empty
+       if [  "$(echo "${dirlist}" | wc -l)" -gt 1 ]; then
+               ${dep_list}print_mtime "$1"
+
+               echo "${dirlist}" | \
+               while read x; do
+                       ${dep_list}parse ${x}
+               done
+       fi
+}
+
+# if only one file is specified and it is .cpio file then use it direct as fs
+# if a directory is specified then add all files in given direcotry to fs
+# if a regular file is specified assume it is in gen_initramfs format
+input_file() {
+       source="$1"
+       if [ -f "$1" ]; then
+               ${dep_list}header "$1"
+               is_cpio="$(echo "$1" | sed 's/^.*\.cpio\(\..*\)\{0,1\}/cpio/')"
+               if [ $2 -eq 0 -a ${is_cpio} = "cpio" ]; then
+                       cpio_file=$1
+                       echo "$1" | grep -q '^.*\.cpio\..*' && is_cpio_compressed="compressed"
+                       [ ! -z ${dep_list} ] && echo "$1"
+                       return 0
+               fi
+               if [ -z ${dep_list} ]; then
+                       print_mtime "$1" >> ${output}
+                       cat "$1"         >> ${output}
+               else
+                       echo "$1 \\"
+                       cat "$1" | while read type dir file perm ; do
+                               if [ "$type" = "file" ]; then
+                                       echo "$file \\";
+                               fi
+                       done
+               fi
+       elif [ -d "$1" ]; then
+               dir_filelist "$1"
+       else
+               echo "  ${prog}: Cannot open '$1'" >&2
+               exit 1
+       fi
+}
+
+prog=$0
+root_uid=0
+root_gid=0
+dep_list=
+cpio_file=
+cpio_list=
+output="/dev/stdout"
+output_file=""
+is_cpio_compressed=
+compr="gzip -n -9 -f"
+
+arg="$1"
+case "$arg" in
+       "-l")   # files included in initramfs - used by kbuild
+               dep_list="list_"
+               echo "deps_initramfs := $0 \\"
+               shift
+               ;;
+       "-o")   # generate compressed cpio image named $1
+               shift
+               output_file="$1"
+               cpio_list="$(mktemp ${TMPDIR:-/tmp}/cpiolist.XXXXXX)"
+               output=${cpio_list}
+               echo "$output_file" | grep -q "\.gz$" \
+                && [ -x "`which gzip 2> /dev/null`" ] \
+                && compr="gzip -n -9 -f"
+               echo "$output_file" | grep -q "\.bz2$" \
+                && [ -x "`which bzip2 2> /dev/null`" ] \
+                && compr="bzip2 -9 -f"
+               echo "$output_file" | grep -q "\.lzma$" \
+                && [ -x "`which lzma 2> /dev/null`" ] \
+                && compr="lzma -9 -f"
+               echo "$output_file" | grep -q "\.xz$" \
+                && [ -x "`which xz 2> /dev/null`" ] \
+                && compr="xz --check=crc32 --lzma2=dict=1MiB"
+               echo "$output_file" | grep -q "\.lzo$" \
+                && [ -x "`which lzop 2> /dev/null`" ] \
+                && compr="lzop -9 -f"
+               echo "$output_file" | grep -q "\.lz4$" \
+                && [ -x "`which lz4 2> /dev/null`" ] \
+                && compr="lz4 -l -9 -f"
+               echo "$output_file" | grep -q "\.cpio$" && compr="cat"
+               shift
+               ;;
+esac
+while [ $# -gt 0 ]; do
+       arg="$1"
+       shift
+       case "$arg" in
+               "-u")   # map $1 to uid=0 (root)
+                       root_uid="$1"
+                       [ "$root_uid" = "-1" ] && root_uid=$(id -u || echo 0)
+                       shift
+                       ;;
+               "-g")   # map $1 to gid=0 (root)
+                       root_gid="$1"
+                       [ "$root_gid" = "-1" ] && root_gid=$(id -g || echo 0)
+                       shift
+                       ;;
+               "-d")   # display default initramfs list
+                       default_list="$arg"
+                       ${dep_list}default_initramfs
+                       ;;
+               "-h")
+                       usage
+                       exit 0
+                       ;;
+               *)
+                       case "$arg" in
+                               "-"*)
+                                       unknown_option
+                                       ;;
+                               *)      # input file/dir - process it
+                                       input_file "$arg" "$#"
+                                       ;;
+                       esac
+                       ;;
+       esac
+done
+
+# If output_file is set we will generate cpio archive and compress it
+# we are careful to delete tmp files
+if [ ! -z ${output_file} ]; then
+       if [ -z ${cpio_file} ]; then
+               timestamp=
+               if test -n "$KBUILD_BUILD_TIMESTAMP"; then
+                       timestamp="$(date -d"$KBUILD_BUILD_TIMESTAMP" +%s || :)"
+                       if test -n "$timestamp"; then
+                               timestamp="-t $timestamp"
+                       fi
+               fi
+               cpio_tfile="$(mktemp ${TMPDIR:-/tmp}/cpiofile.XXXXXX)"
+               usr/gen_init_cpio $timestamp ${cpio_list} > ${cpio_tfile}
+       else
+               cpio_tfile=${cpio_file}
+       fi
+       rm ${cpio_list}
+       if [ "${is_cpio_compressed}" = "compressed" ]; then
+               cat ${cpio_tfile} > ${output_file}
+       else
+               (cat ${cpio_tfile} | ${compr}  - > ${output_file}) \
+               || (rm -f ${output_file} ; false)
+       fi
+       [ -z ${cpio_file} ] && rm ${cpio_tfile}
+fi
+exit 0