diff --git a/Documentation/devicetree/bindings/ata/hisilicon,hi3520dv200-ahci.yaml b/Documentation/devicetree/bindings/ata/hisilicon,hi3520dv200-ahci.yaml new file mode 100644 index 00000000000..04899855850 --- /dev/null +++ b/Documentation/devicetree/bindings/ata/hisilicon,hi3520dv200-ahci.yaml @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/ata/hisilicon,hi3520dv200-ahci.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: HiSilicon Hi3520DV200 AHCI SATA controller + +maintainers: + - Bjorn Stout + +description: + The Hi3520DV200's two-port AHCI controller. Its PHYs are clocked, taken + out of reset and programmed by the driver through the SoC's SATA + clock/reset register (PERI_CRG45) before the AHCI core is started. + +properties: + compatible: + const: hisilicon,hi3520dv200-ahci + + reg: + items: + - description: AHCI registers, including the vendor PHY registers + - description: PERI_CRG45, the SATA clock and reset register + + interrupts: + maxItems: 1 + + hisilicon,phy-config: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Value for the per-port PHY control register (port offset 0x74). + HiSilicon's Hi3520D reference value, 0x0e276756, is the default. + XiongMai boards need 0x0e262709, the value their vendor firmware + writes; with the default their link keeps resetting. + default: 0x0e276756 + +required: + - compatible + - reg + - interrupts + +additionalProperties: false + +examples: + - | + #include + + sata@10080000 { + compatible = "hisilicon,hi3520dv200-ahci"; + reg = <0x10080000 0x10000>, <0x200300b4 0x4>; + interrupts = ; + hisilicon,phy-config = <0x0e262709>; + }; diff --git a/Documentation/devicetree/bindings/cache/hisilicon,hi3520dv200-l2cache.yaml b/Documentation/devicetree/bindings/cache/hisilicon,hi3520dv200-l2cache.yaml new file mode 100644 index 00000000000..2625f7ad8db --- /dev/null +++ b/Documentation/devicetree/bindings/cache/hisilicon,hi3520dv200-l2cache.yaml @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/cache/hisilicon,hi3520dv200-l2cache.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: HiSilicon Hi3520DV200 L2 cache controller (hil2v200) + +maintainers: + - Bjorn Stout + +description: + HiSilicon's own outer cache controller in the Hi3520DV200, 128 KB with + 8 ways and 32-byte lines. It is not an ARM PL310 (its ID register reads 0) + and is maintained by address, by way and set, or a whole way at a time. + +allOf: + - $ref: /schemas/cache-controller.yaml# + +properties: + compatible: + const: hisilicon,hi3520dv200-l2cache + + reg: + maxItems: 1 + + interrupts: + items: + - description: check 0 (error) interrupt + - description: check 1 (error) interrupt + - description: combined interrupt + + cache-unified: true + + cache-level: + const: 2 + +required: + - compatible + - reg + - cache-unified + - cache-level + +unevaluatedProperties: false + +examples: + - | + #include + + cache-controller@20700000 { + compatible = "hisilicon,hi3520dv200-l2cache"; + reg = <0x20700000 0x10000>; + interrupts = , + , + ; + cache-unified; + cache-level = <2>; + }; diff --git a/Documentation/devicetree/bindings/net/hisilicon-femac-mdio.txt b/Documentation/devicetree/bindings/net/hisilicon-femac-mdio.txt index 23a39a309d1..f7e3749e60d 100644 --- a/Documentation/devicetree/bindings/net/hisilicon-femac-mdio.txt +++ b/Documentation/devicetree/bindings/net/hisilicon-femac-mdio.txt @@ -1,8 +1,11 @@ Hisilicon Fast Ethernet MDIO Controller interface Required properties: -- compatible: should be "hisilicon,hisi-femac-mdio". -- reg: address and length of the register set for the device. +- compatible: should be "hisilicon,hisi-femac-mdio", or + "hisilicon,hi3520dv200-femac-mdio" followed by "hisilicon,hisi-femac-mdio". +- reg: address and length of the register set for the device. On + "hisilicon,hi3520dv200-femac-mdio" a second entry gives the internal PHY + control register, whose low five bits set the address the PHY answers at. - clocks: A phandle to the reference clock for this device. - PHY subnode: inherits from phy binding [1] diff --git a/Documentation/devicetree/bindings/spi/hisilicon,hi3520dv200-sfc.yaml b/Documentation/devicetree/bindings/spi/hisilicon,hi3520dv200-sfc.yaml new file mode 100644 index 00000000000..6caacf87985 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/hisilicon,hi3520dv200-sfc.yaml @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/hisilicon,hi3520dv200-sfc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: HiSilicon Hi3520DV200 SPI flash controller (SFC v350) + +maintainers: + - Bjorn Stout + +description: + The SPI-NOR controller of the Hi3520DV200 (hardware version 0x350), with + the register layout of the v3xx controllers handled by spi-hisi-sfc-v3xx. + Without an interrupt the driver polls for completion. + +allOf: + - $ref: spi-controller.yaml# + +properties: + compatible: + const: hisilicon,hi3520dv200-sfc + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + num-cs: + description: + Number of chip selects. The flash on Hi3520DV200 boards is on CS1. + maximum: 2 + default: 1 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + spi@10010000 { + compatible = "hisilicon,hi3520dv200-sfc"; + reg = <0x10010000 0x1000>; + num-cs = <2>; + #address-cells = <1>; + #size-cells = <0>; + + flash@1 { + compatible = "jedec,spi-nor"; + reg = <1>; + label = "hi_sfc"; + spi-max-frequency = <50000000>; + }; + }; diff --git a/arch/arm/boot/dts/hisilicon/Makefile b/arch/arm/boot/dts/hisilicon/Makefile index 5ac6b100566..c191a45f8e4 100644 --- a/arch/arm/boot/dts/hisilicon/Makefile +++ b/arch/arm/boot/dts/hisilicon/Makefile @@ -26,5 +26,7 @@ dtb-$(CONFIG_ARCH_HI3516CV100) += \ hi3516cv100-demb.dtb dtb-$(CONFIG_ARCH_HI3516AV100) += \ hi3516av100-demb.dtb +dtb-$(CONFIG_ARCH_HI3520DV200) += \ + hi3520dv200-nbd6808t.dtb dtb-$(CONFIG_ARCH_HI3519V101) += \ hi3519v101-demb.dtb diff --git a/arch/arm/boot/dts/hisilicon/hi3520dv200-nbd6808t.dts b/arch/arm/boot/dts/hisilicon/hi3520dv200-nbd6808t.dts new file mode 100644 index 00000000000..3c5661f2a7c --- /dev/null +++ b/arch/arm/boot/dts/hisilicon/hi3520dv200-nbd6808t.dts @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR MIT) +/* + * XiongMai NBD6808T-PL NVR (MBD0157 board), Hi3520DV200, 8 MB SPI NOR. + */ + +/dts-v1/; +#include "hi3520dv200.dtsi" + +/ { + model = "XiongMai NBD6808T-PL (Hi3520DV200)"; + compatible = "xiongmai,nbd6808t-pl", "hisilicon,hi3520dv200"; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + /* + * 256 MB of DDR. The vendor firmware gave Linux the first 128 MB and + * the rest to the media memory zone; without the MPP all of it is + * ordinary memory except the VGA framebuffer reserved below. + */ + memory@80000000 { + device_type = "memory"; + reg = <0x80000000 0x10000000>; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + vga_fb_mem: framebuffer@8f000000 { + reg = <0x8f000000 0x400000>; + no-map; + }; + }; + + /* + * VGA, 1920x1080@60. The vendor bootloader drives the display + * controller ("startvo 0 4 10; startgx 0 0x8f000000 3840 0 0 1920 + * 1080" opens VGA at 1080p60 and graphics layer 0 at this buffer, + * scanned out as ARGB1555 with the alpha bit ignored); Linux only + * draws into it. Without those bootloader commands nothing is shown. + */ + framebuffer@8f000000 { + compatible = "simple-framebuffer"; + reg = <0x8f000000 0x3f4800>; + memory-region = <&vga_fb_mem>; + width = <1920>; + height = <1080>; + stride = <3840>; + format = "x1r5g5b5"; + }; +}; + +&uart0 { + status = "okay"; +}; + +/* The RJ45 is on the up port, through the SoC's internal PHY at address 3. */ +&mdio { + status = "okay"; + + phy_up: ethernet-phy@3 { + reg = <3>; + }; +}; + +ð_up { + phy-handle = <&phy_up>; + phy-mode = "mii"; + status = "okay"; +}; + +/* + * 8 MB MX25L6406E on CS1. The partitions below are the stock firmware's + * layout, read-only; they only apply when the bootloader passes no + * "mtdparts=hi_sfc:..." of its own. + */ +&sfc { + status = "okay"; + + flash@1 { + compatible = "jedec,spi-nor"; + reg = <1>; + /* the name both the vendor and OpenIPC bootloaders use in mtdparts= */ + label = "hi_sfc"; + spi-max-frequency = <50000000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "boot"; + reg = <0x000000 0x030000>; + read-only; + }; + partition@30000 { + label = "romfs"; + reg = <0x030000 0x1f0000>; + read-only; + }; + partition@220000 { + label = "usr"; + reg = <0x220000 0x3b0000>; + read-only; + }; + partition@5d0000 { + label = "custom"; + reg = <0x5d0000 0x1a0000>; + read-only; + }; + partition@770000 { + label = "logo"; + reg = <0x770000 0x010000>; + read-only; + }; + partition@780000 { + label = "mtd"; + reg = <0x780000 0x080000>; + read-only; + }; + /* the whole chip, for verifying it against a backup */ + partition@0-all { + label = "all"; + reg = <0x000000 0x800000>; + read-only; + }; + }; + }; +}; + +/* + * The vendor firmware's PHY value; with the Hi3520D reference one this + * board's link keeps resetting. + */ +&sata { + hisilicon,phy-config = <0x0e262709>; + status = "okay"; +}; + +&ohci { + status = "okay"; +}; + +&ehci { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/hisilicon/hi3520dv200.dtsi b/arch/arm/boot/dts/hisilicon/hi3520dv200.dtsi new file mode 100644 index 00000000000..ce9fcb82492 --- /dev/null +++ b/arch/arm/boot/dts/hisilicon/hi3520dv200.dtsi @@ -0,0 +1,210 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR MIT) +/* + * HiSilicon Hi3520DV200 NVR/DVR SoC: a single Cortex-A9 with GIC, SP804 + * timers and a HiSilicon (not PL310) L2 cache controller. + * + * Addresses and interrupt numbers follow the vendor 3.0.8 BSP + * (arch/arm/mach-hi3520d: platform.h, irqs.h). There is no clock driver + * yet: the rates below are fixed-clocks matching what the vendor bootloader + * programs (24 MHz crystal, 330 MHz bus). The SP804s and the PL011s both + * run from bus/4; the vendor kernel selects the APB source for the UARTs + * in PERI_CRG57 (0x200300e4), which the bootloader already leaves set. + */ + +#include +#include + +/ { + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&gic>; + + aliases { + serial0 = &uart0; + serial1 = &uart1; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + reg = <0>; + }; + }; + + xtal: clock-24m { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + clock-output-names = "xtal"; + }; + + /* APB/bus clock; U-Boot leaves the PLL at 1320 MHz, bus = PLL/4. */ + busclk: clock-bus { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <330000000>; + clock-output-names = "busclk"; + }; + + /* bus/4: feeds the SP804 timers and, with the APB source selected, the UARTs. */ + timerclk: clock-timer { + compatible = "fixed-factor-clock"; + #clock-cells = <0>; + clocks = <&busclk>; + clock-div = <4>; + clock-mult = <1>; + clock-output-names = "timerclk"; + }; + + /* SP805 reference clock, measured: LOAD 0x10000000 resets after ~179 s. */ + wdtclk: clock-3m { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <3000000>; + clock-output-names = "wdtclk"; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + scu@20300000 { + compatible = "arm,cortex-a9-scu"; + reg = <0x20300000 0x100>; + }; + + gic: interrupt-controller@20301000 { + compatible = "arm,cortex-a9-gic"; + #interrupt-cells = <3>; + #address-cells = <0>; + interrupt-controller; + reg = <0x20301000 0x1000>, <0x20300100 0x100>; + }; + + /* + * HiSilicon's own L2 controller ("hil2v200"), not a PL310: its + * ID register reads 0. 128 KB, 8 ways, 32-byte lines. + */ + l2: cache-controller@20700000 { + compatible = "hisilicon,hi3520dv200-l2cache"; + reg = <0x20700000 0x10000>; + interrupts = , + , + ; + cache-unified; + cache-level = <2>; + }; + + timer0: timer@20000000 { + compatible = "arm,sp804", "arm,primecell"; + reg = <0x20000000 0x1000>; + interrupts = ; + clocks = <&timerclk>, <&timerclk>, <&busclk>; + clock-names = "timer0clk", "timer1clk", "apb_pclk"; + }; + + timer1: timer@20010000 { + compatible = "arm,sp804", "arm,primecell"; + reg = <0x20010000 0x1000>; + interrupts = ; + clocks = <&timerclk>, <&timerclk>, <&busclk>; + clock-names = "timer0clk", "timer1clk", "apb_pclk"; + status = "disabled"; + }; + + watchdog@20040000 { + compatible = "arm,sp805", "arm,primecell"; + reg = <0x20040000 0x1000>; + clocks = <&wdtclk>, <&busclk>; + clock-names = "wdog_clk", "apb_pclk"; + }; + + /* SFC v350: the register layout of the v3xx SPI-NOR controller. */ + sfc: spi@10010000 { + compatible = "hisilicon,hi3520dv200-sfc"; + reg = <0x10010000 0x1000>; + num-cs = <2>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + /* reg 1 is PERI_CRG45, the SATA clock/reset register */ + sata: sata@10080000 { + compatible = "hisilicon,hi3520dv200-ahci"; + reg = <0x10080000 0x10000>, <0x200300b4 0x4>; + interrupts = ; + status = "disabled"; + }; + + /* + * USB 2.0 host. The bootloader enables its clock and PHY + * (PERI_CRG46 0x200300b8, PERI_USB 0x20050080) when it scans + * the bus. + */ + ohci: usb@100a0000 { + compatible = "generic-ohci"; + reg = <0x100a0000 0x10000>; + interrupts = ; + status = "disabled"; + }; + + ehci: usb@100b0000 { + compatible = "generic-ehci"; + reg = <0x100b0000 0x10000>; + interrupts = ; + status = "disabled"; + }; + + /* + * The "hieth-sf" switch-fabric MAC: two ports, up (0x0000) and + * down (+0x2000), sharing global registers at +0x1300 and an + * MDIO controller at +0x1100. The up port's registers and bits + * are those of hisi-femac, which drives it with the global block + * passed as its second region. + */ + mdio: mdio@10091100 { + compatible = "hisilicon,hi3520dv200-femac-mdio", + "hisilicon,hisi-femac-mdio"; + /* MDIO, then the internal PHY control (SYS_CTRL PERI24) */ + reg = <0x10091100 0x10>, <0x20050094 0x4>; + clocks = <&busclk>; + clock-names = "mdio"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + eth_up: ethernet@10090000 { + compatible = "hisilicon,hisi-femac-v1"; + reg = <0x10090000 0x1000>, <0x10091300 0x200>; + interrupts = ; + clocks = <&busclk>; + status = "disabled"; + }; + + uart0: serial@20080000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x20080000 0x1000>; + interrupts = ; + clocks = <&timerclk>, <&busclk>; + clock-names = "uartclk", "apb_pclk"; + status = "disabled"; + }; + + uart1: serial@20090000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x20090000 0x1000>; + interrupts = ; + clocks = <&timerclk>, <&busclk>; + clock-names = "uartclk", "apb_pclk"; + status = "disabled"; + }; + }; +}; diff --git a/arch/arm/configs/hi3520dv200_defconfig b/arch/arm/configs/hi3520dv200_defconfig new file mode 100644 index 00000000000..76f1833c4f1 --- /dev/null +++ b/arch/arm/configs/hi3520dv200_defconfig @@ -0,0 +1,204 @@ +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_KERNEL_XZ=y +CONFIG_SYSVIPC=y +# CONFIG_CROSS_MEMORY_ATTACH is not set +CONFIG_NO_HZ_IDLE=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_GZIP is not set +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +# CONFIG_RD_ZSTD is not set +# CONFIG_INITRAMFS_PRESERVE_MTIME is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_EXPERT=y +# CONFIG_UID16 is not set +# CONFIG_FHANDLE is not set +# CONFIG_BUG is not set +# CONFIG_AIO is not set +# CONFIG_IO_URING is not set +# CONFIG_ADVISE_SYSCALLS is not set +# CONFIG_MEMBARRIER is not set +# CONFIG_RSEQ is not set +# CONFIG_CACHESTAT_SYSCALL is not set +# CONFIG_KALLSYMS is not set +CONFIG_ARCH_HISI_BVT=y +CONFIG_ARCH_HI3520DV200=y +# CONFIG_HARDEN_BRANCH_PREDICTOR is not set +# CONFIG_HARDEN_BRANCH_HISTORY is not set +# CONFIG_KUSER_HELPERS is not set +# CONFIG_CACHE_L2X0 is not set +CONFIG_ARM_ERRATA_754322=y +# CONFIG_ARM_PATCH_IDIV is not set +# CONFIG_ARM_PAN is not set +CONFIG_ARM_APPENDED_DTB=y +CONFIG_ARM_ATAG_DTB_COMPAT=y +CONFIG_VFP=y +CONFIG_NEON=y +# CONFIG_SUSPEND is not set +# CONFIG_SECCOMP is not set +# CONFIG_STACKPROTECTOR is not set +# CONFIG_VMAP_STACK is not set +# CONFIG_STRICT_KERNEL_RWX is not set +# CONFIG_GCC_PLUGINS is not set +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_BLOCK_LEGACY_AUTOLOAD is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_EFI_PARTITION is not set +# CONFIG_MQ_IOSCHED_DEADLINE is not set +# CONFIG_MQ_IOSCHED_KYBER is not set +# CONFIG_COREDUMP is not set +# CONFIG_SWAP is not set +# CONFIG_SLAB_MERGE_DEFAULT is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_COMPACTION is not set +# CONFIG_VM_EVENT_COUNTERS is not set +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +# CONFIG_AF_UNIX_OOB is not set +CONFIG_INET=y +CONFIG_IP_PNP=y +# CONFIG_INET_DIAG is not set +# CONFIG_IPV6 is not set +# CONFIG_BQL is not set +# CONFIG_WIRELESS is not set +# CONFIG_ETHTOOL_NETLINK is not set +CONFIG_UEVENT_HELPER=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_STANDALONE is not set +# CONFIG_PREVENT_FIRMWARE_BUILD is not set +# CONFIG_FW_LOADER is not set +# CONFIG_ALLOW_DEV_COREDUMP is not set +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_SPI_NOR=y +# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=16384 +# CONFIG_SCSI_PROC_FS is not set +CONFIG_BLK_DEV_SD=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_SCSI_LOWLEVEL is not set +CONFIG_ATA=y +# CONFIG_ATA_VERBOSE_ERROR is not set +# CONFIG_ATA_FORCE is not set +# CONFIG_SATA_PMP is not set +CONFIG_AHCI_HI3520DV200=y +# CONFIG_ATA_SFF is not set +CONFIG_NETDEVICES=y +CONFIG_WIREGUARD=m +# 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_ASIX 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_CIRRUS is not set +# CONFIG_NET_VENDOR_CORTINA is not set +# CONFIG_NET_VENDOR_DAVICOM is not set +# CONFIG_NET_VENDOR_ENGLEDER is not set +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_FUNGIBLE is not set +# CONFIG_NET_VENDOR_GOOGLE is not set +CONFIG_HISI_FEMAC=y +# CONFIG_NET_VENDOR_HUAWEI is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_ADI is not set +# CONFIG_NET_VENDOR_LITEX is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_META 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_MICROSOFT is not set +# CONFIG_NET_VENDOR_MUCSE is not set +# CONFIG_NET_VENDOR_NI is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_PENSANDO is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# 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_SMSC is not set +# CONFIG_NET_VENDOR_SOCIONEXT is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_VERTEXCOM is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WANGXUN is not set +# CONFIG_NET_VENDOR_WIZNET is not set +# CONFIG_NET_VENDOR_XILINX is not set +CONFIG_MDIO_HISI_FEMAC=y +# CONFIG_USB_NET_DRIVERS is not set +# CONFIG_WLAN is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_LEGACY_TIOCSTI is not set +# CONFIG_LDISC_AUTOLOAD is not set +CONFIG_SERIAL_AMBA_PL011=y +CONFIG_SERIAL_AMBA_PL011_CONSOLE=y +# CONFIG_HW_RANDOM is not set +# CONFIG_DEVPORT is not set +CONFIG_SPI=y +CONFIG_SPI_HISI_SFC_V3XX=y +# CONFIG_PTP_1588_CLOCK is not set +# CONFIG_HWMON is not set +CONFIG_WATCHDOG=y +CONFIG_ARM_SP805_WATCHDOG=y +CONFIG_FB=y +CONFIG_FB_SIMPLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_USB=y +# CONFIG_USB_DEFAULT_PERSIST is not set +CONFIG_USB_EHCI_HCD=y +# CONFIG_USB_EHCI_TT_NEWSCHED is not set +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PLATFORM=y +CONFIG_USB_STORAGE=y +# CONFIG_VIRTIO_MENU is not set +# CONFIG_VHOST_MENU is not set +# CONFIG_IOMMU_SUPPORT is not set +# CONFIG_NVMEM is not set +CONFIG_EXT4_FS=y +# CONFIG_EXT4_USE_FOR_EXT2 is not set +# CONFIG_DNOTIFY is not set +CONFIG_OVERLAY_FS=y +# CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW is not set +CONFIG_VFAT_FS=y +# CONFIG_PROC_PAGE_MONITOR is not set +CONFIG_TMPFS=y +CONFIG_TMPFS_XATTR=y +CONFIG_JFFS2_FS=y +# CONFIG_JFFS2_FS_WRITEBUFFER is not set +CONFIG_SQUASHFS=y +CONFIG_SQUASHFS_XZ=y +# CONFIG_NETWORK_FILESYSTEMS is not set +# CONFIG_CRC_OPTIMIZATIONS is not set +# CONFIG_XZ_DEC_X86 is not set +# CONFIG_XZ_DEC_POWERPC is not set +# CONFIG_XZ_DEC_ARM is not set +# CONFIG_XZ_DEC_ARMTHUMB is not set +# CONFIG_XZ_DEC_ARM64 is not set +# CONFIG_XZ_DEC_SPARC is not set +# CONFIG_XZ_DEC_RISCV is not set +CONFIG_FONTS=y +# CONFIG_SYMBOLIC_ERRNAME is not set +# CONFIG_DEBUG_MISC is not set +# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set +# CONFIG_SLUB_DEBUG is not set +# CONFIG_FTRACE is not set +# CONFIG_RUNTIME_TESTING_MENU is not set diff --git a/arch/arm/include/asm/hardware/cache-hil2v200.h b/arch/arm/include/asm/hardware/cache-hil2v200.h new file mode 100644 index 00000000000..d51917e1527 --- /dev/null +++ b/arch/arm/include/asm/hardware/cache-hil2v200.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef __ASM_ARM_HARDWARE_CACHE_HIL2V200_H +#define __ASM_ARM_HARDWARE_CACHE_HIL2V200_H + +#include +#include + +#ifdef CONFIG_CACHE_HIL2V200 +int __init hil2v200_of_init(void); +#else +static inline int hil2v200_of_init(void) { return -ENODEV; } +#endif + +#endif diff --git a/arch/arm/mach-hibvt/Kconfig b/arch/arm/mach-hibvt/Kconfig index 2ae8e548e1e..f4f67ade321 100644 --- a/arch/arm/mach-hibvt/Kconfig +++ b/arch/arm/mach-hibvt/Kconfig @@ -173,6 +173,19 @@ config ARCH_HI3518EV20X help Support for Hisilicon Hi3518ev20x Soc family. +config ARCH_HI3520DV200 + bool "Hisilicon Hi3520DV200 Cortex-A9 family" + depends on ARCH_MULTI_V7 + select ARM_GIC + select HAVE_ARM_SCU + select ARM_TIMER_SP804 + help + Support for the Hisilicon Hi3520DV200, a single Cortex-A9 SoC + used in NVR and DVR boards. It has a GIC, SP804 timers, an + SP805 watchdog, HiSilicon's own L2 cache controller, a SATA + controller, USB 2.0, a switch-fabric Ethernet MAC and an + SFC v350 SPI-NOR controller. + config ARCH_HI3536DV100 bool "Hisilicon Hi3536DV100 Cortex-A7(Single) family" depends on ARCH_MULTI_V7 diff --git a/arch/arm/mach-hibvt/Makefile b/arch/arm/mach-hibvt/Makefile index 51770f67f47..efc252e8a2e 100644 --- a/arch/arm/mach-hibvt/Makefile +++ b/arch/arm/mach-hibvt/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_ARCH_HI3556V200) += mach-hi3556v200.o obj-$(CONFIG_ARCH_HI3559V200) += mach-hi3559v200.o obj-$(CONFIG_ARCH_HI3518EV20X) += mach-hi3518ev20x.o obj-$(CONFIG_ARCH_HI3516CV100) += mach-hi3518ev20x.o +obj-$(CONFIG_ARCH_HI3520DV200) += mach-hi3520dv200.o obj-$(CONFIG_ARCH_HI3536DV100) += mach-hi3536dv100.o obj-$(CONFIG_ARCH_HI3521A) += mach-hi3521a.o obj-$(CONFIG_ARCH_HI3531A) += mach-hi3531a.o diff --git a/arch/arm/mach-hibvt/mach-hi3520dv200.c b/arch/arm/mach-hibvt/mach-hi3520dv200.c new file mode 100644 index 00000000000..a1f53e711a5 --- /dev/null +++ b/arch/arm/mach-hibvt/mach-hi3520dv200.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Hi3520DV200 (single Cortex-A9 NVR/DVR SoC). + * + * Everything the kernel needs comes from the device tree; the GIC and the + * SP804 timers have generic drivers. + */ + +#include +#include +#include + +static const char *const hi3520dv200_compat[] __initconst = { + "hisilicon,hi3520dv200", + NULL, +}; + +/* + * The L2 is HiSilicon's own controller, so it is brought up here, at the + * point where the core would initialise a PL310. + */ +static void __init hi3520dv200_init_irq(void) +{ + irqchip_init(); + hil2v200_of_init(); +} + +DT_MACHINE_START(HI3520DV200_DT, "Hisilicon Hi3520DV200 (Flattened Device Tree)") + .dt_compat = hi3520dv200_compat, + .init_irq = hi3520dv200_init_irq, +MACHINE_END diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 7b27ee9482b..ebe12782eb0 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -984,6 +984,19 @@ config MIGHT_HAVE_CACHE_L2X0 instead of this option, thus preventing the user from inadvertently configuring a broken kernel. +config CACHE_HIL2V200 + bool "Enable the HiSilicon L2 cache controller v200" + depends on ARCH_HI3520DV200 + default y + select OUTER_CACHE + select OUTER_CACHE_SYNC + help + This option enables the HiSilicon "hil2v200" L2 cache controller + found in the Hi3520DV200 (128 KB, 8 ways). It is not a PL310: + lines are maintained by physical address through its own + registers, and it is driven as an outer cache. Without it the + SoC runs with its L2 disabled. + config CACHE_L2X0 bool "Enable the L2x0 outer cache controller" if MIGHT_HAVE_CACHE_L2X0 default MIGHT_HAVE_CACHE_L2X0 diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile index 1e220101337..64dbd206404 100644 --- a/arch/arm/mm/Makefile +++ b/arch/arm/mm/Makefile @@ -94,6 +94,7 @@ obj-$(CONFIG_CFI) += proc.o obj-$(CONFIG_OUTER_CACHE) += l2c-common.o obj-$(CONFIG_CACHE_B15_RAC) += cache-b15-rac.o obj-$(CONFIG_CACHE_FEROCEON_L2) += cache-feroceon-l2.o +obj-$(CONFIG_CACHE_HIL2V200) += cache-hil2v200.o obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o l2c-l2x0-resume.o obj-$(CONFIG_CACHE_L2X0_PMU) += cache-l2x0-pmu.o obj-$(CONFIG_CACHE_XSC3L2) += cache-xsc3l2.o diff --git a/arch/arm/mm/cache-hil2v200.c b/arch/arm/mm/cache-hil2v200.c new file mode 100644 index 00000000000..ab4d061edd9 --- /dev/null +++ b/arch/arm/mm/cache-hil2v200.c @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * HiSilicon L2 cache controller v200 ("hil2v200"), as found in the + * Hi3520DV200. It is not an ARM PL310: maintenance is done a line at a time + * through the INVALID/CLEAN registers, by physical address or by way and + * set, or a whole way at a time through the AUTO register, and a read of + * SYNC drains the controller. + * + * Register layout and enable sequence follow the hil2v200 driver in the + * vendor's 3.0.8 BSP. + */ + +#define pr_fmt(fmt) "hil2v200: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +#define L2_CTRL 0x000 +#define L2_AUCTRL 0x004 +#define AUCTRL_EVENT_BUS_EN BIT(12) +#define AUCTRL_MONITOR_EN BIT(13) +#define L2_INTMASK 0x100 +#define L2_RINT 0x108 +#define RINT_AUTO_END BIT(14) +#define L2_INTCLR 0x10c +#define L2_SYNC 0x200 +#define L2_MAINT_AUTO 0x20c +#define MAINT_AUTO_START BIT(0) +#define MAINT_AUTO_CLEAN BIT(1) +#define MAINT_AUTO_WAY_SHIFT 2 +#define L2_INVALID 0x210 +#define L2_CLEAN 0x214 +/* INVALID/CLEAN take a physical line address, or a way and set index */ +#define OP_BY_ADDRESS BIT(0) +#define OP_WAY_SHIFT 29 +#define OP_SET_SHIFT 5 +#define L2_SPECIAL_CHECK0 0x804 +#define L2_SPECIAL_CHECK1 0x808 + +#define L2_LINE_SIZE 32 +#define L2_WAYS 8 +#define L2_SIZE SZ_128K /* Hi3520DV200 */ +#define L2_SETS (L2_SIZE / L2_WAYS / L2_LINE_SIZE) +/* bytes maintained per hold of the lock, to bound the time with IRQs off */ +#define L2_RANGE_BLOCK SZ_4K + +static void __iomem *l2_base; +static DEFINE_RAW_SPINLOCK(l2_lock); +static bool l2_off __initdata; + +/* "nol2": leave the L2 disabled, for comparisons or as an escape hatch. */ +static int __init hil2_nol2(char *unused) +{ + l2_off = true; + return 0; +} +early_param("nol2", hil2_nol2); + +/* Clean or invalidate one whole way and wait for the controller to finish. */ +static void hil2_way_op(unsigned int way, bool clean) +{ + u32 cmd = (way << MAINT_AUTO_WAY_SHIFT) | MAINT_AUTO_START; + + if (clean) + cmd |= MAINT_AUTO_CLEAN; + writel_relaxed(cmd, l2_base + L2_MAINT_AUTO); + while (!(readl_relaxed(l2_base + L2_RINT) & RINT_AUTO_END)) + cpu_relax(); + writel_relaxed(readl_relaxed(l2_base + L2_RINT), l2_base + L2_INTCLR); +} + +static void __hil2_inv_all(void) +{ + unsigned int way; + + for (way = 0; way < L2_WAYS; way++) + hil2_way_op(way, false); +} + +/* + * Clean and invalidate one line at a time, by way and set index. A clean of + * all ways followed by an invalidate of all ways would drop any line the + * CPU evicts into the L2 in between; there is no combined clean+invalidate + * of a way. + */ +static void hil2_flush_all(void) +{ + unsigned int way, set; + unsigned long flags; + u32 op; + + for (way = 0; way < L2_WAYS; way++) { + raw_spin_lock_irqsave(&l2_lock, flags); + for (set = 0; set < L2_SETS; set++) { + op = (way << OP_WAY_SHIFT) | (set << OP_SET_SHIFT); + writel_relaxed(op, l2_base + L2_CLEAN); + writel_relaxed(op, l2_base + L2_INVALID); + } + raw_spin_unlock_irqrestore(&l2_lock, flags); + } +} + +static void __hil2_flush_line(unsigned long addr) +{ + writel_relaxed(addr | OP_BY_ADDRESS, l2_base + L2_CLEAN); + writel_relaxed(addr | OP_BY_ADDRESS, l2_base + L2_INVALID); +} + +/* Clean (L2_CLEAN), invalidate (L2_INVALID) or both (0) every line in range. */ +static void hil2_range_op(unsigned long start, unsigned long end, + unsigned int reg) +{ + unsigned long addr, blk_end, flags; + + start &= ~(L2_LINE_SIZE - 1); + while (start < end) { + blk_end = start + min(end - start, (unsigned long)L2_RANGE_BLOCK); + + raw_spin_lock_irqsave(&l2_lock, flags); + for (addr = start; addr < blk_end; addr += L2_LINE_SIZE) { + if (reg) + writel_relaxed(addr | OP_BY_ADDRESS, l2_base + reg); + else + __hil2_flush_line(addr); + } + raw_spin_unlock_irqrestore(&l2_lock, flags); + start = blk_end; + } +} + +static void hil2_inv_range(unsigned long start, unsigned long end) +{ + unsigned long flags; + + /* + * Lines only partly in the range may hold dirty data from outside + * it: clean those before invalidating them. + */ + if (start & (L2_LINE_SIZE - 1)) { + start &= ~(L2_LINE_SIZE - 1); + raw_spin_lock_irqsave(&l2_lock, flags); + __hil2_flush_line(start); + raw_spin_unlock_irqrestore(&l2_lock, flags); + start += L2_LINE_SIZE; + } + if (start < end && (end & (L2_LINE_SIZE - 1))) { + end &= ~(L2_LINE_SIZE - 1); + raw_spin_lock_irqsave(&l2_lock, flags); + __hil2_flush_line(end); + raw_spin_unlock_irqrestore(&l2_lock, flags); + } + /* never widened to the whole cache: that would drop other dirty lines */ + hil2_range_op(start, end, L2_INVALID); +} + +static void hil2_clean_range(unsigned long start, unsigned long end) +{ + unsigned long flags; + unsigned int way; + + /* cleaning never loses data, so a whole-way clean is safe */ + if (end - start >= L2_SIZE) { + raw_spin_lock_irqsave(&l2_lock, flags); + for (way = 0; way < L2_WAYS; way++) + hil2_way_op(way, true); + raw_spin_unlock_irqrestore(&l2_lock, flags); + return; + } + hil2_range_op(start, end, L2_CLEAN); +} + +static void hil2_flush_range(unsigned long start, unsigned long end) +{ + hil2_range_op(start, end, 0); +} + +static void hil2_sync(void) +{ + readl_relaxed(l2_base + L2_SYNC); +} + +/* + * Turn the L2 off first, so that nothing is allocated into it any more and + * lines the CPU evicts go straight to memory, then clean and invalidate it. + * The vendor's suspend path does the same. + */ +static void hil2_disable(void) +{ + unsigned long flags; + unsigned int way; + + raw_spin_lock_irqsave(&l2_lock, flags); + writel_relaxed(0, l2_base + L2_CTRL); + for (way = 0; way < L2_WAYS; way++) + hil2_way_op(way, true); + __hil2_inv_all(); + raw_spin_unlock_irqrestore(&l2_lock, flags); +} + +int __init hil2v200_of_init(void) +{ + struct device_node *np; + u32 aux; + + if (l2_off) { + pr_info("disabled on the command line (nol2)\n"); + return -ENODEV; + } + + np = of_find_compatible_node(NULL, NULL, "hisilicon,hi3520dv200-l2cache"); + if (!np || !of_device_is_available(np)) { + of_node_put(np); + return -ENODEV; + } + l2_base = of_iomap(np, 0); + of_node_put(np); + if (!l2_base) + return -ENOMEM; + + writel_relaxed(0, l2_base + L2_CTRL); + + aux = readl_relaxed(l2_base + L2_AUCTRL); + writel_relaxed(aux | AUCTRL_EVENT_BUS_EN | AUCTRL_MONITOR_EN, + l2_base + L2_AUCTRL); + + /* + * Clear stale state. INTCLR is write-1-to-clear: a stale AUTO_END + * would make the first way operation look finished at once. The + * vendor enables all interrupts but AUTO_END. + */ + writel_relaxed(readl_relaxed(l2_base + L2_RINT), l2_base + L2_INTCLR); + writel_relaxed(0, l2_base + L2_SPECIAL_CHECK0); + writel_relaxed(0, l2_base + L2_SPECIAL_CHECK1); + writel_relaxed(0x3fff, l2_base + L2_INTMASK); + + __hil2_inv_all(); + writel_relaxed(1, l2_base + L2_CTRL); + + outer_cache.inv_range = hil2_inv_range; + outer_cache.clean_range = hil2_clean_range; + outer_cache.flush_range = hil2_flush_range; + outer_cache.flush_all = hil2_flush_all; + outer_cache.sync = hil2_sync; + outer_cache.disable = hil2_disable; + + pr_info("%u KB, %u ways, %u B lines, enabled\n", + L2_SIZE / SZ_1K, L2_WAYS, L2_LINE_SIZE); + return 0; +} diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 2349bca136e..42f3af04d33 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -288,6 +288,18 @@ config AHCI_XGENE help This option enables support for APM X-Gene SoC SATA host controller. +config AHCI_HI3520DV200 + tristate "HiSilicon Hi3520DV200 AHCI SATA support" + depends on ARCH_HISI_BVT || COMPILE_TEST + select SATA_HOST + help + This option enables support for the on-chip SATA controller of the + HiSilicon Hi3520DV200 NVR/DVR SoC: a two-port AHCI block whose + PHYs this glue clocks, resets and programs before handing the + controller to the generic AHCI platform code. + + If unsure, say N. + config AHCI_QORIQ tristate "Freescale QorIQ AHCI SATA support" depends on OF diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 20e6645ab73..f79ac48e4b6 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_AHCI_SUNXI) += ahci_sunxi.o libahci.o libahci_platform.o obj-$(CONFIG_AHCI_ST) += ahci_st.o libahci.o libahci_platform.o obj-$(CONFIG_AHCI_TEGRA) += ahci_tegra.o libahci.o libahci_platform.o obj-$(CONFIG_AHCI_XGENE) += ahci_xgene.o libahci.o libahci_platform.o +obj-$(CONFIG_AHCI_HI3520DV200) += ahci_hi3520dv200.o libahci.o libahci_platform.o obj-$(CONFIG_AHCI_QORIQ) += ahci_qoriq.o libahci.o libahci_platform.o # SFF w/ custom DMA diff --git a/drivers/ata/ahci_hi3520dv200.c b/drivers/ata/ahci_hi3520dv200.c new file mode 100644 index 00000000000..00692fc78aa --- /dev/null +++ b/drivers/ata/ahci_hi3520dv200.c @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * AHCI glue for the HiSilicon Hi3520DV200 on-chip SATA controller. + * + * The controller is a standard AHCI block, but its two-port PHY needs to be + * clocked, released from reset and programmed before the AHCI core sees a + * link. The sequence, register values and the per-port bug-bypass setting + * follow the vendor 3.0.8 BSP (drivers/ata/ahci_sys.c and + * ahci_sys_hi3520d_defconfig.c, CONFIG_HI_SATA, 1.5 Gbps mode). + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ahci.h" + +#define DRV_NAME "ahci-hi3520dv200" + +/* PERI_CRG45 (0x200300b4): SATA clocks and resets */ +#define CRG_PHY_RST BIT(0) +#define CRG_HRST BIT(1) +#define CRG_RST BIT(2) +#define CRG_TX0_RST BIT(3) +#define CRG_TX1_RST BIT(4) +#define CRG_RX0_RST BIT(5) +#define CRG_RX1_RST BIT(6) +#define CRG_ALIVE_RST BIT(7) +#define CRG_PORT1_CKEN BIT(8) +#define CRG_PORT0_CKEN BIT(9) +#define CRG_CKEN BIT(10) +#define CRG_CLK_SEL BIT(11) +#define CRG_CLK_ALIVE BIT(12) +#define CRG_CORE_RESETS (CRG_RST | CRG_TX0_RST | CRG_TX1_RST | \ + CRG_RX0_RST | CRG_RX1_RST | CRG_ALIVE_RST) + +/* Vendor registers in the AHCI block */ +#define PHY0_CTLL 0x54 +#define PHY0_CTLH 0x58 +#define PHY1_CTLL 0x60 +#define PHY1_CTLH 0x64 +#define PHY_CTLH_DIS_CLK BIT(12) +#define OOB_CTL 0x6c +#define PORT_BASE(i) (0x100 + (i) * 0x80) +#define PORT_BUG_BYPASS 0x44 +#define PORT_PHYCTL 0x74 + +/* 1.5 Gbps PHY settings from the vendor BSP */ +#define PHY_CTLL_1G5 0x880ec788 +#define PHY_CTLH 0x00002521 +#define OOB_CTL_VAL 0x84060c15 +/* + * Data-transmit-control, record, PM-reset and fetch bypasses plus the + * Seagate R_ERR workaround (bits 13..9), which the vendor sets on every port + * "due to bugs of sata controller". + */ +#define PORT_BUG_BYPASS_VAL 0x3f24 +/* + * Port PHY control. HiSilicon's Hi3520D reference value is 0x0e276756; the + * vendor firmware on XiongMai boards writes 0x0e262709 (the Hi3531/Hi3521 + * value), without which their link keeps resetting. Boards may override it + * with "hisilicon,phy-config". + */ +#define PORT_PHYCTL_DEFAULT 0x0e276756 +#define NR_PORTS 2 + +struct hi3520dv200_sata { + void __iomem *crg; + u32 phy_config; +}; + +static void crg_update(void __iomem *crg, u32 clear, u32 set) +{ + writel((readl(crg) & ~clear) | set, crg); +} + +static void hi3520dv200_sata_phy_init(struct ahci_host_priv *hpriv) +{ + struct hi3520dv200_sata *priv = hpriv->plat_data; + void __iomem *mmio = hpriv->mmio; + void __iomem *crg = priv->crg; + int i; + + /* + * Clocks on, internal PHY clock, per-port bug bypasses. The vendor + * BSP writes the bypasses here, before releasing CRG_HRST (in + * hi_sata_phy_clk_sel(), ahead of hi_sata_unreset()). That works + * because CRG_HRST is clear at power-on (PERI_CRG45 reads 0): only + * the clocks are off, and the values read back after a cold boot. + */ + crg_update(crg, 0, CRG_CKEN | CRG_PORT0_CKEN | CRG_PORT1_CKEN); + crg_update(crg, CRG_CLK_SEL | CRG_CLK_ALIVE, 0); + for (i = 0; i < NR_PORTS; i++) + writel(PORT_BUG_BYPASS_VAL, mmio + PORT_BASE(i) + PORT_BUG_BYPASS); + + /* bus interface, then PHY out of reset */ + crg_update(crg, CRG_HRST, 0); + msleep(20); + crg_update(crg, CRG_PHY_RST, 0); + msleep(20); + + /* program both PHYs with their clocks gated */ + writel(readl(mmio + PHY0_CTLH) | PHY_CTLH_DIS_CLK, mmio + PHY0_CTLH); + writel(readl(mmio + PHY1_CTLH) | PHY_CTLH_DIS_CLK, mmio + PHY1_CTLH); + writel(PHY_CTLL_1G5, mmio + PHY0_CTLL); + writel(PHY_CTLH, mmio + PHY0_CTLH); + writel(PHY_CTLL_1G5, mmio + PHY1_CTLL); + writel(PHY_CTLH, mmio + PHY1_CTLH); + writel(OOB_CTL_VAL, mmio + OOB_CTL); + for (i = 0; i < NR_PORTS; i++) + writel(priv->phy_config, mmio + PORT_BASE(i) + PORT_PHYCTL); + + /* pulse the PHY reset so the settings take, then release the core */ + crg_update(crg, 0, CRG_PHY_RST); + msleep(20); + crg_update(crg, CRG_PHY_RST, 0); + msleep(20); + crg_update(crg, CRG_CORE_RESETS, 0); + msleep(20); +} + +static const struct ata_port_info ahci_hi3520dv200_port_info = { + .flags = AHCI_FLAG_COMMON, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_platform_ops, +}; + +static const struct scsi_host_template ahci_hi3520dv200_sht = { + AHCI_SHT(DRV_NAME), +}; + +static int ahci_hi3520dv200_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct hi3520dv200_sata *priv; + struct ahci_host_priv *hpriv; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->crg = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(priv->crg)) + return PTR_ERR(priv->crg); + + if (of_property_read_u32(dev->of_node, "hisilicon,phy-config", + &priv->phy_config)) + priv->phy_config = PORT_PHYCTL_DEFAULT; + + hpriv = ahci_platform_get_resources(pdev, 0); + if (IS_ERR(hpriv)) + return PTR_ERR(hpriv); + hpriv->plat_data = priv; + + ret = ahci_platform_enable_resources(hpriv); + if (ret) + return ret; + + hi3520dv200_sata_phy_init(hpriv); + + ret = ahci_platform_init_host(pdev, hpriv, &ahci_hi3520dv200_port_info, + &ahci_hi3520dv200_sht); + if (ret) { + ahci_platform_disable_resources(hpriv); + return ret; + } + + dev_info(dev, "PHY config %#010x\n", priv->phy_config); + return 0; +} + +static const struct of_device_id ahci_hi3520dv200_of_match[] = { + { .compatible = "hisilicon,hi3520dv200-ahci" }, + {} +}; +MODULE_DEVICE_TABLE(of, ahci_hi3520dv200_of_match); + +static struct platform_driver ahci_hi3520dv200_driver = { + .probe = ahci_hi3520dv200_probe, + .remove = ata_platform_remove_one, + .driver = { + .name = DRV_NAME, + .of_match_table = ahci_hi3520dv200_of_match, + }, +}; +module_platform_driver(ahci_hi3520dv200_driver); + +MODULE_DESCRIPTION("HiSilicon Hi3520DV200 AHCI SATA driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/hisilicon/hisi_femac.c b/drivers/net/ethernet/hisilicon/hisi_femac.c index 77be7684006..89826068e42 100644 --- a/drivers/net/ethernet/hisilicon/hisi_femac.c +++ b/drivers/net/ethernet/hisilicon/hisi_femac.c @@ -811,7 +811,7 @@ static int hisi_femac_drv_probe(struct platform_device *pdev) goto out_free_netdev; } - priv->mac_rst = devm_reset_control_get(dev, "mac"); + priv->mac_rst = devm_reset_control_get_optional_exclusive(dev, "mac"); if (IS_ERR(priv->mac_rst)) { ret = PTR_ERR(priv->mac_rst); goto out_disable_clk; diff --git a/drivers/net/mdio/mdio-hisi-femac.c b/drivers/net/mdio/mdio-hisi-femac.c index 582bcf7dcc2..378c5f4c28d 100644 --- a/drivers/net/mdio/mdio-hisi-femac.c +++ b/drivers/net/mdio/mdio-hisi-femac.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #define MDIO_RWCTRL 0x00 @@ -80,6 +81,7 @@ struct hisi_femac_mdio_data { void __iomem *fephy_trim_iobase; struct mii_bus *bus; u32 phy_addr; + bool fephy_addr_only; }; static int hisi_femac_mdio_wait_ready(struct hisi_femac_mdio_data *data) @@ -321,6 +323,22 @@ static void hisi_femac_fephy_reset_and_trim(struct hisi_femac_mdio_data *data) hisi_femac_fephy_trim(data); } +/* + * The Hi3520DV200 internal PHY answers at the address in bits 4:0 of its + * control register, which is 0 after power-on. Only the bootloader's network + * code sets it, so a kernel booted without it finds no PHY. This SoC has no + * festa trim data, and its PHY is not a festa, so only the address is set. + */ +static void hisi_femac_fephy_write_addr(struct hisi_femac_mdio_data *data) +{ + u32 val; + + val = readl(data->fephy_iobase); + val &= ~BIT_MASK_FEPHY_ADDR; + val |= data->phy_addr; + writel(val, data->fephy_iobase); +} + static void hisi_femac_fephy_set_phy_addr(struct hisi_femac_mdio_data *data) { u32 val; @@ -424,6 +442,8 @@ static int hisi_femac_mdio_probe(struct platform_device *pdev) } hisi_femac_get_phy_addr(data, np); + data->fephy_addr_only = data->fephy_iobase && + device_get_match_data(&pdev->dev); dev_info(&pdev->dev, "fephy_iobase=%p fephy_rst=%p fephy_clk=%p use_fephy=%d phy_addr=%d\n", data->fephy_iobase, data->fephy_rst, data->fephy_clk, hisi_femac_use_fephy(data), data->phy_addr); @@ -431,7 +451,9 @@ static int hisi_femac_mdio_probe(struct platform_device *pdev) dev_info(&pdev->dev, "FEPHY ctrl reg=0x%08x\n", readl(data->fephy_iobase)); - if (hisi_femac_use_fephy(data)) + if (data->fephy_addr_only) + hisi_femac_fephy_write_addr(data); + else if (hisi_femac_use_fephy(data)) hisi_femac_fephy_reset_and_trim(data); else hisi_femac_fephy_set_phy_addr(data); @@ -465,6 +487,7 @@ static void hisi_femac_mdio_remove(struct platform_device *pdev) } static const struct of_device_id hisi_femac_mdio_dt_ids[] = { + { .compatible = "hisilicon,hi3520dv200-femac-mdio", .data = (void *)true }, { .compatible = "hisilicon,hisi-femac-mdio" }, { } }; diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index c3b2f02f591..cdb77018bb5 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -457,7 +457,7 @@ config SPI_HISI_KUNPENG config SPI_HISI_SFC_V3XX tristate "HiSilicon SPI NOR Flash Controller for Hi16XX chipsets" - depends on (ARM64 && ACPI) || COMPILE_TEST + depends on (ARM64 && ACPI) || ARCH_HISI_BVT || COMPILE_TEST depends on HAS_IOMEM help This enables support for HiSilicon v3xx SPI NOR flash controller diff --git a/drivers/spi/spi-hisi-sfc-v3xx.c b/drivers/spi/spi-hisi-sfc-v3xx.c index b2af2eed197..200155fc06a 100644 --- a/drivers/spi/spi-hisi-sfc-v3xx.c +++ b/drivers/spi/spi-hisi-sfc-v3xx.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -368,7 +369,24 @@ static int hisi_sfc_v3xx_exec_op(struct spi_mem *mem, return hisi_sfc_v3xx_generic_exec_op(host, op, chip_select); } +/* + * Name the flash after its DT "label" when it has one. Bootloaders on + * Hi3520DV200 boards pass "mtdparts=hi_sfc:...", which only matches an MTD + * device of that name; without a label the default (the SPI device name) is + * kept. + */ +static const char *hisi_sfc_v3xx_get_name(struct spi_mem *mem) +{ + const char *name; + + if (!of_property_read_string(mem->spi->dev.of_node, "label", &name)) + return name; + + return dev_name(&mem->spi->dev); +} + static const struct spi_controller_mem_ops hisi_sfc_v3xx_mem_ops = { + .get_name = hisi_sfc_v3xx_get_name, .adjust_op_size = hisi_sfc_v3xx_adjust_op_size, .supports_op = hisi_sfc_v3xx_supports_op, .exec_op = hisi_sfc_v3xx_exec_op, @@ -433,7 +451,7 @@ static int hisi_sfc_v3xx_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct hisi_sfc_v3xx_host *host; struct spi_controller *ctlr; - u32 version, glb_config; + u32 version, glb_config, num_cs; int ret; ctlr = spi_alloc_host(&pdev->dev, sizeof(*host)); @@ -477,7 +495,10 @@ static int hisi_sfc_v3xx_probe(struct platform_device *pdev) } ctlr->bus_num = -1; - ctlr->num_chipselect = 1; + /* The ACPI parts expose one chip select; the Hi3520DV200 flash is on CS1. */ + if (device_property_read_u32(dev, "num-cs", &num_cs)) + num_cs = 1; + ctlr->num_chipselect = num_cs; ctlr->mem_ops = &hisi_sfc_v3xx_mem_ops; /* @@ -519,10 +540,22 @@ static const struct acpi_device_id hisi_sfc_v3xx_acpi_ids[] = { }; MODULE_DEVICE_TABLE(acpi, hisi_sfc_v3xx_acpi_ids); +/* + * The SFC v350 in HiSilicon's Hi3520DV200 has the register layout of the + * v3xx parts (GLB_CFG 0x100, interrupts 0x120-0x12c, CMD_CFG/INS/ADDR + * 0x300-0x30c, a 16-word data buffer at 0x400). + */ +static const struct of_device_id hisi_sfc_v3xx_of_ids[] = { + { .compatible = "hisilicon,hi3520dv200-sfc" }, + {} +}; +MODULE_DEVICE_TABLE(of, hisi_sfc_v3xx_of_ids); + static struct platform_driver hisi_sfc_v3xx_spi_driver = { .driver = { .name = "hisi-sfc-v3xx", .acpi_match_table = hisi_sfc_v3xx_acpi_ids, + .of_match_table = hisi_sfc_v3xx_of_ids, }, .probe = hisi_sfc_v3xx_probe, }; diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c index c2125f204a1..569e28d0c15 100644 --- a/drivers/watchdog/sp805_wdt.c +++ b/drivers/watchdog/sp805_wdt.c @@ -140,7 +140,13 @@ wdt_restart(struct watchdog_device *wdd, unsigned long mode, void *cmd) writel_relaxed(UNLOCK, wdt->base + WDTLOCK); writel_relaxed(0, wdt->base + WDTCONTROL); - writel_relaxed(0, wdt->base + WDTLOAD); + /* + * The smallest load that counts. The SP805 in HiSilicon's Hi3520DV200 + * never resets the system with a load of 0, and stays stuck there, so + * the restart (and any running timeout) silently fails; with 1 it + * resets at once, as a 0 does on other implementations. + */ + writel_relaxed(LOAD_MIN, wdt->base + WDTLOAD); writel_relaxed(INT_ENABLE | RESET_ENABLE, wdt->base + WDTCONTROL); /* Flush posted writes. */