Browse Source

Merge https://source.denx.de/u-boot/custodians/u-boot-riscv

- SiFive FU740 and Unmatched support
Tom Rini 3 years ago
parent
commit
d8729a114e
48 changed files with 5308 additions and 831 deletions
  1. 5 0
      arch/riscv/Kconfig
  2. 1 1
      arch/riscv/cpu/fu540/Kconfig
  3. 37 0
      arch/riscv/cpu/fu740/Kconfig
  4. 12 0
      arch/riscv/cpu/fu740/Makefile
  5. 55 0
      arch/riscv/cpu/fu740/cache.c
  6. 22 0
      arch/riscv/cpu/fu740/cpu.c
  7. 38 0
      arch/riscv/cpu/fu740/dram.c
  8. 38 0
      arch/riscv/cpu/fu740/spl.c
  9. 1 0
      arch/riscv/dts/Makefile
  10. 105 0
      arch/riscv/dts/fu740-c000-u-boot.dtsi
  11. 329 0
      arch/riscv/dts/fu740-c000.dtsi
  12. 1489 0
      arch/riscv/dts/fu740-hifive-unmatched-a00-ddr.dtsi
  13. 41 0
      arch/riscv/dts/hifive-unmatched-a00-u-boot.dtsi
  14. 259 0
      arch/riscv/dts/hifive-unmatched-a00.dts
  15. 14 0
      arch/riscv/include/asm/arch-fu740/cache.h
  16. 14 0
      arch/riscv/include/asm/arch-fu740/clk.h
  17. 38 0
      arch/riscv/include/asm/arch-fu740/gpio.h
  18. 13 0
      arch/riscv/include/asm/arch-fu740/reset.h
  19. 14 0
      arch/riscv/include/asm/arch-fu740/spl.h
  20. 1 0
      board/sifive/unleashed/Kconfig
  21. 51 0
      board/sifive/unmatched/Kconfig
  22. 9 0
      board/sifive/unmatched/MAINTAINERS
  23. 9 0
      board/sifive/unmatched/Makefile
  24. 85 0
      board/sifive/unmatched/spl.c
  25. 24 0
      board/sifive/unmatched/unmatched.c
  26. 2 2
      common/spl/Kconfig
  27. 54 0
      configs/sifive_unmatched_defconfig
  28. 1 0
      doc/board/sifive/index.rst
  29. 536 0
      doc/board/sifive/unmatched.rst
  30. 4 4
      drivers/clk/sifive/Kconfig
  31. 3 1
      drivers/clk/sifive/Makefile
  32. 21 748
      drivers/clk/sifive/fu540-prci.c
  33. 22 0
      drivers/clk/sifive/fu540-prci.h
  34. 158 0
      drivers/clk/sifive/fu740-prci.c
  35. 22 0
      drivers/clk/sifive/fu740-prci.h
  36. 733 0
      drivers/clk/sifive/sifive-prci.c
  37. 323 0
      drivers/clk/sifive/sifive-prci.h
  38. 10 0
      drivers/pci/Kconfig
  39. 1 0
      drivers/pci/Makefile
  40. 29 25
      drivers/pci/pcie_dw_common.c
  41. 507 0
      drivers/pci/pcie_dw_sifive.c
  42. 4 4
      drivers/ram/sifive/Kconfig
  43. 1 1
      drivers/ram/sifive/Makefile
  44. 45 44
      drivers/ram/sifive/sifive_ddr.c
  45. 1 1
      drivers/reset/Kconfig
  46. 83 0
      include/configs/sifive-unmatched.h
  47. 25 0
      include/dt-bindings/clock/sifive-fu740-prci.h
  48. 19 0
      include/dt-bindings/reset/sifive-fu740-prci.h

+ 5 - 0
arch/riscv/Kconfig

@@ -20,6 +20,9 @@ config TARGET_QEMU_VIRT
 config TARGET_SIFIVE_UNLEASHED
 	bool "Support SiFive Unleashed Board"
 
+config TARGET_SIFIVE_UNMATCHED
+	bool "Support SiFive Unmatched Board"
+
 config TARGET_SIPEED_MAIX
 	bool "Support Sipeed Maix Board"
 
@@ -56,11 +59,13 @@ source "board/AndesTech/ax25-ae350/Kconfig"
 source "board/emulation/qemu-riscv/Kconfig"
 source "board/microchip/mpfs_icicle/Kconfig"
 source "board/sifive/unleashed/Kconfig"
+source "board/sifive/unmatched/Kconfig"
 source "board/sipeed/maix/Kconfig"
 
 # platform-specific options below
 source "arch/riscv/cpu/ax25/Kconfig"
 source "arch/riscv/cpu/fu540/Kconfig"
+source "arch/riscv/cpu/fu740/Kconfig"
 source "arch/riscv/cpu/generic/Kconfig"
 
 # architecture-specific options below

+ 1 - 1
arch/riscv/cpu/fu540/Kconfig

@@ -18,7 +18,7 @@ config SIFIVE_FU540
 	imply SPL_LOAD_FIT
 	imply SMP
 	imply CLK_SIFIVE
-	imply CLK_SIFIVE_FU540_PRCI
+	imply CLK_SIFIVE_PRCI
 	imply SIFIVE_SERIAL
 	imply MACB
 	imply MII

+ 37 - 0
arch/riscv/cpu/fu740/Kconfig

@@ -0,0 +1,37 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2020-2021 SiFive, Inc
+# Pragnesh Patel <pragnesh.patel@sifive.com>
+
+config SIFIVE_FU740
+	bool
+	select ARCH_EARLY_INIT_R
+	select RAM
+	select SPL_RAM if SPL
+	imply CPU
+	imply CPU_RISCV
+	imply RISCV_TIMER if (RISCV_SMODE || SPL_RISCV_SMODE)
+	imply SPL_SIFIVE_CLINT
+	imply CMD_CPU
+	imply SPL_CPU
+	imply SPL_OPENSBI
+	imply SPL_LOAD_FIT
+	imply SMP
+	imply CLK_SIFIVE
+	imply CLK_SIFIVE_PRCI
+	imply SIFIVE_SERIAL
+	imply MACB
+	imply MII
+	imply SPI
+	imply SPI_SIFIVE
+	imply MMC
+	imply MMC_SPI
+	imply MMC_BROKEN_CD
+	imply CMD_MMC
+	imply DM_GPIO
+	imply SIFIVE_GPIO
+	imply CMD_GPIO
+	imply MISC
+	imply SIFIVE_OTP
+	imply DM_PWM
+	imply PWM_SIFIVE

+ 12 - 0
arch/riscv/cpu/fu740/Makefile

@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2020-2021 SiFive, Inc
+# Pragnesh Patel <pragnesh.patel@sifive.com>
+
+ifeq ($(CONFIG_SPL_BUILD),y)
+obj-y += spl.o
+else
+obj-y += dram.o
+obj-y += cpu.o
+obj-y += cache.o
+endif

+ 55 - 0
arch/riscv/cpu/fu740/cache.c

@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020-2021 SiFive, Inc
+ *
+ * Authors:
+ *   Pragnesh Patel <pragnesh.patel@sifive.com>
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+#include <asm/global_data.h>
+
+/* Register offsets */
+#define L2_CACHE_CONFIG	0x000
+#define L2_CACHE_ENABLE	0x008
+
+#define MASK_NUM_WAYS	GENMASK(15, 8)
+#define NUM_WAYS_SHIFT	8
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int cache_enable_ways(void)
+{
+	const void *blob = gd->fdt_blob;
+	int node;
+	fdt_addr_t base;
+	u32 config;
+	u32 ways;
+
+	volatile u32 *enable;
+
+	node = fdt_node_offset_by_compatible(blob, -1,
+					     "sifive,fu740-c000-ccache");
+
+	if (node < 0)
+		return node;
+
+	base = fdtdec_get_addr_size_auto_parent(blob, 0, node, "reg", 0,
+						NULL, false);
+	if (base == FDT_ADDR_T_NONE)
+		return FDT_ADDR_T_NONE;
+
+	config = readl((volatile u32 *)base + L2_CACHE_CONFIG);
+	ways = (config & MASK_NUM_WAYS) >> NUM_WAYS_SHIFT;
+
+	enable = (volatile u32 *)(base + L2_CACHE_ENABLE);
+
+	/* memory barrier */
+	mb();
+	(*enable) = ways - 1;
+	/* memory barrier */
+	mb();
+	return 0;
+}

+ 22 - 0
arch/riscv/cpu/fu740/cpu.c

@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#include <irq_func.h>
+#include <asm/cache.h>
+
+/*
+ * cleanup_before_linux() is called just before we call linux
+ * it prepares the processor for linux
+ *
+ * we disable interrupt and caches.
+ */
+int cleanup_before_linux(void)
+{
+	disable_interrupts();
+
+	cache_flush();
+
+	return 0;
+}

+ 38 - 0
arch/riscv/cpu/fu740/dram.c

@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <init.h>
+#include <linux/sizes.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int dram_init(void)
+{
+	return fdtdec_setup_mem_size_base();
+}
+
+int dram_init_banksize(void)
+{
+	return fdtdec_setup_memory_banksize();
+}
+
+ulong board_get_usable_ram_top(ulong total_size)
+{
+#ifdef CONFIG_64BIT
+	/*
+	 * Ensure that we run from first 4GB so that all
+	 * addresses used by U-Boot are 32bit addresses.
+	 *
+	 * This in-turn ensures that 32bit DMA capable
+	 * devices work fine because DMA mapping APIs will
+	 * provide 32bit DMA addresses only.
+	 */
+	if (gd->ram_top > SZ_4G)
+		return SZ_4G;
+#endif
+	return gd->ram_top;
+}

+ 38 - 0
arch/riscv/cpu/fu740/spl.c

