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
subdir-y += sifive
subdir-$(CONFIG_SOC_CANAAN_K210_DTB_BUILTIN) += canaan
subdir-y += microchip
+subdir-y += starfive
obj-$(CONFIG_BUILTIN_DTB) := $(addsuffix /, $(subdir-y))
--- /dev/null
+# SPDX-License-Identifier: GPL-2.0
+dtb-$(CONFIG_SOC_STARFIVE_JH7110) += starfive_jh7110.dtb
--- /dev/null
+// 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";
+ };
+ };
+};
--- /dev/null
+&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
--- /dev/null
+// 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>;
+ };
+};
--- /dev/null
+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
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"
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
--- /dev/null
+/*
+ ******************************************************************************
+ * @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");
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 },
{ }
};
.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,
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)
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);
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;
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;
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)
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
#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;
}
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;
#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 */
--- /dev/null
+#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*/
--- /dev/null
+#!/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