@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020-201 SiFive, Inc
+ * Pragnesh Patel <pragnesh.patel@sifive.com>
+ */
+
+#include <dm.h>
+#include <log.h>
+#include <asm/csr.h>
+
+#define CSR_U74_FEATURE_DISABLE	0x7c1
+
+int spl_soc_init(void)
+{
+	int ret;
+	struct udevice *dev;
+
+	/* DDR init */
+	ret = uclass_get_device(UCLASS_RAM, 0, &dev);
+	if (ret) {
+		debug("DRAM init failed: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+void harts_early_init(void)
+{
+	/*
+	 * Feature Disable CSR
+	 *
+	 * Clear feature disable CSR to '0' to turn on all features for
+	 * each core. This operation must be in M-mode.
+	 */
+	if (CONFIG_IS_ENABLED(RISCV_MMODE))
+		csr_write(CSR_U74_FEATURE_DISABLE, 0);
+}

+ 1 - 0
arch/riscv/dts/Makefile

@@ -4,6 +4,7 @@ dtb-$(CONFIG_TARGET_AX25_AE350) += ae350_32.dtb ae350_64.dtb
 dtb-$(CONFIG_TARGET_MICROCHIP_ICICLE) += microchip-mpfs-icicle-kit.dtb
 dtb-$(CONFIG_TARGET_QEMU_VIRT) += qemu-virt.dtb
 dtb-$(CONFIG_TARGET_SIFIVE_UNLEASHED) += hifive-unleashed-a00.dtb
+dtb-$(CONFIG_TARGET_SIFIVE_UNMATCHED) += hifive-unmatched-a00.dtb
 dtb-$(CONFIG_TARGET_SIPEED_MAIX) += k210-maix-bit.dtb
 
 targets += $(dtb-y)

+ 105 - 0
arch/riscv/dts/fu740-c000-u-boot.dtsi

@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * (C) Copyright 2020-2021 SiFive, Inc
+ */
+
+#include <dt-bindings/reset/sifive-fu740-prci.h>
+
+/ {
+	cpus {
+		assigned-clocks = <&prci PRCI_CLK_COREPLL>;
+		assigned-clock-rates = <1200000000>;
+		u-boot,dm-spl;
+		cpu0: cpu@0 {
+			clocks = <&prci PRCI_CLK_COREPLL>;
+			u-boot,dm-spl;
+			status = "okay";
+			cpu0_intc: interrupt-controller {
+				u-boot,dm-spl;
+			};
+		};
+		cpu1: cpu@1 {
+			clocks = <&prci PRCI_CLK_COREPLL>;
+			u-boot,dm-spl;
+			cpu1_intc: interrupt-controller {
+				u-boot,dm-spl;
+			};
+		};
+		cpu2: cpu@2 {
+			clocks = <&prci PRCI_CLK_COREPLL>;
+			u-boot,dm-spl;
+			cpu2_intc: interrupt-controller {
+				 u-boot,dm-spl;
+			};
+		};
+		cpu3: cpu@3 {
+			clocks = <&prci PRCI_CLK_COREPLL>;
+			u-boot,dm-spl;
+			cpu3_intc: interrupt-controller {
+				u-boot,dm-spl;
+			};
+		};
+		cpu4: cpu@4 {
+			clocks = <&prci PRCI_CLK_COREPLL>;
+			u-boot,dm-spl;
+			cpu4_intc: interrupt-controller {
+				u-boot,dm-spl;
+			};
+		};
+	};
+
+	soc {
+		u-boot,dm-spl;
+		clint: clint@2000000 {
+			compatible = "riscv,clint0";
+			interrupts-extended = <&cpu0_intc 3 &cpu0_intc 7
+					       &cpu1_intc 3 &cpu1_intc 7
+					       &cpu2_intc 3 &cpu2_intc 7
+					       &cpu3_intc 3 &cpu3_intc 7
+					       &cpu4_intc 3 &cpu4_intc 7>;
+			reg = <0x0 0x2000000 0x0 0x10000>;
+			u-boot,dm-spl;
+		};
+		prci: clock-controller@10000000 {
+			#reset-cells = <1>;
+			resets = <&prci PRCI_RST_DDR_CTRL_N>,
+				 <&prci PRCI_RST_DDR_AXI_N>,
+				 <&prci PRCI_RST_DDR_AHB_N>,
+				 <&prci PRCI_RST_DDR_PHY_N>,
+				 <&prci PRCI_RST_GEMGXL_N>,
+				 <&prci PRCI_RST_CLTX_N>;
+			reset-names = "ddr_ctrl", "ddr_axi", "ddr_ahb",
+					"ddr_phy", "gemgxl_reset", "cltx_reset";
+		};
+		dmc: dmc@100b0000 {
+			compatible = "sifive,fu740-c000-ddr";
+			reg = <0x0 0x100b0000 0x0 0x0800
+			       0x0 0x100b2000 0x0 0x2000
+			       0x0 0x100b8000 0x0 0x1000>;
+			clocks = <&prci PRCI_CLK_DDRPLL>;
+			clock-frequency = <933333324>;
+			u-boot,dm-spl;
+		};
+	};
+};
+
+&prci {
+	u-boot,dm-spl;
+};
+
+&uart0 {
+	u-boot,dm-spl;
+};
+
+&spi0 {
+	u-boot,dm-spl;
+};
+
+&eth0 {
+	assigned-clocks = <&prci PRCI_CLK_GEMGXLPLL>;
+	assigned-clock-rates = <125125000>;
+};
+
+&ccache {
+	status = "okay";
+};

+ 329 - 0
arch/riscv/dts/fu740-c000.dtsi

@@ -0,0 +1,329 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Copyright (c) 2020-2021 SiFive, Inc */
+
+/dts-v1/;
+
+#include <dt-bindings/clock/sifive-fu740-prci.h>
+#include <dt-bindings/reset/sifive-fu740-prci.h>
+
+/ {
+	#address-cells = <2>;
+	#size-cells = <2>;
+	compatible = "sifive,fu740-c000", "sifive,fu740";
+
+	aliases {
+		serial0 = &uart0;
+		serial1 = &uart1;
+		ethernet0 = &eth0;
+	};
+
+	chosen {
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		cpu0: cpu@0 {
+			compatible = "sifive,bullet0", "riscv";
+			device_type = "cpu";
+			i-cache-block-size = <64>;
+			i-cache-sets = <128>;
+			i-cache-size = <16384>;
+			next-level-cache = <&ccache>;
+			reg = <0x0>;
+			riscv,isa = "rv64imac";
+			status = "disabled";
+			cpu0_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu1: cpu@1 {
+			compatible = "sifive,bullet0", "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 = <128>;
+			i-cache-size = <32768>;
+			i-tlb-sets = <1>;
+			i-tlb-size = <40>;
+			mmu-type = "riscv,sv39";
+			next-level-cache = <&ccache>;
+			reg = <0x1>;
+			riscv,isa = "rv64imafdc";
+			tlb-split;
+			cpu1_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu2: cpu@2 {
+			compatible = "sifive,bullet0", "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 = <128>;
+			i-cache-size = <32768>;
+			i-tlb-sets = <1>;
+			i-tlb-size = <40>;
+			mmu-type = "riscv,sv39";
+			next-level-cache = <&ccache>;
+			reg = <0x2>;
+			riscv,isa = "rv64imafdc";
+			tlb-split;
+			cpu2_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu3: cpu@3 {
+			compatible = "sifive,bullet0", "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 = <128>;
+			i-cache-size = <32768>;
+			i-tlb-sets = <1>;
+			i-tlb-size = <40>;
+			mmu-type = "riscv,sv39";
+			next-level-cache = <&ccache>;
+			reg = <0x3>;
+			riscv,isa = "rv64imafdc";
+			tlb-split;
+			cpu3_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu4: cpu@4 {
+			compatible = "sifive,bullet0", "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 = <128>;
+			i-cache-size = <32768>;
+			i-tlb-sets = <1>;
+			i-tlb-size = <40>;
+			mmu-type = "riscv,sv39";
+			next-level-cache = <&ccache>;
+			reg = <0x4>;
+			riscv,isa = "rv64imafdc";
+			tlb-split;
+			cpu4_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+	};
+	soc {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		compatible = "sifive,fu740-c000", "sifive,fu740", "simple-bus";
+		ranges;
+		plic0: interrupt-controller@c000000 {
+			#interrupt-cells = <1>;
+			compatible = "sifive,plic-1.0.0";
+			reg = <0x0 0xc000000 0x0 0x4000000>;
+			riscv,ndev = <69>;
+			interrupt-controller;
+			interrupts-extended = <
+				&cpu0_intc 0xffffffff
+				&cpu1_intc 0xffffffff &cpu1_intc 9
+				&cpu2_intc 0xffffffff &cpu2_intc 9
+				&cpu3_intc 0xffffffff &cpu3_intc 9
+				&cpu4_intc 0xffffffff &cpu4_intc 9>;
+		};
+		prci: clock-controller@10000000 {
+			compatible = "sifive,fu740-c000-prci";
+			reg = <0x0 0x10000000 0x0 0x1000>;
+			clocks = <&hfclk>, <&rtcclk>;
+			#clock-cells = <1>;
+			#reset-cells = <1>;
+		};
+		uart0: serial@10010000 {
+			compatible = "sifive,fu740-c000-uart", "sifive,uart0";
+			reg = <0x0 0x10010000 0x0 0x1000>;
+			interrupt-parent = <&plic0>;
+			interrupts = <39>;
+			clocks = <&prci PRCI_CLK_PCLK>;
+			status = "disabled";
+		};
+		uart1: serial@10011000 {
+			compatible = "sifive,fu740-c000-uart", "sifive,uart0";
+			reg = <0x0 0x10011000 0x0 0x1000>;
+			interrupt-parent = <&plic0>;
+			interrupts = <40>;
+			clocks = <&prci PRCI_CLK_PCLK>;
+			status = "disabled";
+		};
+		i2c0: i2c@10030000 {
+			compatible = "sifive,fu740-c000-i2c", "sifive,i2c0";
+			reg = <0x0 0x10030000 0x0 0x1000>;
+			interrupt-parent = <&plic0>;
+			interrupts = <52>;
+			clocks = <&prci PRCI_CLK_PCLK>;
+			reg-shift = <2>;
+			reg-io-width = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+		i2c1: i2c@10031000 {
+			compatible = "sifive,fu740-c000-i2c", "sifive,i2c0";
+			reg = <0x0 0x10031000 0x0 0x1000>;
+			interrupt-parent = <&plic0>;
+			interrupts = <53>;
+			clocks = <&prci PRCI_CLK_PCLK>;
+			reg-shift = <2>;
+			reg-io-width = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+		qspi0: spi@10040000 {
+			compatible = "sifive,fu740-c000-spi", "sifive,spi0";
+			reg = <0x0 0x10040000 0x0 0x1000
+			       0x0 0x20000000 0x0 0x10000000>;
+			interrupt-parent = <&plic0>;
+			interrupts = <41>;
+			clocks = <&prci PRCI_CLK_PCLK>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+		qspi1: spi@10041000 {
+			compatible = "sifive,fu740-c000-spi", "sifive,spi0";
+			reg = <0x0 0x10041000 0x0 0x1000
+			       0x0 0x30000000 0x0 0x10000000>;
+			interrupt-parent = <&plic0>;
+			interrupts = <42>;
+			clocks = <&prci PRCI_CLK_PCLK>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+		spi0: spi@10050000 {
+			compatible = "sifive,fu740-c000-spi", "sifive,spi0";
+			reg = <0x0 0x10050000 0x0 0x1000>;
+			interrupt-parent = <&plic0>;
+			interrupts = <43>;
+			clocks = <&prci PRCI_CLK_PCLK>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+		eth0: ethernet@10090000 {
+			compatible = "sifive,fu540-c000-gem";
+			interrupt-parent = <&plic0>;
+			interrupts = <55>;
+			reg = <0x0 0x10090000 0x0 0x2000
+			       0x0 0x100a0000 0x0 0x1000>;
+			local-mac-address = [00 00 00 00 00 00];
+			clock-names = "pclk", "hclk";
+			clocks = <&prci PRCI_CLK_GEMGXLPLL>,
+				 <&prci PRCI_CLK_GEMGXLPLL>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+		pwm0: pwm@10020000 {
+			compatible = "sifive,fu740-c000-pwm", "sifive,pwm0";
+			reg = <0x0 0x10020000 0x0 0x1000>;
+			interrupt-parent = <&plic0>;
+			interrupts = <44 45 46 47>;
+			clocks = <&prci PRCI_CLK_PCLK>;
+			#pwm-cells = <3>;
+			status = "disabled";
+		};
+		pwm1: pwm@10021000 {
+			compatible = "sifive,fu740-c000-pwm", "sifive,pwm0";
+			reg = <0x0 0x10021000 0x0 0x1000>;
+			interrupt-parent = <&plic0>;
+			interrupts = <48 49 50 51>;
+			clocks = <&prci PRCI_CLK_PCLK>;
+			#pwm-cells = <3>;
+			status = "disabled";
+		};
+		ccache: cache-controller@2010000 {
+			compatible = "sifive,fu740-c000-ccache", "cache";
+			cache-block-size = <64>;
+			cache-level = <2>;
+			cache-sets = <2048>;
+			cache-size = <2097152>;
+			cache-unified;
+			interrupt-parent = <&plic0>;
+			interrupts = <19 21 22 20>;
+			reg = <0x0 0x2010000 0x0 0x1000>;
+		};
+		gpio: gpio@10060000 {
+			compatible = "sifive,fu740-c000-gpio", "sifive,gpio0";
+			interrupt-parent = <&plic0>;
+			interrupts = <23>, <24>, <25>, <26>, <27>, <28>, <29>,
+				     <30>, <31>, <32>, <33>, <34>, <35>, <36>,
+				     <37>, <38>;
+			reg = <0x0 0x10060000 0x0 0x1000>;
+			gpio-controller;
+			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupt-cells = <2>;
+			clocks = <&prci PRCI_CLK_PCLK>;
+			status = "disabled";
+		};
+		pcie@e00000000 {
+			#address-cells = <3>;
+			#interrupt-cells = <1>;
+			#num-lanes = <8>;
+			#size-cells = <2>;
+			compatible = "sifive,fu740-pcie";
+			reg = <0xe 0x00000000 0x1 0x0
+			       0xd 0xf0000000 0x0 0x10000000
+			       0x0 0x100d0000 0x0 0x1000>;
+			reg-names = "dbi", "config", "mgmt";
+			device_type = "pci";
+			dma-coherent;
+			bus-range = <0x0 0xff>;
+			ranges = <0x81000000  0x0 0x60080000  0x0 0x60080000 0x0 0x10000
+				  0x82000000  0x0 0x60090000  0x0 0x60090000 0x0 0xff70000
+				  0x82000000  0x0 0x70000000  0x0 0x70000000 0x0 0x1000000
+				  0xc3000000 0x20 0x00000000 0x20 0x00000000 0x20 0x00000000>;
+			num-lanes = <0x8>;
+			interrupts = <56 57 58 59 60 61 62 63 64>;
+			interrupt-names = "msi", "inta", "intb", "intc", "intd";
+			interrupt-parent = <&plic0>;
+			interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+			interrupt-map = <0x0 0x0 0x0 0x1 &plic0 57>,
+					<0x0 0x0 0x0 0x2 &plic0 58>,
+					<0x0 0x0 0x0 0x3 &plic0 59>,
+					<0x0 0x0 0x0 0x4 &plic0 60>;
+			pwren-gpios = <&gpio 5 0>;
+			reset-gpios = <&gpio 8 0>;
+			clocks = <&prci PRCI_CLK_PCIEAUX>;
+			clock-names = "pcieaux";
+			resets = <&prci PRCI_RST_PCIE_POWER_UP_N>;
+			reset-names = "rst_n";
+
+			status = "okay";
+		};
+	};
+};

+ 1489 - 0
arch/riscv/dts/fu740-hifive-unmatched-a00-ddr.dtsi

@@ -0,0 +1,1489 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * (C) Copyright 2020-2021 SiFive, Inc
+ */
+
+&dmc {
+	sifive,ddr-params = <
+		0x00000a00	/* DENALI_CTL_00_DATA */
+		0x00000000	/* DENALI_CTL_01_DATA */
+		0x00000000	/* DENALI_CTL_02_DATA */
+		0x00000000	/* DENALI_CTL_03_DATA */
+		0x00000000	/* DENALI_CTL_04_DATA */
+		0x00000000	/* DENALI_CTL_05_DATA */
+		0x0000000a	/* DENALI_CTL_06_DATA */
+		0x0002d362	/* DENALI_CTL_07_DATA */
+		0x00071073	/* DENALI_CTL_08_DATA */
+		0x0a1c0255	/* DENALI_CTL_09_DATA */
+		0x1c1c0400	/* DENALI_CTL_10_DATA */
+		0x0404c90b	/* DENALI_CTL_11_DATA */
+		0x2b050405	/* DENALI_CTL_12_DATA */
+		0x0d0c081e	/* DENALI_CTL_13_DATA */
+		0x08090914	/* DENALI_CTL_14_DATA */
+		0x00fde718	/* DENALI_CTL_15_DATA */
+		0x00180a05	/* DENALI_CTL_16_DATA */
+		0x008b130d	/* DENALI_CTL_17_DATA */
+		0x01000118	/* DENALI_CTL_18_DATA */
+		0x0d032001	/* DENALI_CTL_19_DATA */
+		0x00000000	/* DENALI_CTL_20_DATA */
+		0x00000101	/* DENALI_CTL_21_DATA */
+		0x00000000	/* DENALI_CTL_22_DATA */
+		0x0a000000	/* DENALI_CTL_23_DATA */
+		0x00000000	/* DENALI_CTL_24_DATA */
+		0x01450100	/* DENALI_CTL_25_DATA */
+		0x00001c36	/* DENALI_CTL_26_DATA */
+		0x00000005	/* DENALI_CTL_27_DATA */
+		0x00170006	/* DENALI_CTL_28_DATA */
+		0x014e0400	/* DENALI_CTL_29_DATA */
+		0x03010000	/* DENALI_CTL_30_DATA */
+		0x000a0e00	/* DENALI_CTL_31_DATA */
+		0x04030200	/* DENALI_CTL_32_DATA */
+		0x0000031f	/* DENALI_CTL_33_DATA */
+		0x00070004	/* DENALI_CTL_34_DATA */
+		0x00000000	/* DENALI_CTL_35_DATA */
+		0x00000000	/* DENALI_CTL_36_DATA */
+		0x00000000	/* DENALI_CTL_37_DATA */
+		0x00000000	/* DENALI_CTL_38_DATA */
+		0x00000000	/* DENALI_CTL_39_DATA */
+		0x00000000	/* DENALI_CTL_40_DATA */
+		0x00000000	/* DENALI_CTL_41_DATA */
+		0x00000000	/* DENALI_CTL_42_DATA */
+		0x00000000	/* DENALI_CTL_43_DATA */
+		0x00000000	/* DENALI_CTL_44_DATA */
+		0x00000000	/* DENALI_CTL_45_DATA */
+		0x00000000	/* DENALI_CTL_46_DATA */
+		0x00000000	/* DENALI_CTL_47_DATA */
+		0x00000000	/* DENALI_CTL_48_DATA */
+		0x00000000	/* DENALI_CTL_49_DATA */
+		0x00000000	/* DENALI_CTL_50_DATA */
+		0x00000000	/* DENALI_CTL_51_DATA */
+		0x00000000	/* DENALI_CTL_52_DATA */
+		0x00000000	/* DENALI_CTL_53_DATA */
+		0x00000000	/* DENALI_CTL_54_DATA */
+		0x00000000	/* DENALI_CTL_55_DATA */
+		0x00000000	/* DENALI_CTL_56_DATA */
+		0x00000000	/* DENALI_CTL_57_DATA */
+		0x00000000	/* DENALI_CTL_58_DATA */
+		0x00000000	/* DENALI_CTL_59_DATA */
+		0x00000424	/* DENALI_CTL_60_DATA */
+		0x00000201	/* DENALI_CTL_61_DATA */
+		0x00001008	/* DENALI_CTL_62_DATA */
+		0x00000000	/* DENALI_CTL_63_DATA */
+		0x00000200	/* DENALI_CTL_64_DATA */
+		0x00000800	/* DENALI_CTL_65_DATA */
+		0x00000481	/* DENALI_CTL_66_DATA */
+		0x00000400	/* DENALI_CTL_67_DATA */
+		0x00000424	/* DENALI_CTL_68_DATA */
+		0x00000201	/* DENALI_CTL_69_DATA */
+		0x00001008	/* DENALI_CTL_70_DATA */
+		0x00000000	/* DENALI_CTL_71_DATA */
+		0x00000200	/* DENALI_CTL_72_DATA */
+		0x00000800	/* DENALI_CTL_73_DATA */
+		0x00000481	/* DENALI_CTL_74_DATA */
+		0x00000400	/* DENALI_CTL_75_DATA */
+		0x01010000	/* DENALI_CTL_76_DATA */
+		0x00000000	/* DENALI_CTL_77_DATA */
+		0x00000000	/* DENALI_CTL_78_DATA */
+		0x00000000	/* DENALI_CTL_79_DATA */
+		0x00000000	/* DENALI_CTL_80_DATA */
+		0x00000000	/* DENALI_CTL_81_DATA */
+		0x00000000	/* DENALI_CTL_82_DATA */
+		0x00000000	/* DENALI_CTL_83_DATA */
+		0x00000000	/* DENALI_CTL_84_DATA */
+		0x00000000	/* DENALI_CTL_85_DATA */
+		0x00000000	/* DENALI_CTL_86_DATA */
+		0x00000000	/* DENALI_CTL_87_DATA */
+		0x00000000	/* DENALI_CTL_88_DATA */
+		0x00000000	/* DENALI_CTL_89_DATA */
+		0x00000000	/* DENALI_CTL_90_DATA */
+		0x00000000	/* DENALI_CTL_91_DATA */
+		0x00000000	/* DENALI_CTL_92_DATA */
+		0x00000000	/* DENALI_CTL_93_DATA */
+		0x00000000	/* DENALI_CTL_94_DATA */
+		0x00000000	/* DENALI_CTL_95_DATA */
+		0x00000000	/* DENALI_CTL_96_DATA */
+		0x00000000	/* DENALI_CTL_97_DATA */
+		0x00000000	/* DENALI_CTL_98_DATA */
+		0x00000000	/* DENALI_CTL_99_DATA */
+		0x00000000	/* DENALI_CTL_100_DATA */
+		0x00000000	/* DENALI_CTL_101_DATA */
+		0x00000000	/* DENALI_CTL_102_DATA */
+		0x00000000	/* DENALI_CTL_103_DATA */
+		0x00000000	/* DENALI_CTL_104_DATA */
+		0x00000003	/* DENALI_CTL_105_DATA */
+		0x00000000	/* DENALI_CTL_106_DATA */
+		0x00000000	/* DENALI_CTL_107_DATA */
+		0x00000000	/* DENALI_CTL_108_DATA */
+		0x00000000	/* DENALI_CTL_109_DATA */
+		0x01000000	/* DENALI_CTL_110_DATA */
+		0x00040000	/* DENALI_CTL_111_DATA */
+		0x00800200	/* DENALI_CTL_112_DATA */
+		0x00000200	/* DENALI_CTL_113_DATA */
+		0x00000040	/* DENALI_CTL_114_DATA */
+		0x01000100	/* DENALI_CTL_115_DATA */
+		0x0a000002	/* DENALI_CTL_116_DATA */
+		0x0101ffff	/* DENALI_CTL_117_DATA */
+		0x01010101	/* DENALI_CTL_118_DATA */
+		0x01010101	/* DENALI_CTL_119_DATA */
+		0x0000010b	/* DENALI_CTL_120_DATA */
+		0x00000c03	/* DENALI_CTL_121_DATA */
+		0x00000000	/* DENALI_CTL_122_DATA */
+		0x00000000	/* DENALI_CTL_123_DATA */
+		0x00000000	/* DENALI_CTL_124_DATA */
+		0x00000000	/* DENALI_CTL_125_DATA */
+		0x00030300	/* DENALI_CTL_126_DATA */
+		0x00000000	/* DENALI_CTL_127_DATA */
+		0x00010101	/* DENALI_CTL_128_DATA */
+		0x00000000	/* DENALI_CTL_129_DATA */
+		0x00000000	/* DENALI_CTL_130_DATA */
+		0x00000000	/* DENALI_CTL_131_DATA */
+		0x00000000	/* DENALI_CTL_132_DATA */
+		0x00000000	/* DENALI_CTL_133_DATA */
+		0x00000000	/* DENALI_CTL_134_DATA */
+		0x00000000	/* DENALI_CTL_135_DATA */
+		0x00000000	/* DENALI_CTL_136_DATA */
+		0x00000000	/* DENALI_CTL_137_DATA */
+		0x00000000	/* DENALI_CTL_138_DATA */
+		0x00000000	/* DENALI_CTL_139_DATA */
+		0x00000000	/* DENALI_CTL_140_DATA */
+		0x00000000	/* DENALI_CTL_141_DATA */
+		0x00000000	/* DENALI_CTL_142_DATA */
+		0x00000000	/* DENALI_CTL_143_DATA */
+		0x00000000	/* DENALI_CTL_144_DATA */
+		0x00000000	/* DENALI_CTL_145_DATA */
+		0x00000000	/* DENALI_CTL_146_DATA */
+		0x00000000	/* DENALI_CTL_147_DATA */
+		0x00000000	/* DENALI_CTL_148_DATA */
+		0x00000000	/* DENALI_CTL_149_DATA */
+		0x00000000	/* DENALI_CTL_150_DATA */
+		0x00000000	/* DENALI_CTL_151_DATA */
+		0x00000000	/* DENALI_CTL_152_DATA */
+		0x00000000	/* DENALI_CTL_153_DATA */
+		0x00000000	/* DENALI_CTL_154_DATA */
+		0x00000000	/* DENALI_CTL_155_DATA */
+		0x00000000	/* DENALI_CTL_156_DATA */
+		0x00000000	/* DENALI_CTL_157_DATA */
+		0x00000000	/* DENALI_CTL_158_DATA */
+		0x00000000	/* DENALI_CTL_159_DATA */
+		0x00000000	/* DENALI_CTL_160_DATA */
+		0x02010102	/* DENALI_CTL_161_DATA */
+		0x0108070d	/* DENALI_CTL_162_DATA */
+		0x05050300	/* DENALI_CTL_163_DATA */
+		0x04000503	/* DENALI_CTL_164_DATA */
+		0x00000000	/* DENALI_CTL_165_DATA */
+		0x00000000	/* DENALI_CTL_166_DATA */
+		0x00000000	/* DENALI_CTL_167_DATA */
+		0x00000000	/* DENALI_CTL_168_DATA */
+		0x280d0000	/* DENALI_CTL_169_DATA */
+		0x01000000	/* DENALI_CTL_170_DATA */
+		0x00000000	/* DENALI_CTL_171_DATA */
+		0x00030001	/* DENALI_CTL_172_DATA */
+		0x00000000	/* DENALI_CTL_173_DATA */
+		0x00000000	/* DENALI_CTL_174_DATA */
+		0x00000000	/* DENALI_CTL_175_DATA */
+		0x00000000	/* DENALI_CTL_176_DATA */
+		0x00000000	/* DENALI_CTL_177_DATA */
+		0x00000000	/* DENALI_CTL_178_DATA */
+		0x00000000	/* DENALI_CTL_179_DATA */
+		0x00000000	/* DENALI_CTL_180_DATA */
+		0x01000000	/* DENALI_CTL_181_DATA */
+		0x00000001	/* DENALI_CTL_182_DATA */
+		0x00000100	/* DENALI_CTL_183_DATA */
+		0x00010303	/* DENALI_CTL_184_DATA */
+		0x67676701	/* DENALI_CTL_185_DATA */
+		0x67676767	/* DENALI_CTL_186_DATA */
+		0x67676767	/* DENALI_CTL_187_DATA */
+		0x67676767	/* DENALI_CTL_188_DATA */
+		0x67676767	/* DENALI_CTL_189_DATA */
+		0x67676767	/* DENALI_CTL_190_DATA */
+		0x67676767	/* DENALI_CTL_191_DATA */
+		0x67676767	/* DENALI_CTL_192_DATA */
+		0x67676767	/* DENALI_CTL_193_DATA */
+		0x01000067	/* DENALI_CTL_194_DATA */
+		0x00000001	/* DENALI_CTL_195_DATA */
+		0x00000101	/* DENALI_CTL_196_DATA */
+		0x00000000	/* DENALI_CTL_197_DATA */
+		0x00000000	/* DENALI_CTL_198_DATA */
+		0x00000000	/* DENALI_CTL_199_DATA */
+		0x00000000	/* DENALI_CTL_200_DATA */
+		0x00000000	/* DENALI_CTL_201_DATA */
+		0x00000000	/* DENALI_CTL_202_DATA */
+		0x00000000	/* DENALI_CTL_203_DATA */
+		0x00000000	/* DENALI_CTL_204_DATA */
+		0x00000000	/* DENALI_CTL_205_DATA */
+		0x00000000	/* DENALI_CTL_206_DATA */
+		0x00000000	/* DENALI_CTL_207_DATA */
+		0x00000001	/* DENALI_CTL_208_DATA */
+		0x00000000	/* DENALI_CTL_209_DATA */
+		0x007fffff	/* DENALI_CTL_210_DATA */
+		0x00000000	/* DENALI_CTL_211_DATA */
+		0x007fffff	/* DENALI_CTL_212_DATA */
+		0x00000000	/* DENALI_CTL_213_DATA */
+		0x007fffff	/* DENALI_CTL_214_DATA */
+		0x00000000	/* DENALI_CTL_215_DATA */
+		0x007fffff	/* DENALI_CTL_216_DATA */
+		0x00000000	/* DENALI_CTL_217_DATA */
+		0x007fffff	/* DENALI_CTL_218_DATA */
+		0x00000000	/* DENALI_CTL_219_DATA */
+		0x007fffff	/* DENALI_CTL_220_DATA */
+		0x00000000	/* DENALI_CTL_221_DATA */
+		0x007fffff	/* DENALI_CTL_222_DATA */
+		0x00000000	/* DENALI_CTL_223_DATA */
+		0x037fffff	/* DENALI_CTL_224_DATA */
+		0xffffffff	/* DENALI_CTL_225_DATA */
+		0x000f000f	/* DENALI_CTL_226_DATA */
+		0x00ffff03	/* DENALI_CTL_227_DATA */
+		0x000fffff	/* DENALI_CTL_228_DATA */
+		0x0003000f	/* DENALI_CTL_229_DATA */
+		0xffffffff	/* DENALI_CTL_230_DATA */
+		0x000f000f	/* DENALI_CTL_231_DATA */
+		0x00ffff03	/* DENALI_CTL_232_DATA */
+		0x000fffff	/* DENALI_CTL_233_DATA */
+		0x0003000f	/* DENALI_CTL_234_DATA */
+		0xffffffff	/* DENALI_CTL_235_DATA */
+		0x000f000f	/* DENALI_CTL_236_DATA */
+		0x00ffff03	/* DENALI_CTL_237_DATA */
+		0x000fffff	/* DENALI_CTL_238_DATA */
+		0x0003000f	/* DENALI_CTL_239_DATA */
+		0xffffffff	/* DENALI_CTL_240_DATA */
+		0x000f000f	/* DENALI_CTL_241_DATA */
+		0x00ffff03	/* DENALI_CTL_242_DATA */
+		0x000fffff	/* DENALI_CTL_243_DATA */
+		0x6407000f	/* DENALI_CTL_244_DATA */
+		0x01640001	/* DENALI_CTL_245_DATA */
+		0x00000000	/* DENALI_CTL_246_DATA */
+		0x00000000	/* DENALI_CTL_247_DATA */
+		0x00001800	/* DENALI_CTL_248_DATA */
+		0x00386c05	/* DENALI_CTL_249_DATA */
+		0x02000200	/* DENALI_CTL_250_DATA */
+		0x02000200	/* DENALI_CTL_251_DATA */
+		0x0000386c	/* DENALI_CTL_252_DATA */
+		0x00023438	/* DENALI_CTL_253_DATA */
+		0x02020d0f	/* DENALI_CTL_254_DATA */
+		0x00140303	/* DENALI_CTL_255_DATA */
+		0x00000000	/* DENALI_CTL_256_DATA */
+		0x00000000	/* DENALI_CTL_257_DATA */
+		0x00001403	/* DENALI_CTL_258_DATA */
+		0x00000000	/* DENALI_CTL_259_DATA */
+		0x00000000	/* DENALI_CTL_260_DATA */
+		0x00000000	/* DENALI_CTL_261_DATA */
+		0x00000000	/* DENALI_CTL_262_DATA */
+		0x0c010000	/* DENALI_CTL_263_DATA */
+		0x00000008	/* DENALI_CTL_264_DATA */
+		0x01375642	/* DENALI_PHY_00_DATA */
+		0x0004c008	/* DENALI_PHY_01_DATA */
+		0x000000da	/* DENALI_PHY_02_DATA */
+		0x00000000	/* DENALI_PHY_03_DATA */
+		0x00000000	/* DENALI_PHY_04_DATA */
+		0x00010000	/* DENALI_PHY_05_DATA */
+		0x01DDDD90	/* DENALI_PHY_06_DATA */
+		0x01DDDD90	/* DENALI_PHY_07_DATA */
+		0x01030001	/* DENALI_PHY_08_DATA */
+		0x01000000	/* DENALI_PHY_09_DATA */
+		0x00c00000	/* DENALI_PHY_10_DATA */
+		0x00000007	/* DENALI_PHY_11_DATA */
+		0x00000000	/* DENALI_PHY_12_DATA */
+		0x00000000	/* DENALI_PHY_13_DATA */
+		0x04000408	/* DENALI_PHY_14_DATA */
+		0x00000408	/* DENALI_PHY_15_DATA */
+		0x00e4e400	/* DENALI_PHY_16_DATA */
+		0x00000000	/* DENALI_PHY_17_DATA */
+		0x00000000	/* DENALI_PHY_18_DATA */
+		0x00000000	/* DENALI_PHY_19_DATA */
+		0x00000000	/* DENALI_PHY_20_DATA */
+		0x00000000	/* DENALI_PHY_21_DATA */
+		0x00000000	/* DENALI_PHY_22_DATA */
+		0x00000000	/* DENALI_PHY_23_DATA */
+		0x00000000	/* DENALI_PHY_24_DATA */
+		0x00000000	/* DENALI_PHY_25_DATA */
+		0x00000000	/* DENALI_PHY_26_DATA */
+		0x00000000	/* DENALI_PHY_27_DATA */
+		0x00000000	/* DENALI_PHY_28_DATA */
+		0x00000000	/* DENALI_PHY_29_DATA */
+		0x00000000	/* DENALI_PHY_30_DATA */
+		0x00000000	/* DENALI_PHY_31_DATA */
+		0x00000000	/* DENALI_PHY_32_DATA */
+		0x00200000	/* DENALI_PHY_33_DATA */
+		0x00000000	/* DENALI_PHY_34_DATA */
+		0x00000000	/* DENALI_PHY_35_DATA */
+		0x00000000	/* DENALI_PHY_36_DATA */
+		0x00000000	/* DENALI_PHY_37_DATA */
+		0x00000000	/* DENALI_PHY_38_DATA */
+		0x00000000	/* DENALI_PHY_39_DATA */
+		0x02800280	/* DENALI_PHY_40_DATA */
+		0x02800280	/* DENALI_PHY_41_DATA */
+		0x02800280	/* DENALI_PHY_42_DATA */
+		0x02800280	/* DENALI_PHY_43_DATA */
+		0x00000280	/* DENALI_PHY_44_DATA */
+		0x00000000	/* DENALI_PHY_45_DATA */
+		0x00000000	/* DENALI_PHY_46_DATA */
+		0x00000000	/* DENALI_PHY_47_DATA */
+		0x00000000	/* DENALI_PHY_48_DATA */
+		0x00000000	/* DENALI_PHY_49_DATA */
+		0x00800080	/* DENALI_PHY_50_DATA */
+		0x00800080	/* DENALI_PHY_51_DATA */
+		0x00800080	/* DENALI_PHY_52_DATA */
+		0x00800080	/* DENALI_PHY_53_DATA */
+		0x00800080	/* DENALI_PHY_54_DATA */
+		0x00800080	/* DENALI_PHY_55_DATA */
+		0x00800080	/* DENALI_PHY_56_DATA */
+		0x00800080	/* DENALI_PHY_57_DATA */
+		0x00800080	/* DENALI_PHY_58_DATA */
+		0x000100da	/* DENALI_PHY_59_DATA */
+		0x01ff0010	/* DENALI_PHY_60_DATA */
+		0x00000000	/* DENALI_PHY_61_DATA */
+		0x00000000	/* DENALI_PHY_62_DATA */
+		0x00000002	/* DENALI_PHY_63_DATA */
+		0x51313152	/* DENALI_PHY_64_DATA */
+		0x80013130	/* DENALI_PHY_65_DATA */
+		0x02000080	/* DENALI_PHY_66_DATA */
+		0x00100001	/* DENALI_PHY_67_DATA */
+		0x0c064208	/* DENALI_PHY_68_DATA */
+		0x000f0c0f	/* DENALI_PHY_69_DATA */
+		0x01000140	/* DENALI_PHY_70_DATA */
+		0x0000000c	/* DENALI_PHY_71_DATA */
+		0x00000000	/* DENALI_PHY_72_DATA */
+		0x00000000	/* DENALI_PHY_73_DATA */
+		0x00000000	/* DENALI_PHY_74_DATA */
+		0x00000000	/* DENALI_PHY_75_DATA */
+		0x00000000	/* DENALI_PHY_76_DATA */
+		0x00000000	/* DENALI_PHY_77_DATA */
+		0x00000000	/* DENALI_PHY_78_DATA */
+		0x00000000	/* DENALI_PHY_79_DATA */
+		0x00000000	/* DENALI_PHY_80_DATA */
+		0x00000000	/* DENALI_PHY_81_DATA */
+		0x00000000	/* DENALI_PHY_82_DATA */
+		0x00000000	/* DENALI_PHY_83_DATA */
+		0x00000000	/* DENALI_PHY_84_DATA */
+		0x00000000	/* DENALI_PHY_85_DATA */
+		0x00000000	/* DENALI_PHY_86_DATA */
+		0x00000000	/* DENALI_PHY_87_DATA */
+		0x00000000	/* DENALI_PHY_88_DATA */
+		0x00000000	/* DENALI_PHY_89_DATA */
+		0x00000000	/* DENALI_PHY_90_DATA */
+		0x00000000	/* DENALI_PHY_91_DATA */
+		0x00000000	/* DENALI_PHY_92_DATA */
+		0x00000000	/* DENALI_PHY_93_DATA */
+		0x00000000	/* DENALI_PHY_94_DATA */
+		0x00000000	/* DENALI_PHY_95_DATA */
+		0x00000000	/* DENALI_PHY_96_DATA */
+		0x00000000	/* DENALI_PHY_97_DATA */
+		0x00000000	/* DENALI_PHY_98_DATA */
+		0x00000000	/* DENALI_PHY_99_DATA */
+		0x00000000	/* DENALI_PHY_100_DATA */
+		0x00000000	/* DENALI_PHY_101_DATA */
+		0x00000000	/* DENALI_PHY_102_DATA */
+		0x00000000	/* DENALI_PHY_103_DATA */
+		0x00000000	/* DENALI_PHY_104_DATA */
+		0x00000000	/* DENALI_PHY_105_DATA */
+		0x00000000	/* DENALI_PHY_106_DATA */
+		0x00000000	/* DENALI_PHY_107_DATA */
+		0x00000000	/* DENALI_PHY_108_DATA */
+		0x00000000	/* DENALI_PHY_109_DATA */
+		0x00000000	/* DENALI_PHY_110_DATA */
+		0x00000000	/* DENALI_PHY_111_DATA */
+		0x00000000	/* DENALI_PHY_112_DATA */
+		0x00000000	/* DENALI_PHY_113_DATA */
+		0x00000000	/* DENALI_PHY_114_DATA */
+		0x00000000	/* DENALI_PHY_115_DATA */
+		0x00000000	/* DENALI_PHY_116_DATA */
+		0x00000000	/* DENALI_PHY_117_DATA */
+		0x00000000	/* DENALI_PHY_118_DATA */
+		0x00000000	/* DENALI_PHY_119_DATA */
+		0x00000000	/* DENALI_PHY_120_DATA */
+		0x00000000	/* DENALI_PHY_121_DATA */
+		0x00000000	/* DENALI_PHY_122_DATA */
+		0x00000000	/* DENALI_PHY_123_DATA */
+		0x00000000	/* DENALI_PHY_124_DATA */
+		0x00000000	/* DENALI_PHY_125_DATA */
+		0x00000000	/* DENALI_PHY_126_DATA */
+		0x00000000	/* DENALI_PHY_127_DATA */
+		0x40263571	/* DENALI_PHY_128_DATA */
+		0x0004c008	/* DENALI_PHY_129_DATA */
+		0x000000da	/* DENALI_PHY_130_DATA */
+		0x00000000	/* DENALI_PHY_131_DATA */
+		0x00000000	/* DENALI_PHY_132_DATA */
+		0x00010000	/* DENALI_PHY_133_DATA */
+		0x01DDDD90	/* DENALI_PHY_134_DATA */
+		0x01DDDD90	/* DENALI_PHY_135_DATA */
+		0x01030001	/* DENALI_PHY_136_DATA */
+		0x01000000	/* DENALI_PHY_137_DATA */
+		0x00c00000	/* DENALI_PHY_138_DATA */
+		0x00000007	/* DENALI_PHY_139_DATA */
+		0x00000000	/* DENALI_PHY_140_DATA */
+		0x00000000	/* DENALI_PHY_141_DATA */
+		0x04000408	/* DENALI_PHY_142_DATA */
+		0x00000408	/* DENALI_PHY_143_DATA */
+		0x00e4e400	/* DENALI_PHY_144_DATA */
+		0x00000000	/* DENALI_PHY_145_DATA */
+		0x00000000	/* DENALI_PHY_146_DATA */
+		0x00000000	/* DENALI_PHY_147_DATA */
+		0x00000000	/* DENALI_PHY_148_DATA */
+		0x00000000	/* DENALI_PHY_149_DATA */
+		0x00000000	/* DENALI_PHY_150_DATA */
+		0x00000000	/* DENALI_PHY_151_DATA */
+		0x00000000	/* DENALI_PHY_152_DATA */
+		0x00000000	/* DENALI_PHY_153_DATA */
+		0x00000000	/* DENALI_PHY_154_DATA */
+		0x00000000	/* DENALI_PHY_155_DATA */
+		0x00000000	/* DENALI_PHY_156_DATA */
+		0x00000000	/* DENALI_PHY_157_DATA */
+		0x00000000	/* DENALI_PHY_158_DATA */
+		0x00000000	/* DENALI_PHY_159_DATA */
+		0x00000000	/* DENALI_PHY_160_DATA */
+		0x00200000	/* DENALI_PHY_161_DATA */
+		0x00000000	/* DENALI_PHY_162_DATA */
+		0x00000000	/* DENALI_PHY_163_DATA */
+		0x00000000	/* DENALI_PHY_164_DATA */
+		0x00000000	/* DENALI_PHY_165_DATA */
+		0x00000000	/* DENALI_PHY_166_DATA */
+		0x00000000	/* DENALI_PHY_167_DATA */
+		0x02800280	/* DENALI_PHY_168_DATA */
+		0x02800280	/* DENALI_PHY_169_DATA */
+		0x02800280	/* DENALI_PHY_170_DATA */
+		0x02800280	/* DENALI_PHY_171_DATA */
+		0x00000280	/* DENALI_PHY_172_DATA */
+		0x00000000	/* DENALI_PHY_173_DATA */
+		0x00000000	/* DENALI_PHY_174_DATA */
+		0x00000000	/* DENALI_PHY_175_DATA */
+		0x00000000	/* DENALI_PHY_176_DATA */
+		0x00000000	/* DENALI_PHY_177_DATA */
+		0x00800080	/* DENALI_PHY_178_DATA */
+		0x00800080	/* DENALI_PHY_179_DATA */
+		0x00800080	/* DENALI_PHY_180_DATA */
+		0x00800080	/* DENALI_PHY_181_DATA */
+		0x00800080	/* DENALI_PHY_182_DATA */
+		0x00800080	/* DENALI_PHY_183_DATA */
+		0x00800080	/* DENALI_PHY_184_DATA */
+		0x00800080	/* DENALI_PHY_185_DATA */
+		0x00800080	/* DENALI_PHY_186_DATA */
+		0x000100da	/* DENALI_PHY_187_DATA */
+		0x01ff0010	/* DENALI_PHY_188_DATA */
+		0x00000000	/* DENALI_PHY_189_DATA */
+		0x00000000	/* DENALI_PHY_190_DATA */
+		0x00000002	/* DENALI_PHY_191_DATA */
+		0x51313152	/* DENALI_PHY_192_DATA */
+		0x80013130	/* DENALI_PHY_193_DATA */
+		0x02000080	/* DENALI_PHY_194_DATA */
+		0x00100001	/* DENALI_PHY_195_DATA */
+		0x0c064208	/* DENALI_PHY_196_DATA */
+		0x000f0c0f	/* DENALI_PHY_197_DATA */
+		0x01000140	/* DENALI_PHY_198_DATA */
+		0x0000000c	/* DENALI_PHY_199_DATA */
+		0x00000000	/* DENALI_PHY_200_DATA */
+		0x00000000	/* DENALI_PHY_201_DATA */
+		0x00000000	/* DENALI_PHY_202_DATA */
+		0x00000000	/* DENALI_PHY_203_DATA */
+		0x00000000	/* DENALI_PHY_204_DATA */
+		0x00000000	/* DENALI_PHY_205_DATA */
+		0x00000000	/* DENALI_PHY_206_DATA */
+		0x00000000	/* DENALI_PHY_207_DATA */
+		0x00000000	/* DENALI_PHY_208_DATA */
+		0x00000000	/* DENALI_PHY_209_DATA */
+		0x00000000	/* DENALI_PHY_210_DATA */
+		0x00000000	/* DENALI_PHY_211_DATA */
+		0x00000000	/* DENALI_PHY_212_DATA */
+		0x00000000	/* DENALI_PHY_213_DATA */
+		0x00000000	/* DENALI_PHY_214_DATA */
+		0x00000000	/* DENALI_PHY_215_DATA */
+		0x00000000	/* DENALI_PHY_216_DATA */
+		0x00000000	/* DENALI_PHY_217_DATA */
+		0x00000000	/* DENALI_PHY_218_DATA */
+		0x00000000	/* DENALI_PHY_219_DATA */
+		0x00000000	/* DENALI_PHY_220_DATA */
+		0x00000000	/* DENALI_PHY_221_DATA */
+		0x00000000	/* DENALI_PHY_222_DATA */
+		0x00000000	/* DENALI_PHY_223_DATA */
+		0x00000000	/* DENALI_PHY_224_DATA */
+		0x00000000	/* DENALI_PHY_225_DATA */
+		0x00000000	/* DENALI_PHY_226_DATA */
+		0x00000000	/* DENALI_PHY_227_DATA */
+		0x00000000	/* DENALI_PHY_228_DATA */
+		0x00000000	/* DENALI_PHY_229_DATA */
+		0x00000000	/* DENALI_PHY_230_DATA */
+		0x00000000	/* DENALI_PHY_231_DATA */
+		0x00000000	/* DENALI_PHY_232_DATA */
+		0x00000000	/* DENALI_PHY_233_DATA */
+		0x00000000	/* DENALI_PHY_234_DATA */
+		0x00000000	/* DENALI_PHY_235_DATA */
+		0x00000000	/* DENALI_PHY_236_DATA */
+		0x00000000	/* DENALI_PHY_237_DATA */
+		0x00000000	/* DENALI_PHY_238_DATA */
+		0x00000000	/* DENALI_PHY_239_DATA */
+		0x00000000	/* DENALI_PHY_240_DATA */
+		0x00000000	/* DENALI_PHY_241_DATA */
+		0x00000000	/* DENALI_PHY_242_DATA */
+		0x00000000	/* DENALI_PHY_243_DATA */
+		0x00000000	/* DENALI_PHY_244_DATA */
+		0x00000000	/* DENALI_PHY_245_DATA */
+		0x00000000	/* DENALI_PHY_246_DATA */
+		0x00000000	/* DENALI_PHY_247_DATA */
+		0x00000000	/* DENALI_PHY_248_DATA */
+		0x00000000	/* DENALI_PHY_249_DATA */
+		0x00000000	/* DENALI_PHY_250_DATA */
+		0x00000000	/* DENALI_PHY_251_DATA */
+		0x00000000	/* DENALI_PHY_252_DATA */
+		0x00000000	/* DENALI_PHY_253_DATA */
+		0x00000000	/* DENALI_PHY_254_DATA */
+		0x00000000	/* DENALI_PHY_255_DATA */
+		0x46052371	/* DENALI_PHY_256_DATA */
+		0x0004c008	/* DENALI_PHY_257_DATA */
+		0x000000da	/* DENALI_PHY_258_DATA */
+		0x00000000	/* DENALI_PHY_259_DATA */
+		0x00000000	/* DENALI_PHY_260_DATA */
+		0x00010000	/* DENALI_PHY_261_DATA */
+		0x01DDDD90	/* DENALI_PHY_262_DATA */
+		0x01DDDD90	/* DENALI_PHY_263_DATA */
+		0x01030001	/* DENALI_PHY_264_DATA */
+		0x01000000	/* DENALI_PHY_265_DATA */
+		0x00c00000	/* DENALI_PHY_266_DATA */
+		0x00000007	/* DENALI_PHY_267_DATA */
+		0x00000000	/* DENALI_PHY_268_DATA */
+		0x00000000	/* DENALI_PHY_269_DATA */
+		0x04000408	/* DENALI_PHY_270_DATA */
+		0x00000408	/* DENALI_PHY_271_DATA */
+		0x00e4e400	/* DENALI_PHY_272_DATA */
+		0x00000000	/* DENALI_PHY_273_DATA */
+		0x00000000	/* DENALI_PHY_274_DATA */
+		0x00000000	/* DENALI_PHY_275_DATA */
+		0x00000000	/* DENALI_PHY_276_DATA */
+		0x00000000	/* DENALI_PHY_277_DATA */
+		0x00000000	/* DENALI_PHY_278_DATA */
+		0x00000000	/* DENALI_PHY_279_DATA */
+		0x00000000	/* DENALI_PHY_280_DATA */
+		0x00000000	/* DENALI_PHY_281_DATA */
+		0x00000000	/* DENALI_PHY_282_DATA */
+		0x00000000	/* DENALI_PHY_283_DATA */
+		0x00000000	/* DENALI_PHY_284_DATA */
+		0x00000000	/* DENALI_PHY_285_DATA */
+		0x00000000	/* DENALI_PHY_286_DATA */
+		0x00000000	/* DENALI_PHY_287_DATA */
+		0x00000000	/* DENALI_PHY_288_DATA */
+		0x00200000	/* DENALI_PHY_289_DATA */
+		0x00000000	/* DENALI_PHY_290_DATA */
+		0x00000000	/* DENALI_PHY_291_DATA */
+		0x00000000	/* DENALI_PHY_292_DATA */
+		0x00000000	/* DENALI_PHY_293_DATA */
+		0x00000000	/* DENALI_PHY_294_DATA */
+		0x00000000	/* DENALI_PHY_295_DATA */
+		0x02800280	/* DENALI_PHY_296_DATA */
+		0x02800280	/* DENALI_PHY_297_DATA */
+		0x02800280	/* DENALI_PHY_298_DATA */
+		0x02800280	/* DENALI_PHY_299_DATA */
+		0x00000280	/* DENALI_PHY_300_DATA */
+		0x00000000	/* DENALI_PHY_301_DATA */
+		0x00000000	/* DENALI_PHY_302_DATA */
+		0x00000000	/* DENALI_PHY_303_DATA */
+		0x00000000	/* DENALI_PHY_304_DATA */
+		0x00000000	/* DENALI_PHY_305_DATA */
+		0x00800080	/* DENALI_PHY_306_DATA */
+		0x00800080	/* DENALI_PHY_307_DATA */
+		0x00800080	/* DENALI_PHY_308_DATA */
+		0x00800080	/* DENALI_PHY_309_DATA */
+		0x00800080	/* DENALI_PHY_310_DATA */
+		0x00800080	/* DENALI_PHY_311_DATA */
+		0x00800080	/* DENALI_PHY_312_DATA */
+		0x00800080	/* DENALI_PHY_313_DATA */
+		0x00800080	/* DENALI_PHY_314_DATA */
+		0x000100da	/* DENALI_PHY_315_DATA */
+		0x01ff0010	/* DENALI_PHY_316_DATA */
+		0x00000000	/* DENALI_PHY_317_DATA */
+		0x00000000	/* DENALI_PHY_318_DATA */
+		0x00000002	/* DENALI_PHY_319_DATA */
+		0x51313152	/* DENALI_PHY_320_DATA */
+		0x80013130	/* DENALI_PHY_321_DATA */
+		0x02000080	/* DENALI_PHY_322_DATA */
+		0x00100001	/* DENALI_PHY_323_DATA */
+		0x0c064208	/* DENALI_PHY_324_DATA */
+		0x000f0c0f	/* DENALI_PHY_325_DATA */
+		0x01000140	/* DENALI_PHY_326_DATA */
+		0x0000000c	/* DENALI_PHY_327_DATA */
+		0x00000000	/* DENALI_PHY_328_DATA */
+		0x00000000	/* DENALI_PHY_329_DATA */
+		0x00000000	/* DENALI_PHY_330_DATA */
+		0x00000000	/* DENALI_PHY_331_DATA */
+		0x00000000	/* DENALI_PHY_332_DATA */
+		0x00000000	/* DENALI_PHY_333_DATA */
+		0x00000000	/* DENALI_PHY_334_DATA */
+		0x00000000	/* DENALI_PHY_335_DATA */
+		0x00000000	/* DENALI_PHY_336_DATA */
+		0x00000000	/* DENALI_PHY_337_DATA */
+		0x00000000	/* DENALI_PHY_338_DATA */
+		0x00000000	/* DENALI_PHY_339_DATA */
+		0x00000000	/* DENALI_PHY_340_DATA */
+		0x00000000	/* DENALI_PHY_341_DATA */
+		0x00000000	/* DENALI_PHY_342_DATA */
+		0x00000000	/* DENALI_PHY_343_DATA */
+		0x00000000	/* DENALI_PHY_344_DATA */
+		0x00000000	/* DENALI_PHY_345_DATA */
+		0x00000000	/* DENALI_PHY_346_DATA */
+		0x00000000	/* DENALI_PHY_347_DATA */
+		0x00000000	/* DENALI_PHY_348_DATA */
+		0x00000000	/* DENALI_PHY_349_DATA */
+		0x00000000	/* DENALI_PHY_350_DATA */
+		0x00000000	/* DENALI_PHY_351_DATA */
+		0x00000000	/* DENALI_PHY_352_DATA */
+		0x00000000	/* DENALI_PHY_353_DATA */
+		0x00000000	/* DENALI_PHY_354_DATA */
+		0x00000000	/* DENALI_PHY_355_DATA */
+		0x00000000	/* DENALI_PHY_356_DATA */
+		0x00000000	/* DENALI_PHY_357_DATA */
+		0x00000000	/* DENALI_PHY_358_DATA */
+		0x00000000	/* DENALI_PHY_359_DATA */
+		0x00000000	/* DENALI_PHY_360_DATA */
+		0x00000000	/* DENALI_PHY_361_DATA */
+		0x00000000	/* DENALI_PHY_362_DATA */
+		0x00000000	/* DENALI_PHY_363_DATA */
+		0x00000000	/* DENALI_PHY_364_DATA */
+		0x00000000	/* DENALI_PHY_365_DATA */
+		0x00000000	/* DENALI_PHY_366_DATA */
+		0x00000000	/* DENALI_PHY_367_DATA */
+		0x00000000	/* DENALI_PHY_368_DATA */
+		0x00000000	/* DENALI_PHY_369_DATA */
+		0x00000000	/* DENALI_PHY_370_DATA */
+		0x00000000	/* DENALI_PHY_371_DATA */
+		0x00000000	/* DENALI_PHY_372_DATA */
+		0x00000000	/* DENALI_PHY_373_DATA */
+		0x00000000	/* DENALI_PHY_374_DATA */
+		0x00000000	/* DENALI_PHY_375_DATA */
+		0x00000000	/* DENALI_PHY_376_DATA */
+		0x00000000	/* DENALI_PHY_377_DATA */
+		0x00000000	/* DENALI_PHY_378_DATA */
+		0x00000000	/* DENALI_PHY_379_DATA */
+		0x00000000	/* DENALI_PHY_380_DATA */
+		0x00000000	/* DENALI_PHY_381_DATA */
+		0x00000000	/* DENALI_PHY_382_DATA */
+		0x00000000	/* DENALI_PHY_383_DATA */
+		0x37651240	/* DENALI_PHY_384_DATA */
+		0x0004c008	/* DENALI_PHY_385_DATA */
+		0x000000da	/* DENALI_PHY_386_DATA */
+		0x00000000	/* DENALI_PHY_387_DATA */
+		0x00000000	/* DENALI_PHY_388_DATA */
+		0x00010000	/* DENALI_PHY_389_DATA */
+		0x01DDDD90	/* DENALI_PHY_390_DATA */
+		0x01DDDD90	/* DENALI_PHY_391_DATA */
+		0x01030001	/* DENALI_PHY_392_DATA */
+		0x01000000	/* DENALI_PHY_393_DATA */
+		0x00c00000	/* DENALI_PHY_394_DATA */
+		0x00000007	/* DENALI_PHY_395_DATA */
+		0x00000000	/* DENALI_PHY_396_DATA */
+		0x00000000	/* DENALI_PHY_397_DATA */
+		0x04000408	/* DENALI_PHY_398_DATA */
+		0x00000408	/* DENALI_PHY_399_DATA */
+		0x00e4e400	/* DENALI_PHY_400_DATA */
+		0x00000000	/* DENALI_PHY_401_DATA */
+		0x00000000	/* DENALI_PHY_402_DATA */
+		0x00000000	/* DENALI_PHY_403_DATA */
+		0x00000000	/* DENALI_PHY_404_DATA */
+		0x00000000	/* DENALI_PHY_405_DATA */
+		0x00000000	/* DENALI_PHY_406_DATA */
+		0x00000000	/* DENALI_PHY_407_DATA */
+		0x00000000	/* DENALI_PHY_408_DATA */
+		0x00000000	/* DENALI_PHY_409_DATA */
+		0x00000000	/* DENALI_PHY_410_DATA */
+		0x00000000	/* DENALI_PHY_411_DATA */
+		0x00000000	/* DENALI_PHY_412_DATA */
+		0x00000000	/* DENALI_PHY_413_DATA */
+		0x00000000	/* DENALI_PHY_414_DATA */
+		0x00000000	/* DENALI_PHY_415_DATA */
+		0x00000000	/* DENALI_PHY_416_DATA */
+		0x00200000	/* DENALI_PHY_417_DATA */
+		0x00000000	/* DENALI_PHY_418_DATA */
+		0x00000000	/* DENALI_PHY_419_DATA */
+		0x00000000	/* DENALI_PHY_420_DATA */
+		0x00000000	/* DENALI_PHY_421_DATA */
+		0x00000000	/* DENALI_PHY_422_DATA */
+		0x00000000	/* DENALI_PHY_423_DATA */
+		0x02800280	/* DENALI_PHY_424_DATA */
+		0x02800280	/* DENALI_PHY_425_DATA */
+		0x02800280	/* DENALI_PHY_426_DATA */
+		0x02800280	/* DENALI_PHY_427_DATA */
+		0x00000280	/* DENALI_PHY_428_DATA */
+		0x00000000	/* DENALI_PHY_429_DATA */
+		0x00000000	/* DENALI_PHY_430_DATA */
+		0x00000000	/* DENALI_PHY_431_DATA */
+		0x00000000	/* DENALI_PHY_432_DATA */
+		0x00000000	/* DENALI_PHY_433_DATA */
+		0x00800080	/* DENALI_PHY_434_DATA */
+		0x00800080	/* DENALI_PHY_435_DATA */
+		0x00800080	/* DENALI_PHY_436_DATA */
+		0x00800080	/* DENALI_PHY_437_DATA */
+		0x00800080	/* DENALI_PHY_438_DATA */
+		0x00800080	/* DENALI_PHY_439_DATA */
+		0x00800080	/* DENALI_PHY_440_DATA */
+		0x00800080	/* DENALI_PHY_441_DATA */
+		0x00800080	/* DENALI_PHY_442_DATA */
+		0x000100da	/* DENALI_PHY_443_DATA */
+		0x01ff0010	/* DENALI_PHY_444_DATA */
+		0x00000000	/* DENALI_PHY_445_DATA */
+		0x00000000	/* DENALI_PHY_446_DATA */
+		0x00000002	/* DENALI_PHY_447_DATA */
+		0x51313152	/* DENALI_PHY_448_DATA */
+		0x80013130	/* DENALI_PHY_449_DATA */
+		0x02000080	/* DENALI_PHY_450_DATA */
+		0x00100001	/* DENALI_PHY_451_DATA */
+		0x0c064208	/* DENALI_PHY_452_DATA */
+		0x000f0c0f	/* DENALI_PHY_453_DATA */
+		0x01000140	/* DENALI_PHY_454_DATA */
+		0x0000000c	/* DENALI_PHY_455_DATA */
+		0x00000000	/* DENALI_PHY_456_DATA */
+		0x00000000	/* DENALI_PHY_457_DATA */
+		0x00000000	/* DENALI_PHY_458_DATA */
+		0x00000000	/* DENALI_PHY_459_DATA */
+		0x00000000	/* DENALI_PHY_460_DATA */
+		0x00000000	/* DENALI_PHY_461_DATA */
+		0x00000000	/* DENALI_PHY_462_DATA */
+		0x00000000	/* DENALI_PHY_463_DATA */
+		0x00000000	/* DENALI_PHY_464_DATA */
+		0x00000000	/* DENALI_PHY_465_DATA */
+		0x00000000	/* DENALI_PHY_466_DATA */
+		0x00000000	/* DENALI_PHY_467_DATA */
+		0x00000000	/* DENALI_PHY_468_DATA */
+		0x00000000	/* DENALI_PHY_469_DATA */
+		0x00000000	/* DENALI_PHY_470_DATA */
+		0x00000000	/* DENALI_PHY_471_DATA */
+		0x00000000	/* DENALI_PHY_472_DATA */
+		0x00000000	/* DENALI_PHY_473_DATA */
+		0x00000000	/* DENALI_PHY_474_DATA */
+		0x00000000	/* DENALI_PHY_475_DATA */
+		0x00000000	/* DENALI_PHY_476_DATA */
+		0x00000000	/* DENALI_PHY_477_DATA */
+		0x00000000	/* DENALI_PHY_478_DATA */
+		0x00000000	/* DENALI_PHY_479_DATA */
+		0x00000000	/* DENALI_PHY_480_DATA */
+		0x00000000	/* DENALI_PHY_481_DATA */
+		0x00000000	/* DENALI_PHY_482_DATA */
+		0x00000000	/* DENALI_PHY_483_DATA */
+		0x00000000	/* DENALI_PHY_484_DATA */
+		0x00000000	/* DENALI_PHY_485_DATA */
+		0x00000000	/* DENALI_PHY_486_DATA */
+		0x00000000	/* DENALI_PHY_487_DATA */
+		0x00000000	/* DENALI_PHY_488_DATA */
+		0x00000000	/* DENALI_PHY_489_DATA */
+		0x00000000	/* DENALI_PHY_490_DATA */
+		0x00000000	/* DENALI_PHY_491_DATA */
+		0x00000000	/* DENALI_PHY_492_DATA */
+		0x00000000	/* DENALI_PHY_493_DATA */
+		0x00000000	/* DENALI_PHY_494_DATA */
+		0x00000000	/* DENALI_PHY_495_DATA */
+		0x00000000	/* DENALI_PHY_496_DATA */
+		0x00000000	/* DENALI_PHY_497_DATA */
+		0x00000000	/* DENALI_PHY_498_DATA */
+		0x00000000	/* DENALI_PHY_499_DATA */
+		0x00000000	/* DENALI_PHY_500_DATA */
+		0x00000000	/* DENALI_PHY_501_DATA */
+		0x00000000	/* DENALI_PHY_502_DATA */
+		0x00000000	/* DENALI_PHY_503_DATA */
+		0x00000000	/* DENALI_PHY_504_DATA */
+		0x00000000	/* DENALI_PHY_505_DATA */
+		0x00000000	/* DENALI_PHY_506_DATA */
+		0x00000000	/* DENALI_PHY_507_DATA */
+		0x00000000	/* DENALI_PHY_508_DATA */
+		0x00000000	/* DENALI_PHY_509_DATA */
+		0x00000000	/* DENALI_PHY_510_DATA */
+		0x00000000	/* DENALI_PHY_511_DATA */
+		0x34216750	/* DENALI_PHY_512_DATA */
+		0x0004c008	/* DENALI_PHY_513_DATA */
+		0x000000da	/* DENALI_PHY_514_DATA */
+		0x00000000	/* DENALI_PHY_515_DATA */
+		0x00000000	/* DENALI_PHY_516_DATA */
+		0x00010000	/* DENALI_PHY_517_DATA */
+		0x01DDDD90	/* DENALI_PHY_518_DATA */
+		0x01DDDD90	/* DENALI_PHY_519_DATA */
+		0x01030001	/* DENALI_PHY_520_DATA */
+		0x01000000	/* DENALI_PHY_521_DATA */
+		0x00c00000	/* DENALI_PHY_522_DATA */
+		0x00000007	/* DENALI_PHY_523_DATA */
+		0x00000000	/* DENALI_PHY_524_DATA */
+		0x00000000	/* DENALI_PHY_525_DATA */
+		0x04000408	/* DENALI_PHY_526_DATA */
+		0x00000408	/* DENALI_PHY_527_DATA */
+		0x00e4e400	/* DENALI_PHY_528_DATA */
+		0x00000000	/* DENALI_PHY_529_DATA */
+		0x00000000	/* DENALI_PHY_530_DATA */
+		0x00000000	/* DENALI_PHY_531_DATA */
+		0x00000000	/* DENALI_PHY_532_DATA */
+		0x00000000	/* DENALI_PHY_533_DATA */
+		0x00000000	/* DENALI_PHY_534_DATA */
+		0x00000000	/* DENALI_PHY_535_DATA */
+		0x00000000	/* DENALI_PHY_536_DATA */
+		0x00000000	/* DENALI_PHY_537_DATA */
+		0x00000000	/* DENALI_PHY_538_DATA */
+		0x00000000	/* DENALI_PHY_539_DATA */
+		0x00000000	/* DENALI_PHY_540_DATA */
+		0x00000000	/* DENALI_PHY_541_DATA */
+		0x00000000	/* DENALI_PHY_542_DATA */
+		0x00000000	/* DENALI_PHY_543_DATA */
+		0x00000000	/* DENALI_PHY_544_DATA */
+		0x00200000	/* DENALI_PHY_545_DATA */
+		0x00000000	/* DENALI_PHY_546_DATA */
+		0x00000000	/* DENALI_PHY_547_DATA */
+		0x00000000	/* DENALI_PHY_548_DATA */
+		0x00000000	/* DENALI_PHY_549_DATA */
+		0x00000000	/* DENALI_PHY_550_DATA */
+		0x00000000	/* DENALI_PHY_551_DATA */
+		0x02800280	/* DENALI_PHY_552_DATA */
+		0x02800280	/* DENALI_PHY_553_DATA */
+		0x02800280	/* DENALI_PHY_554_DATA */
+		0x02800280	/* DENALI_PHY_555_DATA */
+		0x00000280	/* DENALI_PHY_556_DATA */
+		0x00000000	/* DENALI_PHY_557_DATA */
+		0x00000000	/* DENALI_PHY_558_DATA */
+		0x00000000	/* DENALI_PHY_559_DATA */
+		0x00000000	/* DENALI_PHY_560_DATA */
+		0x00000000	/* DENALI_PHY_561_DATA */
+		0x00800080	/* DENALI_PHY_562_DATA */
+		0x00800080	/* DENALI_PHY_563_DATA */
+		0x00800080	/* DENALI_PHY_564_DATA */
+		0x00800080	/* DENALI_PHY_565_DATA */
+		0x00800080	/* DENALI_PHY_566_DATA */
+		0x00800080	/* DENALI_PHY_567_DATA */
+		0x00800080	/* DENALI_PHY_568_DATA */
+		0x00800080	/* DENALI_PHY_569_DATA */
+		0x00800080	/* DENALI_PHY_570_DATA */
+		0x000100da	/* DENALI_PHY_571_DATA */
+		0x01ff0010	/* DENALI_PHY_572_DATA */
+		0x00000000	/* DENALI_PHY_573_DATA */
+		0x00000000	/* DENALI_PHY_574_DATA */
+		0x00000002	/* DENALI_PHY_575_DATA */
+		0x51313152	/* DENALI_PHY_576_DATA */
+		0x80013130	/* DENALI_PHY_577_DATA */
+		0x02000080	/* DENALI_PHY_578_DATA */
+		0x00100001	/* DENALI_PHY_579_DATA */
+		0x0c064208	/* DENALI_PHY_580_DATA */
+		0x000f0c0f	/* DENALI_PHY_581_DATA */
+		0x01000140	/* DENALI_PHY_582_DATA */
+		0x0000000c	/* DENALI_PHY_583_DATA */
+		0x00000000	/* DENALI_PHY_584_DATA */
+		0x00000000	/* DENALI_PHY_585_DATA */
+		0x00000000	/* DENALI_PHY_586_DATA */
+		0x00000000	/* DENALI_PHY_587_DATA */
+		0x00000000	/* DENALI_PHY_588_DATA */
+		0x00000000	/* DENALI_PHY_589_DATA */
+		0x00000000	/* DENALI_PHY_590_DATA */
+		0x00000000	/* DENALI_PHY_591_DATA */
+		0x00000000	/* DENALI_PHY_592_DATA */
+		0x00000000	/* DENALI_PHY_593_DATA */
+		0x00000000	/* DENALI_PHY_594_DATA */
+		0x00000000	/* DENALI_PHY_595_DATA */
+		0x00000000	/* DENALI_PHY_596_DATA */
+		0x00000000	/* DENALI_PHY_597_DATA */
+		0x00000000	/* DENALI_PHY_598_DATA */
+		0x00000000	/* DENALI_PHY_599_DATA */
+		0x00000000	/* DENALI_PHY_600_DATA */
+		0x00000000	/* DENALI_PHY_601_DATA */
+		0x00000000	/* DENALI_PHY_602_DATA */
+		0x00000000	/* DENALI_PHY_603_DATA */
+		0x00000000	/* DENALI_PHY_604_DATA */
+		0x00000000	/* DENALI_PHY_605_DATA */
+		0x00000000	/* DENALI_PHY_606_DATA */
+		0x00000000	/* DENALI_PHY_607_DATA */
+		0x00000000	/* DENALI_PHY_608_DATA */
+		0x00000000	/* DENALI_PHY_609_DATA */
+		0x00000000	/* DENALI_PHY_610_DATA */
+		0x00000000	/* DENALI_PHY_611_DATA */
+		0x00000000	/* DENALI_PHY_612_DATA */
+		0x00000000	/* DENALI_PHY_613_DATA */
+		0x00000000	/* DENALI_PHY_614_DATA */
+		0x00000000	/* DENALI_PHY_615_DATA */
+		0x00000000	/* DENALI_PHY_616_DATA */
+		0x00000000	/* DENALI_PHY_617_DATA */
+		0x00000000	/* DENALI_PHY_618_DATA */
+		0x00000000	/* DENALI_PHY_619_DATA */
+		0x00000000	/* DENALI_PHY_620_DATA */
+		0x00000000	/* DENALI_PHY_621_DATA */
+		0x00000000	/* DENALI_PHY_622_DATA */
+		0x00000000	/* DENALI_PHY_623_DATA */
+		0x00000000	/* DENALI_PHY_624_DATA */
+		0x00000000	/* DENALI_PHY_625_DATA */
+		0x00000000	/* DENALI_PHY_626_DATA */
+		0x00000000	/* DENALI_PHY_627_DATA */
+		0x00000000	/* DENALI_PHY_628_DATA */
+		0x00000000	/* DENALI_PHY_629_DATA */
+		0x00000000	/* DENALI_PHY_630_DATA */
+		0x00000000	/* DENALI_PHY_631_DATA */
+		0x00000000	/* DENALI_PHY_632_DATA */
+		0x00000000	/* DENALI_PHY_633_DATA */
+		0x00000000	/* DENALI_PHY_634_DATA */
+		0x00000000	/* DENALI_PHY_635_DATA */
+		0x00000000	/* DENALI_PHY_636_DATA */
+		0x00000000	/* DENALI_PHY_637_DATA */
+		0x00000000	/* DENALI_PHY_638_DATA */
+		0x00000000	/* DENALI_PHY_639_DATA */
+		0x35176402	/* DENALI_PHY_640_DATA */
+		0x0004c008	/* DENALI_PHY_641_DATA */
+		0x000000da	/* DENALI_PHY_642_DATA */
+		0x00000000	/* DENALI_PHY_643_DATA */
+		0x00000000	/* DENALI_PHY_644_DATA */
+		0x00010000	/* DENALI_PHY_645_DATA */
+		0x01DDDD90	/* DENALI_PHY_646_DATA */
+		0x01DDDD90	/* DENALI_PHY_647_DATA */
+		0x01030001	/* DENALI_PHY_648_DATA */
+		0x01000000	/* DENALI_PHY_649_DATA */
+		0x00c00000	/* DENALI_PHY_650_DATA */
+		0x00000007	/* DENALI_PHY_651_DATA */
+		0x00000000	/* DENALI_PHY_652_DATA */
+		0x00000000	/* DENALI_PHY_653_DATA */
+		0x04000408	/* DENALI_PHY_654_DATA */
+		0x00000408	/* DENALI_PHY_655_DATA */
+		0x00e4e400	/* DENALI_PHY_656_DATA */
+		0x00000000	/* DENALI_PHY_657_DATA */
+		0x00000000	/* DENALI_PHY_658_DATA */
+		0x00000000	/* DENALI_PHY_659_DATA */
+		0x00000000	/* DENALI_PHY_660_DATA */
+		0x00000000	/* DENALI_PHY_661_DATA */
+		0x00000000	/* DENALI_PHY_662_DATA */
+		0x00000000	/* DENALI_PHY_663_DATA */
+		0x00000000	/* DENALI_PHY_664_DATA */
+		0x00000000	/* DENALI_PHY_665_DATA */
+		0x00000000	/* DENALI_PHY_666_DATA */
+		0x00000000	/* DENALI_PHY_667_DATA */
+		0x00000000	/* DENALI_PHY_668_DATA */
+		0x00000000	/* DENALI_PHY_669_DATA */
+		0x00000000	/* DENALI_PHY_670_DATA */
+		0x00000000	/* DENALI_PHY_671_DATA */
+		0x00000000	/* DENALI_PHY_672_DATA */
+		0x00200000	/* DENALI_PHY_673_DATA */
+		0x00000000	/* DENALI_PHY_674_DATA */
+		0x00000000	/* DENALI_PHY_675_DATA */
+		0x00000000	/* DENALI_PHY_676_DATA */
+		0x00000000	/* DENALI_PHY_677_DATA */
+		0x00000000	/* DENALI_PHY_678_DATA */
+		0x00000000	/* DENALI_PHY_679_DATA */
+		0x02800280	/* DENALI_PHY_680_DATA */
+		0x02800280	/* DENALI_PHY_681_DATA */
+		0x02800280	/* DENALI_PHY_682_DATA */
+		0x02800280	/* DENALI_PHY_683_DATA */
+		0x00000280	/* DENALI_PHY_684_DATA */
+		0x00000000	/* DENALI_PHY_685_DATA */
+		0x00000000	/* DENALI_PHY_686_DATA */
+		0x00000000	/* DENALI_PHY_687_DATA */
+		0x00000000	/* DENALI_PHY_688_DATA */
+		0x00000000	/* DENALI_PHY_689_DATA */
+		0x00800080	/* DENALI_PHY_690_DATA */
+		0x00800080	/* DENALI_PHY_691_DATA */
+		0x00800080	/* DENALI_PHY_692_DATA */
+		0x00800080	/* DENALI_PHY_693_DATA */
+		0x00800080	/* DENALI_PHY_694_DATA */
+		0x00800080	/* DENALI_PHY_695_DATA */
+		0x00800080	/* DENALI_PHY_696_DATA */
+		0x00800080	/* DENALI_PHY_697_DATA */
+		0x00800080	/* DENALI_PHY_698_DATA */
+		0x000100da	/* DENALI_PHY_699_DATA */
+		0x01ff0010	/* DENALI_PHY_700_DATA */
+		0x00000000	/* DENALI_PHY_701_DATA */
+		0x00000000	/* DENALI_PHY_702_DATA */
+		0x00000002	/* DENALI_PHY_703_DATA */
+		0x51313152	/* DENALI_PHY_704_DATA */
+		0x80013130	/* DENALI_PHY_705_DATA */
+		0x02000080	/* DENALI_PHY_706_DATA */
+		0x00100001	/* DENALI_PHY_707_DATA */
+		0x0c064208	/* DENALI_PHY_708_DATA */
+		0x000f0c0f	/* DENALI_PHY_709_DATA */
+		0x01000140	/* DENALI_PHY_710_DATA */
+		0x0000000c	/* DENALI_PHY_711_DATA */
+		0x00000000	/* DENALI_PHY_712_DATA */
+		0x00000000	/* DENALI_PHY_713_DATA */
+		0x00000000	/* DENALI_PHY_714_DATA */
+		0x00000000	/* DENALI_PHY_715_DATA */
+		0x00000000	/* DENALI_PHY_716_DATA */
+		0x00000000	/* DENALI_PHY_717_DATA */
+		0x00000000	/* DENALI_PHY_718_DATA */
+		0x00000000	/* DENALI_PHY_719_DATA */
+		0x00000000	/* DENALI_PHY_720_DATA */
+		0x00000000	/* DENALI_PHY_721_DATA */
+		0x00000000	/* DENALI_PHY_722_DATA */
+		0x00000000	/* DENALI_PHY_723_DATA */
+		0x00000000	/* DENALI_PHY_724_DATA */
+		0x00000000	/* DENALI_PHY_725_DATA */
+		0x00000000	/* DENALI_PHY_726_DATA */
+		0x00000000	/* DENALI_PHY_727_DATA */
+		0x00000000	/* DENALI_PHY_728_DATA */
+		0x00000000	/* DENALI_PHY_729_DATA */
+		0x00000000	/* DENALI_PHY_730_DATA */
+		0x00000000	/* DENALI_PHY_731_DATA */
+		0x00000000	/* DENALI_PHY_732_DATA */
+		0x00000000	/* DENALI_PHY_733_DATA */
+		0x00000000	/* DENALI_PHY_734_DATA */
+		0x00000000	/* DENALI_PHY_735_DATA */
+		0x00000000	/* DENALI_PHY_736_DATA */
+		0x00000000	/* DENALI_PHY_737_DATA */
+		0x00000000	/* DENALI_PHY_738_DATA */
+		0x00000000	/* DENALI_PHY_739_DATA */
+		0x00000000	/* DENALI_PHY_740_DATA */
+		0x00000000	/* DENALI_PHY_741_DATA */
+		0x00000000	/* DENALI_PHY_742_DATA */
+		0x00000000	/* DENALI_PHY_743_DATA */
+		0x00000000	/* DENALI_PHY_744_DATA */
+		0x00000000	/* DENALI_PHY_745_DATA */
+		0x00000000	/* DENALI_PHY_746_DATA */
+		0x00000000	/* DENALI_PHY_747_DATA */
+		0x00000000	/* DENALI_PHY_748_DATA */
+		0x00000000	/* DENALI_PHY_749_DATA */
+		0x00000000	/* DENALI_PHY_750_DATA */
+		0x00000000	/* DENALI_PHY_751_DATA */
+		0x00000000	/* DENALI_PHY_752_DATA */
+		0x00000000	/* DENALI_PHY_753_DATA */
+		0x00000000	/* DENALI_PHY_754_DATA */
+		0x00000000	/* DENALI_PHY_755_DATA */
+		0x00000000	/* DENALI_PHY_756_DATA */
+		0x00000000	/* DENALI_PHY_757_DATA */
+		0x00000000	/* DENALI_PHY_758_DATA */
+		0x00000000	/* DENALI_PHY_759_DATA */
+		0x00000000	/* DENALI_PHY_760_DATA */
+		0x00000000	/* DENALI_PHY_761_DATA */
+		0x00000000	/* DENALI_PHY_762_DATA */
+		0x00000000	/* DENALI_PHY_763_DATA */
+		0x00000000	/* DENALI_PHY_764_DATA */
+		0x00000000	/* DENALI_PHY_765_DATA */
+		0x00000000	/* DENALI_PHY_766_DATA */
+		0x00000000	/* DENALI_PHY_767_DATA */
+		0x10526347	/* DENALI_PHY_768_DATA */
+		0x0004c008	/* DENALI_PHY_769_DATA */
+		0x000000da	/* DENALI_PHY_770_DATA */
+		0x00000000	/* DENALI_PHY_771_DATA */
+		0x00000000	/* DENALI_PHY_772_DATA */
+		0x00010000	/* DENALI_PHY_773_DATA */
+		0x01DDDD90	/* DENALI_PHY_774_DATA */
+		0x01DDDD90	/* DENALI_PHY_775_DATA */
+		0x01030001	/* DENALI_PHY_776_DATA */
+		0x01000000	/* DENALI_PHY_777_DATA */
+		0x00c00000	/* DENALI_PHY_778_DATA */
+		0x00000007	/* DENALI_PHY_779_DATA */
+		0x00000000	/* DENALI_PHY_780_DATA */
+		0x00000000	/* DENALI_PHY_781_DATA */
+		0x04000408	/* DENALI_PHY_782_DATA */
+		0x00000408	/* DENALI_PHY_783_DATA */
+		0x00e4e400	/* DENALI_PHY_784_DATA */
+		0x00000000	/* DENALI_PHY_785_DATA */
+		0x00000000	/* DENALI_PHY_786_DATA */
+		0x00000000	/* DENALI_PHY_787_DATA */
+		0x00000000	/* DENALI_PHY_788_DATA */
+		0x00000000	/* DENALI_PHY_789_DATA */
+		0x00000000	/* DENALI_PHY_790_DATA */
+		0x00000000	/* DENALI_PHY_791_DATA */
+		0x00000000	/* DENALI_PHY_792_DATA */
+		0x00000000	/* DENALI_PHY_793_DATA */
+		0x00000000	/* DENALI_PHY_794_DATA */
+		0x00000000	/* DENALI_PHY_795_DATA */
+		0x00000000	/* DENALI_PHY_796_DATA */
+		0x00000000	/* DENALI_PHY_797_DATA */
+		0x00000000	/* DENALI_PHY_798_DATA */
+		0x00000000	/* DENALI_PHY_799_DATA */
+		0x00000000	/* DENALI_PHY_800_DATA */
+		0x00200000	/* DENALI_PHY_801_DATA */
+		0x00000000	/* DENALI_PHY_802_DATA */
+		0x00000000	/* DENALI_PHY_803_DATA */
+		0x00000000	/* DENALI_PHY_804_DATA */
+		0x00000000	/* DENALI_PHY_805_DATA */
+		0x00000000	/* DENALI_PHY_806_DATA */
+		0x00000000	/* DENALI_PHY_807_DATA */
+		0x02800280	/* DENALI_PHY_808_DATA */
+		0x02800280	/* DENALI_PHY_809_DATA */
+		0x02800280	/* DENALI_PHY_810_DATA */
+		0x02800280	/* DENALI_PHY_811_DATA */
+		0x00000280	/* DENALI_PHY_812_DATA */
+		0x00000000	/* DENALI_PHY_813_DATA */
+		0x00000000	/* DENALI_PHY_814_DATA */
+		0x00000000	/* DENALI_PHY_815_DATA */
+		0x00000000	/* DENALI_PHY_816_DATA */
+		0x00000000	/* DENALI_PHY_817_DATA */
+		0x00800080	/* DENALI_PHY_818_DATA */
+		0x00800080	/* DENALI_PHY_819_DATA */
+		0x00800080	/* DENALI_PHY_820_DATA */
+		0x00800080	/* DENALI_PHY_821_DATA */
+		0x00800080	/* DENALI_PHY_822_DATA */
+		0x00800080	/* DENALI_PHY_823_DATA */
+		0x00800080	/* DENALI_PHY_824_DATA */
+		0x00800080	/* DENALI_PHY_825_DATA */
+		0x00800080	/* DENALI_PHY_826_DATA */
+		0x000100da	/* DENALI_PHY_827_DATA */
+		0x01ff0010	/* DENALI_PHY_828_DATA */
+		0x00000000	/* DENALI_PHY_829_DATA */
+		0x00000000	/* DENALI_PHY_830_DATA */
+		0x00000002	/* DENALI_PHY_831_DATA */
+		0x51313152	/* DENALI_PHY_832_DATA */
+		0x80013130	/* DENALI_PHY_833_DATA */
+		0x02000080	/* DENALI_PHY_834_DATA */
+		0x00100001	/* DENALI_PHY_835_DATA */
+		0x0c064208	/* DENALI_PHY_836_DATA */
+		0x000f0c0f	/* DENALI_PHY_837_DATA */
+		0x01000140	/* DENALI_PHY_838_DATA */
+		0x0000000c	/* DENALI_PHY_839_DATA */
+		0x00000000	/* DENALI_PHY_840_DATA */
+		0x00000000	/* DENALI_PHY_841_DATA */
+		0x00000000	/* DENALI_PHY_842_DATA */
+		0x00000000	/* DENALI_PHY_843_DATA */
+		0x00000000	/* DENALI_PHY_844_DATA */
+		0x00000000	/* DENALI_PHY_845_DATA */
+		0x00000000	/* DENALI_PHY_846_DATA */
+		0x00000000	/* DENALI_PHY_847_DATA */
+		0x00000000	/* DENALI_PHY_848_DATA */
+		0x00000000	/* DENALI_PHY_849_DATA */
+		0x00000000	/* DENALI_PHY_850_DATA */
+		0x00000000	/* DENALI_PHY_851_DATA */
+		0x00000000	/* DENALI_PHY_852_DATA */
+		0x00000000	/* DENALI_PHY_853_DATA */
+		0x00000000	/* DENALI_PHY_854_DATA */
+		0x00000000	/* DENALI_PHY_855_DATA */
+		0x00000000	/* DENALI_PHY_856_DATA */
+		0x00000000	/* DENALI_PHY_857_DATA */
+		0x00000000	/* DENALI_PHY_858_DATA */
+		0x00000000	/* DENALI_PHY_859_DATA */
+		0x00000000	/* DENALI_PHY_860_DATA */
+		0x00000000	/* DENALI_PHY_861_DATA */
+		0x00000000	/* DENALI_PHY_862_DATA */
+		0x00000000	/* DENALI_PHY_863_DATA */
+		0x00000000	/* DENALI_PHY_864_DATA */
+		0x00000000	/* DENALI_PHY_865_DATA */
+		0x00000000	/* DENALI_PHY_866_DATA */
+		0x00000000	/* DENALI_PHY_867_DATA */
+		0x00000000	/* DENALI_PHY_868_DATA */
+		0x00000000	/* DENALI_PHY_869_DATA */
+		0x00000000	/* DENALI_PHY_870_DATA */
+		0x00000000	/* DENALI_PHY_871_DATA */
+		0x00000000	/* DENALI_PHY_872_DATA */
+		0x00000000	/* DENALI_PHY_873_DATA */
+		0x00000000	/* DENALI_PHY_874_DATA */
+		0x00000000	/* DENALI_PHY_875_DATA */
+		0x00000000	/* DENALI_PHY_876_DATA */
+		0x00000000	/* DENALI_PHY_877_DATA */
+		0x00000000	/* DENALI_PHY_878_DATA */
+		0x00000000	/* DENALI_PHY_879_DATA */
+		0x00000000	/* DENALI_PHY_880_DATA */
+		0x00000000	/* DENALI_PHY_881_DATA */
+		0x00000000	/* DENALI_PHY_882_DATA */
+		0x00000000	/* DENALI_PHY_883_DATA */
+		0x00000000	/* DENALI_PHY_884_DATA */
+		0x00000000	/* DENALI_PHY_885_DATA */
+		0x00000000	/* DENALI_PHY_886_DATA */
+		0x00000000	/* DENALI_PHY_887_DATA */
+		0x00000000	/* DENALI_PHY_888_DATA */
+		0x00000000	/* DENALI_PHY_889_DATA */
+		0x00000000	/* DENALI_PHY_890_DATA */
+		0x00000000	/* DENALI_PHY_891_DATA */
+		0x00000000	/* DENALI_PHY_892_DATA */
+		0x00000000	/* DENALI_PHY_893_DATA */
+		0x00000000	/* DENALI_PHY_894_DATA */
+		0x00000000	/* DENALI_PHY_895_DATA */
+		0x41753260	/* DENALI_PHY_896_DATA */
+		0x0004c008	/* DENALI_PHY_897_DATA */
+		0x000000da	/* DENALI_PHY_898_DATA */
+		0x00000000	/* DENALI_PHY_899_DATA */
+		0x00000000	/* DENALI_PHY_900_DATA */
+		0x00010000	/* DENALI_PHY_901_DATA */
+		0x01DDDD90	/* DENALI_PHY_902_DATA */
+		0x01DDDD90	/* DENALI_PHY_903_DATA */
+		0x01030001	/* DENALI_PHY_904_DATA */
+		0x01000000	/* DENALI_PHY_905_DATA */
+		0x00c00000	/* DENALI_PHY_906_DATA */
+		0x00000007	/* DENALI_PHY_907_DATA */
+		0x00000000	/* DENALI_PHY_908_DATA */
+		0x00000000	/* DENALI_PHY_909_DATA */
+		0x04000408	/* DENALI_PHY_910_DATA */
+		0x00000408	/* DENALI_PHY_911_DATA */
+		0x00e4e400	/* DENALI_PHY_912_DATA */
+		0x00000000	/* DENALI_PHY_913_DATA */
+		0x00000000	/* DENALI_PHY_914_DATA */
+		0x00000000	/* DENALI_PHY_915_DATA */
+		0x00000000	/* DENALI_PHY_916_DATA */
+		0x00000000	/* DENALI_PHY_917_DATA */
+		0x00000000	/* DENALI_PHY_918_DATA */
+		0x00000000	/* DENALI_PHY_919_DATA */
+		0x00000000	/* DENALI_PHY_920_DATA */
+		0x00000000	/* DENALI_PHY_921_DATA */
+		0x00000000	/* DENALI_PHY_922_DATA */
+		0x00000000	/* DENALI_PHY_923_DATA */
+		0x00000000	/* DENALI_PHY_924_DATA */
+		0x00000000	/* DENALI_PHY_925_DATA */
+		0x00000000	/* DENALI_PHY_926_DATA */
+		0x00000000	/* DENALI_PHY_927_DATA */
+		0x00000000	/* DENALI_PHY_928_DATA */
+		0x00200000	/* DENALI_PHY_929_DATA */
+		0x00000000	/* DENALI_PHY_930_DATA */
+		0x00000000	/* DENALI_PHY_931_DATA */
+		0x00000000	/* DENALI_PHY_932_DATA */
+		0x00000000	/* DENALI_PHY_933_DATA */
+		0x00000000	/* DENALI_PHY_934_DATA */
+		0x00000000	/* DENALI_PHY_935_DATA */
+		0x02800280	/* DENALI_PHY_936_DATA */
+		0x02800280	/* DENALI_PHY_937_DATA */
+		0x02800280	/* DENALI_PHY_938_DATA */
+		0x02800280	/* DENALI_PHY_939_DATA */
+		0x00000280	/* DENALI_PHY_940_DATA */
+		0x00000000	/* DENALI_PHY_941_DATA */
+		0x00000000	/* DENALI_PHY_942_DATA */
+		0x00000000	/* DENALI_PHY_943_DATA */
+		0x00000000	/* DENALI_PHY_944_DATA */
+		0x00000000	/* DENALI_PHY_945_DATA */
+		0x00800080	/* DENALI_PHY_946_DATA */
+		0x00800080	/* DENALI_PHY_947_DATA */
+		0x00800080	/* DENALI_PHY_948_DATA */
+		0x00800080	/* DENALI_PHY_949_DATA */
+		0x00800080	/* DENALI_PHY_950_DATA */
+		0x00800080	/* DENALI_PHY_951_DATA */
+		0x00800080	/* DENALI_PHY_952_DATA */
+		0x00800080	/* DENALI_PHY_953_DATA */
+		0x00800080	/* DENALI_PHY_954_DATA */
+		0x000100da	/* DENALI_PHY_955_DATA */
+		0x01ff0010	/* DENALI_PHY_956_DATA */
+		0x00000000	/* DENALI_PHY_957_DATA */
+		0x00000000	/* DENALI_PHY_958_DATA */
+		0x00000002	/* DENALI_PHY_959_DATA */
+		0x51313152	/* DENALI_PHY_960_DATA */
+		0x80013130	/* DENALI_PHY_961_DATA */
+		0x02000080	/* DENALI_PHY_962_DATA */
+		0x00100001	/* DENALI_PHY_963_DATA */
+		0x0c064208	/* DENALI_PHY_964_DATA */
+		0x000f0c0f	/* DENALI_PHY_965_DATA */
+		0x01000140	/* DENALI_PHY_966_DATA */
+		0x0000000c	/* DENALI_PHY_967_DATA */
+		0x00000000	/* DENALI_PHY_968_DATA */
+		0x00000000	/* DENALI_PHY_969_DATA */
+		0x00000000	/* DENALI_PHY_970_DATA */
+		0x00000000	/* DENALI_PHY_971_DATA */
+		0x00000000	/* DENALI_PHY_972_DATA */
+		0x00000000	/* DENALI_PHY_973_DATA */
+		0x00000000	/* DENALI_PHY_974_DATA */
+		0x00000000	/* DENALI_PHY_975_DATA */
+		0x00000000	/* DENALI_PHY_976_DATA */
+		0x00000000	/* DENALI_PHY_977_DATA */
+		0x00000000	/* DENALI_PHY_978_DATA */
+		0x00000000	/* DENALI_PHY_979_DATA */
+		0x00000000	/* DENALI_PHY_980_DATA */
+		0x00000000	/* DENALI_PHY_981_DATA */
+		0x00000000	/* DENALI_PHY_982_DATA */
+		0x00000000	/* DENALI_PHY_983_DATA */
+		0x00000000	/* DENALI_PHY_984_DATA */
+		0x00000000	/* DENALI_PHY_985_DATA */
+		0x00000000	/* DENALI_PHY_986_DATA */
+		0x00000000	/* DENALI_PHY_987_DATA */
+		0x00000000	/* DENALI_PHY_988_DATA */
+		0x00000000	/* DENALI_PHY_989_DATA */
+		0x00000000	/* DENALI_PHY_990_DATA */
+		0x00000000	/* DENALI_PHY_991_DATA */
+		0x00000000	/* DENALI_PHY_992_DATA */
+		0x00000000	/* DENALI_PHY_993_DATA */
+		0x00000000	/* DENALI_PHY_994_DATA */
+		0x00000000	/* DENALI_PHY_995_DATA */
+		0x00000000	/* DENALI_PHY_996_DATA */
+		0x00000000	/* DENALI_PHY_997_DATA */
+		0x00000000	/* DENALI_PHY_998_DATA */
+		0x00000000	/* DENALI_PHY_999_DATA */
+		0x00000000	/* DENALI_PHY_1000_DATA */
+		0x00000000	/* DENALI_PHY_1001_DATA */
+		0x00000000	/* DENALI_PHY_1002_DATA */
+		0x00000000	/* DENALI_PHY_1003_DATA */
+		0x00000000	/* DENALI_PHY_1004_DATA */
+		0x00000000	/* DENALI_PHY_1005_DATA */
+		0x00000000	/* DENALI_PHY_1006_DATA */
+		0x00000000	/* DENALI_PHY_1007_DATA */
+		0x00000000	/* DENALI_PHY_1008_DATA */
+		0x00000000	/* DENALI_PHY_1009_DATA */
+		0x00000000	/* DENALI_PHY_1010_DATA */
+		0x00000000	/* DENALI_PHY_1011_DATA */
+		0x00000000	/* DENALI_PHY_1012_DATA */
+		0x00000000	/* DENALI_PHY_1013_DATA */
+		0x00000000	/* DENALI_PHY_1014_DATA */
+		0x00000000	/* DENALI_PHY_1015_DATA */
+		0x00000000	/* DENALI_PHY_1016_DATA */
+		0x00000000	/* DENALI_PHY_1017_DATA */
+		0x00000000	/* DENALI_PHY_1018_DATA */
+		0x00000000	/* DENALI_PHY_1019_DATA */
+		0x00000000	/* DENALI_PHY_1020_DATA */
+		0x00000000	/* DENALI_PHY_1021_DATA */
+		0x00000000	/* DENALI_PHY_1022_DATA */
+		0x00000000	/* DENALI_PHY_1023_DATA */
+		0x76543210	/* DENALI_PHY_1024_DATA */
+		0x0004c008	/* DENALI_PHY_1025_DATA */
+		0x000000da	/* DENALI_PHY_1026_DATA */
+		0x00000000	/* DENALI_PHY_1027_DATA */
+		0x00000000	/* DENALI_PHY_1028_DATA */
+		0x00010000	/* DENALI_PHY_1029_DATA */
+		0x01665555	/* DENALI_PHY_1030_DATA */
+		0x01665555	/* DENALI_PHY_1031_DATA */
+		0x01030001	/* DENALI_PHY_1032_DATA */
+		0x01000000	/* DENALI_PHY_1033_DATA */
+		0x00c00000	/* DENALI_PHY_1034_DATA */
+		0x00000007	/* DENALI_PHY_1035_DATA */
+		0x00000000	/* DENALI_PHY_1036_DATA */
+		0x00000000	/* DENALI_PHY_1037_DATA */
+		0x04000408	/* DENALI_PHY_1038_DATA */
+		0x00000408	/* DENALI_PHY_1039_DATA */
+		0x00e4e400	/* DENALI_PHY_1040_DATA */
+		0x00000000	/* DENALI_PHY_1041_DATA */
+		0x00000000	/* DENALI_PHY_1042_DATA */
+		0x00000000	/* DENALI_PHY_1043_DATA */
+		0x00000000	/* DENALI_PHY_1044_DATA */
+		0x00000000	/* DENALI_PHY_1045_DATA */
+		0x00000000	/* DENALI_PHY_1046_DATA */
+		0x00000000	/* DENALI_PHY_1047_DATA */
+		0x00000000	/* DENALI_PHY_1048_DATA */
+		0x00000000	/* DENALI_PHY_1049_DATA */
+		0x00000000	/* DENALI_PHY_1050_DATA */
+		0x00000000	/* DENALI_PHY_1051_DATA */
+		0x00000000	/* DENALI_PHY_1052_DATA */
+		0x00000000	/* DENALI_PHY_1053_DATA */
+		0x00000000	/* DENALI_PHY_1054_DATA */
+		0x00000000	/* DENALI_PHY_1055_DATA */
+		0x00000000	/* DENALI_PHY_1056_DATA */
+		0x00200000	/* DENALI_PHY_1057_DATA */
+		0x00000000	/* DENALI_PHY_1058_DATA */
+		0x00000000	/* DENALI_PHY_1059_DATA */
+		0x00000000	/* DENALI_PHY_1060_DATA */
+		0x00000000	/* DENALI_PHY_1061_DATA */
+		0x00000000	/* DENALI_PHY_1062_DATA */
+		0x00000000	/* DENALI_PHY_1063_DATA */
+		0x02800280	/* DENALI_PHY_1064_DATA */
+		0x02800280	/* DENALI_PHY_1065_DATA */
+		0x02800280	/* DENALI_PHY_1066_DATA */
+		0x02800280	/* DENALI_PHY_1067_DATA */
+		0x00000280	/* DENALI_PHY_1068_DATA */
+		0x00000000	/* DENALI_PHY_1069_DATA */
+		0x00000000	/* DENALI_PHY_1070_DATA */
+		0x00000000	/* DENALI_PHY_1071_DATA */
+		0x00000000	/* DENALI_PHY_1072_DATA */
+		0x00000000	/* DENALI_PHY_1073_DATA */
+		0x00800080	/* DENALI_PHY_1074_DATA */
+		0x00800080	/* DENALI_PHY_1075_DATA */
+		0x00800080	/* DENALI_PHY_1076_DATA */
+		0x00800080	/* DENALI_PHY_1077_DATA */
+		0x00800080	/* DENALI_PHY_1078_DATA */
+		0x00800080	/* DENALI_PHY_1079_DATA */
+		0x00800080	/* DENALI_PHY_1080_DATA */
+		0x00800080	/* DENALI_PHY_1081_DATA */
+		0x00800080	/* DENALI_PHY_1082_DATA */
+		0x000100da	/* DENALI_PHY_1083_DATA */
+		0x01ff0010	/* DENALI_PHY_1084_DATA */
+		0x00000000	/* DENALI_PHY_1085_DATA */
+		0x00000000	/* DENALI_PHY_1086_DATA */
+		0x00000002	/* DENALI_PHY_1087_DATA */
+		0x51313152	/* DENALI_PHY_1088_DATA */
+		0x80013130	/* DENALI_PHY_1089_DATA */
+		0x02000080	/* DENALI_PHY_1090_DATA */
+		0x00100001	/* DENALI_PHY_1091_DATA */
+		0x0c064208	/* DENALI_PHY_1092_DATA */
+		0x000f0c0f	/* DENALI_PHY_1093_DATA */
+		0x01000140	/* DENALI_PHY_1094_DATA */
+		0x0000000c	/* DENALI_PHY_1095_DATA */
+		0x00000000	/* DENALI_PHY_1096_DATA */
+		0x00000000	/* DENALI_PHY_1097_DATA */
+		0x00000000	/* DENALI_PHY_1098_DATA */
+		0x00000000	/* DENALI_PHY_1099_DATA */
+		0x00000000	/* DENALI_PHY_1100_DATA */
+		0x00000000	/* DENALI_PHY_1101_DATA */
+		0x00000000	/* DENALI_PHY_1102_DATA */
+		0x00000000	/* DENALI_PHY_1103_DATA */
+		0x00000000	/* DENALI_PHY_1104_DATA */
+		0x00000000	/* DENALI_PHY_1105_DATA */
+		0x00000000	/* DENALI_PHY_1106_DATA */
+		0x00000000	/* DENALI_PHY_1107_DATA */
+		0x00000000	/* DENALI_PHY_1108_DATA */
+		0x00000000	/* DENALI_PHY_1109_DATA */
+		0x00000000	/* DENALI_PHY_1110_DATA */
+		0x00000000	/* DENALI_PHY_1111_DATA */
+		0x00000000	/* DENALI_PHY_1112_DATA */
+		0x00000000	/* DENALI_PHY_1113_DATA */
+		0x00000000	/* DENALI_PHY_1114_DATA */
+		0x00000000	/* DENALI_PHY_1115_DATA */
+		0x00000000	/* DENALI_PHY_1116_DATA */
+		0x00000000	/* DENALI_PHY_1117_DATA */
+		0x00000000	/* DENALI_PHY_1118_DATA */
+		0x00000000	/* DENALI_PHY_1119_DATA */
+		0x00000000	/* DENALI_PHY_1120_DATA */
+		0x00000000	/* DENALI_PHY_1121_DATA */
+		0x00000000	/* DENALI_PHY_1122_DATA */
+		0x00000000	/* DENALI_PHY_1123_DATA */
+		0x00000000	/* DENALI_PHY_1124_DATA */
+		0x00000000	/* DENALI_PHY_1125_DATA */
+		0x00000000	/* DENALI_PHY_1126_DATA */
+		0x00000000	/* DENALI_PHY_1127_DATA */
+		0x00000000	/* DENALI_PHY_1128_DATA */
+		0x00000000	/* DENALI_PHY_1129_DATA */
+		0x00000000	/* DENALI_PHY_1130_DATA */
+		0x00000000	/* DENALI_PHY_1131_DATA */
+		0x00000000	/* DENALI_PHY_1132_DATA */
+		0x00000000	/* DENALI_PHY_1133_DATA */
+		0x00000000	/* DENALI_PHY_1134_DATA */
+		0x00000000	/* DENALI_PHY_1135_DATA */
+		0x00000000	/* DENALI_PHY_1136_DATA */
+		0x00000000	/* DENALI_PHY_1137_DATA */
+		0x00000000	/* DENALI_PHY_1138_DATA */
+		0x00000000	/* DENALI_PHY_1139_DATA */
+		0x00000000	/* DENALI_PHY_1140_DATA */
+		0x00000000	/* DENALI_PHY_1141_DATA */
+		0x00000000	/* DENALI_PHY_1142_DATA */
+		0x00000000	/* DENALI_PHY_1143_DATA */
+		0x00000000	/* DENALI_PHY_1144_DATA */
+		0x00000000	/* DENALI_PHY_1145_DATA */
+		0x00000000	/* DENALI_PHY_1146_DATA */
+		0x00000000	/* DENALI_PHY_1147_DATA */
+		0x00000000	/* DENALI_PHY_1148_DATA */
+		0x00000000	/* DENALI_PHY_1149_DATA */
+		0x00000000	/* DENALI_PHY_1150_DATA */
+		0x00000000	/* DENALI_PHY_1151_DATA */
+		0x00000000	/* DENALI_PHY_1152_DATA */
+		0x00000000	/* DENALI_PHY_1153_DATA */
+		0x00050000	/* DENALI_PHY_1154_DATA */
+		0x00000000	/* DENALI_PHY_1155_DATA */
+		0x00000000	/* DENALI_PHY_1156_DATA */
+		0x00000000	/* DENALI_PHY_1157_DATA */
+		0x00000100	/* DENALI_PHY_1158_DATA */
+		0x00000000	/* DENALI_PHY_1159_DATA */
+		0x00000000	/* DENALI_PHY_1160_DATA */
+		0x00506401	/* DENALI_PHY_1161_DATA */
+		0x01221102	/* DENALI_PHY_1162_DATA */
+		0x00000122	/* DENALI_PHY_1163_DATA */
+		0x00000000	/* DENALI_PHY_1164_DATA */
+		0x000B1F00	/* DENALI_PHY_1165_DATA */
+		0x0B1F0B1F	/* DENALI_PHY_1166_DATA */
+		0x0B1F0B1F	/* DENALI_PHY_1167_DATA */
+		0x0B1F0B1F	/* DENALI_PHY_1168_DATA */
+		0x0B1F0B1F	/* DENALI_PHY_1169_DATA */
+		0x00000B00	/* DENALI_PHY_1170_DATA */
+		0x42080010	/* DENALI_PHY_1171_DATA */
+		0x01000100	/* DENALI_PHY_1172_DATA */
+		0x01000100	/* DENALI_PHY_1173_DATA */
+		0x01000100	/* DENALI_PHY_1174_DATA */
+		0x01000100	/* DENALI_PHY_1175_DATA */
+		0x00000000	/* DENALI_PHY_1176_DATA */
+		0x00000000	/* DENALI_PHY_1177_DATA */
+		0x00000000	/* DENALI_PHY_1178_DATA */
+		0x00000000	/* DENALI_PHY_1179_DATA */
+		0x00000000	/* DENALI_PHY_1180_DATA */
+		0x00000803	/* DENALI_PHY_1181_DATA */
+		0x223FFF00	/* DENALI_PHY_1182_DATA */
+		0x000008FF	/* DENALI_PHY_1183_DATA */
+		0x0000057F	/* DENALI_PHY_1184_DATA */
+		0x0000057F	/* DENALI_PHY_1185_DATA */
+		0x00037FFF	/* DENALI_PHY_1186_DATA */
+		0x00037FFF	/* DENALI_PHY_1187_DATA */
+		0x00004410	/* DENALI_PHY_1188_DATA */
+		0x00004410	/* DENALI_PHY_1189_DATA */
+		0x00004410	/* DENALI_PHY_1190_DATA */
+		0x00004410	/* DENALI_PHY_1191_DATA */
+		0x00004410	/* DENALI_PHY_1192_DATA */
+		0x00000111	/* DENALI_PHY_1193_DATA */
+		0x00000111	/* DENALI_PHY_1194_DATA */
+		0x00000000	/* DENALI_PHY_1195_DATA */
+		0x00000000	/* DENALI_PHY_1196_DATA */
+		0x00000000	/* DENALI_PHY_1197_DATA */
+		0x04000000	/* DENALI_PHY_1198_DATA */
+		0x00000000	/* DENALI_PHY_1199_DATA */
+		0x00000000	/* DENALI_PHY_1200_DATA */
+		0x00000108	/* DENALI_PHY_1201_DATA */
+		0x00000000	/* DENALI_PHY_1202_DATA */
+		0x00000000	/* DENALI_PHY_1203_DATA */
+		0x00000000	/* DENALI_PHY_1204_DATA */
+		0x00000001	/* DENALI_PHY_1205_DATA */
+		0x00000000	/* DENALI_PHY_1206_DATA */
+		0x00000000	/* DENALI_PHY_1207_DATA */
+		0x00000000	/* DENALI_PHY_1208_DATA */
+		0x00000000	/* DENALI_PHY_1209_DATA */
+		0x00000000	/* DENALI_PHY_1210_DATA */
+		0x00000000	/* DENALI_PHY_1211_DATA */
+		0x00020100	/* DENALI_PHY_1212_DATA */
+		0x00000000	/* DENALI_PHY_1213_DATA */
+		0x00000000	/* DENALI_PHY_1214_DATA */
+	>;
+};

+ 41 - 0
arch/riscv/dts/hifive-unmatched-a00-u-boot.dtsi

@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2020-2021 SiFive, Inc
+ */
+
+#include "binman.dtsi"
+#include "fu740-c000-u-boot.dtsi"
+#include "fu740-hifive-unmatched-a00-ddr.dtsi"
+
+/ {
+	aliases {
+		spi0 = &spi0;
+	};
+
+	memory@80000000 {
+		u-boot,dm-spl;
+	};
+
+	hfclk {
+		u-boot,dm-spl;
+	};
+
+	rtcclk {
+		u-boot,dm-spl;
+	};
+
+};
+
+&clint {
+	clocks = <&rtcclk>;
+};
+
+&spi0 {
+	mmc@0 {
+		u-boot,dm-spl;
+	};
+};
+
+&gpio {
+	u-boot,dm-spl;
+};

+ 259 - 0
arch/riscv/dts/hifive-unmatched-a00.dts

@@ -0,0 +1,259 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (c) 2019-2021 SiFive, Inc */
+
+#include "fu740-c000.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/* Clock frequency (in Hz) of the PCB crystal for rtcclk */
+#define RTCCLK_FREQ		1000000
+
+/ {
+	#address-cells = <2>;
+	#size-cells = <2>;
+	model = "SiFive HiFive Unmatched A00";
+	compatible = "sifive,hifive-unmatched-a00", "sifive,fu740-c000",
+		     "sifive,fu740";
+
+	chosen {
+		stdout-path = "serial0";
+	};
+
+	cpus {
+		timebase-frequency = <RTCCLK_FREQ>;
+	};
+
+	memory@80000000 {
+		device_type = "memory";
+		reg = <0x0 0x80000000 0x4 0x00000000>;
+	};
+
+	soc {
+	};
+
+	hfclk: hfclk {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		clock-frequency = <26000000>;
+		clock-output-names = "hfclk";
+	};
+
+	rtcclk: rtcclk {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		clock-frequency = <RTCCLK_FREQ>;
+		clock-output-names = "rtcclk";
+	};
+
+	gpio-poweroff {
+		compatible = "gpio-poweroff";
+		gpios = <&gpio 2 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart1 {
+	status = "okay";
+};
+
+&i2c0 {
+	status = "okay";
+
+	temperature-sensor@4c {
+		compatible = "ti,tmp451";
+		reg = <0x4c>;
+		interrupt-parent = <&gpio>;
+		interrupts = <6 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	pmic@58 {
+		compatible = "dlg,da9063";
+		reg = <0x58>;
+		interrupt-parent = <&gpio>;
+		interrupts = <1 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-controller;
+
+		regulators {
+			vdd_bcore1: bcore1 {
+				regulator-min-microvolt = <1050000>;
+				regulator-max-microvolt = <1050000>;
+				regulator-min-microamp = <5000000>;
+				regulator-max-microamp = <5000000>;
+				regulator-always-on;
+			};
+
+			vdd_bcore2: bcore2 {
+				regulator-min-microvolt = <1050000>;
+				regulator-max-microvolt = <1050000>;
+				regulator-min-microamp = <5000000>;
+				regulator-max-microamp = <5000000>;
+				regulator-always-on;
+			};
+
+			vdd_bpro: bpro {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-min-microamp = <2500000>;
+				regulator-max-microamp = <2500000>;
+				regulator-always-on;
+			};
+
+			vdd_bperi: bperi {
+				regulator-min-microvolt = <1050000>;
+				regulator-max-microvolt = <1050000>;
+				regulator-min-microamp = <1500000>;
+				regulator-max-microamp = <1500000>;
+				regulator-always-on;
+			};
+
+			vdd_bmem: bmem {
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-min-microamp = <3000000>;
+				regulator-max-microamp = <3000000>;
+				regulator-always-on;
+			};
+
+			vdd_bio: bio {
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-min-microamp = <3000000>;
+				regulator-max-microamp = <3000000>;
+				regulator-always-on;
+			};
+
+			vdd_ldo1: ldo1 {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-min-microamp = <100000>;
+				regulator-max-microamp = <100000>;
+				regulator-always-on;
+			};
+
+			vdd_ldo2: ldo2 {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-min-microamp = <200000>;
+				regulator-max-microamp = <200000>;
+				regulator-always-on;
+			};
+
+			vdd_ldo3: ldo3 {
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-min-microamp = <200000>;
+				regulator-max-microamp = <200000>;
+				regulator-always-on;
+			};
+
+			vdd_ldo4: ldo4 {
+				regulator-min-microvolt = <2500000>;
+				regulator-max-microvolt = <2500000>;
+				regulator-min-microamp = <200000>;
+				regulator-max-microamp = <200000>;
+				regulator-always-on;
+			};
+
+			vdd_ldo5: ldo5 {
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-min-microamp = <100000>;
+				regulator-max-microamp = <100000>;
+				regulator-always-on;
+			};
+
+			vdd_ldo6: ldo6 {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-min-microamp = <200000>;
+				regulator-max-microamp = <200000>;
+				regulator-always-on;
+			};
+
+			vdd_ldo7: ldo7 {
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-min-microamp = <200000>;
+				regulator-max-microamp = <200000>;
+				regulator-always-on;
+			};
+
+			vdd_ldo8: ldo8 {
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-min-microamp = <200000>;
+				regulator-max-microamp = <200000>;
+				regulator-always-on;
+			};
+
+			vdd_ld09: ldo9 {
+				regulator-min-microvolt = <1050000>;
+				regulator-max-microvolt = <1050000>;
+				regulator-min-microamp = <200000>;
+				regulator-max-microamp = <200000>;
+			};
+
+			vdd_ldo10: ldo10 {
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-min-microamp = <300000>;
+				regulator-max-microamp = <300000>;
+			};
+
+			vdd_ldo11: ldo11 {
+				regulator-min-microvolt = <2500000>;
+				regulator-max-microvolt = <2500000>;
+				regulator-min-microamp = <300000>;
+				regulator-max-microamp = <300000>;
+				regulator-always-on;
+			};
+		};
+	};
+};
+
+&qspi0 {
+	status = "okay";
+	flash@0 {
+		compatible = "issi,is25wp256", "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <50000000>;
+		m25p,fast-read;
+		spi-tx-bus-width = <4>;
+		spi-rx-bus-width = <4>;
+	};
+};
+
+&spi0 {
+	status = "okay";
+	mmc@0 {
+		compatible = "mmc-spi-slot";
+		reg = <0>;
+		spi-max-frequency = <20000000>;
+		voltage-ranges = <3300 3300>;
+		disable-wp;
+	};
+};
+
+&eth0 {
+	status = "okay";
+	phy-mode = "gmii";
+	phy-handle = <&phy0>;
+	phy0: ethernet-phy@0 {
+		reg = <0>;
+	};
+};
+
+&pwm0 {
+	status = "okay";
+};
+
+&pwm1 {
+	status = "okay";
+};
+
+&gpio {
+	status = "okay";
+};

+ 14 - 0
arch/riscv/include/asm/arch-fu740/cache.h

@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2020-2021 SiFive, Inc.
+ *
+ * Authors:
+ *   Pragnesh Patel <pragnesh.patel@sifve.com>
+ */
+
+#ifndef _CACHE_SIFIVE_H
+#define _CACHE_SIFIVE_H
+
+int cache_enable_ways(void);
+
+#endif /* _CACHE_SIFIVE_H */

+ 14 - 0
arch/riscv/include/asm/arch-fu740/clk.h

@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2020-2021 SiFive Inc
+ *
+ * Authors:
+ *   Pragnesh Patel <pragnesh.patel@sifive.com>
+ */
+
+#ifndef __CLK_SIFIVE_H
+#define __CLK_SIFIVE_H
+
+/* Note: This is a placeholder header for driver compilation. */
+
+#endif

+ 38 - 0
arch/riscv/include/asm/arch-fu740/gpio.h

@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2020-2021 SiFive, Inc.
+ */
+
+#ifndef _GPIO_SIFIVE_H
+#define _GPIO_SIFIVE_H
+
+#define GPIO_INPUT_VAL	0x00
+#define GPIO_INPUT_EN	0x04
+#define GPIO_OUTPUT_EN	0x08
+#define GPIO_OUTPUT_VAL	0x0C
+#define GPIO_RISE_IE	0x18
+#define GPIO_RISE_IP	0x1C
+#define GPIO_FALL_IE	0x20
+#define GPIO_FALL_IP	0x24
+#define GPIO_HIGH_IE	0x28
+#define GPIO_HIGH_IP	0x2C
+#define GPIO_LOW_IE	0x30
+#define GPIO_LOW_IP	0x34
+#define GPIO_OUTPUT_XOR	0x40
+
+#define NR_GPIOS	16
+
+enum gpio_state {
+	LOW,
+	HIGH
+};
+
+/* Details about a GPIO bank */
+struct sifive_gpio_plat {
+	void *base;     /* address of registers in physical memory */
+};
+
+#define SIFIVE_GENERIC_GPIO_NR(port, index) \
+		(((port) * NR_GPIOS) + ((index) & (NR_GPIOS - 1)))
+
+#endif /* _GPIO_SIFIVE_H */

+ 13 - 0
arch/riscv/include/asm/arch-fu740/reset.h

@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2020-2021 SiFive, Inc.
+ *
+ * Author: Sagar Kadam <sagar.kadam@sifive.com>
+ */
+
+#ifndef __RESET_SIFIVE_H
+#define __RESET_SIFIVE_H
+
+int sifive_reset_bind(struct udevice *dev, ulong count);
+
+#endif

+ 14 - 0
arch/riscv/include/asm/arch-fu740/spl.h

@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2020-2021 SiFive, Inc.
+ *
+ * Authors:
+ *   Pragnesh Patel <pragnesh.patel@sifve.com>
+ */
+
+#ifndef _SPL_SIFIVE_H
+#define _SPL_SIFIVE_H
+
+int spl_soc_init(void);
+
+#endif /* _SPL_SIFIVE_H */

+ 1 - 0
board/sifive/unleashed/Kconfig

@@ -28,6 +28,7 @@ config BOARD_SPECIFIC_OPTIONS # dummy
 	select SIFIVE_FU540
 	select ENV_IS_IN_SPI_FLASH
 	select BINMAN
+	select RESET_SIFIVE
 	imply CMD_DHCP
 	imply CMD_EXT2
 	imply CMD_EXT4

+ 51 - 0
board/sifive/unmatched/Kconfig

@@ -0,0 +1,51 @@
+if TARGET_SIFIVE_UNMATCHED
+
+config SYS_BOARD
+	default "unmatched"
+
+config SYS_VENDOR
+	default "sifive"
+
+config SYS_CPU
+	default "fu740"
+
+config SYS_CONFIG_NAME
+	default "sifive-unmatched"
+
+config SYS_TEXT_BASE
+	default 0x80200000 if SPL
+	default 0x80000000 if !RISCV_SMODE
+	default 0x80200000 if RISCV_SMODE
+
+config SPL_TEXT_BASE
+	default 0x08000000
+
+config SPL_OPENSBI_LOAD_ADDR
+	default 0x80000000
+
+config BOARD_SPECIFIC_OPTIONS # dummy
+	def_bool y
+	select SIFIVE_FU740
+	select SUPPORT_SPL
+	select RESET_SIFIVE
+	select BINMAN
+	imply CMD_DHCP
+	imply CMD_EXT2
+	imply CMD_EXT4
+	imply CMD_FAT
+	imply CMD_FS_GENERIC
+	imply CMD_GPT
+	imply PARTITION_TYPE_GUID
+	imply CMD_NET
+	imply CMD_PING
+	imply CMD_SF
+	imply DOS_PARTITION
+	imply EFI_PARTITION
+	imply IP_DYN
+	imply ISO_PARTITION
+	imply PHY_LIB
+	imply PHY_MSCC
+	imply SYSRESET
+	imply SYSRESET_GPIO
+
+endif

+ 9 - 0
board/sifive/unmatched/MAINTAINERS

@@ -0,0 +1,9 @@
+SiFive HiFive Unmatched FU740 BOARD
+M:	Paul Walmsley <paul.walmsley@sifive.com>
+M:	Pragnesh Patel <pragnesh.patel@sifive.com>
+M:	Green Wan <green.wan@sifive.com>
+S:	Maintained
+F:	board/sifive/unmatched/
+F:	doc/board/sifive/hifive-unmatched-fu740.rst
+F:	include/configs/sifive-unmatched.h
+F:	configs/sifive_unmatched_defconfig

+ 9 - 0
board/sifive/unmatched/Makefile

@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2020-2021 SiFive, Inc
+
+obj-y   += unmatched.o
+
+ifdef CONFIG_SPL_BUILD
+obj-y += spl.o
+endif

+ 85 - 0
board/sifive/unmatched/spl.c

@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2020-2021 SiFive, Inc
+ *
+ * Authors:
+ *   Pragnesh Patel <pragnesh.patel@sifive.com>
+ */
+
+#include <init.h>
+#include <spl.h>
+#include <misc.h>
+#include <log.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <asm/gpio.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/spl.h>
+
+#define GEM_PHY_RESET	SIFIVE_GENERIC_GPIO_NR(0, 12)
+
+#define MODE_SELECT_REG		0x1000
+#define MODE_SELECT_SD		0xb
+#define MODE_SELECT_MASK	GENMASK(3, 0)
+
+int spl_board_init_f(void)
+{
+	int ret;
+
+	ret = spl_soc_init();
+	if (ret) {
+		debug("HiFive Unmatched FU740 SPL init failed: %d\n", ret);
+		return ret;
+	}
+
+	/*
+	 * GEMGXL init VSC8541 PHY reset sequence;
+	 * leave pull-down active for 2ms
+	 */
+	udelay(2000);
+	ret = gpio_request(GEM_PHY_RESET, "gem_phy_reset");
+	if (ret) {
+		debug("gem_phy_reset gpio request failed: %d\n", ret);
+		return ret;
+	}
+
+	/* Set GPIO 12 (PHY NRESET) */
+	ret = gpio_direction_output(GEM_PHY_RESET, 1);
+	if (ret) {
+		debug("gem_phy_reset gpio direction set failed: %d\n", ret);
+		return ret;
+	}
+
+	udelay(1);
+
+	/* Reset PHY again to enter unmanaged mode */
+	gpio_set_value(GEM_PHY_RESET, 0);
+	udelay(1);
+	gpio_set_value(GEM_PHY_RESET, 1);
+	mdelay(15);
+
+	return 0;
+}
+
+u32 spl_boot_device(void)
+{
+	u32 mode_select = readl((void *)MODE_SELECT_REG);
+	u32 boot_device = mode_select & MODE_SELECT_MASK;
+
+	switch (boot_device) {
+	case MODE_SELECT_SD:
+		return BOOT_DEVICE_MMC1;
+	default:
+		debug("Unsupported boot device 0x%x but trying MMC1\n",
+		      boot_device);
+		return BOOT_DEVICE_MMC1;
+	}
+}
+
+#ifdef CONFIG_SPL_LOAD_FIT
+int board_fit_config_name_match(const char *name)
+{
+	/* boot using first FIT config */
+	return 0;
+}
+#endif

+ 24 - 0
board/sifive/unmatched/unmatched.c

@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2020-2021, SiFive Inc
+ *
+ * Authors:
+ *   Pragnesh Patel <pragnesh.patel@sifive.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <asm/arch/cache.h>
+
+int board_init(void)
+{
+	int ret;
+
+	/* enable all cache ways */
+	ret = cache_enable_ways();
+	if (ret) {
+		debug("%s: could not enable cache ways\n", __func__);
+		return ret;
+	}
+	return 0;
+}

+ 2 - 2
common/spl/Kconfig

@@ -322,7 +322,7 @@ config SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR
 		     ARCH_ROCKCHIP || ARCH_MVEBU ||  ARCH_SOCFPGA || \
 		     ARCH_AT91 || ARCH_ZYNQ || ARCH_KEYSTONE || OMAP34XX || \
 		     OMAP44XX || OMAP54XX || AM33XX || AM43XX || \
-		     TARGET_SIFIVE_UNLEASHED
+		     TARGET_SIFIVE_UNLEASHED || TARGET_SIFIVE_UNMATCHED
 	help
 	  Use sector number for specifying U-Boot location on MMC/SD in
 	  raw mode.
@@ -339,7 +339,7 @@ config SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR
 	default 0x300 if ARCH_ZYNQ || ARCH_KEYSTONE || OMAP34XX || OMAP44XX || \
 		         OMAP54XX || AM33XX || AM43XX || ARCH_K3
 	default 0x4000 if ARCH_ROCKCHIP
-	default 0x822 if TARGET_SIFIVE_UNLEASHED
+	default 0x822 if TARGET_SIFIVE_UNLEASHED || TARGET_SIFIVE_UNMATCHED
 	help
 	  Address on the MMC to load U-Boot from, when the MMC is being used
 	  in raw mode. Units: MMC sectors (1 sector = 512 bytes).

+ 54 - 0
configs/sifive_unmatched_defconfig

@@ -0,0 +1,54 @@
+CONFIG_RISCV=y
+CONFIG_SPL_GPIO_SUPPORT=y
+CONFIG_SYS_MALLOC_F_LEN=0x3000
+CONFIG_NR_DRAM_BANKS=1
+CONFIG_SPL_DM_SPI=y
+CONFIG_SPL_MMC_SUPPORT=y
+CONFIG_SPL=y
+CONFIG_SPL_SPI_SUPPORT=y
+CONFIG_DEFAULT_DEVICE_TREE="hifive-unmatched-a00"
+CONFIG_TARGET_SIFIVE_UNMATCHED=y
+CONFIG_ARCH_RV64I=y
+CONFIG_RISCV_SMODE=y
+CONFIG_DISTRO_DEFAULTS=y
+CONFIG_FIT=y
+CONFIG_SPL_LOAD_FIT_ADDRESS=0x84000000
+CONFIG_DISPLAY_CPUINFO=y
+CONFIG_DISPLAY_BOARDINFO=y
+CONFIG_DISPLAY_BOARDINFO_LATE=y
+CONFIG_SPL_SEPARATE_BSS=y
+CONFIG_SPL_DM_RESET=y
+CONFIG_SPL_YMODEM_SUPPORT=y
+CONFIG_SYS_RELOC_GD_ENV_ADDR=y
+CONFIG_SPL_CLK=y
+CONFIG_DM_RESET=y
+CONFIG_CMD_PCI=y
+CONFIG_PCI=y
+CONFIG_DM_PCI=y
+CONFIG_PCI_PNP=y
+CONFIG_PCIE_DW_SIFIVE=y
+CONFIG_NVME=y
+CONFIG_DM_ETH=y
+CONFIG_NETDEVICES=y
+CONFIG_E1000=y
+CONFIG_USB=y
+CONFIG_CMD_USB=y
+CONFIG_DM_USB=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_XHCI_PCI=y
+CONFIG_CMD_PART=y
+CONFIG_CMD_NVME=y
+CONFIG_SYS_USB_EVENT_POLL=y
+CONFIG_CMD_GPT=y
+CONFIG_CMD_GPT_RENAME=y
+CONFIG_CMD_EEPROM=y
+CONFIG_CMD_MEMINFO=y
+CONFIG_CMD_I2C=y
+CONFIG_DM_I2C=y
+CONFIG_SYS_I2C_OCORES=y
+CONFIG_CLK_SIFIVE_PRCI=y
+CONFIG_DM_PWM=y
+CONFIG_PWM_SIFIVE=y
+CONFIG_CMD_PWM=y
+CONFIG_SPL_USE_ARCH_MEMMOVE=n

+ 1 - 0
doc/board/sifive/index.rst

@@ -7,3 +7,4 @@ SiFive
    :maxdepth: 2
 
    unleashed
+   unmatched

+ 536 - 0
doc/board/sifive/unmatched.rst

@@ -0,0 +1,536 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+HiFive Unmatched
+================
+
+FU740-C000 RISC-V SoC
+---------------------
+The FU740-C000 is a 4+1 64-bit RISC-V core SoC from SiFive.
+
+The HiFive Unmatched development platform is based on FU740-C000 and capable
+of running Linux.
+
+Mainline support
+----------------
+The support for following drivers are already enabled:
+
+1. SiFive UART Driver.
+2. SiFive PRCI Driver for clock.
+3. Cadence MACB ethernet driver for networking support.
+4. SiFive SPI Driver.
+5. MMC SPI Driver for MMC/SD support.
+
+Booting from uSD using U-Boot SPL
+---------------------------------
+
+Building
+--------
+
+Before building U-Boot SPL, OpenSBI must be built first. OpenSBI can be
+cloned and built for FU740 as below:
+
+.. code-block:: console
+
+	git clone https://github.com/riscv/opensbi.git
+	cd opensbi
+	make PLATFORM=generic
+	export OPENSBI=<path to opensbi/build/platform/generic/firmware/fw_dynamic.bin>
+
+Now build the U-Boot SPL and U-Boot proper
+
+.. code-block:: console
+
+	cd <U-Boot-dir>
+	make sifive_unmatched_defconfig
+	make
+
+This will generate spl/u-boot-spl.bin and u-boot.itb
+
+
+Flashing
+--------
+
+ZSBL loads the U-Boot SPL (u-boot-spl.bin) from a partition with GUID type
+5B193300-FC78-40CD-8002-E86C45580B47
+
+U-Boot SPL expects u-boot.itb from a partition with GUID
+type 2E54B353-1271-4842-806F-E436D6AF6985
+
+u-boot.itb is a combination of fw_dynamic.bin, u-boot-nodtb.bin and
+device tree blob (hifive-unmatched-a00.dtb)
+
+Format the SD card (make sure the disk has GPT, otherwise use gdisk to switch)
+
+.. code-block:: none
+
+	# sudo sgdisk -g --clear -a 1 \
+	> --new=1:34:2081         --change-name=1:spl --typecode=1:5B193300-FC78-40CD-8002-E86C45580B47 \
+	> --new=2:2082:10273      --change-name=2:uboot  --typecode=2:2E54B353-1271-4842-806F-E436D6AF6985 \
+	> --new=3:16384:282623    --change-name=3:boot --typecode=3:0x0700 \
+	> --new=4:286720:13918207 --change-name=4:root --typecode=4:0x8300 \
+	> /dev/sdb
+
+Copy linux Image.gz and hifive-unmatched-a00.dtb to boot partition
+
+.. code-block:: none
+
+	sudo mkfs.vfat /dev/sdb3
+	sudo mkfs.ext4 /dev/sdb4
+
+	sudo mount /dev/sdb3 /media/sdb3
+	sudo cp Image.gz hifive-unmatched-a00.dtb /media/sdb3/
+
+Program the SD card
+
+.. code-block:: none
+
+	sudo dd if=spl/u-boot-spl.bin of=/dev/sda seek=34
+	sudo dd if=u-boot.itb of=/dev/sda seek=2082
+
+Booting
+-------
+Once you plugin the sdcard and power up, you should see the U-Boot prompt.
+
+
+Loading the kernel and dtb
+
+.. code-block:: none
+
+	fatload mmc 0:3 ${kernel_addr_r} Image.gz
+	fatload mmc 0:3 ${fdt_addr_r} hifive-unmatched-a00.dtb
+	booti ${kernel_addr_r} - ${fdt_addr_r}
+
+
+Sample boot log from HiFive Unmatched board
+-------------------------------------------
+
+.. code-block:: none
+
+	U-Boot SPL 2021.04-rc4-00009-g7d70643cc3-dirty (Mar 16 2021 - 18:03:14 +0800)
+	Trying to boot from MMC1
+
+	U-Boot 2021.04-rc4-00009-g7d70643cc3-dirty (Mar 16 2021 - 18:03:14 +0800)
+
+	CPU:   rv64imafdc
+	Model: SiFive HiFive Unmatched A00
+	DRAM:  16 GiB
+	MMC:   spi@10050000:mmc@0: 0
+	In:    serial@10010000
+	Out:   serial@10010000
+	Err:   serial@10010000
+	Model: SiFive HiFive Unmatched A00
+	Net:
+	Error: ethernet@10090000 address not set.
+	No ethernet found.
+
+	Hit any key to stop autoboot:  0
+	PCIe Link up, Gen1
+
+	Device 0: Vendor: 0x126f Rev: S1111A0L Prod: AA000000000000001995
+		    Type: Hard Disk
+		    Capacity: 488386.3 MB = 476.9 GB (1000215216 x 512)
+	... is now current device
+	Scanning nvme 0:1...
+	libfdt fdt_check_header(): FDT_ERR_BADMAGIC
+	Scanning disk mmc@0.blk...
+	** Unrecognized filesystem type **
+	** Unrecognized filesystem type **
+	Scanning disk nvme#0.blk#0...
+	Found 8 disks
+	No EFI system partition
+
+	Error: ethernet@10090000 address not set.
+	BootOrder not defined
+	EFI boot manager: Cannot load any image
+	starting USB...
+	Bus xhci_pci: Register 4000840 NbrPorts 4
+	Starting the controller
+	USB XHCI 1.00
+	scanning bus xhci_pci for devices... 3 USB Device(s) found
+	       scanning usb for storage devices... 0 Storage Device(s) found
+
+	Device 0: unknown device
+	switch to partitions #0, OK
+	mmc0 is current device
+	Scanning mmc 0:3...
+	Found /extlinux/extlinux.conf
+	Retrieving file: /extlinux/extlinux.conf
+	205 bytes read in 9 ms (21.5 KiB/s)
+	1:      OpenEmbedded-SiFive-HiFive-Unmatched
+	Retrieving file: /Image.gz
+	7225919 bytes read in 4734 ms (1.5 MiB/s)
+	append: root=/dev/mmcblk0p4 rootfstype=ext4 rootwait console=ttySIF0,115200 earlycon=sbi
+	Retrieving file: /hifive-unmatched-a00.dtb
+	10445 bytes read in 13 ms (784.2 KiB/s)
+	   Uncompressing Kernel Image
+	Moving Image from 0x84000000 to 0x80200000, end=81629000
+	## Flattened Device Tree blob at 88000000
+	   Booting using the fdt blob at 0x88000000
+	   Using Device Tree in place at 0000000088000000, end 00000000880058cc
+
+	Starting kernel ...
+
+	[    0.000000] Linux version 5.10.15 (oe-user@oe-host) (riscv64-oe-linux-gcc (GCC) 10.2.0, GNU ld (GNU Binutils) 2.35.0.201
+	[    0.000000] OF: fdt: Ignoring memory range 0x80000000 - 0x80200000
+	[    0.000000] earlycon: sbi0 at I/O port 0x0 (options '')
+	[    0.000000] printk: bootconsole [sbi0] enabled
+	[    0.000000] efi: UEFI not found.
+	[    0.000000] Zone ranges:
+	[    0.000000]   DMA32    [mem 0x0000000080200000-0x00000000ffffffff]
+	[    0.000000]   Normal   [mem 0x0000000100000000-0x000000027fffffff]
+	[    0.000000] Movable zone start for each node
+	[    0.000000] Early memory node ranges
+	[    0.000000]   node   0: [mem 0x0000000080200000-0x000000027fffffff]
+	[    0.000000] Zeroed struct page in unavailable ranges: 512 pages
+	[    0.000000] Initmem setup node 0 [mem 0x0000000080200000-0x000000027fffffff]
+	[    0.000000] software IO TLB: mapped [mem 0x00000000fbfff000-0x00000000fffff000] (64MB)
+	[    0.000000] SBI specification v0.3 detected
+	[    0.000000] SBI implementation ID=0x1 Version=0x9
+	[    0.000000] SBI v0.2 TIME extension detected
+	[    0.000000] SBI v0.2 IPI extension detected
+	[    0.000000] SBI v0.2 RFENCE extension detected
+	[    0.000000] SBI v0.2 HSM extension detected
+	[    0.000000] CPU with hartid=0 is not available
+	[    0.000000] CPU with hartid=0 is not available
+	[    0.000000] riscv: ISA extensions acdfim
+	[    0.000000] riscv: ELF capabilities acdfim
+	[    0.000000] percpu: Embedded 26 pages/cpu s66904 r8192 d31400 u106496
+	[    0.000000] Built 1 zonelists, mobility grouping on.  Total pages: 2067975
+	[    0.000000] Kernel command line: root=/dev/mmcblk0p4 rootfstype=ext4 rootwait console=ttySIF0,115200 earlycon=sbi
+	[    0.000000] Dentry cache hash table entries: 1048576 (order: 11, 8388608 bytes, linear)
+	[    0.000000] Inode-cache hash table entries: 524288 (order: 10, 4194304 bytes, linear)
+	[    0.000000] Sorting __ex_table...
+	[    0.000000] mem auto-init: stack:off, heap alloc:off, heap free:off
+	[    0.000000] Memory: 8155880K/8386560K available (8490K kernel code, 5515K rwdata, 4096K rodata, 285K init, 383K bss, 23)
+	[    0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1
+	[    0.000000] rcu: Hierarchical RCU implementation.
+	[    0.000000] rcu:     RCU restricting CPUs from NR_CPUS=8 to nr_cpu_ids=4.
+	[    0.000000]  Tracing variant of Tasks RCU enabled.
+	[    0.000000] rcu: RCU calculated value of scheduler-enlistment delay is 25 jiffies.
+	[    0.000000] rcu: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=4
+	[    0.000000] NR_IRQS: 64, nr_irqs: 64, preallocated irqs: 0
+	[    0.000000] CPU with hartid=0 is not available
+	[    0.000000] riscv-intc: unable to find hart id for /cpus/cpu@0/interrupt-controller
+	[    0.000000] riscv-intc: 64 local interrupts mapped
+	[    0.000000] plic: interrupt-controller@c000000: mapped 69 interrupts with 4 handlers for 9 contexts.
+	[    0.000000] random: get_random_bytes called from 0xffffffe000002a6a with crng_init=0
+	[    0.000000] riscv_timer_init_dt: Registering clocksource cpuid [0] hartid [1]
+	[    0.000000] clocksource: riscv_clocksource: mask: 0xffffffffffffffff max_cycles: 0x1d854df40, max_idle_ns: 352636161696s
+	[    0.000007] sched_clock: 64 bits at 1000kHz, resolution 1000ns, wraps every 2199023255500ns
+	[    0.008626] Console: colour dummy device 80x25
+	[    0.013049] Calibrating delay loop (skipped), value calculated using timer frequency.. 2.00 BogoMIPS (lpj=4000)
+	[    0.023115] pid_max: default: 32768 minimum: 301
+	[    0.028423] Mount-cache hash table entries: 16384 (order: 5, 131072 bytes, linear)
+	[    0.035919] Mountpoint-cache hash table entries: 16384 (order: 5, 131072 bytes, linear)
+	[    0.045957] rcu: Hierarchical SRCU implementation.
+	[    0.050393] EFI services will not be available.
+	[    0.055132] smp: Bringing up secondary CPUs ...
+	[    0.061824] smp: Brought up 1 node, 4 CPUs
+	[    0.067458] devtmpfs: initialized
+	[    0.072700] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645041785100000 ns
+	[    0.081789] futex hash table entries: 1024 (order: 4, 65536 bytes, linear)
+	[    0.089738] NET: Registered protocol family 16
+	[    0.093999] thermal_sys: Registered thermal governor 'step_wise'
+	[    0.109208] iommu: Default domain type: Translated
+	[    0.119694] vgaarb: loaded
+	[    0.122571] SCSI subsystem initialized
+	[    0.126499] usbcore: registered new interface driver usbfs
+	[    0.131686] usbcore: registered new interface driver hub
+	[    0.137071] usbcore: registered new device driver usb
+	[    0.142286] EDAC MC: Ver: 3.0.0
+	[    0.145760] Advanced Linux Sound Architecture Driver Initialized.
+	[    0.152205] clocksource: Switched to clocksource riscv_clocksource
+	[    1.046286] VFS: Disk quotas dquot_6.6.0
+	[    1.049651] VFS: Dquot-cache hash table entries: 512 (order 0, 4096 bytes)
+	[    1.062844] NET: Registered protocol family 2
+	[    1.067172] tcp_listen_portaddr_hash hash table entries: 4096 (order: 4, 65536 bytes, linear)
+	[    1.075455] TCP established hash table entries: 65536 (order: 7, 524288 bytes, linear)
+	[    1.085428] TCP bind hash table entries: 65536 (order: 8, 1048576 bytes, linear)
+	[    1.096548] TCP: Hash tables configured (established 65536 bind 65536)
+	[    1.103043] UDP hash table entries: 4096 (order: 5, 131072 bytes, linear)
+	[    1.109879] UDP-Lite hash table entries: 4096 (order: 5, 131072 bytes, linear)
+	[    1.117413] NET: Registered protocol family 1
+	[    1.121881] RPC: Registered named UNIX socket transport module.
+	[    1.127139] RPC: Registered udp transport module.
+	[    1.131901] RPC: Registered tcp transport module.
+	[    1.136677] RPC: Registered tcp NFSv4.1 backchannel transport module.
+	[    1.143194] PCI: CLS 0 bytes, default 64
+	[    1.148359] Initialise system trusted keyrings
+	[    1.152364] workingset: timestamp_bits=62 max_order=21 bucket_order=0
+	[    1.165382] NFS: Registering the id_resolver key type
+	[    1.169781] Key type id_resolver registered
+	[    1.174011] Key type id_legacy registered
+	[    1.178179] nfs4filelayout_init: NFSv4 File Layout Driver Registering...
+	[    1.184874] Installing knfsd (copyright (C) 1996 okir@monad.swb.de).
+	[    1.192453] 9p: Installing v9fs 9p2000 file system support
+	[    1.198116] NET: Registered protocol family 38
+	[    1.201886] Key type asymmetric registered
+	[    1.206046] Asymmetric key parser 'x509' registered
+	[    1.211029] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 252)
+	[    1.218468] io scheduler mq-deadline registered
+	[    1.223072] io scheduler kyber registered
+	[    1.228803] shpchp: Standard Hot Plug PCI Controller Driver version: 0.4
+	[    1.235017] fu740-pcie e00000000.pcie: FPGA PCIE PROBE
+	[    1.281706] fu740-pcie e00000000.pcie: PCIE-PERSTN is GPIO 504
+	[    1.286922] fu740-pcie e00000000.pcie: PWREN is GPIO 501
+	[    1.292377] fu740-pcie e00000000.pcie: host bridge /soc/pcie@e00000000 ranges:
+	[    1.299603] fu740-pcie e00000000.pcie:       IO 0x0060080000..0x006008ffff -> 0x0060080000
+	[    1.307922] fu740-pcie e00000000.pcie:      MEM 0x0060090000..0x0070ffffff -> 0x0060090000
+	[    1.316244] fu740-pcie e00000000.pcie:      MEM 0x2000000000..0x3fffffffff -> 0x2000000000
+	[    1.432223] fu740-pcie e00000000.pcie: PWREN enabling
+	[    1.436607] fu740-pcie e00000000.pcie: PWREN valid
+	[    1.560226] fu740-pcie e00000000.pcie: invalid resource
+	[    1.664802] fu740-pcie e00000000.pcie: Link up
+	[    1.768582] fu740-pcie e00000000.pcie: Link up
+	[    1.872369] fu740-pcie e00000000.pcie: Link up
+	[    1.876116] fu740-pcie e00000000.pcie: Link up, Gen3
+	[    1.881352] fu740-pcie e00000000.pcie: PCI host bridge to bus 0000:00
+	[    1.887700] pci_bus 0000:00: root bus resource [bus 00-ff]
+	[    1.893247] pci_bus 0000:00: root bus resource [io  0x0000-0xffff] (bus address [0x60080000-0x6008ffff])
+	[    1.902807] pci_bus 0000:00: root bus resource [mem 0x60090000-0x70ffffff]
+	[    1.909748] pci_bus 0000:00: root bus resource [mem 0x2000000000-0x3fffffffff pref]
+	[    1.917517] pci 0000:00:00.0: [f15e:0000] type 01 class 0x060400
+	[    1.923569] pci 0000:00:00.0: reg 0x10: [mem 0x00000000-0x000fffff]
+	[    1.929902] pci 0000:00:00.0: reg 0x38: [mem 0x00000000-0x0000ffff pref]
+	[    1.936723] pci 0000:00:00.0: supports D1
+	[    1.940755] pci 0000:00:00.0: PME# supported from D0 D1 D3hot
+	[    1.947619] pci 0000:01:00.0: [1b21:2824] type 01 class 0x060400
+	[    1.953052] pci 0000:01:00.0: enabling Extended Tags
+	[    1.958165] pci 0000:01:00.0: PME# supported from D0 D3hot D3cold
+	[    1.976890] pci 0000:01:00.0: bridge configuration invalid ([bus 00-00]), reconfiguring
+	[    1.984425] pci 0000:02:00.0: [1b21:2824] type 01 class 0x060400
+	[    1.990396] pci 0000:02:00.0: enabling Extended Tags
+	[    1.995509] pci 0000:02:00.0: PME# supported from D0 D3hot D3cold
+	[    2.001938] pci 0000:02:02.0: [1b21:2824] type 01 class 0x060400
+	[    2.007682] pci 0000:02:02.0: enabling Extended Tags
+	[    2.012793] pci 0000:02:02.0: PME# supported from D0 D3hot D3cold
+	[    2.019167] pci 0000:02:03.0: [1b21:2824] type 01 class 0x060400
+	[    2.024966] pci 0000:02:03.0: enabling Extended Tags
+	[    2.030075] pci 0000:02:03.0: PME# supported from D0 D3hot D3cold
+	[    2.036468] pci 0000:02:04.0: [1b21:2824] type 01 class 0x060400
+	[    2.042250] pci 0000:02:04.0: enabling Extended Tags
+	[    2.047359] pci 0000:02:04.0: PME# supported from D0 D3hot D3cold
+	[    2.053811] pci 0000:02:08.0: [1b21:2824] type 01 class 0x060400
+	[    2.059534] pci 0000:02:08.0: enabling Extended Tags
+	[    2.064647] pci 0000:02:08.0: PME# supported from D0 D3hot D3cold
+	[    2.071499] pci 0000:02:00.0: bridge configuration invalid ([bus 00-00]), reconfiguring
+	[    2.078837] pci 0000:02:02.0: bridge configuration invalid ([bus 00-00]), reconfiguring
+	[    2.086911] pci 0000:02:03.0: bridge configuration invalid ([bus 00-00]), reconfiguring
+	[    2.094987] pci 0000:02:04.0: bridge configuration invalid ([bus 00-00]), reconfiguring
+	[    2.103075] pci 0000:02:08.0: bridge configuration invalid ([bus 00-00]), reconfiguring
+	[    2.111901] pci_bus 0000:03: busn_res: [bus 03-ff] end is updated to 03
+	[    2.118031] pci 0000:04:00.0: [1b21:1142] type 00 class 0x0c0330
+	[    2.123968] pci 0000:04:00.0: reg 0x10: [mem 0x00000000-0x00007fff 64bit]
+	[    2.131038] pci 0000:04:00.0: PME# supported from D3cold
+	[    2.148888] pci_bus 0000:04: busn_res: [bus 04-ff] end is updated to 04
+	[    2.155588] pci_bus 0000:05: busn_res: [bus 05-ff] end is updated to 05
+	[    2.162286] pci_bus 0000:06: busn_res: [bus 06-ff] end is updated to 06
+	[    2.168408] pci 0000:07:00.0: [126f:2263] type 00 class 0x010802
+	[    2.174351] pci 0000:07:00.0: reg 0x10: [mem 0x00000000-0x00003fff 64bit]
+	[    2.192890] pci_bus 0000:07: busn_res: [bus 07-ff] end is updated to 07
+	[    2.198837] pci_bus 0000:02: busn_res: [bus 02-ff] end is updated to 07
+	[    2.205522] pci_bus 0000:01: busn_res: [bus 01-ff] end is updated to 07
+	[    2.212241] pci 0000:00:00.0: BAR 0: assigned [mem 0x60100000-0x601fffff]
+	[    2.219067] pci 0000:00:00.0: BAR 14: assigned [mem 0x60200000-0x603fffff]
+	[    2.226010] pci 0000:00:00.0: BAR 6: assigned [mem 0x60090000-0x6009ffff pref]
+	[    2.233308] pci 0000:01:00.0: BAR 14: assigned [mem 0x60200000-0x603fffff]
+	[    2.240259] pci 0000:02:02.0: BAR 14: assigned [mem 0x60200000-0x602fffff]
+	[    2.247203] pci 0000:02:08.0: BAR 14: assigned [mem 0x60300000-0x603fffff]
+	[    2.254150] pci 0000:02:00.0: PCI bridge to [bus 03]
+	[    2.259217] pci 0000:04:00.0: BAR 0: assigned [mem 0x60200000-0x60207fff 64bit]
+	[    2.266594] pci 0000:02:02.0: PCI bridge to [bus 04]
+	[    2.271615] pci 0000:02:02.0:   bridge window [mem 0x60200000-0x602fffff]
+	[    2.278485] pci 0000:02:03.0: PCI bridge to [bus 05]
+	[    2.283529] pci 0000:02:04.0: PCI bridge to [bus 06]
+	[    2.288572] pci 0000:07:00.0: BAR 0: assigned [mem 0x60300000-0x60303fff 64bit]
+	[    2.295952] pci 0000:02:08.0: PCI bridge to [bus 07]
+	[    2.300973] pci 0000:02:08.0:   bridge window [mem 0x60300000-0x603fffff]
+	[    2.307842] pci 0000:01:00.0: PCI bridge to [bus 02-07]
+	[    2.313133] pci 0000:01:00.0:   bridge window [mem 0x60200000-0x603fffff]
+	[    2.320009] pci 0000:00:00.0: PCI bridge to [bus 01-07]
+	[    2.325288] pci 0000:00:00.0:   bridge window [mem 0x60200000-0x603fffff]
+	[    2.332808] pcieport 0000:00:00.0: AER: enabled with IRQ 51
+	[    2.337946] pcieport 0000:01:00.0: enabling device (0000 -> 0002)
+	[    2.344786] pcieport 0000:02:02.0: enabling device (0000 -> 0002)
+	[    2.351328] pcieport 0000:02:08.0: enabling device (0000 -> 0002)
+	[    2.357091] pci 0000:04:00.0: enabling device (0000 -> 0002)
+	[    2.362751] switchtec: loaded.
+	[    2.365933] L2CACHE: DataError @ 0x00000003.00964470
+	[    2.365992] L2CACHE: No. of Banks in the cache: 4
+	[    2.375414] L2CACHE: No. of ways per bank: 16
+	[    2.379846] L2CACHE: Sets per bank: 512
+	[    2.383751] L2CACHE: Bytes per cache block: 64
+	[    2.388267] L2CACHE: Index of the largest way enabled: 15
+	[    2.434865] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
+	[    2.441695] 10010000.serial: ttySIF0 at MMIO 0x10010000 (irq = 1, base_baud = 115200) is a SiFive UART v0
+	[    2.450625] printk: console [ttySIF0] enabled
+	[    2.450625] printk: console [ttySIF0] enabled
+	[    2.459360] printk: bootconsole [sbi0] disabled
+	[    2.459360] printk: bootconsole [sbi0] disabled
+	[    2.468824] 10011000.serial: ttySIF1 at MMIO 0x10011000 (irq = 2, base_baud = 115200) is a SiFive UART v0
+	[    2.493853] loop: module loaded
+	[    2.526475] nvme nvme0: pci function 0000:07:00.0
+	[    2.530852] nvme 0000:07:00.0: enabling device (0000 -> 0002)
+	[    2.537716] Rounding down aligned max_sectors from 4294967295 to 4294967288
+	[    2.544470] db_root: cannot open: /etc/target
+	[    2.545926] nvme nvme0: allocated 64 MiB host memory buffer.
+	[    2.549020] sifive_spi 10040000.spi: mapped; irq=4, cs=1
+	[    2.559941] spi-nor spi0.0: is25wp256 (32768 Kbytes)
+	[    2.566431] sifive_spi 10050000.spi: mapped; irq=6, cs=1
+	[    2.566707] nvme nvme0: 4/0/0 default/read/poll queues
+	[    2.571935] libphy: Fixed MDIO Bus: probed
+	[    2.580950] macb 10090000.ethernet: Registered clk switch 'sifive-gemgxl-mgmt'
+	[    2.587536] macb 10090000.ethernet: invalid hw address, using random
+	[    2.588100]  nvme0n1: p1 p2
+	[    2.593875] BEU: Load or Store TILINK BUS ERR occurred
+	[    2.594342] libphy: MACB_mii_bus: probed
+	[    2.599312] macb 10090000.ethernet eth0: Cadence GEM rev 0x10070109 at 0x10090000 irq 7 (5e:57:b8:ab:24:4a)
+	[    2.615501] e1000e: Intel(R) PRO/1000 Network Driver
+	[    2.620251] e1000e: Copyright(c) 1999 - 2015 Intel Corporation.
+	[    2.626463] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
+	[    2.632684] ehci-pci: EHCI PCI platform driver
+	[    2.637144] ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
+	[    2.643273] ohci-pci: OHCI PCI platform driver
+	[    2.647731] uhci_hcd: USB Universal Host Controller Interface driver
+	[    2.654315] xhci_hcd 0000:04:00.0: xHCI Host Controller
+	[    2.659450] xhci_hcd 0000:04:00.0: new USB bus registered, assigned bus number 1
+	[    2.807373] xhci_hcd 0000:04:00.0: hcc params 0x0200e081 hci version 0x100 quirks 0x0000000010000410
+	[    2.816609] usb usb1: New USB device found, idVendor=1d6b, idProduct=0002, bcdDevice= 5.10
+	[    2.824115] usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
+	[    2.831312] usb usb1: Product: xHCI Host Controller
+	[    2.836174] usb usb1: Manufacturer: Linux 5.10.15 xhci-hcd
+	[    2.841652] usb usb1: SerialNumber: 0000:04:00.0
+	[    2.846639] hub 1-0:1.0: USB hub found
+	[    2.850037] hub 1-0:1.0: 2 ports detected
+	[    2.854306] xhci_hcd 0000:04:00.0: xHCI Host Controller
+	[    2.859335] xhci_hcd 0000:04:00.0: new USB bus registered, assigned bus number 2
+	[    2.866599] xhci_hcd 0000:04:00.0: Host supports USB 3.0 SuperSpeed
+	[    2.873638] usb usb2: We don't know the algorithms for LPM for this host, disabling LPM.
+	[    2.881074] usb usb2: New USB device found, idVendor=1d6b, idProduct=0003, bcdDevice= 5.10
+	[    2.889212] usb usb2: New USB device strings: Mfr=3, Product=2, SerialNumber=1
+	[    2.896422] usb usb2: Product: xHCI Host Controller
+	[    2.901282] usb usb2: Manufacturer: Linux 5.10.15 xhci-hcd
+	[    2.906752] usb usb2: SerialNumber: 0000:04:00.0
+	[    2.911671] hub 2-0:1.0: USB hub found
+	[    2.915130] hub 2-0:1.0: 2 ports detected
+	[    2.919486] usbcore: registered new interface driver usb-storage
+	[    2.925212] usbcore: registered new interface driver usbserial_generic
+	[    2.931620] usbserial: USB Serial support registered for generic
+	[    2.937771] mousedev: PS/2 mouse device common for all mice
+	[    2.943220] usbcore: registered new interface driver usbtouchscreen
+	[    2.949466] i2c /dev entries driver
+	[    2.954218] lm90 0-004c: supply vcc not found, using dummy regulator
+	[    2.961629] EDAC DEVICE0: Giving out device to module Sifive ECC Manager controller sifive_edac.0: DEV sifive_edac.0 (I)
+	[    2.997874] mmc_spi spi1.0: SD/MMC host mmc0, no DMA, no WP, no poweroff, cd polling
+	[    3.005138] ledtrig-cpu: registered to indicate activity on CPUs
+	[    3.010980] usbcore: registered new interface driver usbhid
+	[    3.016407] usbhid: USB HID core driver
+	[    3.020540] usbcore: registered new interface driver snd-usb-audio
+	[    3.027209] NET: Registered protocol family 10
+	[    3.031878] Segment Routing with IPv6
+	[    3.034864] sit: IPv6, IPv4 and MPLS over IPv4 tunneling driver
+	[    3.041232] NET: Registered protocol family 17
+	[    3.045324] 9pnet: Installing 9P2000 support
+	[    3.049397] Key type dns_resolver registered
+	[    3.053786] Loading compiled-in X.509 certificates
+	[    3.059729] ALSA device list:
+	[    3.061943]   No soundcards found.
+	[    3.066057] Waiting for root device /dev/mmcblk0p4...
+	[    3.077319] mmc0: host does not support reading read-only switch, assuming write-enable
+	[    3.084564] mmc0: new SDHC card on SPI
+	[    3.089699] mmcblk0: mmc0:0000 SD32G 29.7 GiB
+	[    3.126488] GPT:Primary header thinks Alt. header is not at the end of the disk.
+	[    3.133144] GPT:13918241 != 62333951
+	[    3.136679] GPT:Alternate GPT header not at the end of the disk.
+	[    3.142673] GPT:13918241 != 62333951
+	[    3.146231] GPT: Use GNU Parted to correct GPT errors.
+	[    3.151398]  mmcblk0: p1 p2 p3 p4
+	[    3.212226] usb 1-2: new high-speed USB device number 2 using xhci_hcd
+	[    3.258310] EXT4-fs (mmcblk0p4): INFO: recovery required on readonly filesystem
+	[    3.264855] EXT4-fs (mmcblk0p4): write access will be enabled during recovery
+	[    3.458247] usb 1-2: New USB device found, idVendor=174c, idProduct=2074, bcdDevice= 0.01
+	[    3.465662] usb 1-2: New USB device strings: Mfr=2, Product=3, SerialNumber=1
+	[    3.472775] usb 1-2: Product: AS2107
+	[    3.476336] usb 1-2: Manufacturer: ASMedia
+	[    3.480419] usb 1-2: SerialNumber: USB2.0 Hub
+	[    3.533583] EXT4-fs (mmcblk0p4): recovery complete
+	[    3.543756] EXT4-fs (mmcblk0p4): mounted filesystem with ordered data mode. Opts: (null)
+	[    3.551132] VFS: Mounted root (ext4 filesystem) readonly on device 179:4.
+	[    3.554682] hub 1-2:1.0: USB hub found
+	[    3.561105] devtmpfs: mounted
+	[    3.561778] hub 1-2:1.0: 4 ports detected
+	[    3.565546] Freeing unused kernel memory: 284K
+	[    3.572964] Kernel memory protection not selected by kernel config.
+	[    3.579225] Run /sbin/init as init process
+	[    3.613136] usb 2-2: new SuperSpeed Gen 1 USB device number 2 using xhci_hcd
+	[    3.643539] usb 2-2: New USB device found, idVendor=174c, idProduct=3074, bcdDevice= 0.01
+	[    3.650948] usb 2-2: New USB device strings: Mfr=2, Product=3, SerialNumber=1
+	[    3.658072] usb 2-2: Product: AS2107
+	[    3.661630] usb 2-2: Manufacturer: ASMedia
+	[    3.665709] usb 2-2: SerialNumber: USB2.0 Hub
+	[    3.762380] hub 2-2:1.0: USB hub found
+	[    3.766074] hub 2-2:1.0: 4 ports detected
+	[    7.487226] systemd[1]: System time before build time, advancing clock.
+	[    7.788093] systemd[1]: systemd 247.2+ running in system mode. (+PAM -AUDIT -SELINUX +IMA -APPARMOR -SMACK +SYSVINIT +U)
+	[    7.809694] systemd[1]: Detected architecture riscv64.
+
+	Welcome to OpenEmbedded nodistro.0!
+
+	[    7.832648] systemd[1]: Set hostname to <unmatched>.
+	[    9.397499] systemd[1]: Queued start job for default target Multi-User System.
+	[    9.408518] random: systemd: uninitialized urandom read (16 bytes read)
+	[    9.429329] systemd[1]: Created slice system-getty.slice.
+	[  OK  ] Created slice system-getty.slice.
+	[    9.440400] random: systemd: uninitialized urandom read (16 bytes read)
+	[    9.447086] systemd[1]: Created slice system-modprobe.slice.
+	[  OK  ] Created slice system-modprobe.slice.
+	[    9.458480] random: systemd: uninitialized urandom read (16 bytes read)
+	[    9.465436] systemd[1]: Created slice system-serial\x2dgetty.slice.
+	[  OK  ] Created slice system-serial\x2dgetty.slice.
+	[    9.478594] systemd[1]: Created slice User and Session Slice.
+	[  OK  ] Created slice User and Session Slice.
+	[    9.490225] systemd[1]: Started Dispatch Password Requests to Console Directory Watch.
+	[  OK  ] Started Dispatch Password ��…ts to Console Directory Watch.
+	[    9.506407] systemd[1]: Started Forward Password Requests to Wall Directory Watch.
+	[  OK  ] Started Forward Password R��…uests to Wall Directory Watch.
+	[    9.522312] systemd[1]: Reached target Paths.
+	[  OK  ] Reached target Paths.
+	[    9.531078] systemd[1]: Reached target Remote File Systems.
+	[  OK  ] Reached target Remote File Systems.
+	[    9.542855] systemd[1]: Reached target Slices.
+	[  OK  ] Reached target Slices.
+	[    9.552712] systemd[1]: Reached target Swap.
+	[  OK  ] Reached target Swap.
+	[    9.561566] systemd[1]: Listening on initctl Compatibility Named Pipe.
+	[  OK  ] Listening on initctl Compatibility Named Pipe.
+	[    9.578686] systemd[1]: Condition check resulted in Journal Audit Socket being skipped.
+	[    9.586545] systemd[1]: Listening on Journal Socket (/dev/log).
+	[  OK  ] Listening on Journal Socket (/dev/log).
+
+	[snip]
+
+	[  OK  ] Reached target System Time Synchronized.
+	[  OK  ] Reached target Timers.
+	[  OK  ] Listening on D-Bus System Message Bus Socket.
+	[  OK  ] Reached target Sockets.
+	[  OK  ] Reached target Basic System.
+	[  OK  ] Started D-Bus System Message Bus.
+		 Starting User Login Management...
+		 Starting Permit User Sessions...
+	[  OK  ] Started Xinetd A Powerful Replacement For Inetd.
+	[  OK  ] Finished Permit User Sessions.
+	[  OK  ] Started Getty on tty1.
+	[  OK  ] Started Serial Getty on hvc0.
+	[  OK  ] Started Serial Getty on ttySIF0.
+	[  OK  ] Reached target Login Prompts.
+	[  OK  ] Started User Login Management.
+	[  OK  ] Reached target Multi-User System.
+		 Starting Update UTMP about System Runlevel Changes...
+	[  OK  ] Finished Update UTMP about System Runlevel Changes.
+
+	OpenEmbedded nodistro.0 unmatched hvc0
+
+	unmatched login:
+	OpenEmbedded nodistro.0 unmatched ttySIF0
+
+	unmatched login:

+ 4 - 4
drivers/clk/sifive/Kconfig

@@ -6,11 +6,11 @@ config CLK_SIFIVE
 	help
 	  SoC drivers for SiFive Linux-capable SoCs.
 
-config CLK_SIFIVE_FU540_PRCI
-	bool "PRCI driver for SiFive FU540 SoCs"
+config CLK_SIFIVE_PRCI
+	bool "PRCI driver for SiFive SoCs"
 	depends on CLK_SIFIVE
 	select CLK_ANALOGBITS_WRPLL_CLN28HPC
 	help
 	  Supports the Power Reset Clock interface (PRCI) IP block found in
-	  FU540 SoCs.  If this kernel is meant to run on a SiFive FU540 SoC,
-	  enable this driver.
+	  FU540/FU740 SoCs. If this kernel is meant to run on a SiFive FU540/
+	  FU740 SoCs, enable this driver.

+ 3 - 1
drivers/clk/sifive/Makefile

@@ -1,3 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0+
 
-obj-$(CONFIG_CLK_SIFIVE_FU540_PRCI)		+= fu540-prci.o
+obj-y += sifive-prci.o
+
+obj-$(CONFIG_CLK_SIFIVE_PRCI) += fu540-prci.o fu740-prci.o

+ 21 - 748
drivers/clk/sifive/fu540-prci.c

@@ -5,6 +5,8 @@
  * Copyright (C) 2018 SiFive, Inc.
  * Wesley Terpstra
  * Paul Walmsley
+ * Zong Li
+ * Pragnesh Patel
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -15,632 +17,48 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
- * The FU540 PRCI implements clock and reset control for the SiFive
- * FU540-C000 chip.   This driver assumes that it has sole control
- * over all PRCI resources.
- *
- * This driver is based on the PRCI driver written by Wesley Terpstra.
- *
- * Refer, commit 999529edf517ed75b56659d456d221b2ee56bb60 of:
- * https://github.com/riscv/riscv-linux
- *
  * References:
  * - SiFive FU540-C000 manual v1p0, Chapter 7 "Clocking and Reset"
  */
 
-#include <common.h>
-#include <clk-uclass.h>
-#include <clk.h>
-#include <div64.h>
-#include <dm.h>
-#include <dm/device.h>
-#include <dm/device_compat.h>
-#include <dm/uclass.h>
 #include <dt-bindings/clock/sifive-fu540-prci.h>
-#include <dt-bindings/reset/sifive-fu540-prci.h>
-#include <errno.h>
-#include <reset-uclass.h>
-#include <asm/io.h>
-#include <asm/arch/reset.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/math64.h>
-#include <linux/clk/analogbits-wrpll-cln28hpc.h>
-
-/*
- * EXPECTED_CLK_PARENT_COUNT: how many parent clocks this driver expects:
- *     hfclk and rtcclk
- */
-#define EXPECTED_CLK_PARENT_COUNT	2
-
-/*
- * Register offsets and bitmasks
- */
-
-/* COREPLLCFG0 */
-#define PRCI_COREPLLCFG0_OFFSET		0x4
-#define PRCI_COREPLLCFG0_DIVR_SHIFT	0
-#define PRCI_COREPLLCFG0_DIVR_MASK	(0x3f << PRCI_COREPLLCFG0_DIVR_SHIFT)
-#define PRCI_COREPLLCFG0_DIVF_SHIFT	6
-#define PRCI_COREPLLCFG0_DIVF_MASK	(0x1ff << PRCI_COREPLLCFG0_DIVF_SHIFT)
-#define PRCI_COREPLLCFG0_DIVQ_SHIFT	15
-#define PRCI_COREPLLCFG0_DIVQ_MASK	(0x7 << PRCI_COREPLLCFG0_DIVQ_SHIFT)
-#define PRCI_COREPLLCFG0_RANGE_SHIFT	18
-#define PRCI_COREPLLCFG0_RANGE_MASK	(0x7 << PRCI_COREPLLCFG0_RANGE_SHIFT)
-#define PRCI_COREPLLCFG0_BYPASS_SHIFT	24
-#define PRCI_COREPLLCFG0_BYPASS_MASK	(0x1 << PRCI_COREPLLCFG0_BYPASS_SHIFT)
-#define PRCI_COREPLLCFG0_FSE_SHIFT	25
-#define PRCI_COREPLLCFG0_FSE_MASK	(0x1 << PRCI_COREPLLCFG0_FSE_SHIFT)
-#define PRCI_COREPLLCFG0_LOCK_SHIFT	31
-#define PRCI_COREPLLCFG0_LOCK_MASK	(0x1 << PRCI_COREPLLCFG0_LOCK_SHIFT)
-
-/* COREPLLCFG1 */
-#define PRCI_COREPLLCFG1_OFFSET		0x8
-#define PRCI_COREPLLCFG1_CKE_SHIFT	31
-#define PRCI_COREPLLCFG1_CKE_MASK	(0x1 << PRCI_COREPLLCFG1_CKE_SHIFT)
-
-/* DDRPLLCFG0 */
-#define PRCI_DDRPLLCFG0_OFFSET		0xc
-#define PRCI_DDRPLLCFG0_DIVR_SHIFT	0
-#define PRCI_DDRPLLCFG0_DIVR_MASK	(0x3f << PRCI_DDRPLLCFG0_DIVR_SHIFT)
-#define PRCI_DDRPLLCFG0_DIVF_SHIFT	6
-#define PRCI_DDRPLLCFG0_DIVF_MASK	(0x1ff << PRCI_DDRPLLCFG0_DIVF_SHIFT)
-#define PRCI_DDRPLLCFG0_DIVQ_SHIFT	15
-#define PRCI_DDRPLLCFG0_DIVQ_MASK	(0x7 << PRCI_DDRPLLCFG0_DIVQ_SHIFT)
-#define PRCI_DDRPLLCFG0_RANGE_SHIFT	18
-#define PRCI_DDRPLLCFG0_RANGE_MASK	(0x7 << PRCI_DDRPLLCFG0_RANGE_SHIFT)
-#define PRCI_DDRPLLCFG0_BYPASS_SHIFT	24
-#define PRCI_DDRPLLCFG0_BYPASS_MASK	(0x1 << PRCI_DDRPLLCFG0_BYPASS_SHIFT)
-#define PRCI_DDRPLLCFG0_FSE_SHIFT	25
-#define PRCI_DDRPLLCFG0_FSE_MASK	(0x1 << PRCI_DDRPLLCFG0_FSE_SHIFT)
-#define PRCI_DDRPLLCFG0_LOCK_SHIFT	31
-#define PRCI_DDRPLLCFG0_LOCK_MASK	(0x1 << PRCI_DDRPLLCFG0_LOCK_SHIFT)
-
-/* DDRPLLCFG1 */
-#define PRCI_DDRPLLCFG1_OFFSET		0x10
-#define PRCI_DDRPLLCFG1_CKE_SHIFT	31
-#define PRCI_DDRPLLCFG1_CKE_MASK	(0x1 << PRCI_DDRPLLCFG1_CKE_SHIFT)
-
-/* GEMGXLPLLCFG0 */
-#define PRCI_GEMGXLPLLCFG0_OFFSET	0x1c
-#define PRCI_GEMGXLPLLCFG0_DIVR_SHIFT	0
-#define PRCI_GEMGXLPLLCFG0_DIVR_MASK	\
-			(0x3f << PRCI_GEMGXLPLLCFG0_DIVR_SHIFT)
-#define PRCI_GEMGXLPLLCFG0_DIVF_SHIFT	6
-#define PRCI_GEMGXLPLLCFG0_DIVF_MASK	\
-			(0x1ff << PRCI_GEMGXLPLLCFG0_DIVF_SHIFT)
-#define PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT	15
-#define PRCI_GEMGXLPLLCFG0_DIVQ_MASK	(0x7 << PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT)
-#define PRCI_GEMGXLPLLCFG0_RANGE_SHIFT	18
-#define PRCI_GEMGXLPLLCFG0_RANGE_MASK	\
-			(0x7 << PRCI_GEMGXLPLLCFG0_RANGE_SHIFT)
-#define PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT 24
-#define PRCI_GEMGXLPLLCFG0_BYPASS_MASK	\
-			(0x1 << PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT)
-#define PRCI_GEMGXLPLLCFG0_FSE_SHIFT	25
-#define PRCI_GEMGXLPLLCFG0_FSE_MASK	\
-			(0x1 << PRCI_GEMGXLPLLCFG0_FSE_SHIFT)
-#define PRCI_GEMGXLPLLCFG0_LOCK_SHIFT	31
-#define PRCI_GEMGXLPLLCFG0_LOCK_MASK	(0x1 << PRCI_GEMGXLPLLCFG0_LOCK_SHIFT)
-
-/* GEMGXLPLLCFG1 */
-#define PRCI_GEMGXLPLLCFG1_OFFSET	0x20
-#define PRCI_GEMGXLPLLCFG1_CKE_SHIFT	31
-#define PRCI_GEMGXLPLLCFG1_CKE_MASK	(0x1 << PRCI_GEMGXLPLLCFG1_CKE_SHIFT)
-
-/* CORECLKSEL */
-#define PRCI_CORECLKSEL_OFFSET		0x24
-#define PRCI_CORECLKSEL_CORECLKSEL_SHIFT 0
-#define PRCI_CORECLKSEL_CORECLKSEL_MASK \
-			(0x1 << PRCI_CORECLKSEL_CORECLKSEL_SHIFT)
-
-/* DEVICESRESETREG */
-#define PRCI_DEVICESRESETREG_OFFSET	0x28
-#define PRCI_DEVICERESETCNT 5
-
-#define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_MASK \
-			(0x1 << PRCI_RST_DDR_CTRL_N)
-#define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_MASK \
-			(0x1 << PRCI_RST_DDR_AXI_N)
-#define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_MASK \
-			(0x1 << PRCI_RST_DDR_AHB_N)
-#define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_MASK \
-			(0x1 << PRCI_RST_DDR_PHY_N)
-#define PRCI_DEVICESRESETREG_GEMGXL_RST_N_MASK \
-			(0x1 << PRCI_RST_GEMGXL_N)
-
-/* CLKMUXSTATUSREG */
-#define PRCI_CLKMUXSTATUSREG_OFFSET	0x2c
-#define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT 1
-#define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK \
-			(0x1 << PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT)
-
-/* PROCMONCFG */
-#define PRCI_PROCMONCFG_OFFSET		0xF0
-#define PRCI_PROCMONCFG_CORE_CLOCK_SHIFT	24
-#define PRCI_PROCMONCFG_CORE_CLOCK_MASK \
-			(0x1 << PRCI_PROCMONCFG_CORE_CLOCK_SHIFT)
-
-/*
- * Private structures
- */
-
-/**
- * struct __prci_data - per-device-instance data
- * @va: base virtual address of the PRCI IP block
- * @parent: parent clk instance
- *
- * PRCI per-device instance data
- */
-struct __prci_data {
-	void *va;
-	struct clk parent_hfclk;
-	struct clk parent_rtcclk;
-};
-
-/**
- * struct __prci_wrpll_data - WRPLL configuration and integration data
- * @c: WRPLL current configuration record
- * @enable_bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL)
- * @disable_bypass: fn ptr to code to not bypass the WRPLL (or NULL)
- * @cfg0_offs: WRPLL CFG0 register offset (in bytes) from the PRCI base address
- * @cfg1_offs: WRPLL CFG1 register offset (in bytes) from the PRCI base address
- * @release_reset: fn ptr to code to release clock reset
- *
- * @enable_bypass and @disable_bypass are used for WRPLL instances
- * that contain a separate external glitchless clock mux downstream
- * from the PLL.  The WRPLL internal bypass mux is not glitchless.
- */
-struct __prci_wrpll_data {
-	struct wrpll_cfg c;
-	void (*enable_bypass)(struct __prci_data *pd);
-	void (*disable_bypass)(struct __prci_data *pd);
-	u8 cfg0_offs;
-	u8 cfg1_offs;
-	void (*release_reset)(struct __prci_data *pd);
-};
-
-struct __prci_clock;
-
-/* struct __prci_clock_ops - clock operations */
-struct __prci_clock_ops {
-	int (*set_rate)(struct __prci_clock *pc,
-			unsigned long rate,
-			unsigned long parent_rate);
-	unsigned long (*round_rate)(struct __prci_clock *pc,
-				    unsigned long rate,
-				    unsigned long *parent_rate);
-	unsigned long (*recalc_rate)(struct __prci_clock *pc,
-				     unsigned long parent_rate);
-	int (*enable_clk)(struct __prci_clock *pc, bool enable);
-};
-
-/**
- * struct __prci_clock - describes a clock device managed by PRCI
- * @name: user-readable clock name string - should match the manual
- * @parent_name: parent name for this clock
- * @ops: struct __prci_clock_ops for control
- * @pwd: WRPLL-specific data, associated with this clock (if not NULL)
- * @pd: PRCI-specific data associated with this clock (if not NULL)
- *
- * PRCI clock data.  Used by the PRCI driver to register PRCI-provided
- * clocks to the Linux clock infrastructure.
- */
-struct __prci_clock {
-	const char *name;
-	const char *parent_name;
-	const struct __prci_clock_ops *ops;
-	struct __prci_wrpll_data *pwd;
-	struct __prci_data *pd;
-};
-
-/*
- * Private functions
- */
-
-/**
- * __prci_readl() - read from a PRCI register
- * @pd: PRCI context
- * @offs: register offset to read from (in bytes, from PRCI base address)
- *
- * Read the register located at offset @offs from the base virtual
- * address of the PRCI register target described by @pd, and return
- * the value to the caller.
- *
- * Context: Any context.
- *
- * Return: the contents of the register described by @pd and @offs.
- */
-static u32 __prci_readl(struct __prci_data *pd, u32 offs)
-{
-	return readl(pd->va + offs);
-}
-
-static void __prci_writel(u32 v, u32 offs, struct __prci_data *pd)
-{
-	writel(v, pd->va + offs);
-}
-
-/* WRPLL-related private functions */
-
-/**
- * __prci_wrpll_unpack() - unpack WRPLL configuration registers into parameters
- * @c: ptr to a struct wrpll_cfg record to write config into
- * @r: value read from the PRCI PLL configuration register
- *
- * Given a value @r read from an FU540 PRCI PLL configuration register,
- * split it into fields and populate it into the WRPLL configuration record
- * pointed to by @c.
- *
- * The COREPLLCFG0 macros are used below, but the other *PLLCFG0 macros
- * have the same register layout.
- *
- * Context: Any context.
- */
-static void __prci_wrpll_unpack(struct wrpll_cfg *c, u32 r)
-{
-	u32 v;
-
-	v = r & PRCI_COREPLLCFG0_DIVR_MASK;
-	v >>= PRCI_COREPLLCFG0_DIVR_SHIFT;
-	c->divr = v;
-
-	v = r & PRCI_COREPLLCFG0_DIVF_MASK;
-	v >>= PRCI_COREPLLCFG0_DIVF_SHIFT;
-	c->divf = v;
-
-	v = r & PRCI_COREPLLCFG0_DIVQ_MASK;
-	v >>= PRCI_COREPLLCFG0_DIVQ_SHIFT;
-	c->divq = v;
-
-	v = r & PRCI_COREPLLCFG0_RANGE_MASK;
-	v >>= PRCI_COREPLLCFG0_RANGE_SHIFT;
-	c->range = v;
-
-	c->flags &= (WRPLL_FLAGS_INT_FEEDBACK_MASK |
-		     WRPLL_FLAGS_EXT_FEEDBACK_MASK);
-
-	/* external feedback mode not supported */
-	c->flags |= WRPLL_FLAGS_INT_FEEDBACK_MASK;
-}
-
-/**
- * __prci_wrpll_pack() - pack PLL configuration parameters into a register value
- * @c: pointer to a struct wrpll_cfg record containing the PLL's cfg
- *
- * Using a set of WRPLL configuration values pointed to by @c,
- * assemble a PRCI PLL configuration register value, and return it to
- * the caller.
- *
- * Context: Any context.  Caller must ensure that the contents of the
- *          record pointed to by @c do not change during the execution
- *          of this function.
- *
- * Returns: a value suitable for writing into a PRCI PLL configuration
- *          register
- */
-static u32 __prci_wrpll_pack(const struct wrpll_cfg *c)
-{
-	u32 r = 0;
-
-	r |= c->divr << PRCI_COREPLLCFG0_DIVR_SHIFT;
-	r |= c->divf << PRCI_COREPLLCFG0_DIVF_SHIFT;
-	r |= c->divq << PRCI_COREPLLCFG0_DIVQ_SHIFT;
-	r |= c->range << PRCI_COREPLLCFG0_RANGE_SHIFT;
-
-	/* external feedback mode not supported */
-	r |= PRCI_COREPLLCFG0_FSE_MASK;
-
-	return r;
-}
-
-/**
- * __prci_wrpll_read_cfg0() - read the WRPLL configuration from the PRCI
- * @pd: PRCI context
- * @pwd: PRCI WRPLL metadata
- *
- * Read the current configuration of the PLL identified by @pwd from
- * the PRCI identified by @pd, and store it into the local configuration
- * cache in @pwd.
- *
- * Context: Any context.  Caller must prevent the records pointed to by
- *          @pd and @pwd from changing during execution.
- */
-static void __prci_wrpll_read_cfg0(struct __prci_data *pd,
-				   struct __prci_wrpll_data *pwd)
-{
-	__prci_wrpll_unpack(&pwd->c, __prci_readl(pd, pwd->cfg0_offs));
-}
-
-/**
- * __prci_wrpll_write_cfg0() - write WRPLL configuration into the PRCI
- * @pd: PRCI context
- * @pwd: PRCI WRPLL metadata
- * @c: WRPLL configuration record to write
- *
- * Write the WRPLL configuration described by @c into the WRPLL
- * configuration register identified by @pwd in the PRCI instance
- * described by @c.  Make a cached copy of the WRPLL's current
- * configuration so it can be used by other code.
- *
- * Context: Any context.  Caller must prevent the records pointed to by
- *          @pd and @pwd from changing during execution.
- */
-static void __prci_wrpll_write_cfg0(struct __prci_data *pd,
-				    struct __prci_wrpll_data *pwd,
-				    struct wrpll_cfg *c)
-{
-	__prci_writel(__prci_wrpll_pack(c), pwd->cfg0_offs, pd);
-
-	memcpy(&pwd->c, c, sizeof(*c));
-}
-
-/**
- * __prci_wrpll_write_cfg1() - write Clock enable/disable configuration
- * into the PRCI
- * @pd: PRCI context
- * @pwd: PRCI WRPLL metadata
- * @enable: Clock enable or disable value
- */
-static void __prci_wrpll_write_cfg1(struct __prci_data *pd,
-				    struct __prci_wrpll_data *pwd,
-				    u32 enable)
-{
-	__prci_writel(enable, pwd->cfg1_offs, pd);
-}
-
-/* Core clock mux control */
-
-/**
- * __prci_coreclksel_use_hfclk() - switch the CORECLK mux to output HFCLK
- * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg
- *
- * Switch the CORECLK mux to the HFCLK input source; return once complete.
- *
- * Context: Any context.  Caller must prevent concurrent changes to the
- *          PRCI_CORECLKSEL_OFFSET register.
- */
-static void __prci_coreclksel_use_hfclk(struct __prci_data *pd)
-{
-	u32 r;
-
-	r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
-	r |= PRCI_CORECLKSEL_CORECLKSEL_MASK;
-	__prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
-
-	r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */
-}
-
-/**
- * __prci_coreclksel_use_corepll() - switch the CORECLK mux to output COREPLL
- * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg
- *
- * Switch the CORECLK mux to the PLL output clock; return once complete.
- *
- * Context: Any context.  Caller must prevent concurrent changes to the
- *          PRCI_CORECLKSEL_OFFSET register.
- */
-static void __prci_coreclksel_use_corepll(struct __prci_data *pd)
-{
-	u32 r;
-
-	r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
-	r &= ~PRCI_CORECLKSEL_CORECLKSEL_MASK;
-	__prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
-
-	r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */
-}
-
-static unsigned long sifive_fu540_prci_wrpll_recalc_rate(
-						struct __prci_clock *pc,
-						unsigned long parent_rate)
-{
-	struct __prci_wrpll_data *pwd = pc->pwd;
 
-	return wrpll_calc_output_rate(&pwd->c, parent_rate);
-}
-
-static unsigned long sifive_fu540_prci_wrpll_round_rate(
-						struct __prci_clock *pc,
-						unsigned long rate,
-						unsigned long *parent_rate)
-{
-	struct __prci_wrpll_data *pwd = pc->pwd;
-	struct wrpll_cfg c;
-
-	memcpy(&c, &pwd->c, sizeof(c));
-
-	wrpll_configure_for_rate(&c, rate, *parent_rate);
-
-	return wrpll_calc_output_rate(&c, *parent_rate);
-}
-
-static int sifive_fu540_prci_wrpll_set_rate(struct __prci_clock *pc,
-					    unsigned long rate,
-					    unsigned long parent_rate)
-{
-	struct __prci_wrpll_data *pwd = pc->pwd;
-	struct __prci_data *pd = pc->pd;
-	int r;
-
-	r = wrpll_configure_for_rate(&pwd->c, rate, parent_rate);
-	if (r)
-		return r;
-
-	if (pwd->enable_bypass)
-		pwd->enable_bypass(pd);
-
-	__prci_wrpll_write_cfg0(pd, pwd, &pwd->c);
-
-	udelay(wrpll_calc_max_lock_us(&pwd->c));
-
-	if (pwd->disable_bypass)
-		pwd->disable_bypass(pd);
-
-	return 0;
-}
-
-static int sifive_fu540_prci_clock_enable(struct __prci_clock *pc, bool enable)
-{
-	struct __prci_wrpll_data *pwd = pc->pwd;
-	struct __prci_data *pd = pc->pd;
-
-	if (enable) {
-		__prci_wrpll_write_cfg1(pd, pwd, PRCI_COREPLLCFG1_CKE_MASK);
-
-		if (pwd->release_reset)
-			pwd->release_reset(pd);
-	} else {
-		u32 r;
-
-		r = __prci_readl(pd, pwd->cfg1_offs);
-		r &= ~PRCI_COREPLLCFG1_CKE_MASK;
-
-		__prci_wrpll_write_cfg1(pd, pwd, r);
-	}
-
-	return 0;
-}
-
-static const struct __prci_clock_ops sifive_fu540_prci_wrpll_clk_ops = {
-	.set_rate = sifive_fu540_prci_wrpll_set_rate,
-	.round_rate = sifive_fu540_prci_wrpll_round_rate,
-	.recalc_rate = sifive_fu540_prci_wrpll_recalc_rate,
-	.enable_clk = sifive_fu540_prci_clock_enable,
-};
-
-/* TLCLKSEL clock integration */
-
-static unsigned long sifive_fu540_prci_tlclksel_recalc_rate(
-						struct __prci_clock *pc,
-						unsigned long parent_rate)
-{
-	struct __prci_data *pd = pc->pd;
-	u32 v;
-	u8 div;
-
-	v = __prci_readl(pd, PRCI_CLKMUXSTATUSREG_OFFSET);
-	v &= PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK;
-	div = v ? 1 : 2;
-
-	return div_u64(parent_rate, div);
-}
-
-static const struct __prci_clock_ops sifive_fu540_prci_tlclksel_clk_ops = {
-	.recalc_rate = sifive_fu540_prci_tlclksel_recalc_rate,
-};
-
-static int __prci_consumer_reset(const char *rst_name, bool trigger)
-{
-	struct udevice *dev;
-	struct reset_ctl rst_sig;
-	int ret;
-
-	ret = uclass_get_device_by_driver(UCLASS_RESET,
-					  DM_DRIVER_GET(sifive_reset),
-					  &dev);
-	if (ret) {
-		dev_err(dev, "Reset driver not found: %d\n", ret);
-		return ret;
-	}
-
-	ret = reset_get_by_name(dev, rst_name, &rst_sig);
-	if (ret) {
-		dev_err(dev, "failed to get %s reset\n", rst_name);
-		return ret;
-	}
-
-	if (reset_valid(&rst_sig)) {
-		if (trigger)
-			ret = reset_deassert(&rst_sig);
-		else
-			ret = reset_assert(&rst_sig);
-		if (ret) {
-			dev_err(dev, "failed to trigger reset id = %ld\n",
-				rst_sig.id);
-			return ret;
-		}
-	}
-
-	return ret;
-}
-
-/**
- * __prci_ddr_release_reset() - Release DDR reset
- * @pd: struct __prci_data * for the PRCI containing the DDRCLK mux reg
- *
- */
-static void __prci_ddr_release_reset(struct __prci_data *pd)
-{
-	/* Release DDR ctrl reset */
-	__prci_consumer_reset("ddr_ctrl", true);
-
-	/* HACK to get the '1 full controller clock cycle'. */
-	asm volatile ("fence");
-
-	/* Release DDR AXI reset */
-	__prci_consumer_reset("ddr_axi", true);
-
-	/* Release DDR AHB reset */
-	__prci_consumer_reset("ddr_ahb", true);
-
-	/* Release DDR PHY reset */
-	__prci_consumer_reset("ddr_phy", true);
-
-	/* HACK to get the '1 full controller clock cycle'. */
-	asm volatile ("fence");
-
-	/*
-	 * These take like 16 cycles to actually propagate. We can't go sending
-	 * stuff before they come out of reset. So wait.
-	 */
-	for (int i = 0; i < 256; i++)
-		asm volatile ("nop");
-}
-
-/**
- * __prci_ethernet_release_reset() - Release ethernet reset
- * @pd: struct __prci_data * for the PRCI containing the Ethernet CLK mux reg
- *
- */
-static void __prci_ethernet_release_reset(struct __prci_data *pd)
-{
-	/* Release GEMGXL reset */
-	__prci_consumer_reset("gemgxl_reset", true);
-
-	/* Procmon => core clock */
-	__prci_writel(PRCI_PROCMONCFG_CORE_CLOCK_MASK, PRCI_PROCMONCFG_OFFSET,
-		      pd);
-}
-
-/*
- * PRCI integration data for each WRPLL instance
- */
+#include "sifive-prci.h"
 
+/* PRCI integration data for each WRPLL instance */
 static struct __prci_wrpll_data __prci_corepll_data = {
 	.cfg0_offs = PRCI_COREPLLCFG0_OFFSET,
 	.cfg1_offs = PRCI_COREPLLCFG1_OFFSET,
-	.enable_bypass = __prci_coreclksel_use_hfclk,
-	.disable_bypass = __prci_coreclksel_use_corepll,
+	.enable_bypass = sifive_prci_coreclksel_use_hfclk,
+	.disable_bypass = sifive_prci_coreclksel_use_corepll,
 };
 
 static struct __prci_wrpll_data __prci_ddrpll_data = {
 	.cfg0_offs = PRCI_DDRPLLCFG0_OFFSET,
 	.cfg1_offs = PRCI_DDRPLLCFG1_OFFSET,
-	.release_reset = __prci_ddr_release_reset,
+	.release_reset = sifive_prci_ddr_release_reset,
 };
 
 static struct __prci_wrpll_data __prci_gemgxlpll_data = {
 	.cfg0_offs = PRCI_GEMGXLPLLCFG0_OFFSET,
 	.cfg1_offs = PRCI_GEMGXLPLLCFG1_OFFSET,
-	.release_reset = __prci_ethernet_release_reset,
+	.release_reset = sifive_prci_ethernet_release_reset,
 };
 
-/*
- * List of clock controls provided by the PRCI
- */
+/* Linux clock framework integration */
+static const struct __prci_clock_ops sifive_fu540_prci_wrpll_clk_ops = {
+	.set_rate = sifive_prci_wrpll_set_rate,
+	.round_rate = sifive_prci_wrpll_round_rate,
+	.recalc_rate = sifive_prci_wrpll_recalc_rate,
+	.enable_clk = sifive_prci_clock_enable,
+};
 
-static struct __prci_clock __prci_init_clocks[] = {
+static const struct __prci_clock_ops sifive_fu540_prci_tlclksel_clk_ops = {
+	.recalc_rate = sifive_prci_tlclksel_recalc_rate,
+};
+
+/* List of clock controls provided by the PRCI */
+struct __prci_clock __prci_init_clocks_fu540[] = {
 	[PRCI_CLK_COREPLL] = {
 		.name = "corepll",
 		.parent_name = "hfclk",
@@ -665,148 +83,3 @@ static struct __prci_clock __prci_init_clocks[] = {
 		.ops = &sifive_fu540_prci_tlclksel_clk_ops,
 	},
 };
-
-static ulong sifive_fu540_prci_parent_rate(struct __prci_clock *pc)
-{
-	ulong parent_rate;
-	struct __prci_clock *p;
-
-	if (strcmp(pc->parent_name, "corepll") == 0) {
-		p = &__prci_init_clocks[PRCI_CLK_COREPLL];
-		if (!p->pd || !p->ops->recalc_rate)
-			return -ENXIO;
-
-		return p->ops->recalc_rate(p, sifive_fu540_prci_parent_rate(p));
-	}
-
-	if (strcmp(pc->parent_name, "rtcclk") == 0)
-		parent_rate = clk_get_rate(&pc->pd->parent_rtcclk);
-	else
-		parent_rate = clk_get_rate(&pc->pd->parent_hfclk);
-
-	return parent_rate;
-}
-
-static ulong sifive_fu540_prci_get_rate(struct clk *clk)
-{
-	struct __prci_clock *pc;
-
-	if (ARRAY_SIZE(__prci_init_clocks) <= clk->id)
-		return -ENXIO;
-
-	pc = &__prci_init_clocks[clk->id];
-	if (!pc->pd || !pc->ops->recalc_rate)
-		return -ENXIO;
-
-	return pc->ops->recalc_rate(pc, sifive_fu540_prci_parent_rate(pc));
-}
-
-static ulong sifive_fu540_prci_set_rate(struct clk *clk, ulong rate)
-{
-	int err;
-	struct __prci_clock *pc;
-
-	if (ARRAY_SIZE(__prci_init_clocks) <= clk->id)
-		return -ENXIO;
-
-	pc = &__prci_init_clocks[clk->id];
-	if (!pc->pd || !pc->ops->set_rate)
-		return -ENXIO;
-
-	err = pc->ops->set_rate(pc, rate, sifive_fu540_prci_parent_rate(pc));
-	if (err)
-		return err;
-
-	return rate;
-}
-
-static int sifive_fu540_prci_enable(struct clk *clk)
-{
-	struct __prci_clock *pc;
-	int ret = 0;
-
-	if (ARRAY_SIZE(__prci_init_clocks) <= clk->id)
-		return -ENXIO;
-
-	pc = &__prci_init_clocks[clk->id];
-	if (!pc->pd)
-		return -ENXIO;
-
-	if (pc->ops->enable_clk)
-		ret = pc->ops->enable_clk(pc, 1);
-
-	return ret;
-}
-
-static int sifive_fu540_prci_disable(struct clk *clk)
-{
-	struct __prci_clock *pc;
-	int ret = 0;
-
-	if (ARRAY_SIZE(__prci_init_clocks) <= clk->id)
-		return -ENXIO;
-
-	pc = &__prci_init_clocks[clk->id];
-	if (!pc->pd)
-		return -ENXIO;
-
-	if (pc->ops->enable_clk)
-		ret = pc->ops->enable_clk(pc, 0);
-
-	return ret;
-}
-
-static int sifive_fu540_prci_probe(struct udevice *dev)
-{
-	int i, err;
-	struct __prci_clock *pc;
-	struct __prci_data *pd = dev_get_priv(dev);
-
-	pd->va = (void *)dev_read_addr(dev);
-	if (IS_ERR(pd->va))
-		return PTR_ERR(pd->va);
-
-	err = clk_get_by_index(dev, 0, &pd->parent_hfclk);
-	if (err)
-		return err;
-
-	err = clk_get_by_index(dev, 1, &pd->parent_rtcclk);
-	if (err)
-		return err;
-
-	for (i = 0; i < ARRAY_SIZE(__prci_init_clocks); ++i) {
-		pc = &__prci_init_clocks[i];
-		pc->pd = pd;
-		if (pc->pwd)
-			__prci_wrpll_read_cfg0(pd, pc->pwd);
-	}
-
-	return 0;
-}
-
-static struct clk_ops sifive_fu540_prci_ops = {
-	.set_rate = sifive_fu540_prci_set_rate,
-	.get_rate = sifive_fu540_prci_get_rate,
-	.enable = sifive_fu540_prci_enable,
-	.disable = sifive_fu540_prci_disable,
-};
-
-static int sifive_fu540_clk_bind(struct udevice *dev)
-{
-	return sifive_reset_bind(dev, PRCI_DEVICERESETCNT);
-}
-
-static const struct udevice_id sifive_fu540_prci_ids[] = {
-	{ .compatible = "sifive,fu540-c000-prci" },
-	{ }
-};
-
-U_BOOT_DRIVER(sifive_fu540_prci) = {
-	.name = "sifive-fu540-prci",
-	.id = UCLASS_CLK,
-	.of_match = sifive_fu540_prci_ids,
-	.probe = sifive_fu540_prci_probe,
-	.ops = &sifive_fu540_prci_ops,
-	.priv_auto	= sizeof(struct __prci_data),
-	.bind = sifive_fu540_clk_bind,
-};

+ 22 - 0
drivers/clk/sifive/fu540-prci.h

@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020-2021 SiFive, Inc.
+ * Zong Li
+ * Pragnesh Patel
+ */
+
+#ifndef __SIFIVE_CLK_FU540_PRCI_H
+#define __SIFIVE_CLK_FU540_PRCI_H
+
+#include "sifive-prci.h"
+
+#define NUM_CLOCK_FU540	4
+
+extern struct __prci_clock __prci_init_clocks_fu540[NUM_CLOCK_FU540];
+
+static const struct prci_clk_desc prci_clk_fu540 = {
+	.clks = __prci_init_clocks_fu540,
+	.num_clks = ARRAY_SIZE(__prci_init_clocks_fu540),
+};
+
+#endif /* __SIFIVE_CLK_FU540_PRCI_H */

+ 158 - 0
drivers/clk/sifive/fu740-prci.c

@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018-2021 SiFive, Inc.
+ * Wesley Terpstra
+ * Paul Walmsley
+ * Zong Li
+ * Pragnesh Patel
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/clock/sifive-fu740-prci.h>
+#include "sifive-prci.h"
+#include <asm/io.h>
+
+int sifive_prci_fu740_pciauxclk_enable(struct __prci_clock *pc, bool enable)
+{
+	struct __prci_wrpll_data *pwd = pc->pwd;
+	struct __prci_data *pd = pc->pd;
+	u32 v;
+
+	if (pwd->cfg1_offs != PRCI_PCIEAUXCFG1_OFFSET)
+		return -EINVAL;
+
+	v = readl(pd->va + pwd->cfg1_offs);
+	v = enable ? (v | PRCI_PCIEAUXCFG1_MASK) : (v & ~PRCI_PCIEAUXCFG1_MASK);
+	writel(v, pd->va + pwd->cfg1_offs);
+
+	return 0;
+}
+
+/* PRCI integration data for each WRPLL instance */
+static struct __prci_wrpll_data __prci_corepll_data = {
+	.cfg0_offs = PRCI_COREPLLCFG0_OFFSET,
+	.cfg1_offs = PRCI_COREPLLCFG1_OFFSET,
+	.enable_bypass = sifive_prci_coreclksel_use_hfclk,
+	.disable_bypass = sifive_prci_coreclksel_use_final_corepll,
+};
+
+static struct __prci_wrpll_data __prci_ddrpll_data = {
+	.cfg0_offs = PRCI_DDRPLLCFG0_OFFSET,
+	.cfg1_offs = PRCI_DDRPLLCFG1_OFFSET,
+	.release_reset = sifive_prci_ddr_release_reset,
+};
+
+static struct __prci_wrpll_data __prci_gemgxlpll_data = {
+	.cfg0_offs = PRCI_GEMGXLPLLCFG0_OFFSET,
+	.cfg1_offs = PRCI_GEMGXLPLLCFG1_OFFSET,
+	.release_reset = sifive_prci_ethernet_release_reset,
+};
+
+static struct __prci_wrpll_data __prci_dvfscorepll_data = {
+	.cfg0_offs = PRCI_DVFSCOREPLLCFG0_OFFSET,
+	.cfg1_offs = PRCI_DVFSCOREPLLCFG1_OFFSET,
+	.enable_bypass = sifive_prci_corepllsel_use_corepll,
+	.disable_bypass = sifive_prci_corepllsel_use_dvfscorepll,
+};
+
+static struct __prci_wrpll_data __prci_hfpclkpll_data = {
+	.cfg0_offs = PRCI_HFPCLKPLLCFG0_OFFSET,
+	.cfg1_offs = PRCI_HFPCLKPLLCFG1_OFFSET,
+	.enable_bypass = sifive_prci_hfpclkpllsel_use_hfclk,
+	.disable_bypass = sifive_prci_hfpclkpllsel_use_hfpclkpll,
+};
+
+static struct __prci_wrpll_data __prci_cltxpll_data = {
+	.cfg0_offs = PRCI_CLTXPLLCFG0_OFFSET,
+	.cfg1_offs = PRCI_CLTXPLLCFG1_OFFSET,
+	.release_reset = sifive_prci_cltx_release_reset,
+};
+
+static struct __prci_wrpll_data __prci_pcieaux_data = {
+	.cfg1_offs = PRCI_PCIEAUXCFG1_OFFSET,
+};
+
+/* Linux clock framework integration */
+
+static const struct __prci_clock_ops sifive_fu740_prci_wrpll_clk_ops = {
+	.set_rate = sifive_prci_wrpll_set_rate,
+	.round_rate = sifive_prci_wrpll_round_rate,
+	.recalc_rate = sifive_prci_wrpll_recalc_rate,
+	.enable_clk = sifive_prci_clock_enable,
+};
+
+static const struct __prci_clock_ops sifive_fu740_prci_tlclksel_clk_ops = {
+	.recalc_rate = sifive_prci_tlclksel_recalc_rate,
+};
+
+static const struct __prci_clock_ops sifive_fu740_prci_hfpclkplldiv_clk_ops = {
+	.recalc_rate = sifive_prci_hfpclkplldiv_recalc_rate,
+};
+
+static const struct __prci_clock_ops sifive_fu740_prci_pcieaux_clk_ops = {
+	.enable_clk = sifive_prci_fu740_pciauxclk_enable,
+};
+
+/* List of clock controls provided by the PRCI */
+struct __prci_clock __prci_init_clocks_fu740[] = {
+	[PRCI_CLK_COREPLL] = {
+		.name = "corepll",
+		.parent_name = "hfclk",
+		.ops = &sifive_fu740_prci_wrpll_clk_ops,
+		.pwd = &__prci_corepll_data,
+	},
+	[PRCI_CLK_DDRPLL] = {
+		.name = "ddrpll",
+		.parent_name = "hfclk",
+		.ops = &sifive_fu740_prci_wrpll_clk_ops,
+		.pwd = &__prci_ddrpll_data,
+	},
+	[PRCI_CLK_GEMGXLPLL] = {
+		.name = "gemgxlpll",
+		.parent_name = "hfclk",
+		.ops = &sifive_fu740_prci_wrpll_clk_ops,
+		.pwd = &__prci_gemgxlpll_data,
+	},
+	[PRCI_CLK_DVFSCOREPLL] = {
+		.name = "dvfscorepll",
+		.parent_name = "hfclk",
+		.ops = &sifive_fu740_prci_wrpll_clk_ops,
+		.pwd = &__prci_dvfscorepll_data,
+	},
+	[PRCI_CLK_HFPCLKPLL] = {
+		.name = "hfpclkpll",
+		.parent_name = "hfclk",
+		.ops = &sifive_fu740_prci_wrpll_clk_ops,
+		.pwd = &__prci_hfpclkpll_data,
+	},
+	[PRCI_CLK_CLTXPLL] = {
+		.name = "cltxpll",
+		.parent_name = "hfclk",
+		.ops = &sifive_fu740_prci_wrpll_clk_ops,
+		.pwd = &__prci_cltxpll_data,
+	},
+	[PRCI_CLK_TLCLK] = {
+		.name = "tlclk",
+		.parent_name = "corepll",
+		.ops = &sifive_fu740_prci_tlclksel_clk_ops,
+	},
+	[PRCI_CLK_PCLK] = {
+		.name = "pclk",
+		.parent_name = "hfpclkpll",
+		.ops = &sifive_fu740_prci_hfpclkplldiv_clk_ops,
+	},
+	[PRCI_CLK_PCIEAUX] {
+		.name = "pciaux",
+		.parent_name = "",
+		.ops = &sifive_fu740_prci_pcieaux_clk_ops,
+		.pwd = &__prci_pcieaux_data,
+	}
+};

+ 22 - 0
drivers/clk/sifive/fu740-prci.h

@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020-2021 SiFive, Inc.
+ * Zong Li
+ * Pragnesh Patel
+ */
+
+#ifndef __SIFIVE_CLK_FU740_PRCI_H
+#define __SIFIVE_CLK_FU740_PRCI_H
+
+#include "sifive-prci.h"
+
+#define NUM_CLOCK_FU740		9
+
+extern struct __prci_clock __prci_init_clocks_fu740[NUM_CLOCK_FU740];
+
+static const struct prci_clk_desc prci_clk_fu740 = {
+	.clks = __prci_init_clocks_fu740,
+	.num_clks = ARRAY_SIZE(__prci_init_clocks_fu740),
+};
+
+#endif /* __SIFIVE_CLK_FU740_PRCI_H */

+ 733 - 0
drivers/clk/sifive/sifive-prci.c

@@ -0,0 +1,733 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018-2021 SiFive, Inc.
+ * Wesley Terpstra
+ * Paul Walmsley
+ * Zong Li
+ * Pragnesh Patel
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * The PRCI implements clock and reset control for the SiFive chip.
+ * This driver assumes that it has sole control over all PRCI resources.
+ *
+ * This driver is based on the PRCI driver written by Wesley Terpstra:
+ * https://github.com/riscv/riscv-linux/commit/999529edf517ed75b56659d456d221b2ee56bb60
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <reset.h>
+#include <asm/io.h>
+#include <asm/arch/reset.h>
+#include <linux/delay.h>
+#include <linux/math64.h>
+#include <dt-bindings/clock/sifive-fu740-prci.h>
+
+#include "fu540-prci.h"
+#include "fu740-prci.h"
+
+/*
+ * Private functions
+ */
+
+/**
+ * __prci_readl() - read from a PRCI register
+ * @pd: PRCI context
+ * @offs: register offset to read from (in bytes, from PRCI base address)
+ *
+ * Read the register located at offset @offs from the base virtual
+ * address of the PRCI register target described by @pd, and return
+ * the value to the caller.
+ *
+ * Context: Any context.
+ *
+ * Return: the contents of the register described by @pd and @offs.
+ */
+static u32 __prci_readl(struct __prci_data *pd, u32 offs)
+{
+	return readl(pd->va + offs);
+}
+
+static void __prci_writel(u32 v, u32 offs, struct __prci_data *pd)
+{
+	writel(v, pd->va + offs);
+}
+
+/* WRPLL-related private functions */
+
+/**
+ * __prci_wrpll_unpack() - unpack WRPLL configuration registers into parameters
+ * @c: ptr to a struct wrpll_cfg record to write config into
+ * @r: value read from the PRCI PLL configuration register
+ *
+ * Given a value @r read from an FU540 PRCI PLL configuration register,
+ * split it into fields and populate it into the WRPLL configuration record
+ * pointed to by @c.
+ *
+ * The COREPLLCFG0 macros are used below, but the other *PLLCFG0 macros
+ * have the same register layout.
+ *
+ * Context: Any context.
+ */
+static void __prci_wrpll_unpack(struct wrpll_cfg *c, u32 r)
+{
+	u32 v;
+
+	v = r & PRCI_COREPLLCFG0_DIVR_MASK;
+	v >>= PRCI_COREPLLCFG0_DIVR_SHIFT;
+	c->divr = v;
+
+	v = r & PRCI_COREPLLCFG0_DIVF_MASK;
+	v >>= PRCI_COREPLLCFG0_DIVF_SHIFT;
+	c->divf = v;
+
+	v = r & PRCI_COREPLLCFG0_DIVQ_MASK;
+	v >>= PRCI_COREPLLCFG0_DIVQ_SHIFT;
+	c->divq = v;
+
+	v = r & PRCI_COREPLLCFG0_RANGE_MASK;
+	v >>= PRCI_COREPLLCFG0_RANGE_SHIFT;
+	c->range = v;
+
+	c->flags &= (WRPLL_FLAGS_INT_FEEDBACK_MASK |
+		     WRPLL_FLAGS_EXT_FEEDBACK_MASK);
+
+	/* external feedback mode not supported */
+	c->flags |= WRPLL_FLAGS_INT_FEEDBACK_MASK;
+}
+
+/**
+ * __prci_wrpll_pack() - pack PLL configuration parameters into a register value
+ * @c: pointer to a struct wrpll_cfg record containing the PLL's cfg
+ *
+ * Using a set of WRPLL configuration values pointed to by @c,
+ * assemble a PRCI PLL configuration register value, and return it to
+ * the caller.
+ *
+ * Context: Any context.  Caller must ensure that the contents of the
+ *          record pointed to by @c do not change during the execution
+ *          of this function.
+ *
+ * Returns: a value suitable for writing into a PRCI PLL configuration
+ *          register
+ */
+static u32 __prci_wrpll_pack(const struct wrpll_cfg *c)
+{
+	u32 r = 0;
+
+	r |= c->divr << PRCI_COREPLLCFG0_DIVR_SHIFT;
+	r |= c->divf << PRCI_COREPLLCFG0_DIVF_SHIFT;
+	r |= c->divq << PRCI_COREPLLCFG0_DIVQ_SHIFT;
+	r |= c->range << PRCI_COREPLLCFG0_RANGE_SHIFT;
+
+	/* external feedback mode not supported */
+	r |= PRCI_COREPLLCFG0_FSE_MASK;
+
+	return r;
+}
+
+/**
+ * __prci_wrpll_read_cfg0() - read the WRPLL configuration from the PRCI
+ * @pd: PRCI context
+ * @pwd: PRCI WRPLL metadata
+ *
+ * Read the current configuration of the PLL identified by @pwd from
+ * the PRCI identified by @pd, and store it into the local configuration
+ * cache in @pwd.
+ *
+ * Context: Any context.  Caller must prevent the records pointed to by
+ *          @pd and @pwd from changing during execution.
+ */
+static void __prci_wrpll_read_cfg0(struct __prci_data *pd,
+				   struct __prci_wrpll_data *pwd)
+{
+	__prci_wrpll_unpack(&pwd->c, __prci_readl(pd, pwd->cfg0_offs));
+}
+
+/**
+ * __prci_wrpll_write_cfg0() - write WRPLL configuration into the PRCI
+ * @pd: PRCI context
+ * @pwd: PRCI WRPLL metadata
+ * @c: WRPLL configuration record to write
+ *
+ * Write the WRPLL configuration described by @c into the WRPLL
+ * configuration register identified by @pwd in the PRCI instance
+ * described by @c.  Make a cached copy of the WRPLL's current
+ * configuration so it can be used by other code.
+ *
+ * Context: Any context.  Caller must prevent the records pointed to by
+ *          @pd and @pwd from changing during execution.
+ */
+static void __prci_wrpll_write_cfg0(struct __prci_data *pd,
+				    struct __prci_wrpll_data *pwd,
+				    struct wrpll_cfg *c)
+{
+	__prci_writel(__prci_wrpll_pack(c), pwd->cfg0_offs, pd);
+
+	memcpy(&pwd->c, c, sizeof(*c));
+}
+
+/**
+ * __prci_wrpll_write_cfg1() - write Clock enable/disable configuration
+ * into the PRCI
+ * @pd: PRCI context
+ * @pwd: PRCI WRPLL metadata
+ * @enable: Clock enable or disable value
+ */
+static void __prci_wrpll_write_cfg1(struct __prci_data *pd,
+				    struct __prci_wrpll_data *pwd,
+				    u32 enable)
+{
+	__prci_writel(enable, pwd->cfg1_offs, pd);
+}
+
+unsigned long sifive_prci_wrpll_recalc_rate(struct __prci_clock *pc,
+					    unsigned long parent_rate)
+{
+	struct __prci_wrpll_data *pwd = pc->pwd;
+
+	return wrpll_calc_output_rate(&pwd->c, parent_rate);
+}
+
+unsigned long sifive_prci_wrpll_round_rate(struct __prci_clock *pc,
+					   unsigned long rate,
+					   unsigned long *parent_rate)
+{
+	struct __prci_wrpll_data *pwd = pc->pwd;
+	struct wrpll_cfg c;
+
+	memcpy(&c, &pwd->c, sizeof(c));
+
+	wrpll_configure_for_rate(&c, rate, *parent_rate);
+
+	return wrpll_calc_output_rate(&c, *parent_rate);
+}
+
+int sifive_prci_wrpll_set_rate(struct __prci_clock *pc,
+			       unsigned long rate,
+			       unsigned long parent_rate)
+{
+	struct __prci_wrpll_data *pwd = pc->pwd;
+	struct __prci_data *pd = pc->pd;
+	int r;
+
+	r = wrpll_configure_for_rate(&pwd->c, rate, parent_rate);
+	if (r)
+		return r;
+
+	if (pwd->enable_bypass)
+		pwd->enable_bypass(pd);
+
+	__prci_wrpll_write_cfg0(pd, pwd, &pwd->c);
+
+	udelay(wrpll_calc_max_lock_us(&pwd->c));
+
+	return 0;
+}
+
+int sifive_prci_clock_enable(struct __prci_clock *pc, bool enable)
+{
+	struct __prci_wrpll_data *pwd = pc->pwd;
+	struct __prci_data *pd = pc->pd;
+
+	if (enable) {
+		__prci_wrpll_write_cfg1(pd, pwd, PRCI_COREPLLCFG1_CKE_MASK);
+
+		if (pwd->disable_bypass)
+			pwd->disable_bypass(pd);
+
+		if (pwd->release_reset)
+			pwd->release_reset(pd);
+	} else {
+		u32 r;
+
+		if (pwd->enable_bypass)
+			pwd->enable_bypass(pd);
+
+		r = __prci_readl(pd, pwd->cfg1_offs);
+		r &= ~PRCI_COREPLLCFG1_CKE_MASK;
+
+		__prci_wrpll_write_cfg1(pd, pwd, r);
+	}
+
+	return 0;
+}
+
+/* TLCLKSEL clock integration */
+
+unsigned long sifive_prci_tlclksel_recalc_rate(struct __prci_clock *pc,
+					       unsigned long parent_rate)
+{
+	struct __prci_data *pd = pc->pd;
+	u32 v;
+	u8 div;
+
+	v = __prci_readl(pd, PRCI_CLKMUXSTATUSREG_OFFSET);
+	v &= PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK;
+	div = v ? 1 : 2;
+
+	return div_u64(parent_rate, div);
+}
+
+/* HFPCLK clock integration */
+
+unsigned long sifive_prci_hfpclkplldiv_recalc_rate(struct __prci_clock *pc,
+						   unsigned long parent_rate)
+{
+	struct __prci_data *pd = pc->pd;
+	u32 div = __prci_readl(pd, PRCI_HFPCLKPLLDIV_OFFSET);
+
+	return div_u64(parent_rate, div + 2);
+}
+
+/**
+ * sifive_prci_coreclksel_use_final_corepll() - switch the CORECLK mux to output
+ * FINAL_COREPLL
+ * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg
+ *
+ * Switch the CORECLK mux to the final COREPLL output clock; return once
+ * complete.
+ *
+ * Context: Any context.  Caller must prevent concurrent changes to the
+ *          PRCI_CORECLKSEL_OFFSET register.
+ */
+void sifive_prci_coreclksel_use_final_corepll(struct __prci_data *pd)
+{
+	u32 r;
+
+	r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
+	r &= ~PRCI_CORECLKSEL_CORECLKSEL_MASK;
+	__prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
+
+	r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);   /* barrier */
+}
+
+/**
+ * sifive_prci_corepllsel_use_dvfscorepll() - switch the COREPLL mux to
+ * output DVFS_COREPLL
+ * @pd: struct __prci_data * for the PRCI containing the COREPLL mux reg
+ *
+ * Switch the COREPLL mux to the DVFSCOREPLL output clock; return once complete.
+ *
+ * Context: Any context.  Caller must prevent concurrent changes to the
+ *          PRCI_COREPLLSEL_OFFSET register.
+ */
+void sifive_prci_corepllsel_use_dvfscorepll(struct __prci_data *pd)
+{
+	u32 r;
+
+	r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET);
+	r |= PRCI_COREPLLSEL_COREPLLSEL_MASK;
+	__prci_writel(r, PRCI_COREPLLSEL_OFFSET, pd);
+
+	r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET);   /* barrier */
+}
+
+/**
+ * sifive_prci_corepllsel_use_corepll() - switch the COREPLL mux to
+ * output COREPLL
+ * @pd: struct __prci_data * for the PRCI containing the COREPLL mux reg
+ *
+ * Switch the COREPLL mux to the COREPLL output clock; return once complete.
+ *
+ * Context: Any context.  Caller must prevent concurrent changes to the
+ *          PRCI_COREPLLSEL_OFFSET register.
+ */
+void sifive_prci_corepllsel_use_corepll(struct __prci_data *pd)
+{
+	u32 r;
+
+	r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET);
+	r &= ~PRCI_COREPLLSEL_COREPLLSEL_MASK;
+	__prci_writel(r, PRCI_COREPLLSEL_OFFSET, pd);
+
+	r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET);   /* barrier */
+}
+
+/**
+ * sifive_prci_hfpclkpllsel_use_hfclk() - switch the HFPCLKPLL mux to
+ * output HFCLK
+ * @pd: struct __prci_data * for the PRCI containing the HFPCLKPLL mux reg
+ *
+ * Switch the HFPCLKPLL mux to the HFCLK input source; return once complete.
+ *
+ * Context: Any context.  Caller must prevent concurrent changes to the
+ *          PRCI_HFPCLKPLLSEL_OFFSET register.
+ */
+void sifive_prci_hfpclkpllsel_use_hfclk(struct __prci_data *pd)
+{
+	u32 r;
+
+	r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET);
+	r |= PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_MASK;
+	__prci_writel(r, PRCI_HFPCLKPLLSEL_OFFSET, pd);
+
+	r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET); /* barrier */
+}
+
+/**
+ * sifive_prci_hfpclkpllsel_use_hfpclkpll() - switch the HFPCLKPLL mux to
+ * output HFPCLKPLL
+ * @pd: struct __prci_data * for the PRCI containing the HFPCLKPLL mux reg
+ *
+ * Switch the HFPCLKPLL mux to the HFPCLKPLL output clock; return once complete.
+ *
+ * Context: Any context.  Caller must prevent concurrent changes to the
+ *          PRCI_HFPCLKPLLSEL_OFFSET register.
+ */
+void sifive_prci_hfpclkpllsel_use_hfpclkpll(struct __prci_data *pd)
+{
+	u32 r;
+
+	r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET);
+	r &= ~PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_MASK;
+	__prci_writel(r, PRCI_HFPCLKPLLSEL_OFFSET, pd);
+
+	r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET); /* barrier */
+}
+
+static int __prci_consumer_reset(const char *rst_name, bool trigger)
+{
+	struct udevice *dev;
+	struct reset_ctl rst_sig;
+	int ret;
+
+	ret = uclass_get_device_by_driver(UCLASS_RESET,
+					  DM_DRIVER_GET(sifive_reset),
+					  &dev);
+	if (ret) {
+		dev_err(dev, "Reset driver not found: %d\n", ret);
+		return ret;
+	}
+
+	ret = reset_get_by_name(dev, rst_name, &rst_sig);
+	if (ret) {
+		dev_err(dev, "failed to get %s reset\n", rst_name);
+		return ret;
+	}
+
+	if (reset_valid(&rst_sig)) {
+		if (trigger)
+			ret = reset_deassert(&rst_sig);
+		else
+			ret = reset_assert(&rst_sig);
+		if (ret) {
+			dev_err(dev, "failed to trigger reset id = %ld\n",
+				rst_sig.id);
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+/**
+ * sifive_prci_ddr_release_reset() - Release DDR reset
+ * @pd: struct __prci_data * for the PRCI containing the DDRCLK mux reg
+ *
+ */
+void sifive_prci_ddr_release_reset(struct __prci_data *pd)
+{
+	/* Release DDR ctrl reset */
+	__prci_consumer_reset("ddr_ctrl", true);
+
+	/* HACK to get the '1 full controller clock cycle'. */
+	asm volatile ("fence");
+
+	/* Release DDR AXI reset */
+	__prci_consumer_reset("ddr_axi", true);
+
+	/* Release DDR AHB reset */
+	__prci_consumer_reset("ddr_ahb", true);
+
+	/* Release DDR PHY reset */
+	__prci_consumer_reset("ddr_phy", true);
+
+	/* HACK to get the '1 full controller clock cycle'. */
+	asm volatile ("fence");
+
+	/*
+	 * These take like 16 cycles to actually propagate. We can't go sending
+	 * stuff before they come out of reset. So wait.
+	 */
+	for (int i = 0; i < 256; i++)
+		asm volatile ("nop");
+}
+
+/**
+ * sifive_prci_ethernet_release_reset() - Release ethernet reset
+ * @pd: struct __prci_data * for the PRCI containing the Ethernet CLK mux reg
+ *
+ */
+void sifive_prci_ethernet_release_reset(struct __prci_data *pd)
+{
+	/* Release GEMGXL reset */
+	__prci_consumer_reset("gemgxl_reset", true);
+
+	/* Procmon => core clock */
+	__prci_writel(PRCI_PROCMONCFG_CORE_CLOCK_MASK, PRCI_PROCMONCFG_OFFSET,
+		      pd);
+
+	/* Release Chiplink reset */
+	__prci_consumer_reset("cltx_reset", true);
+}
+
+/**
+ * sifive_prci_cltx_release_reset() - Release cltx reset
+ * @pd: struct __prci_data * for the PRCI containing the Ethernet CLK mux reg
+ *
+ */
+void sifive_prci_cltx_release_reset(struct __prci_data *pd)
+{
+	/* Release CLTX reset */
+	__prci_consumer_reset("cltx_reset", true);
+}
+
+/* Core clock mux control */
+
+/**
+ * sifive_prci_coreclksel_use_hfclk() - switch the CORECLK mux to output HFCLK
+ * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg
+ *
+ * Switch the CORECLK mux to the HFCLK input source; return once complete.
+ *
+ * Context: Any context.  Caller must prevent concurrent changes to the
+ *          PRCI_CORECLKSEL_OFFSET register.
+ */
+void sifive_prci_coreclksel_use_hfclk(struct __prci_data *pd)
+{
+	u32 r;
+
+	r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
+	r |= PRCI_CORECLKSEL_CORECLKSEL_MASK;
+	__prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
+
+	r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */
+}
+
+/**
+ * sifive_prci_coreclksel_use_corepll() - switch the CORECLK mux to output COREPLL
+ * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg
+ *
+ * Switch the CORECLK mux to the PLL output clock; return once complete.
+ *
+ * Context: Any context.  Caller must prevent concurrent changes to the
+ *          PRCI_CORECLKSEL_OFFSET register.
+ */
+void sifive_prci_coreclksel_use_corepll(struct __prci_data *pd)
+{
+	u32 r;
+
+	r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
+	r &= ~PRCI_CORECLKSEL_CORECLKSEL_MASK;
+	__prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
+
+	r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */
+}
+
+static ulong sifive_prci_parent_rate(struct __prci_clock *pc, struct prci_clk_desc *data)
+{
+	ulong parent_rate;
+	ulong i;
+	struct __prci_clock *p;
+
+	if (strcmp(pc->parent_name, "corepll") == 0 ||
+	    strcmp(pc->parent_name, "hfpclkpll") == 0) {
+		for (i = 0; i < data->num_clks; i++) {
+			if (strcmp(pc->parent_name, data->clks[i].name) == 0)
+				break;
+		}
+
+		if (i >= data->num_clks)
+			return -ENXIO;
+
+		p = &data->clks[i];
+		if (!p->pd || !p->ops->recalc_rate)
+			return -ENXIO;
+
+		return p->ops->recalc_rate(p, sifive_prci_parent_rate(p, data));
+	}
+
+	if (strcmp(pc->parent_name, "rtcclk") == 0)
+		parent_rate = clk_get_rate(&pc->pd->parent_rtcclk);
+	else
+		parent_rate = clk_get_rate(&pc->pd->parent_hfclk);
+
+	return parent_rate;
+}
+
+static ulong sifive_prci_get_rate(struct clk *clk)
+{
+	struct __prci_clock *pc;
+	struct prci_clk_desc *data =
+		(struct prci_clk_desc *)dev_get_driver_data(clk->dev);
+
+	if (data->num_clks <= clk->id)
+		return -ENXIO;
+
+	pc = &data->clks[clk->id];
+	if (!pc->pd || !pc->ops->recalc_rate)
+		return -ENXIO;
+
+	return pc->ops->recalc_rate(pc, sifive_prci_parent_rate(pc, data));
+}
+
+static ulong sifive_prci_set_rate(struct clk *clk, ulong rate)
+{
+	int err;
+	struct __prci_clock *pc;
+	struct prci_clk_desc *data =
+		(struct prci_clk_desc *)dev_get_driver_data(clk->dev);
+
+	if (data->num_clks <= clk->id)
+		return -ENXIO;
+
+	pc = &data->clks[clk->id];
+	if (!pc->pd || !pc->ops->set_rate)
+		return -ENXIO;
+
+	err = pc->ops->set_rate(pc, rate, sifive_prci_parent_rate(pc, data));
+	if (err)
+		return err;
+
+	return rate;
+}
+
+static int sifive_prci_enable(struct clk *clk)
+{
+	struct __prci_clock *pc;
+	int ret = 0;
+	struct prci_clk_desc *data =
+		(struct prci_clk_desc *)dev_get_driver_data(clk->dev);
+
+	if (data->num_clks <= clk->id)
+		return -ENXIO;
+
+	pc = &data->clks[clk->id];
+	if (!pc->pd)
+		return -ENXIO;
+
+	if (pc->ops->enable_clk)
+		ret = pc->ops->enable_clk(pc, 1);
+
+	return ret;
+}
+
+static int sifive_prci_disable(struct clk *clk)
+{
+	struct __prci_clock *pc;
+	int ret = 0;
+	struct prci_clk_desc *data =
+		(struct prci_clk_desc *)dev_get_driver_data(clk->dev);
+
+	if (data->num_clks <= clk->id)
+		return -ENXIO;
+
+	pc = &data->clks[clk->id];
+	if (!pc->pd)
+		return -ENXIO;
+
+	if (pc->ops->enable_clk)
+		ret = pc->ops->enable_clk(pc, 0);
+
+	return ret;
+}
+
+static int sifive_prci_probe(struct udevice *dev)
+{
+	int i, err;
+	struct __prci_clock *pc;
+	struct __prci_data *pd = dev_get_priv(dev);
+
+	struct prci_clk_desc *data =
+		(struct prci_clk_desc *)dev_get_driver_data(dev);
+
+	pd->va = (void *)dev_read_addr(dev);
+	if (IS_ERR(pd->va))
+		return PTR_ERR(pd->va);
+
+	err = clk_get_by_index(dev, 0, &pd->parent_hfclk);
+	if (err)
+		return err;
+
+	err = clk_get_by_index(dev, 1, &pd->parent_rtcclk);
+	if (err)
+		return err;
+
+	for (i = 0; i < data->num_clks; ++i) {
+		pc = &data->clks[i];
+		pc->pd = pd;
+		if (pc->pwd)
+			__prci_wrpll_read_cfg0(pd, pc->pwd);
+	}
+
+	if (IS_ENABLED(CONFIG_SPL_BUILD)) {
+		if (device_is_compatible(dev, "sifive,fu740-c000-prci")) {
+			u32 prci_pll_reg;
+			unsigned long parent_rate;
+
+			prci_pll_reg = readl(pd->va + PRCI_PRCIPLL_OFFSET);
+
+			if (prci_pll_reg & PRCI_PRCIPLL_HFPCLKPLL) {
+				/*
+				 * Only initialize the HFPCLK PLL. In this
+				 * case the design uses hfpclk to drive
+				 * Chiplink
+				 */
+				pc = &data->clks[PRCI_CLK_HFPCLKPLL];
+				parent_rate = sifive_prci_parent_rate(pc, data);
+				sifive_prci_wrpll_set_rate(pc, 260000000,
+							   parent_rate);
+				pc->ops->enable_clk(pc, 1);
+			} else if (prci_pll_reg & PRCI_PRCIPLL_CLTXPLL) {
+				/* CLTX pll init */
+				pc = &data->clks[PRCI_CLK_CLTXPLL];
+				parent_rate = sifive_prci_parent_rate(pc, data);
+				sifive_prci_wrpll_set_rate(pc, 260000000,
+							   parent_rate);
+				pc->ops->enable_clk(pc, 1);
+			}
+		}
+	}
+
+	return 0;
+}
+
+static struct clk_ops sifive_prci_ops = {
+	.set_rate = sifive_prci_set_rate,
+	.get_rate = sifive_prci_get_rate,
+	.enable = sifive_prci_enable,
+	.disable = sifive_prci_disable,
+};
+
+static int sifive_clk_bind(struct udevice *dev)
+{
+	return sifive_reset_bind(dev, PRCI_DEVICERESETCNT);
+}
+
+static const struct udevice_id sifive_prci_ids[] = {
+	{ .compatible = "sifive,fu540-c000-prci", .data = (ulong)&prci_clk_fu540 },
+	{ .compatible = "sifive,fu740-c000-prci", .data = (ulong)&prci_clk_fu740 },
+	{ }
+};
+
+U_BOOT_DRIVER(sifive_prci) = {
+	.name = "sifive-prci",
+	.id = UCLASS_CLK,
+	.of_match = sifive_prci_ids,
+	.probe = sifive_prci_probe,
+	.ops = &sifive_prci_ops,
+	.priv_auto = sizeof(struct __prci_data),
+	.bind = sifive_clk_bind,
+};

+ 323 - 0
drivers/clk/sifive/sifive-prci.h

@@ -0,0 +1,323 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020-2021 SiFive, Inc.
+ * Wesley Terpstra
+ * Paul Walmsley
+ * Zong Li
+ * Pragnesh Patel
+ */
+
+#ifndef __SIFIVE_CLK_SIFIVE_PRCI_H
+#define __SIFIVE_CLK_SIFIVE_PRCI_H
+
+#include <clk.h>
+#include <linux/clk/analogbits-wrpll-cln28hpc.h>
+
+/*
+ * EXPECTED_CLK_PARENT_COUNT: how many parent clocks this driver expects:
+ *     hfclk and rtcclk
+ */
+#define EXPECTED_CLK_PARENT_COUNT       2
+
+/*
+ * Register offsets and bitmasks
+ */
+
+/* COREPLLCFG0 */
+#define PRCI_COREPLLCFG0_OFFSET		0x4
+#define PRCI_COREPLLCFG0_DIVR_SHIFT	0
+#define PRCI_COREPLLCFG0_DIVR_MASK	(0x3f << PRCI_COREPLLCFG0_DIVR_SHIFT)
+#define PRCI_COREPLLCFG0_DIVF_SHIFT	6
+#define PRCI_COREPLLCFG0_DIVF_MASK	(0x1ff << PRCI_COREPLLCFG0_DIVF_SHIFT)
+#define PRCI_COREPLLCFG0_DIVQ_SHIFT	15
+#define PRCI_COREPLLCFG0_DIVQ_MASK	(0x7 << PRCI_COREPLLCFG0_DIVQ_SHIFT)
+#define PRCI_COREPLLCFG0_RANGE_SHIFT	18
+#define PRCI_COREPLLCFG0_RANGE_MASK	(0x7 << PRCI_COREPLLCFG0_RANGE_SHIFT)
+#define PRCI_COREPLLCFG0_BYPASS_SHIFT	24
+#define PRCI_COREPLLCFG0_BYPASS_MASK	(0x1 << PRCI_COREPLLCFG0_BYPASS_SHIFT)
+#define PRCI_COREPLLCFG0_FSE_SHIFT	25
+#define PRCI_COREPLLCFG0_FSE_MASK	(0x1 << PRCI_COREPLLCFG0_FSE_SHIFT)
+#define PRCI_COREPLLCFG0_LOCK_SHIFT	31
+#define PRCI_COREPLLCFG0_LOCK_MASK	(0x1 << PRCI_COREPLLCFG0_LOCK_SHIFT)
+
+/* COREPLLCFG1 */
+#define PRCI_COREPLLCFG1_OFFSET		0x8
+#define PRCI_COREPLLCFG1_CKE_SHIFT	31
+#define PRCI_COREPLLCFG1_CKE_MASK	(0x1 << PRCI_COREPLLCFG1_CKE_SHIFT)
+
+/* DDRPLLCFG0 */
+#define PRCI_DDRPLLCFG0_OFFSET		0xc
+#define PRCI_DDRPLLCFG0_DIVR_SHIFT	0
+#define PRCI_DDRPLLCFG0_DIVR_MASK	(0x3f << PRCI_DDRPLLCFG0_DIVR_SHIFT)
+#define PRCI_DDRPLLCFG0_DIVF_SHIFT	6
+#define PRCI_DDRPLLCFG0_DIVF_MASK	(0x1ff << PRCI_DDRPLLCFG0_DIVF_SHIFT)
+#define PRCI_DDRPLLCFG0_DIVQ_SHIFT	15
+#define PRCI_DDRPLLCFG0_DIVQ_MASK	(0x7 << PRCI_DDRPLLCFG0_DIVQ_SHIFT)
+#define PRCI_DDRPLLCFG0_RANGE_SHIFT	18
+#define PRCI_DDRPLLCFG0_RANGE_MASK	(0x7 << PRCI_DDRPLLCFG0_RANGE_SHIFT)
+#define PRCI_DDRPLLCFG0_BYPASS_SHIFT	24
+#define PRCI_DDRPLLCFG0_BYPASS_MASK	(0x1 << PRCI_DDRPLLCFG0_BYPASS_SHIFT)
+#define PRCI_DDRPLLCFG0_FSE_SHIFT	25
+#define PRCI_DDRPLLCFG0_FSE_MASK	(0x1 << PRCI_DDRPLLCFG0_FSE_SHIFT)
+#define PRCI_DDRPLLCFG0_LOCK_SHIFT	31
+#define PRCI_DDRPLLCFG0_LOCK_MASK	(0x1 << PRCI_DDRPLLCFG0_LOCK_SHIFT)
+
+/* DDRPLLCFG1 */
+#define PRCI_DDRPLLCFG1_OFFSET		0x10
+#define PRCI_DDRPLLCFG1_CKE_SHIFT	31
+#define PRCI_DDRPLLCFG1_CKE_MASK	(0x1 << PRCI_DDRPLLCFG1_CKE_SHIFT)
+
+/* PCIEAUXCFG1 */
+#define PRCI_PCIEAUXCFG1_OFFSET		0x14
+#define PRCI_PCIEAUXCFG1_SHIFT		0
+#define PRCI_PCIEAUXCFG1_MASK		(0x1 << PRCI_PCIEAUXCFG1_SHIFT)
+
+/* GEMGXLPLLCFG0 */
+#define PRCI_GEMGXLPLLCFG0_OFFSET	0x1c
+#define PRCI_GEMGXLPLLCFG0_DIVR_SHIFT	0
+#define PRCI_GEMGXLPLLCFG0_DIVR_MASK	\
+			(0x3f << PRCI_GEMGXLPLLCFG0_DIVR_SHIFT)
+#define PRCI_GEMGXLPLLCFG0_DIVF_SHIFT	6
+#define PRCI_GEMGXLPLLCFG0_DIVF_MASK	\
+			(0x1ff << PRCI_GEMGXLPLLCFG0_DIVF_SHIFT)
+#define PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT	15
+#define PRCI_GEMGXLPLLCFG0_DIVQ_MASK	(0x7 << PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT)
+#define PRCI_GEMGXLPLLCFG0_RANGE_SHIFT	18
+#define PRCI_GEMGXLPLLCFG0_RANGE_MASK	\
+			(0x7 << PRCI_GEMGXLPLLCFG0_RANGE_SHIFT)
+#define PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT	24
+#define PRCI_GEMGXLPLLCFG0_BYPASS_MASK	\
+			(0x1 << PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT)
+#define PRCI_GEMGXLPLLCFG0_FSE_SHIFT	25
+#define PRCI_GEMGXLPLLCFG0_FSE_MASK	\
+			(0x1 << PRCI_GEMGXLPLLCFG0_FSE_SHIFT)
+#define PRCI_GEMGXLPLLCFG0_LOCK_SHIFT	31
+#define PRCI_GEMGXLPLLCFG0_LOCK_MASK	(0x1 << PRCI_GEMGXLPLLCFG0_LOCK_SHIFT)
+
+/* GEMGXLPLLCFG1 */
+#define PRCI_GEMGXLPLLCFG1_OFFSET	0x20
+#define PRCI_GEMGXLPLLCFG1_CKE_SHIFT	31
+#define PRCI_GEMGXLPLLCFG1_CKE_MASK	(0x1 << PRCI_GEMGXLPLLCFG1_CKE_SHIFT)
+
+/* CORECLKSEL */
+#define PRCI_CORECLKSEL_OFFSET		0x24
+#define PRCI_CORECLKSEL_CORECLKSEL_SHIFT	0
+#define PRCI_CORECLKSEL_CORECLKSEL_MASK \
+			(0x1 << PRCI_CORECLKSEL_CORECLKSEL_SHIFT)
+
+/* DEVICESRESETREG */
+#define PRCI_DEVICESRESETREG_OFFSET	0x28
+#define PRCI_DEVICERESETCNT	6
+
+/* CLKMUXSTATUSREG */
+#define PRCI_CLKMUXSTATUSREG_OFFSET	0x2c
+#define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT	1
+#define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK \
+			(0x1 << PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT)
+
+/* CLTXPLLCFG0 */
+#define PRCI_CLTXPLLCFG0_OFFSET		0x30
+#define PRCI_CLTXPLLCFG0_DIVR_SHIFT	0
+#define PRCI_CLTXPLLCFG0_DIVR_MASK	(0x3f << PRCI_CLTXPLLCFG0_DIVR_SHIFT)
+#define PRCI_CLTXPLLCFG0_DIVF_SHIFT	6
+#define PRCI_CLTXPLLCFG0_DIVF_MASK	(0x1ff << PRCI_CLTXPLLCFG0_DIVF_SHIFT)
+#define PRCI_CLTXPLLCFG0_DIVQ_SHIFT	15
+#define PRCI_CLTXPLLCFG0_DIVQ_MASK	(0x7 << PRCI_CLTXPLLCFG0_DIVQ_SHIFT)
+#define PRCI_CLTXPLLCFG0_RANGE_SHIFT	18
+#define PRCI_CLTXPLLCFG0_RANGE_MASK	(0x7 << PRCI_CLTXPLLCFG0_RANGE_SHIFT)
+#define PRCI_CLTXPLLCFG0_BYPASS_SHIFT	24
+#define PRCI_CLTXPLLCFG0_BYPASS_MASK	(0x1 << PRCI_CLTXPLLCFG0_BYPASS_SHIFT)
+#define PRCI_CLTXPLLCFG0_FSE_SHIFT	25
+#define PRCI_CLTXPLLCFG0_FSE_MASK	(0x1 << PRCI_CLTXPLLCFG0_FSE_SHIFT)
+#define PRCI_CLTXPLLCFG0_LOCK_SHIFT	31
+#define PRCI_CLTXPLLCFG0_LOCK_MASK	(0x1 << PRCI_CLTXPLLCFG0_LOCK_SHIFT)
+
+/* CLTXPLLCFG1 */
+#define PRCI_CLTXPLLCFG1_OFFSET		0x34
+#define PRCI_CLTXPLLCFG1_CKE_SHIFT	24
+#define PRCI_CLTXPLLCFG1_CKE_MASK	(0x1 << PRCI_CLTXPLLCFG1_CKE_SHIFT)
+
+/* DVFSCOREPLLCFG0 */
+#define PRCI_DVFSCOREPLLCFG0_OFFSET	0x38
+
+/* DVFSCOREPLLCFG1 */
+#define PRCI_DVFSCOREPLLCFG1_OFFSET	0x3c
+#define PRCI_DVFSCOREPLLCFG1_CKE_SHIFT	24
+#define PRCI_DVFSCOREPLLCFG1_CKE_MASK	(0x1 << PRCI_DVFSCOREPLLCFG1_CKE_SHIFT)
+
+/* COREPLLSEL */
+#define PRCI_COREPLLSEL_OFFSET		0x40
+#define PRCI_COREPLLSEL_COREPLLSEL_SHIFT	0
+#define PRCI_COREPLLSEL_COREPLLSEL_MASK	\
+		(0x1 << PRCI_COREPLLSEL_COREPLLSEL_SHIFT)
+
+/* HFPCLKPLLCFG0 */
+#define PRCI_HFPCLKPLLCFG0_OFFSET		0x50
+#define PRCI_HFPCLKPLL_CFG0_DIVR_SHIFT		0
+#define PRCI_HFPCLKPLL_CFG0_DIVR_MASK	\
+		(0x3f << PRCI_HFPCLKPLLCFG0_DIVR_SHIFT)
+#define PRCI_HFPCLKPLL_CFG0_DIVF_SHIFT		6
+#define PRCI_HFPCLKPLL_CFG0_DIVF_MASK	\
+		(0x1ff << PRCI_HFPCLKPLLCFG0_DIVF_SHIFT)
+#define PRCI_HFPCLKPLL_CFG0_DIVQ_SHIFT		15
+#define PRCI_HFPCLKPLL_CFG0_DIVQ_MASK	\
+		(0x7 << PRCI_HFPCLKPLLCFG0_DIVQ_SHIFT)
+#define PRCI_HFPCLKPLL_CFG0_RANGE_SHIFT		18
+#define PRCI_HFPCLKPLL_CFG0_RANGE_MASK	\
+		(0x7 << PRCI_HFPCLKPLLCFG0_RANGE_SHIFT)
+#define PRCI_HFPCLKPLL_CFG0_BYPASS_SHIFT	24
+#define PRCI_HFPCLKPLL_CFG0_BYPASS_MASK	\
+		(0x1 << PRCI_HFPCLKPLLCFG0_BYPASS_SHIFT)
+#define PRCI_HFPCLKPLL_CFG0_FSE_SHIFT		25
+#define PRCI_HFPCLKPLL_CFG0_FSE_MASK	\
+		(0x1 << PRCI_HFPCLKPLLCFG0_FSE_SHIFT)
+#define PRCI_HFPCLKPLL_CFG0_LOCK_SHIFT		31
+#define PRCI_HFPCLKPLL_CFG0_LOCK_MASK	\
+		(0x1 << PRCI_HFPCLKPLLCFG0_LOCK_SHIFT)
+
+/* HFPCLKPLLCFG1 */
+#define PRCI_HFPCLKPLLCFG1_OFFSET		0x54
+#define PRCI_HFPCLKPLLCFG1_CKE_SHIFT		24
+#define PRCI_HFPCLKPLLCFG1_CKE_MASK	\
+		(0x1 << PRCI_HFPCLKPLLCFG1_CKE_SHIFT)
+
+/* HFPCLKPLLSEL */
+#define PRCI_HFPCLKPLLSEL_OFFSET		0x58
+#define PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_SHIFT	0
+#define PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_MASK	\
+		(0x1 << PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_SHIFT)
+
+/* HFPCLKPLLDIV */
+#define PRCI_HFPCLKPLLDIV_OFFSET		0x5c
+
+/* PRCIPLL */
+#define PRCI_PRCIPLL_OFFSET			0xe0
+
+#define PRCI_PRCIPLL_CLTXPLL			(0x1 << 0)
+#define PRCI_PRCIPLL_GEMGXLPLL			(0x1 << 1)
+#define PRCI_PRCIPLL_DDRPLL			(0x1 << 2)
+#define PRCI_PRCIPLL_HFPCLKPLL			(0x1 << 3)
+#define PRCI_PRCIPLL_DVFSCOREPLL		(0x1 << 4)
+#define PRCI_PRCIPLL_COREPLL			(0x1 << 5)
+
+/* PROCMONCFG */
+#define PRCI_PROCMONCFG_OFFSET		0xF0
+#define PRCI_PROCMONCFG_CORE_CLOCK_SHIFT	24
+#define PRCI_PROCMONCFG_CORE_CLOCK_MASK \
+			(0x1 << PRCI_PROCMONCFG_CORE_CLOCK_SHIFT)
+
+/*
+ * Private structures
+ */
+
+/**
+ * struct __prci_data - per-device-instance data
+ * @va: base virtual address of the PRCI IP block
+ * @parent: parent clk instance
+ *
+ * PRCI per-device instance data
+ */
+struct __prci_data {
+	void *va;
+	struct clk parent_hfclk;
+	struct clk parent_rtcclk;
+};
+
+/**
+ * struct __prci_wrpll_data - WRPLL configuration and integration data
+ * @c: WRPLL current configuration record
+ * @enable_bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL)
+ * @disable_bypass: fn ptr to code to not bypass the WRPLL (or NULL)
+ * @cfg0_offs: WRPLL CFG0 register offset (in bytes) from the PRCI base address
+ * @cfg1_offs: WRPLL CFG1 register offset (in bytes) from the PRCI base address
+ * @release_reset: fn ptr to code to release clock reset
+ *
+ * @enable_bypass and @disable_bypass are used for WRPLL instances
+ * that contain a separate external glitchless clock mux downstream
+ * from the PLL.  The WRPLL internal bypass mux is not glitchless.
+ */
+struct __prci_wrpll_data {
+	struct wrpll_cfg c;
+	void (*enable_bypass)(struct __prci_data *pd);
+	void (*disable_bypass)(struct __prci_data *pd);
+	u8 cfg0_offs;
+	u8 cfg1_offs;
+	void (*release_reset)(struct __prci_data *pd);
+};
+
+/**
+ * struct __prci_clock - describes a clock device managed by PRCI
+ * @name: user-readable clock name string - should match the manual
+ * @parent_name: parent name for this clock
+ * @ops: struct __prci_clock_ops for control
+ * @pwd: WRPLL-specific data, associated with this clock (if not NULL)
+ * @pd: PRCI-specific data associated with this clock (if not NULL)
+ *
+ * PRCI clock data.  Used by the PRCI driver to register PRCI-provided
+ * clocks to the Linux clock infrastructure.
+ */
+struct __prci_clock {
+	const char *name;
+	const char *parent_name;
+	const struct __prci_clock_ops *ops;
+	struct __prci_wrpll_data *pwd;
+	struct __prci_data *pd;
+};
+
+/* struct __prci_clock_ops - clock operations */
+struct __prci_clock_ops {
+	int (*set_rate)(struct __prci_clock *pc,
+			unsigned long rate,
+			unsigned long parent_rate);
+	unsigned long (*round_rate)(struct __prci_clock *pc,
+				    unsigned long rate,
+				    unsigned long *parent_rate);
+	unsigned long (*recalc_rate)(struct __prci_clock *pc,
+				     unsigned long parent_rate);
+	int (*enable_clk)(struct __prci_clock *pc, bool enable);
+};
+
+/*
+ * struct prci_clk_desc - describes the information of clocks of each SoCs
+ * @clks: point to a array of __prci_clock
+ * @num_clks: the number of element of clks
+ */
+struct prci_clk_desc {
+	struct __prci_clock *clks;
+	size_t num_clks;
+};
+
+void sifive_prci_ethernet_release_reset(struct __prci_data *pd);
+void sifive_prci_ddr_release_reset(struct __prci_data *pd);
+void sifive_prci_cltx_release_reset(struct __prci_data *pd);
+
+/* Core clock mux control */
+void sifive_prci_coreclksel_use_hfclk(struct __prci_data *pd);
+void sifive_prci_coreclksel_use_corepll(struct __prci_data *pd);
+void sifive_prci_coreclksel_use_final_corepll(struct __prci_data *pd);
+void sifive_prci_corepllsel_use_dvfscorepll(struct __prci_data *pd);
+void sifive_prci_corepllsel_use_corepll(struct __prci_data *pd);
+void sifive_prci_hfpclkpllsel_use_hfclk(struct __prci_data *pd);
+void sifive_prci_hfpclkpllsel_use_hfpclkpll(struct __prci_data *pd);
+
+unsigned long sifive_prci_wrpll_round_rate(struct __prci_clock *pc,
+					   unsigned long rate,
+					   unsigned long *parent_rate);
+
+/* Linux clock framework integration */
+int sifive_prci_wrpll_set_rate(struct __prci_clock *pc,
+			       unsigned long rate,
+			       unsigned long parent_rate);
+
+unsigned long sifive_prci_wrpll_recalc_rate(struct __prci_clock *pc,
+					    unsigned long parent_rate);
+
+unsigned long sifive_prci_tlclksel_recalc_rate(struct __prci_clock *pc,
+					       unsigned long parent_rate);
+
+unsigned long sifive_prci_hfpclkplldiv_recalc_rate(struct __prci_clock *pc,
+						   unsigned long parent_rate);
+
+int sifive_prci_clock_enable(struct __prci_clock *pc, bool enable);
+
+#endif /* __SIFIVE_CLK_SIFIVE_PRCI_H */

+ 10 - 0
drivers/pci/Kconfig

@@ -97,6 +97,16 @@ config PCIE_DW_MVEBU
 	  Armada-8K SoCs. The PCIe controller on Armada-8K is based on
 	  DesignWare hardware.
 
+config PCIE_DW_SIFIVE
+	bool "Enable SiFive FU740 PCIe"
+	depends on CLK_SIFIVE_PRCI
+	depends on RESET_SIFIVE
+	depends on SIFIVE_GPIO
+	select PCIE_DW_COMMON
+	help
+	  Say Y here if you want to enable PCIe controller support on
+	  FU740.
+
 config PCIE_FSL
 	bool "FSL PowerPC PCIe support"
 	depends on DM_PCI

+ 1 - 0
drivers/pci/Makefile

@@ -54,3 +54,4 @@ obj-$(CONFIG_PCIE_DW_MESON) += pcie_dw_meson.o
 obj-$(CONFIG_PCI_BRCMSTB) += pcie_brcmstb.o
 obj-$(CONFIG_PCI_OCTEONTX) += pci_octeontx.o
 obj-$(CONFIG_PCIE_OCTEON) += pcie_octeon.o
+obj-$(CONFIG_PCIE_DW_SIFIVE) += pcie_dw_sifive.o

+ 29 - 25
drivers/pci/pcie_dw_common.c

@@ -213,7 +213,7 @@ int pcie_dw_read_config(const struct udevice *bus, pci_dev_t bdf,
 
 	va_address = set_cfg_address(pcie, bdf, offset);
 
-	value = readl(va_address);
+	value = readl((void __iomem *)va_address);
 
 	debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
 	*valuep = pci_conv_32_to_size(value, offset, size);
@@ -257,9 +257,9 @@ int pcie_dw_write_config(struct udevice *bus, pci_dev_t bdf,
 
 	va_address = set_cfg_address(pcie, bdf, offset);
 
-	old = readl(va_address);
+	old = readl((void __iomem *)va_address);
 	value = pci_conv_size_to_32(old, value, offset, size);
-	writel(value, va_address);
+	writel(value, (void __iomem *)va_address);
 
 	return pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
 						 PCIE_ATU_TYPE_IO, pcie->io.phys_start,
@@ -333,33 +333,37 @@ void pcie_dw_setup_host(struct pcie_dw *pci)
 		}
 	}
 
-	dev_dbg(pci->dev, "Config space: [0x%p - 0x%p, size 0x%llx]\n",
-		pci->cfg_base, pci->cfg_base + pci->cfg_size,
-		pci->cfg_size);
+	dev_dbg(pci->dev, "Config space: [0x%llx - 0x%llx, size 0x%llx]\n",
+		(u64)pci->cfg_base, (u64)pci->cfg_base + pci->cfg_size,
+		(u64)pci->cfg_size);
 
-	dev_dbg(pci->dev, "IO space: [0x%llx - 0x%llx, size 0x%lx]\n",
-		pci->io.phys_start, pci->io.phys_start + pci->io.size,
-		pci->io.size);
+	dev_dbg(pci->dev, "IO space: [0x%llx - 0x%llx, size 0x%llx]\n",
+		(u64)pci->io.phys_start, (u64)pci->io.phys_start + pci->io.size,
+		(u64)pci->io.size);
 
-	dev_dbg(pci->dev, "IO bus:   [0x%lx - 0x%lx, size 0x%lx]\n",
-		pci->io.bus_start, pci->io.bus_start + pci->io.size,
-		pci->io.size);
+	dev_dbg(pci->dev, "IO bus:   [0x%llx - 0x%llx, size 0x%llx]\n",
+		(u64)pci->io.bus_start,	(u64)pci->io.bus_start + pci->io.size,
+		(u64)pci->io.size);
 
-	dev_dbg(pci->dev, "MEM space: [0x%llx - 0x%llx, size 0x%lx]\n",
-		pci->mem.phys_start, pci->mem.phys_start + pci->mem.size,
-		pci->mem.size);
+	dev_dbg(pci->dev, "MEM space: [0x%llx - 0x%llx, size 0x%llx]\n",
+		(u64)pci->mem.phys_start,
+		(u64)pci->mem.phys_start + pci->mem.size,
+		(u64)pci->mem.size);
 
-	dev_dbg(pci->dev, "MEM bus:   [0x%lx - 0x%lx, size 0x%lx]\n",
-		pci->mem.bus_start, pci->mem.bus_start + pci->mem.size,
-		pci->mem.size);
+	dev_dbg(pci->dev, "MEM bus:   [0x%llx - 0x%llx, size 0x%llx]\n",
+		(u64)pci->mem.bus_start,
+		(u64)pci->mem.bus_start + pci->mem.size,
+		(u64)pci->mem.size);
 
 	if (pci->prefetch.size) {
-		dev_dbg(pci->dev, "PREFETCH space: [0x%llx - 0x%llx, size 0x%lx]\n",
-			pci->prefetch.phys_start, pci->prefetch.phys_start + pci->prefetch.size,
-			pci->prefetch.size);
-
-		dev_dbg(pci->dev, "PREFETCH bus:   [0x%lx - 0x%lx, size 0x%lx]\n",
-			pci->prefetch.bus_start, pci->prefetch.bus_start + pci->prefetch.size,
-			pci->prefetch.size);
+		dev_dbg(pci->dev, "PREFETCH space: [0x%llx - 0x%llx, size 0x%llx]\n",
+			(u64)pci->prefetch.phys_start,
+			(u64)pci->prefetch.phys_start + pci->prefetch.size,
+			(u64)pci->prefetch.size);
+
+		dev_dbg(pci->dev, "PREFETCH bus:   [0x%llx - 0x%llx, size 0x%llx]\n",
+			(u64)pci->prefetch.bus_start,
+			(u64)pci->prefetch.bus_start + pci->prefetch.size,
+			(u64)pci->prefetch.size);
 	}
 }

+ 507 - 0
drivers/pci/pcie_dw_sifive.c

@@ -0,0 +1,507 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * SiFive FU740 DesignWare PCIe Controller
+ *
+ * Copyright (C) 2020-2021 SiFive, Inc.
+ *
+ * Based in early part on the i.MX6 PCIe host controller shim which is:
+ *
+ * Copyright (C) 2013 Kosagi
+ *		http://www.kosagi.com
+ *
+ * Based on driver from author: Alan Mikhak <amikhak@wirelessfabric.com>
+ */
+#include <asm/io.h>
+#include <asm-generic/gpio.h>
+#include <clk.h>
+#include <common.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <generic-phy.h>
+#include <linux/bitops.h>
+#include <linux/log2.h>
+#include <pci.h>
+#include <pci_ep.h>
+#include <pci_ids.h>
+#include <regmap.h>
+#include <reset.h>
+#include <syscon.h>
+
+#include "pcie_dw_common.h"
+
+struct pcie_sifive {
+	/* Must be first member of the struct */
+	struct pcie_dw dw;
+
+	/* private control regs */
+	void __iomem *priv_base;
+
+	/* reset, power, clock resources */
+	int sys_int_pin;
+	struct gpio_desc pwren_gpio;
+	struct gpio_desc reset_gpio;
+	struct clk aux_ck;
+	struct reset_ctl reset;
+};
+
+enum pcie_sifive_devtype {
+	SV_PCIE_UNKNOWN_TYPE = 0,
+	SV_PCIE_ENDPOINT_TYPE = 1,
+	SV_PCIE_HOST_TYPE = 3
+};
+
+#define ASSERTION_DELAY		100
+#define PCIE_PERST_ASSERT	0x0
+#define PCIE_PERST_DEASSERT	0x1
+#define PCIE_PHY_RESET		0x1
+#define PCIE_PHY_RESET_DEASSERT	0x0
+#define GPIO_LOW		0x0
+#define GPIO_HIGH		0x1
+#define PCIE_PHY_SEL		0x1
+
+#define sv_info(sv, fmt, arg...)	printf(fmt, ## arg)
+#define sv_warn(sv, fmt, arg...)	printf(fmt, ## arg)
+#define sv_debug(sv, fmt, arg...)	debug(fmt, ## arg)
+#define sv_err(sv, fmt, arg...)		printf(fmt, ## arg)
+
+/* Doorbell Interface */
+#define DBI_OFFSET			0x0
+#define DBI_SIZE			0x1000
+
+#define PL_OFFSET			0x700
+
+#define PHY_DEBUG_R0			(PL_OFFSET + 0x28)
+
+#define PHY_DEBUG_R1			(PL_OFFSET + 0x2c)
+#define PHY_DEBUG_R1_LINK_UP		(0x1 << 4)
+#define PHY_DEBUG_R1_LINK_IN_TRAINING	(0x1 << 29)
+
+#define PCIE_MISC_CONTROL_1		0x8bc
+#define DBI_RO_WR_EN			BIT(0)
+
+/* pcie reset */
+#define PCIEX8MGMT_PERST_N		0x0
+
+/* LTSSM */
+#define PCIEX8MGMT_APP_LTSSM_ENABLE	0x10
+#define LTSSM_ENABLE_BIT		BIT(0)
+
+/* phy reset */
+#define PCIEX8MGMT_APP_HOLD_PHY_RST	0x18
+
+/* device type */
+#define PCIEX8MGMT_DEVICE_TYPE		0x708
+#define DEVICE_TYPE_EP			0x0
+#define DEVICE_TYPE_RC			0x4
+
+/* phy control registers*/
+#define PCIEX8MGMT_PHY0_CR_PARA_ADDR	0x860
+#define PCIEX8MGMT_PHY0_CR_PARA_RD_EN	0x870
+#define PCIEX8MGMT_PHY0_CR_PARA_RD_DATA	0x878
+#define PCIEX8MGMT_PHY0_CR_PARA_SEL	0x880
+#define PCIEX8MGMT_PHY0_CR_PARA_WR_DATA	0x888
+#define PCIEX8MGMT_PHY0_CR_PARA_WR_EN	0x890
+#define PCIEX8MGMT_PHY0_CR_PARA_ACK	0x898
+#define PCIEX8MGMT_PHY1_CR_PARA_ADDR	0x8a0
+#define PCIEX8MGMT_PHY1_CR_PARA_RD_EN	0x8b0
+#define PCIEX8MGMT_PHY1_CR_PARA_RD_DATA	0x8b8
+#define PCIEX8MGMT_PHY1_CR_PARA_SEL	0x8c0
+#define PCIEX8MGMT_PHY1_CR_PARA_WR_DATA	0x8c8
+#define PCIEX8MGMT_PHY1_CR_PARA_WR_EN	0x8d0
+#define PCIEX8MGMT_PHY1_CR_PARA_ACK	0x8d8
+
+#define PCIEX8MGMT_LANE_NUM		8
+#define PCIEX8MGMT_LANE			0x1008
+#define PCIEX8MGMT_LANE_OFF		0x100
+#define PCIEX8MGMT_TERM_MODE		0x0e21
+
+#define PCIE_CAP_BASE			0x70
+#define PCI_CONFIG(r)			(DBI_OFFSET + (r))
+#define PCIE_CAPABILITIES(r)		PCI_CONFIG(PCIE_CAP_BASE + (r))
+
+/* Link capability */
+#define PF0_PCIE_CAP_LINK_CAP		PCIE_CAPABILITIES(0xc)
+#define PCIE_LINK_CAP_MAX_SPEED_MASK	0xf
+#define PCIE_LINK_CAP_MAX_SPEED_GEN1	BIT(0)
+#define PCIE_LINK_CAP_MAX_SPEED_GEN2	BIT(1)
+#define PCIE_LINK_CAP_MAX_SPEED_GEN3	BIT(2)
+#define PCIE_LINK_CAP_MAX_SPEED_GEN4	BIT(3)
+
+static enum pcie_sifive_devtype pcie_sifive_get_devtype(struct pcie_sifive *sv)
+{
+	u32 val;
+
+	val = readl(sv->priv_base + PCIEX8MGMT_DEVICE_TYPE);
+	switch (val) {
+	case DEVICE_TYPE_RC:
+		return SV_PCIE_HOST_TYPE;
+	case DEVICE_TYPE_EP:
+		return SV_PCIE_ENDPOINT_TYPE;
+	default:
+		return SV_PCIE_UNKNOWN_TYPE;
+	}
+}
+
+static void pcie_sifive_priv_set_state(struct pcie_sifive *sv, u32 reg,
+				       u32 bits, int state)
+{
+	u32 val;
+
+	val = readl(sv->priv_base + reg);
+	val = state ? (val | bits) : (val & !bits);
+	writel(val, sv->priv_base + reg);
+}
+
+static void pcie_sifive_assert_reset(struct pcie_sifive *sv)
+{
+	dm_gpio_set_value(&sv->reset_gpio, GPIO_LOW);
+	writel(PCIE_PERST_ASSERT, sv->priv_base + PCIEX8MGMT_PERST_N);
+	mdelay(ASSERTION_DELAY);
+}
+
+static void pcie_sifive_power_on(struct pcie_sifive *sv)
+{
+	dm_gpio_set_value(&sv->pwren_gpio, GPIO_HIGH);
+	mdelay(ASSERTION_DELAY);
+}
+
+static void pcie_sifive_deassert_reset(struct pcie_sifive *sv)
+{
+	writel(PCIE_PERST_DEASSERT, sv->priv_base + PCIEX8MGMT_PERST_N);
+	dm_gpio_set_value(&sv->reset_gpio, GPIO_HIGH);
+	mdelay(ASSERTION_DELAY);
+}
+
+static int pcie_sifive_setphy(const u8 phy, const u8 write,
+			      const u16 addr, const u16 wrdata,
+			      u16 *rddata, struct pcie_sifive *sv)
+{
+	unsigned char ack = 0;
+
+	if (!(phy == 0 || phy == 1))
+		return -2;
+
+	/* setup phy para */
+	writel(addr, sv->priv_base +
+	       (phy ? PCIEX8MGMT_PHY1_CR_PARA_ADDR :
+		PCIEX8MGMT_PHY0_CR_PARA_ADDR));
+
+	if (write)
+		writel(wrdata, sv->priv_base +
+		       (phy ? PCIEX8MGMT_PHY1_CR_PARA_WR_DATA :
+			PCIEX8MGMT_PHY0_CR_PARA_WR_DATA));
+
+	/* enable access if write */
+	if (write)
+		writel(1, sv->priv_base +
+		       (phy ? PCIEX8MGMT_PHY1_CR_PARA_WR_EN :
+			PCIEX8MGMT_PHY0_CR_PARA_WR_EN));
+	else
+		writel(1, sv->priv_base +
+		       (phy ? PCIEX8MGMT_PHY1_CR_PARA_RD_EN :
+			PCIEX8MGMT_PHY0_CR_PARA_RD_EN));
+
+	/* wait for wait_idle */
+	do {
+		u32 val;
+
+		val = readl(sv->priv_base +
+			    (phy ? PCIEX8MGMT_PHY1_CR_PARA_ACK :
+			     PCIEX8MGMT_PHY0_CR_PARA_ACK));
+		if (val) {
+			ack = 1;
+			if (!write)
+				readl(sv->priv_base +
+				      (phy ? PCIEX8MGMT_PHY1_CR_PARA_RD_DATA :
+				       PCIEX8MGMT_PHY0_CR_PARA_RD_DATA));
+			mdelay(1);
+		}
+	} while (!ack);
+
+	/* clear */
+	if (write)
+		writel(0, sv->priv_base +
+		       (phy ? PCIEX8MGMT_PHY1_CR_PARA_WR_EN :
+			PCIEX8MGMT_PHY0_CR_PARA_WR_EN));
+	else
+		writel(0, sv->priv_base +
+		       (phy ? PCIEX8MGMT_PHY1_CR_PARA_RD_EN :
+			PCIEX8MGMT_PHY0_CR_PARA_RD_EN));
+
+	while (readl(sv->priv_base +
+		     (phy ? PCIEX8MGMT_PHY1_CR_PARA_ACK :
+		      PCIEX8MGMT_PHY0_CR_PARA_ACK))) {
+		/* wait for ~wait_idle */
+	}
+
+	return 0;
+}
+
+static void pcie_sifive_init_phy(struct pcie_sifive *sv)
+{
+	int lane;
+
+	/* enable phy cr_para_sel interfaces */
+	writel(PCIE_PHY_SEL, sv->priv_base + PCIEX8MGMT_PHY0_CR_PARA_SEL);
+	writel(PCIE_PHY_SEL, sv->priv_base + PCIEX8MGMT_PHY1_CR_PARA_SEL);
+	mdelay(1);
+
+	/* set PHY AC termination mode */
+	for (lane = 0; lane < PCIEX8MGMT_LANE_NUM; lane++) {
+		pcie_sifive_setphy(0, 1,
+				   PCIEX8MGMT_LANE +
+				   (PCIEX8MGMT_LANE_OFF * lane),
+				   PCIEX8MGMT_TERM_MODE, NULL, sv);
+		pcie_sifive_setphy(1, 1,
+				   PCIEX8MGMT_LANE +
+				   (PCIEX8MGMT_LANE_OFF * lane),
+				   PCIEX8MGMT_TERM_MODE, NULL, sv);
+	}
+}
+
+static int pcie_sifive_check_link(struct pcie_sifive *sv)
+{
+	u32 val;
+
+	val = readl(sv->dw.dbi_base + PHY_DEBUG_R1);
+	return (val & PHY_DEBUG_R1_LINK_UP) &&
+		!(val & PHY_DEBUG_R1_LINK_IN_TRAINING);
+}
+
+static void pcie_sifive_force_gen1(struct pcie_sifive *sv)
+{
+	u32 val, linkcap;
+
+	/*
+	 * Force Gen1 operation when starting the link. In case the link is
+	 * started in Gen2 mode, there is a possibility the devices on the
+	 * bus will not be detected at all. This happens with PCIe switches.
+	 */
+
+	/* ctrl_ro_wr_enable */
+	val = readl(sv->dw.dbi_base + PCIE_MISC_CONTROL_1);
+	val |= DBI_RO_WR_EN;
+	writel(val, sv->dw.dbi_base + PCIE_MISC_CONTROL_1);
+
+	/* configure link cap */
+	linkcap = readl(sv->dw.dbi_base + PF0_PCIE_CAP_LINK_CAP);
+	linkcap |= PCIE_LINK_CAP_MAX_SPEED_MASK;
+	writel(linkcap, sv->dw.dbi_base + PF0_PCIE_CAP_LINK_CAP);
+
+	/* ctrl_ro_wr_disable */
+	val &= ~DBI_RO_WR_EN;
+	writel(val, sv->dw.dbi_base + PCIE_MISC_CONTROL_1);
+}
+
+static void pcie_sifive_print_phy_debug(struct pcie_sifive *sv)
+{
+	sv_err(sv, "PHY DEBUG_R0=0x%08x DEBUG_R1=0x%08x\n",
+	       readl(sv->dw.dbi_base + PHY_DEBUG_R0),
+	       readl(sv->dw.dbi_base + PHY_DEBUG_R1));
+}
+
+static int pcie_sifive_wait_for_link(struct pcie_sifive *sv)
+{
+	u32 val;
+	int timeout;
+
+	/* Wait for the link to train */
+	mdelay(20);
+	timeout = 20;
+
+	do {
+		mdelay(1);
+	} while (--timeout && !pcie_sifive_check_link(sv));
+
+	val = readl(sv->dw.dbi_base + PHY_DEBUG_R1);
+	if (!(val & PHY_DEBUG_R1_LINK_UP) ||
+	    (val & PHY_DEBUG_R1_LINK_IN_TRAINING)) {
+		sv_info(sv, "Failed to negotiate PCIe link!\n");
+		pcie_sifive_print_phy_debug(sv);
+		writel(PCIE_PHY_RESET,
+		       sv->priv_base + PCIEX8MGMT_APP_HOLD_PHY_RST);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int pcie_sifive_start_link(struct pcie_sifive *sv)
+{
+	if (pcie_sifive_check_link(sv))
+		return -EALREADY;
+
+	pcie_sifive_force_gen1(sv);
+
+	/* set ltssm */
+	pcie_sifive_priv_set_state(sv, PCIEX8MGMT_APP_LTSSM_ENABLE,
+				   LTSSM_ENABLE_BIT, 1);
+	return 0;
+}
+
+static int pcie_sifive_init_port(struct udevice *dev,
+				 enum pcie_sifive_devtype mode)
+{
+	struct pcie_sifive *sv = dev_get_priv(dev);
+	int ret;
+
+	/* Power on reset */
+	pcie_sifive_assert_reset(sv);
+	pcie_sifive_power_on(sv);
+	pcie_sifive_deassert_reset(sv);
+
+	/* Enable pcieauxclk */
+	ret = clk_enable(&sv->aux_ck);
+	if (ret)
+		dev_err(dev, "unable to enable pcie_aux clock\n");
+
+	/*
+	 * assert hold_phy_rst (hold the controller LTSSM in reset
+	 * after power_up_rst_n for register programming with cr_para)
+	 */
+	writel(PCIE_PHY_RESET, sv->priv_base + PCIEX8MGMT_APP_HOLD_PHY_RST);
+
+	/* deassert power_up_rst_n */
+	ret = reset_deassert(&sv->reset);
+	if (ret < 0) {
+		dev_err(dev, "failed to deassert reset");
+		return -EINVAL;
+	}
+
+	pcie_sifive_init_phy(sv);
+
+	/* disable pcieauxclk */
+	clk_disable(&sv->aux_ck);
+
+	/* deassert hold_phy_rst */
+	writel(PCIE_PHY_RESET_DEASSERT,
+	       sv->priv_base + PCIEX8MGMT_APP_HOLD_PHY_RST);
+
+	/* enable pcieauxclk */
+	clk_enable(&sv->aux_ck);
+
+	/* Set desired mode while core is not operational */
+	if (mode == SV_PCIE_HOST_TYPE)
+		writel(DEVICE_TYPE_RC,
+		       sv->priv_base + PCIEX8MGMT_DEVICE_TYPE);
+	else
+		writel(DEVICE_TYPE_EP,
+		       sv->priv_base + PCIEX8MGMT_DEVICE_TYPE);
+
+	/* Confirm desired mode from operational core */
+	if (pcie_sifive_get_devtype(sv) != mode)
+		return -EINVAL;
+
+	pcie_dw_setup_host(&sv->dw);
+
+	if (pcie_sifive_start_link(sv) == -EALREADY)
+		sv_info(sv, "PCIe link is already up\n");
+	else if (pcie_sifive_wait_for_link(sv) == -ETIMEDOUT)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static int pcie_sifive_probe(struct udevice *dev)
+{
+	struct pcie_sifive *sv = dev_get_priv(dev);
+	struct udevice *parent = pci_get_controller(dev);
+	struct pci_controller *hose = dev_get_uclass_priv(parent);
+	int err;
+
+	sv->dw.first_busno = dev_seq(dev);
+	sv->dw.dev = dev;
+
+	err = pcie_sifive_init_port(dev, SV_PCIE_HOST_TYPE);
+	if (err) {
+		sv_info(sv, "Failed to init port.\n");
+		return err;
+	}
+
+	printf("PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n",
+	       dev_seq(dev), pcie_dw_get_link_speed(&sv->dw),
+	       pcie_dw_get_link_width(&sv->dw),
+	       hose->first_busno);
+
+	return pcie_dw_prog_outbound_atu_unroll(&sv->dw,
+						PCIE_ATU_REGION_INDEX0,
+						PCIE_ATU_TYPE_MEM,
+						sv->dw.mem.phys_start,
+						sv->dw.mem.bus_start,
+						sv->dw.mem.size);
+}
+
+static void __iomem *get_fdt_addr(struct udevice *dev, const char *name)
+{
+	fdt_addr_t addr;
+
+	addr = dev_read_addr_name(dev, name);
+
+	return (addr == FDT_ADDR_T_NONE) ? NULL : (void __iomem *)addr;
+}
+
+static int pcie_sifive_of_to_plat(struct udevice *dev)
+{
+	struct pcie_sifive *sv = dev_get_priv(dev);
+	int err;
+
+	/* get designware DBI base addr */
+	sv->dw.dbi_base = get_fdt_addr(dev, "dbi");
+	if (!sv->dw.dbi_base)
+		return -EINVAL;
+
+	/* get private control base addr */
+	sv->priv_base = get_fdt_addr(dev, "mgmt");
+	if (!sv->priv_base)
+		return -EINVAL;
+
+	gpio_request_by_name(dev, "pwren-gpios", 0, &sv->pwren_gpio,
+			     GPIOD_IS_OUT);
+
+	if (!dm_gpio_is_valid(&sv->pwren_gpio)) {
+		sv_info(sv, "pwren_gpio is invalid\n");
+		return -EINVAL;
+	}
+
+	gpio_request_by_name(dev, "reset-gpios", 0, &sv->reset_gpio,
+			     GPIOD_IS_OUT);
+
+	if (!dm_gpio_is_valid(&sv->reset_gpio)) {
+		sv_info(sv, "reset_gpio is invalid\n");
+		return -EINVAL;
+	}
+
+	err = clk_get_by_index(dev, 0, &sv->aux_ck);
+	if (err) {
+		sv_info(sv, "clk_get_by_index(aux_ck) failed: %d\n", err);
+		return err;
+	}
+
+	err = reset_get_by_index(dev, 0, &sv->reset);
+	if (err) {
+		sv_info(sv, "reset_get_by_index(reset) failed: %d\n", err);
+		return err;
+	}
+
+	return 0;
+}
+
+static const struct dm_pci_ops pcie_sifive_ops = {
+	.read_config	= pcie_dw_read_config,
+	.write_config	= pcie_dw_write_config,
+};
+
+static const struct udevice_id pcie_sifive_ids[] = {
+	{ .compatible = "sifive,fu740-pcie" },
+	{}
+};
+
+U_BOOT_DRIVER(pcie_sifive) = {
+	.name		= "pcie_sifive",
+	.id		= UCLASS_PCI,
+	.of_match	= pcie_sifive_ids,
+	.ops		= &pcie_sifive_ops,
+	.of_to_plat	= pcie_sifive_of_to_plat,
+	.probe		= pcie_sifive_probe,
+	.priv_auto	= sizeof(struct pcie_sifive),
+};

+ 4 - 4
drivers/ram/sifive/Kconfig

@@ -5,9 +5,9 @@ config RAM_SIFIVE
 	help
 	  This enables support for ram drivers of SiFive SoCs.
 
-config SIFIVE_FU540_DDR
-	bool "SiFive FU540 DDR driver"
+config SIFIVE_DDR
+	bool "SiFive DDR driver"
 	depends on RAM_SIFIVE
-	default y if TARGET_SIFIVE_UNLEASHED
+	default y if TARGET_SIFIVE_UNLEASHED || TARGET_SIFIVE_UNMATCHED
 	help
-	  This enables DDR support for the platforms based on SiFive FU540 SoC.
+	  This enables DDR support for the platforms based on SiFive SoC.

+ 1 - 1
drivers/ram/sifive/Makefile

@@ -3,4 +3,4 @@
 # Copyright (c) 2020 SiFive, Inc
 #
 
-obj-$(CONFIG_SIFIVE_FU540_DDR) += fu540_ddr.o
+obj-$(CONFIG_SIFIVE_DDR) += sifive_ddr.o

+ 45 - 44
drivers/ram/sifive/fu540_ddr.c → drivers/ram/sifive/sifive_ddr.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
 /*
- * (C) Copyright 2020 SiFive, Inc.
+ * (C) Copyright 2020-2021 SiFive, Inc.
  *
  * Authors:
  *   Pragnesh Patel <pragnesh.patel@sifive.com>
@@ -65,16 +65,16 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
-struct fu540_ddrctl {
+struct sifive_ddrctl {
 	volatile u32 denali_ctl[265];
 };
 
-struct fu540_ddrphy {
+struct sifive_ddrphy {
 	volatile u32 denali_phy[1215];
 };
 
 /**
- * struct fu540_ddr_info
+ * struct sifive_ddr_info
  *
  * @dev                         : pointer for the device
  * @info                        : UCLASS RAM information
@@ -83,23 +83,23 @@ struct fu540_ddrphy {
  * @ctrl                        : DDR control base address
  * @physical_filter_ctrl        : DDR physical filter control base address
  */
-struct fu540_ddr_info {
+struct sifive_ddr_info {
 	struct udevice *dev;
 	struct ram_info info;
-	struct fu540_ddrctl *ctl;
-	struct fu540_ddrphy *phy;
+	struct sifive_ddrctl *ctl;
+	struct sifive_ddrphy *phy;
 	struct clk ddr_clk;
 	u32 *physical_filter_ctrl;
 };
 
 #if defined(CONFIG_SPL_BUILD)
-struct fu540_ddr_params {
-	struct fu540_ddrctl pctl_regs;
-	struct fu540_ddrphy phy_regs;
+struct sifive_ddr_params {
+	struct sifive_ddrctl pctl_regs;
+	struct sifive_ddrphy phy_regs;
 };
 
 struct sifive_dmc_plat {
-	struct fu540_ddr_params ddr_params;
+	struct sifive_ddr_params ddr_params;
 };
 
 /*
@@ -118,7 +118,7 @@ static void sdram_copy_to_reg(volatile u32 *dest,
 	}
 }
 
-static void fu540_ddr_setup_range_protection(volatile u32 *ctl, u64 end_addr)
+static void sifive_ddr_setup_range_protection(volatile u32 *ctl, u64 end_addr)
 {
 	u32 end_addr_16kblocks = ((end_addr >> 14) & 0x7FFFFF) - 1;
 
@@ -135,8 +135,8 @@ static void fu540_ddr_setup_range_protection(volatile u32 *ctl, u64 end_addr)
 		     0x1 << PORT_ADDR_PROTECTION_EN_OFFSET);
 }
 
-static void fu540_ddr_start(volatile u32 *ctl, u32 *physical_filter_ctrl,
-			    u64 ddr_end)
+static void sifive_ddr_start(volatile u32 *ctl, u32 *physical_filter_ctrl,
+			     u64 ddr_end)
 {
 	volatile u64 *filterreg = (volatile u64 *)physical_filter_ctrl;
 
@@ -149,7 +149,7 @@ static void fu540_ddr_start(volatile u32 *ctl, u32 *physical_filter_ctrl,
 	filterreg[0] = 0x0f00000000000000UL | (ddr_end >> 2);
 }
 
-static void fu540_ddr_check_errata(u32 regbase, u32 updownreg)
+static void sifive_ddr_check_errata(u32 regbase, u32 updownreg)
 {
 	u64 fails     = 0;
 	u32 dq        = 0;
@@ -202,7 +202,7 @@ static void fu540_ddr_check_errata(u32 regbase, u32 updownreg)
 	}
 }
 
-static u64 fu540_ddr_phy_fixup(volatile u32 *ddrphyreg)
+static u64 sifive_ddr_phy_fixup(volatile u32 *ddrphyreg)
 {
 	u32 slicebase = 0;
 
@@ -213,7 +213,7 @@ static u64 fu540_ddr_phy_fixup(volatile u32 *ddrphyreg)
 		for (u32 reg = 0; reg < 4; reg++) {
 			u32 updownreg = readl(regbase + reg + ddrphyreg);
 
-			fu540_ddr_check_errata(regbase, updownreg);
+			sifive_ddr_check_errata(regbase, updownreg);
 		}
 		slicebase += 128;
 	}
@@ -221,18 +221,18 @@ static u64 fu540_ddr_phy_fixup(volatile u32 *ddrphyreg)
 	return(0);
 }
 
-static u32 fu540_ddr_get_dram_class(volatile u32 *ctl)
+static u32 sifive_ddr_get_dram_class(volatile u32 *ctl)
 {
 	u32 reg = readl(DENALI_CTL_0 + ctl);
 
 	return ((reg >> DRAM_CLASS_OFFSET) & 0xF);
 }
 
-static int fu540_ddr_setup(struct udevice *dev)
+static int sifive_ddr_setup(struct udevice *dev)
 {
-	struct fu540_ddr_info *priv = dev_get_priv(dev);
+	struct sifive_ddr_info *priv = dev_get_priv(dev);
 	struct sifive_dmc_plat *plat = dev_get_plat(dev);
-	struct fu540_ddr_params *params = &plat->ddr_params;
+	struct sifive_ddr_params *params = &plat->ddr_params;
 	volatile u32 *denali_ctl =  priv->ctl->denali_ctl;
 	volatile u32 *denali_phy =  priv->phy->denali_phy;
 	const u64 ddr_size = priv->info.size;
@@ -251,7 +251,7 @@ static int fu540_ddr_setup(struct udevice *dev)
 
 	sdram_copy_to_reg(priv->ctl->denali_ctl,
 			  params->pctl_regs.denali_ctl,
-			  sizeof(struct fu540_ddrctl));
+			  sizeof(struct sifive_ddrctl));
 
 	/* phy reset */
 	for (i = DENALI_PHY_1152; i <= DENALI_PHY_1214; i++) {
@@ -285,7 +285,7 @@ static int fu540_ddr_setup(struct udevice *dev)
 	setbits_le32(DENALI_CTL_182 + denali_ctl,
 		     1 << DFI_PHY_RDLVL_GATE_MODE_OFFSET);
 
-	if (fu540_ddr_get_dram_class(denali_ctl) == DRAM_CLASS_DDR4) {
+	if (sifive_ddr_get_dram_class(denali_ctl) == DRAM_CLASS_DDR4) {
 		/* Enable vref training DENALI_CTL_184 */
 		setbits_le32(DENALI_CTL_184 + denali_ctl, 1 << VREF_EN_OFFSET);
 	}
@@ -302,15 +302,15 @@ static int fu540_ddr_setup(struct udevice *dev)
 		     | (1 << MULTIPLE_OUT_OF_RANGE_OFFSET));
 
 	/* set up range protection */
-	fu540_ddr_setup_range_protection(denali_ctl, priv->info.size);
+	sifive_ddr_setup_range_protection(denali_ctl, priv->info.size);
 
 	/* Mask off port command error interrupt DENALI_CTL_136 */
 	setbits_le32(DENALI_CTL_136 + denali_ctl,
 		     1 << PORT_COMMAND_CHANNEL_ERROR_OFFSET);
 
-	fu540_ddr_start(denali_ctl, priv->physical_filter_ctrl, ddr_end);
+	sifive_ddr_start(denali_ctl, priv->physical_filter_ctrl, ddr_end);
 
-	fu540_ddr_phy_fixup(denali_phy);
+	sifive_ddr_phy_fixup(denali_phy);
 
 	/* check size */
 	priv->info.size = get_ram_size((long *)priv->info.base,
@@ -329,9 +329,9 @@ static int fu540_ddr_setup(struct udevice *dev)
 }
 #endif
 
-static int fu540_ddr_probe(struct udevice *dev)
+static int sifive_ddr_probe(struct udevice *dev)
 {
-	struct fu540_ddr_info *priv = dev_get_priv(dev);
+	struct sifive_ddr_info *priv = dev_get_priv(dev);
 
 	/* Read memory base and size from DT */
 	fdtdec_setup_mem_size_base();
@@ -342,7 +342,7 @@ static int fu540_ddr_probe(struct udevice *dev)
 	int ret;
 	u32 clock = 0;
 
-	debug("FU540 DDR probe\n");
+	debug("sifive DDR probe\n");
 	priv->dev = dev;
 
 	ret = clk_get_by_index(dev, 0, &priv->ddr_clk);
@@ -369,42 +369,43 @@ static int fu540_ddr_probe(struct udevice *dev)
 		return ret;
 	}
 
-	priv->ctl = (struct fu540_ddrctl *)dev_read_addr_index(dev, 0);
-	priv->phy = (struct fu540_ddrphy *)dev_read_addr_index(dev, 1);
+	priv->ctl = (struct sifive_ddrctl *)dev_read_addr_index(dev, 0);
+	priv->phy = (struct sifive_ddrphy *)dev_read_addr_index(dev, 1);
 	priv->physical_filter_ctrl = (u32 *)dev_read_addr_index(dev, 2);
 
-	return fu540_ddr_setup(dev);
+	return sifive_ddr_setup(dev);
 #endif
 
 	return 0;
 }
 
-static int fu540_ddr_get_info(struct udevice *dev, struct ram_info *info)
+static int sifive_ddr_get_info(struct udevice *dev, struct ram_info *info)
 {
-	struct fu540_ddr_info *priv = dev_get_priv(dev);
+	struct sifive_ddr_info *priv = dev_get_priv(dev);
 
 	*info = priv->info;
 
 	return 0;
 }
 
-static struct ram_ops fu540_ddr_ops = {
-	.get_info = fu540_ddr_get_info,
+static struct ram_ops sifive_ddr_ops = {
+	.get_info = sifive_ddr_get_info,
 };
 
-static const struct udevice_id fu540_ddr_ids[] = {
+static const struct udevice_id sifive_ddr_ids[] = {
 	{ .compatible = "sifive,fu540-c000-ddr" },
+	{ .compatible = "sifive,fu740-c000-ddr" },
 	{ }
 };
 
-U_BOOT_DRIVER(fu540_ddr) = {
-	.name = "fu540_ddr",
+U_BOOT_DRIVER(sifive_ddr) = {
+	.name = "sifive_ddr",
 	.id = UCLASS_RAM,
-	.of_match = fu540_ddr_ids,
-	.ops = &fu540_ddr_ops,
-	.probe = fu540_ddr_probe,
-	.priv_auto	= sizeof(struct fu540_ddr_info),
+	.of_match = sifive_ddr_ids,
+	.ops = &sifive_ddr_ops,
+	.probe = sifive_ddr_probe,
+	.priv_auto = sizeof(struct sifive_ddr_info),
 #if defined(CONFIG_SPL_BUILD)
-	.plat_auto	= sizeof(struct sifive_dmc_plat),
+	.plat_auto = sizeof(struct sifive_dmc_plat),
 #endif
 };

+ 1 - 1
drivers/reset/Kconfig

@@ -166,7 +166,7 @@ config RESET_IPQ419
 
 config RESET_SIFIVE
 	bool "Reset Driver for SiFive SoC's"
-	depends on DM_RESET && CLK_SIFIVE_FU540_PRCI && TARGET_SIFIVE_UNLEASHED
+	depends on DM_RESET && CLK_SIFIVE_PRCI && (TARGET_SIFIVE_UNLEASHED || TARGET_SIFIVE_UNMATCHED)
 	default y
 	help
 	  PRCI module within SiFive SoC's provides mechanism to reset

+ 83 - 0
include/configs/sifive-unmatched.h

@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2020-2021 SiFive, Inc
+ *
+ * Authors:
+ *   Pragnesh Patel <pragnesh.patel@sifive.com>
+ */
+
+#ifndef __SIFIVE_UNMATCHED_H
+#define __SIFIVE_UNMATCHED_H
+
+#include <linux/sizes.h>
+
+#ifdef CONFIG_SPL
+
+#define CONFIG_SPL_MAX_SIZE		0x00100000
+#define CONFIG_SPL_BSS_START_ADDR	0x85000000
+#define CONFIG_SPL_BSS_MAX_SIZE		0x00100000
+#define CONFIG_SYS_SPL_MALLOC_START	(CONFIG_SPL_BSS_START_ADDR + \
+					 CONFIG_SPL_BSS_MAX_SIZE)
+#define CONFIG_SYS_SPL_MALLOC_SIZE	0x00100000
+
+#define CONFIG_SPL_STACK	(0x08000000 + 0x001D0000 - \
+				 GENERATED_GBL_DATA_SIZE)
+
+#endif
+
+#define CONFIG_SYS_SDRAM_BASE		0x80000000
+#define CONFIG_SYS_INIT_SP_ADDR		(CONFIG_SYS_SDRAM_BASE + SZ_2M)
+
+#define CONFIG_SYS_LOAD_ADDR		(CONFIG_SYS_SDRAM_BASE + SZ_2M)
+
+#define CONFIG_SYS_MALLOC_LEN		SZ_8M
+
+#define CONFIG_SYS_BOOTM_LEN		SZ_64M
+
+#define CONFIG_STANDALONE_LOAD_ADDR	0x80200000
+
+#define CONFIG_SYS_PCI_64BIT		1	/* enable 64-bit resources */
+
+#define CONFIG_SYS_CACHELINE_SIZE	64
+
+/* Environment options */
+
+#ifndef CONFIG_SPL_BUILD
+#define BOOT_TARGET_DEVICES(func) \
+	func(NVME, nvme, 0) \
+	func(USB, usb, 0) \
+	func(MMC, mmc, 0) \
+	func(PXE, pxe, na) \
+	func(DHCP, dhcp, na)
+
+#include <config_distro_bootcmd.h>
+
+#define TYPE_GUID_LOADER1	"5B193300-FC78-40CD-8002-E86C45580B47"
+#define TYPE_GUID_LOADER2	"2E54B353-1271-4842-806F-E436D6AF6985"
+#define TYPE_GUID_SYSTEM	"0FC63DAF-8483-4772-8E79-3D69D8477DE4"
+
+#define PARTS_DEFAULT \
+	"name=loader1,start=17K,size=1M,type=${type_guid_gpt_loader1};" \
+	"name=loader2,size=4MB,type=${type_guid_gpt_loader2};" \
+	"name=system,size=-,bootable,type=${type_guid_gpt_system};"
+
+#define CONFIG_EXTRA_ENV_SETTINGS \
+	"kernel_addr_r=0x84000000\0" \
+	"fdt_addr_r=0x88000000\0" \
+	"scriptaddr=0x88100000\0" \
+	"pxefile_addr_r=0x88200000\0" \
+	"ramdisk_addr_r=0x88300000\0" \
+	"kernel_comp_addr_r=0x90000000\0" \
+	"kernel_comp_size=0x4000000\0" \
+	"type_guid_gpt_loader1=" TYPE_GUID_LOADER1 "\0" \
+	"type_guid_gpt_loader2=" TYPE_GUID_LOADER2 "\0" \
+	"type_guid_gpt_system=" TYPE_GUID_SYSTEM "\0" \
+	"partitions=" PARTS_DEFAULT "\0" \
+	BOOTENV
+
+#define CONFIG_PREBOOT \
+	"setenv fdt_addr ${fdtcontroladdr};" \
+	"fdt addr ${fdtcontroladdr};"
+#endif /* CONFIG_SPL_BUILD */
+
+#endif /* __SIFIVE_UNMATCHED_H */

+ 25 - 0
include/dt-bindings/clock/sifive-fu740-prci.h

@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 OR MIT */
+/*
+ * Copyright (C) 2020-2021 SiFive, Inc.
+ * Wesley Terpstra
+ * Paul Walmsley
+ * Zong Li
+ * Pragnesh Patel
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_SIFIVE_FU740_PRCI_H
+#define __DT_BINDINGS_CLOCK_SIFIVE_FU740_PRCI_H
+
+/* Clock indexes for use by Device Tree data and the PRCI driver */
+
+#define PRCI_CLK_COREPLL	0
+#define PRCI_CLK_DDRPLL		1
+#define PRCI_CLK_GEMGXLPLL	2
+#define PRCI_CLK_DVFSCOREPLL	3
+#define PRCI_CLK_HFPCLKPLL	4
+#define PRCI_CLK_CLTXPLL	5
+#define PRCI_CLK_TLCLK		6
+#define PRCI_CLK_PCLK		7
+#define PRCI_CLK_PCIEAUX	8
+
+#endif

+ 19 - 0
include/dt-bindings/reset/sifive-fu740-prci.h

@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 OR MIT */
+/*
+ * Copyright (C) 2020-2021 Sifive, Inc.
+ * Author: Pragnesh Patel <pragnesh.patel@sifive.com>
+ */
+
+#ifndef __DT_BINDINGS_RESET_SIFIVE_FU740_PRCI_H
+#define __DT_BINDINGS_RESET_SIFIVE_FU740_PRCI_H
+
+/* Reset indexes for use by device tree data and the PRCI driver */
+#define PRCI_RST_DDR_CTRL_N		0
+#define PRCI_RST_DDR_AXI_N		1
+#define PRCI_RST_DDR_AHB_N		2
+#define PRCI_RST_DDR_PHY_N		3
+#define PRCI_RST_PCIE_POWER_UP_N	4
+#define PRCI_RST_GEMGXL_N		5
+#define PRCI_RST_CLTX_N			6
+
+#endif