riscv64: add support for 5.4
authorZoltan HERPAI <wigyori@uid0.hu>
Sun, 26 Jan 2020 22:47:36 +0000 (23:47 +0100)
committerZoltan HERPAI <wigyori@uid0.hu>
Wed, 22 Apr 2020 14:15:10 +0000 (16:15 +0200)
Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
target/linux/riscv64/Makefile
target/linux/riscv64/config-5.4 [new file with mode: 0644]
target/linux/riscv64/patches/0009-RISC-V-Networking-fix-Hack.patch [deleted file]
target/linux/riscv64/patches/002-clk-sifive-prci.patch [deleted file]
target/linux/riscv64/patches/003-clk-gemgxl.patch [deleted file]
target/linux/riscv64/patches/004-spi-sifive.patch [deleted file]
target/linux/riscv64/patches/005-spi-is25wp256d.patch [deleted file]
target/linux/riscv64/patches/006-uart-sifive-serial-driver.patch [deleted file]
target/linux/riscv64/patches/007-gpio-sifive-support-GPIO-on-SiFive-SoCs.patch [deleted file]

index 8d8e5908434bb64a7282d9a0317193f4e7f422a3..3485e9b8a6e41c5eea3a7a3bcb5bcb378a95eb0b 100644 (file)
@@ -13,6 +13,7 @@ FEATURES:=ext4
 MAINTAINER:=Zoltan HERPAI <wigyori@uid0.hu>
 
 KERNEL_PATCHVER:=4.19
+KERNEL_TESTING_PATCHVER:=5.4
 
 include $(INCLUDE_DIR)/target.mk
 
diff --git a/target/linux/riscv64/config-5.4 b/target/linux/riscv64/config-5.4
new file mode 100644 (file)
index 0000000..8b58723
--- /dev/null
@@ -0,0 +1,437 @@
+CONFIG_64BIT=y
+CONFIG_64BIT_TIME=y
+# CONFIG_ADIN_PHY is not set
+# CONFIG_AL_FIC is not set
+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
+CONFIG_ARCH_HAS_BINFMT_FLAT=y
+CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
+CONFIG_ARCH_HAS_GIGANTIC_PAGE=y
+CONFIG_ARCH_HAS_MMIOWB=y
+CONFIG_ARCH_HAS_PTE_SPECIAL=y
+CONFIG_ARCH_MMAP_RND_BITS=18
+CONFIG_ARCH_MMAP_RND_BITS_MAX=24
+CONFIG_ARCH_MMAP_RND_BITS_MIN=18
+# CONFIG_ARCH_RV32I is not set
+CONFIG_ARCH_RV64I=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SUPPORTS_INT128=y
+CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT=y
+CONFIG_ARCH_WANT_FRAME_POINTERS=y
+CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
+CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y
+CONFIG_ASN1=y
+CONFIG_ASSOCIATIVE_ARRAY=y
+CONFIG_ASYMMETRIC_KEY_TYPE=y
+CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y
+CONFIG_ATA=y
+CONFIG_ATA_VERBOSE_ERROR=y
+# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_MQ_PCI=y
+CONFIG_BLK_MQ_VIRTIO=y
+CONFIG_BLK_SCSI_REQUEST=y
+CONFIG_CAVIUM_PTP=y
+CONFIG_CC_CAN_LINK=y
+CONFIG_CC_HAS_ASM_INLINE=y
+CONFIG_CC_HAS_KASAN_GENERIC=y
+CONFIG_CC_HAS_WARN_MAYBE_UNINITIALIZED=y
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_CLK_ANALOGBITS_WRPLL_CLN28HPC=y
+CONFIG_CLK_GEMGXL_MGMT=y
+CONFIG_CLK_SIFIVE=y
+CONFIG_CLK_SIFIVE_FU540_PRCI=y
+CONFIG_CLK_U54_PRCI=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_CLZ_TAB=y
+CONFIG_CMDLINE="earlyprintk root=/dev/mmcblk0p2 rootwait console=ttySI0"
+CONFIG_CMDLINE_FALLBACK=y
+CONFIG_CMODEL_MEDANY=y
+# CONFIG_CMODEL_MEDLOW is not set
+CONFIG_COMMON_CLK=y
+# CONFIG_COMMON_CLK_FIXED_MMIO is not set
+# CONFIG_COMMON_CLK_SI5341 is not set
+CONFIG_COMPAT_BRK=y
+CONFIG_COREDUMP=y
+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
+# CONFIG_COUNTER is not set
+CONFIG_CPU_ISOLATION=y
+CONFIG_CPU_RMAP=y
+CONFIG_CRC16=y
+# CONFIG_CRC32_SARWATE is not set
+CONFIG_CRC32_SLICEBY8=y
+CONFIG_CRC7=y
+CONFIG_CRC_ITU_T=y
+CONFIG_CRYPTO_ACOMP2=y
+# CONFIG_CRYPTO_ADIANTUM is not set
+CONFIG_CRYPTO_AEAD=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_AKCIPHER=y
+CONFIG_CRYPTO_AKCIPHER2=y
+CONFIG_CRYPTO_CRC32C=y
+CONFIG_CRYPTO_DRBG=y
+CONFIG_CRYPTO_DRBG_HMAC=y
+CONFIG_CRYPTO_DRBG_MENU=y
+CONFIG_CRYPTO_ECHAINIV=y
+# CONFIG_CRYPTO_ECRDSA is not set
+# CONFIG_CRYPTO_ESSIV is not set
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_HASH_INFO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_JITTERENTROPY=y
+CONFIG_CRYPTO_KPP2=y
+CONFIG_CRYPTO_LIB_AES=y
+CONFIG_CRYPTO_LIB_SHA256=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+CONFIG_CRYPTO_NULL=y
+CONFIG_CRYPTO_NULL2=y
+# CONFIG_CRYPTO_OFB is not set
+CONFIG_CRYPTO_RNG=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_RNG_DEFAULT=y
+CONFIG_CRYPTO_RSA=y
+CONFIG_CRYPTO_SHA256=y
+# CONFIG_CRYPTO_STREEBOG is not set
+# CONFIG_CRYPTO_XXHASH is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_FS is not set
+CONFIG_DEBUG_MISC=y
+# CONFIG_DEBUG_PLIST is not set
+CONFIG_DEBUG_SECTION_MISMATCH=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DEVMEM=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_DMA_DECLARE_COHERENT=y
+CONFIG_DNOTIFY=y
+CONFIG_DTC=y
+CONFIG_E1000E=y
+CONFIG_EDAC_SUPPORT=y
+# CONFIG_EEPROM_EE1004 is not set
+CONFIG_ELF_CORE=y
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_EXFAT_FS is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_EXT4_FS=y
+CONFIG_FAILOVER=y
+CONFIG_FHANDLE=y
+# CONFIG_FIELDBUS_DEV is not set
+CONFIG_FIXED_PHY=y
+CONFIG_FIX_EARLYCON_MEM=y
+CONFIG_FPU=y
+CONFIG_FRAME_POINTER=y
+CONFIG_FRAME_WARN=2048
+CONFIG_FS_IOMAP=y
+CONFIG_FS_MBCACHE=y
+# CONFIG_FS_VERITY is not set
+# CONFIG_FW_LOADER_COMPRESS is not set
+CONFIG_FW_LOADER_PAGED_BUF=y
+CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_GENERIC_ARCH_TOPOLOGY=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CPU_DEVICES=y
+CONFIG_GENERIC_CSUM=y
+CONFIG_GENERIC_IRQ_MULTI_HANDLER=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_MSI_IRQ=y
+CONFIG_GENERIC_MSI_IRQ_DOMAIN=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_STRNCPY_FROM_USER=y
+CONFIG_GENERIC_STRNLEN_USER=y
+CONFIG_GLOB=y
+CONFIG_GPIOLIB=y
+# CONFIG_GPIO_AMD_FCH is not set
+# CONFIG_GPIO_CADENCE is not set
+# CONFIG_GPIO_GW_PLD is not set
+# CONFIG_GVE is not set
+# CONFIG_HABANA_AI is not set
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+CONFIG_HAVE_ARCH_AUDITSYSCALL=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_ASM_MODVERSIONS=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_CLK_PREPARE=y
+CONFIG_HAVE_COPY_THREAD_TLS=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y
+CONFIG_HAVE_EBPF_JIT=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUTEX_CMPXCHG=y
+CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
+CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
+CONFIG_HAVE_NET_DSA=y
+CONFIG_HAVE_PCI=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_HAVE_PERF_REGS=y
+CONFIG_HAVE_PERF_USER_STACK_DUMP=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
+# CONFIG_HEADERS_INSTALL is not set
+# CONFIG_HEADER_TEST is not set
+CONFIG_HID=y
+# CONFIG_HID_CREATIVE_SB0540 is not set
+CONFIG_HID_GENERIC=y
+# CONFIG_HID_MACALLY is not set
+# CONFIG_HID_MALTRON is not set
+# CONFIG_HID_VIEWSONIC is not set
+# CONFIG_HUGETLBFS is not set
+CONFIG_HVC_DRIVER=y
+# CONFIG_HVC_RISCV_SBI is not set
+CONFIG_HZ_PERIODIC=y
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_HELPER_AUTO=y
+# CONFIG_I2C_NVIDIA_GPU is not set
+CONFIG_I2C_OCORES=y
+# CONFIG_I3C is not set
+# CONFIG_IGC is not set
+# CONFIG_IKHEADERS is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set
+# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set
+CONFIG_INIT_STACK_NONE=y
+CONFIG_INPUT=y
+# CONFIG_INPUT_GPIO_VIBRA is not set
+# CONFIG_INPUT_MSM_VIBRATOR is not set
+# CONFIG_INTERCONNECT is not set
+# CONFIG_IONIC is not set
+CONFIG_IO_URING=y
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_DOMAIN_HIERARCHY=y
+CONFIG_IRQ_WORK=y
+CONFIG_JBD2=y
+CONFIG_KALLSYMS=y
+CONFIG_KASAN_STACK=1
+CONFIG_KEYS=y
+# CONFIG_KEYS_REQUEST_CACHE is not set
+# CONFIG_LCD_CLASS_DEVICE is not set
+# CONFIG_LEDS_AN30259A is not set
+# CONFIG_LEDS_LM3532 is not set
+# CONFIG_LEDS_TRIGGER_AUDIO is not set
+# CONFIG_LEDS_TRIGGER_PATTERN is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+CONFIG_LIBFDT=y
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity"
+CONFIG_MACB=y
+# CONFIG_MACB_PCI is not set
+CONFIG_MACB_USE_HWSTAMP=y
+CONFIG_MANDATORY_FILE_LOCKING=y
+CONFIG_MAXPHYSMEM_128GB=y
+# CONFIG_MAXPHYSMEM_2GB is not set
+CONFIG_MDIO_BUS=y
+# CONFIG_MDIO_BUS_MUX_MULTIPLEXER is not set
+CONFIG_MDIO_DEVICE=y
+CONFIG_MEMFD_CREATE=y
+# CONFIG_MFD_LOCHNAGAR is not set
+# CONFIG_MFD_MAX77650 is not set
+# CONFIG_MFD_ROHM_BD70528 is not set
+# CONFIG_MFD_STMFX is not set
+# CONFIG_MFD_STPMIC1 is not set
+# CONFIG_MFD_TQMX86 is not set
+CONFIG_MICROSEMI_PHY=y
+CONFIG_MIGRATION=y
+# CONFIG_MISC_ALCOR_PCI is not set
+CONFIG_MMC=y
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_SPI=y
+# CONFIG_MMC_TIFM_SD is not set
+CONFIG_MMIOWB=y
+CONFIG_MODULES_USE_ELF_RELA=y
+# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set
+CONFIG_MODULE_SECTIONS=y
+CONFIG_MPILIB=y
+CONFIG_MQ_IOSCHED_DEADLINE=y
+CONFIG_MQ_IOSCHED_KYBER=y
+# CONFIG_MTD_HYPERBUS is not set
+# CONFIG_MTD_RAW_NAND is not set
+CONFIG_MTD_SPI_NOR=y
+CONFIG_MTD_SPI_NOR_USE_4K_SECTORS=y
+CONFIG_NAMESPACES=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NET_FAILOVER=y
+CONFIG_NET_FLOW_LIMIT=y
+CONFIG_NET_NS=y
+CONFIG_NET_PTP_CLASSIFY=y
+# CONFIG_NET_SCH_TAPRIO is not set
+CONFIG_NET_VENDOR_GOOGLE=y
+CONFIG_NET_VENDOR_PENSANDO=y
+# CONFIG_NI_XGE_MANAGEMENT_ENET is not set
+CONFIG_NLS=y
+CONFIG_NR_CPUS=8
+# CONFIG_NULL_TTY is not set
+CONFIG_NVMEM=y
+CONFIG_NVMEM_SYSFS=y
+CONFIG_OF=y
+CONFIG_OF_ADDRESS=y
+CONFIG_OF_EARLY_FLATTREE=y
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_GPIO=y
+CONFIG_OF_IRQ=y
+CONFIG_OF_KOBJ=y
+CONFIG_OF_MDIO=y
+CONFIG_OF_NET=y
+CONFIG_OF_RESERVED_MEM=y
+CONFIG_OID_REGISTRY=y
+# CONFIG_PACKING is not set
+CONFIG_PADATA=y
+CONFIG_PAGE_OFFSET=0xffffffe000000000
+CONFIG_PANIC_TIMEOUT=0
+CONFIG_PA_BITS=56
+CONFIG_PCI=y
+CONFIG_PCIE_MICROSEMI=y
+CONFIG_PCI_DEBUG=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_DOMAINS_GENERIC=y
+# CONFIG_PCI_MESON is not set
+CONFIG_PCI_MSI=y
+CONFIG_PCI_MSI_IRQ_DOMAIN=y
+CONFIG_PGTABLE_LEVELS=3
+CONFIG_PHYLIB=y
+CONFIG_PHYS_ADDR_T_64BIT=y
+# CONFIG_PHY_CADENCE_DP is not set
+# CONFIG_PHY_CADENCE_DPHY is not set
+# CONFIG_PHY_FSL_IMX8MQ_USB is not set
+# CONFIG_PHY_MIXEL_MIPI_DPHY is not set
+CONFIG_PID_NS=y
+CONFIG_PKCS7_MESSAGE_PARSER=y
+# CONFIG_PKCS8_PRIVATE_KEY_PARSER is not set
+CONFIG_PPS=y
+# CONFIG_PRINTK_CALLER is not set
+CONFIG_PRINTK_TIME=y
+# CONFIG_PSI is not set
+CONFIG_PTP_1588_CLOCK=y
+# CONFIG_PVPANIC is not set
+CONFIG_PWM=y
+# CONFIG_PWM_SIFIVE is not set
+CONFIG_PWM_SYSFS=y
+CONFIG_R8169=y
+# CONFIG_RANDOM_TRUST_BOOTLOADER is not set
+CONFIG_RATIONAL=y
+CONFIG_RCU_NEED_SEGCBLIST=y
+CONFIG_RCU_STALL_COMMON=y
+CONFIG_RCU_TRACE=y
+CONFIG_RD_GZIP=y
+CONFIG_REALTEK_PHY=y
+# CONFIG_REED_SOLOMON_TEST is not set
+CONFIG_REGMAP=y
+CONFIG_REGMAP_I2C=y
+CONFIG_REGMAP_SPI=y
+CONFIG_RFS_ACCEL=y
+CONFIG_RISCV=y
+CONFIG_RISCV_ISA_C=y
+CONFIG_RISCV_TIMER=y
+CONFIG_RPS=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_I2C_AND_SPI=y
+CONFIG_SATA_AHCI=y
+CONFIG_SATA_PMP=y
+CONFIG_SATA_SIL24=y
+CONFIG_SCHED_DEBUG=y
+CONFIG_SCSI=y
+# CONFIG_SCSI_MYRS is not set
+CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_EARLYCON_RISCV_SBI is not set
+# CONFIG_SERIAL_FSL_LINFLEXUART is not set
+CONFIG_SERIAL_MCTRL_GPIO=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SERIAL_SIFIVE=y
+CONFIG_SERIAL_SIFIVE_CONSOLE=y
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SGL_ALLOC=y
+CONFIG_SG_POOL=y
+# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set
+CONFIG_SIFIVE_PLIC=y
+CONFIG_SLUB_DEBUG=y
+CONFIG_SMP=y
+CONFIG_SOC_SIFIVE=y
+CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_SPI=y
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_MASTER=y
+CONFIG_SPI_MEM=y
+# CONFIG_SPI_MTK_QUADSPI is not set
+CONFIG_SPI_SIFIVE=y
+CONFIG_SRCU=y
+CONFIG_STACKTRACE=y
+CONFIG_SWIOTLB=y
+CONFIG_SWPHY=y
+CONFIG_SYSCTL_EXCEPTION_TRACE=y
+CONFIG_SYSFS_SYSCALL=y
+CONFIG_SYS_SUPPORTS_HUGETLBFS=y
+# CONFIG_TEST_BLACKHOLE_DEV is not set
+# CONFIG_TEST_MEMCAT_P is not set
+# CONFIG_TEST_MEMINIT is not set
+# CONFIG_TEST_STACKINIT is not set
+# CONFIG_TEST_STRSCPY is not set
+# CONFIG_TEST_VMALLOC is not set
+# CONFIG_TEST_XARRAY is not set
+CONFIG_THREAD_INFO_IN_TASK=y
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TIMER_OF=y
+CONFIG_TIMER_PROBE=y
+# CONFIG_TI_CPSW_PHY_SEL is not set
+CONFIG_TRACE_CLOCK=y
+CONFIG_TREE_RCU=y
+CONFIG_TREE_SRCU=y
+CONFIG_TUNE_GENERIC=y
+CONFIG_UBSAN_ALIGNMENT=y
+CONFIG_UEVENT_HELPER_PATH=""
+# CONFIG_UNICODE is not set
+CONFIG_UNIX_SCM=y
+CONFIG_USB=y
+CONFIG_USB_COMMON=y
+# CONFIG_USB_CONN_GPIO is not set
+# CONFIG_USB_EHCI_FSL is not set
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_HCD_PLATFORM is not set
+CONFIG_USB_EHCI_PCI=y
+CONFIG_USB_HID=y
+CONFIG_USB_NET_DRIVERS=y
+CONFIG_USB_PCI=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_SUPPORT=y
+# CONFIG_USB_UHCI_HCD is not set
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_XHCI_PCI=y
+# CONFIG_USB_XHCI_PLATFORM is not set
+# CONFIG_USERIO is not set
+# CONFIG_USER_NS is not set
+CONFIG_UTS_NS=y
+# CONFIG_VALIDATE_FS_PARSER is not set
+CONFIG_VA_BITS=39
+CONFIG_VGA_ARB=y
+CONFIG_VGA_ARB_MAX_GPUS=16
+CONFIG_VIRTIO=y
+CONFIG_VIRTIO_BLK=y
+CONFIG_VIRTIO_CONSOLE=y
+CONFIG_VIRTIO_MMIO=y
+# CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES is not set
+CONFIG_VIRTIO_NET=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_WATCHDOG_OPEN_TIMEOUT=0
+CONFIG_X509_CERTIFICATE_PARSER=y
+# CONFIG_XILINX_SDFEC is not set
+CONFIG_XPS=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZONE_DMA32=y
diff --git a/target/linux/riscv64/patches/0009-RISC-V-Networking-fix-Hack.patch b/target/linux/riscv64/patches/0009-RISC-V-Networking-fix-Hack.patch
deleted file mode 100644 (file)
index 35009a2..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-From aa230e7dc2ab01db5b630f427e57297ffc25c884 Mon Sep 17 00:00:00 2001
-From: Atish Patra <atish.patra@wdc.com>
-Date: Fri, 7 Sep 2018 10:22:27 -0700
-Subject: [PATCH 09/11] RISC-V: Networking fix Hack
-
-It looks like that kernel driver now supports reseting the
-signal one additional time. As it had been  already reset
-twice in FSBL, PHY gets into incorrect state causing below error.
-
-----------------------------------------------------------------------
-macb 10090000.ethernet (unnamed net_device) (uninitialized): Could not attach to PHY
-macb: probe of 10090000.ethernet failed with error -110
-----------------------------------------------------------------------
-
-This patch is just a temporary fix until we have a fix a FSBL.
-It is just a **HACK** and **NOT TO BE MERGED** into mainline.
-
-Signed-off-by: Atish Patra <atish.patra@wdc.com>
----
- drivers/net/phy/mdio_bus.c | 3 ---
- 1 file changed, 3 deletions(-)
-
-diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
-index 98f4b1f7..02c31f83 100644
---- a/drivers/net/phy/mdio_bus.c
-+++ b/drivers/net/phy/mdio_bus.c
-@@ -64,9 +64,6 @@ static int mdiobus_register_gpiod(struct mdio_device *mdiodev)
-       mdiodev->reset = gpiod;
--      /* Assert the reset signal again */
--      mdio_device_reset(mdiodev, 1);
--
-       return 0;
- }
--- 
-2.7.4
-
diff --git a/target/linux/riscv64/patches/002-clk-sifive-prci.patch b/target/linux/riscv64/patches/002-clk-sifive-prci.patch
deleted file mode 100644 (file)
index 11e2725..0000000
+++ /dev/null
@@ -1,509 +0,0 @@
-From 7f45b80bb9675e9ace37bc1c4fd8f0351dfd9de9 Mon Sep 17 00:00:00 2001
-From: "Wesley W. Terpstra" <wesley@sifive.com>
-Date: Tue, 13 Feb 2018 19:39:41 -0800
-Subject: [PATCH 1/5] u54-prci: driver for core U54 clocks
-
----
- drivers/clk/sifive/Kconfig    |   4 +
- drivers/clk/sifive/Makefile   |   1 +
- drivers/clk/sifive/u54-prci.c | 314 ++++++++++++++++++++++++++++++++++
- 3 files changed, 319 insertions(+)
- create mode 100644 drivers/clk/sifive/Kconfig
- create mode 100644 drivers/clk/sifive/Makefile
- create mode 100644 drivers/clk/sifive/u54-prci.c
-
-diff --git a/drivers/clk/sifive/Kconfig b/drivers/clk/sifive/Kconfig
-new file mode 100644
-index 0000000000000..a562e0c6dc67e
---- /dev/null
-+++ b/drivers/clk/sifive/Kconfig
-@@ -0,0 +1,4 @@
-+config CLK_U54_PRCI
-+      bool "PRCI driver for U54 SoCs"
-+      ---help---
-+        Supports Power Reset Clock interface found in U540 SoCs
-diff --git a/drivers/clk/sifive/Makefile b/drivers/clk/sifive/Makefile
-new file mode 100644
-index 0000000000000..0c2b175b5846d
---- /dev/null
-+++ b/drivers/clk/sifive/Makefile
-@@ -0,0 +1 @@
-+obj-$(CONFIG_CLK_U54_PRCI)    += u54-prci.o
-diff --git a/drivers/clk/sifive/u54-prci.c b/drivers/clk/sifive/u54-prci.c
-new file mode 100644
-index 0000000000000..edc4b7818e710
---- /dev/null
-+++ b/drivers/clk/sifive/u54-prci.c
-@@ -0,0 +1,314 @@
-+/*
-+ * 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.
-+ *
-+ * Copyright (C) 2018 SiFive, Inc.
-+ */
-+
-+#include <linux/clkdev.h>
-+#include <linux/clk-provider.h>
-+#include <linux/clk.h>
-+#include <linux/err.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <linux/slab.h>
-+#include <linux/log2.h>
-+
-+#define CORE_CLOCK 0
-+#define GEMTX_CLOCK 1
-+#define PRCI_CLOCKS 2
-+
-+#define MIN_REF 7000000UL
-+#define MAX_REF 200000000UL
-+#define MAX_PARENT 600000000UL
-+#define MAX_VCO 4800000000UL
-+#define MAX_DIV 64
-+#define MAX_R 64UL
-+
-+#define PLL_LOCK 0x80000000U
-+#define NAME_LEN 40
-+
-+struct sifive_u54_prci_driver;
-+
-+struct sifive_u54_prci_pll {
-+      struct clk_hw hw;
-+      struct sifive_u54_prci_driver *driver;
-+      char name[NAME_LEN];
-+      u32 freq;
-+      u32 glcm;
-+};
-+
-+struct sifive_u54_prci_driver {
-+      struct clk_onecell_data table;
-+      struct clk *clks[PRCI_CLOCKS];
-+      struct sifive_u54_prci_pll plls[PRCI_CLOCKS];
-+      void __iomem *reg;
-+};
-+
-+#define to_sifive_u54_prci_pll(hw) container_of(hw, struct sifive_u54_prci_pll, hw)
-+
-+struct sifive_u54_pll_cfg {
-+      unsigned long r, f, q, a;
-+};
-+
-+static struct sifive_u54_pll_cfg sifive_u54_pll_cfg(u32 reg)
-+{
-+      struct sifive_u54_pll_cfg cfg;
-+      cfg.r = (reg >>  0) & 0x3f;
-+      cfg.f = (reg >>  6) & 0x1ff;
-+      cfg.q = (reg >> 15) & 0x7;
-+      cfg.a = (reg >> 18) & 0x7;
-+      return cfg;
-+}
-+
-+static u32 sifive_u54_pll_reg(struct sifive_u54_pll_cfg cfg)
-+{
-+      u32 reg = 0;
-+      reg |= (cfg.r & 0x3f)  << 0;
-+      reg |= (cfg.f & 0x1ff) << 6;
-+      reg |= (cfg.q & 0x7)   << 15;
-+      reg |= (cfg.a & 0x7)   << 18;
-+      reg |= 1<<25; // internal feedback
-+      return reg;
-+}
-+
-+static unsigned long sifive_u54_pll_rate(struct sifive_u54_pll_cfg cfg, unsigned long parent)
-+{
-+      return (parent*2*(cfg.f+1) / (cfg.r+1)) >> cfg.q;
-+}
-+
-+static struct sifive_u54_pll_cfg sifive_u54_pll_configure(unsigned long target, unsigned long parent)
-+{
-+      struct sifive_u54_pll_cfg cfg;
-+      unsigned long scale, ratio, best_delta, filter;
-+      u32 max_r, best_r, best_f, r;
-+
-+      /* Confirm input frequency is within bounds */
-+      if (WARN_ON(parent > MAX_PARENT)) { parent = MAX_PARENT; }
-+      if (WARN_ON(parent < MIN_REF))    { parent = MIN_REF; }
-+
-+      /* Calculate the Q shift and target VCO */
-+      scale = MAX_VCO / target;
-+      if (scale <= 1) {
-+              cfg.q = 1;
-+              target = MAX_VCO;
-+      } else if (scale > MAX_DIV) {
-+              cfg.q = ilog2(MAX_DIV);
-+              target = MAX_VCO/2;
-+      } else {
-+              cfg.q = ilog2(scale);
-+              target = target << cfg.q;
-+      }
-+
-+      /* Precalcualte the target ratio */
-+      ratio = (target << 20) / parent;
-+
-+      /* Placeholder values */
-+      best_r = 0;
-+      best_f = 0;
-+      best_delta = MAX_VCO;
-+
-+      /* Consider all values for R which land within [MIN_REF, MAX_REF]; prefer smaller R */
-+      max_r = min(MAX_R, parent / MIN_REF);
-+      for (r = DIV_ROUND_UP(parent, MAX_REF); r <= max_r; ++r) {
-+              /* What is the best F we can pick in this case? */
-+              u32 f = (ratio*r + (1<<20)) >> 21;
-+              unsigned long ref = parent / r;
-+              unsigned long vco = ref * f * 2;
-+              unsigned long delta;
-+
-+              /* Ensure rounding didn't take us out of range */
-+              if (vco > target) --f;
-+              if (vco < MAX_VCO/2) ++f;
-+              vco = ref * f * 2;
-+
-+              delta = abs(target - vco);
-+              if (delta < best_delta) {
-+                      best_delta = delta;
-+                      best_r = r;
-+                      best_f = f;
-+              }
-+      }
-+
-+      cfg.r = best_r - 1;
-+      cfg.f = best_f - 1;
-+
-+      /* Pick the best PLL jitter filter */
-+      filter = parent / best_r;
-+      BUG_ON(filter < 7000000);
-+      if (filter < 11000000) {
-+              cfg.a = 1;
-+      } else if (filter < 18000000) {
-+              cfg.a = 2;
-+      } else if (filter < 30000000) {
-+              cfg.a = 3;
-+      } else if (filter < 50000000) {
-+              cfg.a = 4;
-+      } else if (filter < 80000000) {
-+              cfg.a = 5;
-+      } else if (filter < 130000000) {
-+              cfg.a = 6;
-+      } else {
-+              BUG_ON (filter > 200000000);
-+              cfg.a = 7;
-+      }
-+
-+      return cfg;
-+}
-+
-+static unsigned long sifive_u54_prci_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
-+{
-+      struct sifive_u54_prci_pll *pll = to_sifive_u54_prci_pll(hw);
-+      struct sifive_u54_prci_driver *driver = pll->driver;
-+
-+      u32 reg = ioread32(driver->reg + pll->freq);
-+      struct sifive_u54_pll_cfg cfg = sifive_u54_pll_cfg(reg);
-+
-+      return sifive_u54_pll_rate(cfg, parent_rate);
-+}
-+
-+static long sifive_u54_prci_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate)
-+{
-+      struct sifive_u54_pll_cfg cfg = sifive_u54_pll_configure(rate, *parent_rate);
-+      return sifive_u54_pll_rate(cfg, *parent_rate);
-+}
-+
-+static int sifive_u54_prci_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate)
-+{
-+      struct sifive_u54_prci_pll *pll = to_sifive_u54_prci_pll(hw);
-+      struct sifive_u54_prci_driver *driver = pll->driver;
-+
-+      struct sifive_u54_pll_cfg cfg = sifive_u54_pll_configure(rate, parent_rate);
-+      u32 reg = sifive_u54_pll_reg(cfg);
-+
-+      /* Switch to reg clock and reconfigure PLL */
-+      iowrite32(1, driver->reg + pll->glcm);
-+      iowrite32(reg, driver->reg + pll->freq);
-+
-+      /* Wait for lock and switch back to PLL */
-+      while (!(ioread32(driver->reg + pll->freq) & PLL_LOCK));
-+      iowrite32(0, driver->reg + pll->glcm);
-+
-+      return 0;
-+}
-+
-+static const struct clk_ops sifive_u54_prci_ops_rw = {
-+      .recalc_rate = sifive_u54_prci_recalc_rate,
-+      .round_rate = sifive_u54_prci_round_rate,
-+      .set_rate = sifive_u54_prci_set_rate,
-+};
-+
-+static const struct clk_ops sifive_u54_prci_ops_ro = {
-+      .recalc_rate = sifive_u54_prci_recalc_rate,
-+};
-+
-+static ssize_t sifive_u54_pll_show(struct device *dev, struct device_attribute *attr, char *buf)
-+{
-+      struct sifive_u54_prci_driver *driver = dev_get_drvdata(dev);
-+      return sprintf(buf, "%ld", clk_get_rate(driver->clks[0]));
-+}
-+
-+static ssize_t sifive_u54_pll_rate_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-+{
-+      struct sifive_u54_prci_driver *driver = dev_get_drvdata(dev);
-+      unsigned long rate;
-+      char *endp;
-+
-+      rate = simple_strtoul(buf, &endp, 0);
-+      if (*endp != 0 && *endp != '\n')
-+              return -EINVAL;
-+
-+      clk_set_rate(driver->clks[0], rate);
-+      return count;
-+}
-+
-+static DEVICE_ATTR(rate, 0644, sifive_u54_pll_show, sifive_u54_pll_rate_store);
-+
-+static int sifive_u54_prci_probe(struct platform_device *pdev)
-+{
-+      struct device *dev = &pdev->dev;
-+      struct clk_init_data init;
-+      struct sifive_u54_prci_driver *driver;
-+      struct resource *res;
-+      const char *parent;
-+      int i;
-+
-+      parent = of_clk_get_parent_name(dev->of_node, 0);
-+      if (!parent) {
-+              dev_err(dev, "No OF parent clocks found\n");
-+              return -EINVAL;
-+      }
-+
-+      driver = devm_kzalloc(dev, sizeof(*driver), GFP_KERNEL);
-+      if (!driver) {
-+              dev_err(dev, "Out of memory\n");
-+              return -ENOMEM;
-+      }
-+
-+      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+      driver->reg = devm_ioremap_resource(dev, res);
-+      if (IS_ERR(driver->reg))
-+              return PTR_ERR(driver->reg);
-+
-+      /* Link the data structure */
-+      driver->table.clk_num = PRCI_CLOCKS;
-+      driver->table.clks = &driver->clks[0];
-+      dev_set_drvdata(dev, driver);
-+
-+      /* Describe the clocks */
-+      snprintf(driver->plls[CORE_CLOCK].name, NAME_LEN, "%s.core", dev->of_node->name);
-+      driver->plls[CORE_CLOCK].freq = 0x4;
-+      driver->plls[CORE_CLOCK].glcm = 0x24;
-+      snprintf(driver->plls[GEMTX_CLOCK].name, NAME_LEN, "%s.gemtx", dev->of_node->name);
-+      driver->plls[GEMTX_CLOCK].freq = 0x1c;
-+      driver->plls[GEMTX_CLOCK].glcm = 0; /* None; cannot be set_rate */
-+
-+      /* Export the clocks */
-+      for (i = 0; i < PRCI_CLOCKS; ++i) {
-+              init.name = &driver->plls[i].name[0];
-+              init.ops = driver->plls[i].glcm ? &sifive_u54_prci_ops_rw : &sifive_u54_prci_ops_ro;
-+              init.num_parents = 1;
-+              init.parent_names = &parent;
-+              init.flags = 0;
-+
-+              driver->plls[i].driver = driver;
-+              driver->plls[i].hw.init = &init;
-+
-+              driver->clks[i] = devm_clk_register(dev, &driver->plls[i].hw);
-+              if (IS_ERR(driver->clks[i])) {
-+                      dev_err(dev, "Failed to register clock %d, %ld\n", i, PTR_ERR(driver->clks[i]));
-+                      return PTR_ERR(driver->clks[i]);
-+              }
-+      }
-+
-+      of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, &driver->table);
-+      device_create_file(dev, &dev_attr_rate);
-+      dev_info(dev, "Registered U54 core clocks\n");
-+
-+      return 0;
-+}
-+
-+static const struct of_device_id sifive_u54_prci_of_match[] = {
-+      { .compatible = "sifive,aloeprci0", },
-+      {}
-+};
-+
-+static struct platform_driver sifive_u54_prci_driver = {
-+      .driver = {
-+              .name = "sifive-u54-prci",
-+              .of_match_table = sifive_u54_prci_of_match,
-+      },
-+      .probe = sifive_u54_prci_probe,
-+};
-+
-+static int __init sifive_u54_prci_init(void)
-+{
-+      return platform_driver_register(&sifive_u54_prci_driver);
-+}
-+core_initcall(sifive_u54_prci_init);
-
-From 9b47a41c087008233d3024cc3f5005984a6c504c Mon Sep 17 00:00:00 2001
-From: Palmer Dabbelt <palmer@sifive.com>
-Date: Wed, 21 Feb 2018 10:06:48 -0800
-Subject: [PATCH 2/5] Fix some overflow warnings
-
----
- drivers/clk/sifive/u54-prci.c | 18 +++++++++---------
- 1 file changed, 9 insertions(+), 9 deletions(-)
-
-diff --git a/drivers/clk/sifive/u54-prci.c b/drivers/clk/sifive/u54-prci.c
-index edc4b7818e710..b8a93d1ebc2db 100644
---- a/drivers/clk/sifive/u54-prci.c
-+++ b/drivers/clk/sifive/u54-prci.c
-@@ -24,15 +24,15 @@
- #define GEMTX_CLOCK 1
- #define PRCI_CLOCKS 2
--#define MIN_REF 7000000UL
--#define MAX_REF 200000000UL
--#define MAX_PARENT 600000000UL
--#define MAX_VCO 4800000000UL
--#define MAX_DIV 64
--#define MAX_R 64UL
--
--#define PLL_LOCK 0x80000000U
--#define NAME_LEN 40
-+#define MIN_REF 7000000ULL
-+#define MAX_REF 200000000ULL
-+#define MAX_PARENT 600000000ULL
-+#define MAX_VCO 4800000000ULL
-+#define MAX_DIV 64ULL
-+#define MAX_R 64ULL
-+
-+#define PLL_LOCK 0x80000000ULL
-+#define NAME_LEN 40ULL
- struct sifive_u54_prci_driver;
-
-From 031060d77cfbd86d39dfb8863e4fa4f95b435b1b Mon Sep 17 00:00:00 2001
-From: Palmer Dabbelt <palmer@sifive.com>
-Date: Wed, 21 Feb 2018 13:00:16 -0800
-Subject: [PATCH 3/5] Include the sifive kconfig
-
----
- drivers/clk/Kconfig | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
-index 721572a8c4296..5b4bb0a23ffd3 100644
---- a/drivers/clk/Kconfig
-+++ b/drivers/clk/Kconfig
-@@ -288,6 +288,7 @@ source "drivers/clk/mvebu/Kconfig"
- source "drivers/clk/qcom/Kconfig"
- source "drivers/clk/renesas/Kconfig"
- source "drivers/clk/samsung/Kconfig"
-+source "drivers/clk/sifive/Kconfig"
- source "drivers/clk/sprd/Kconfig"
- source "drivers/clk/sunxi-ng/Kconfig"
- source "drivers/clk/tegra/Kconfig"
-
-From 9f8ca54f7c62aeb3245d8a70150d15e25ffb4f15 Mon Sep 17 00:00:00 2001
-From: Palmer Dabbelt <palmer@sifive.com>
-Date: Wed, 21 Feb 2018 13:40:10 -0800
-Subject: [PATCH 4/5] Only show the U64 clock driver on RISC-V
-
-This will probably only be on a RISC-V system, and it doesn't build on
-32-bit systems without 64-bit divides which is a headache.
-
-Signed-off-by: Palmer Dabbelt <palmer@sifive.com>
----
- drivers/clk/sifive/Kconfig | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/drivers/clk/sifive/Kconfig b/drivers/clk/sifive/Kconfig
-index a562e0c6dc67e..c324161700271 100644
---- a/drivers/clk/sifive/Kconfig
-+++ b/drivers/clk/sifive/Kconfig
-@@ -1,4 +1,5 @@
- config CLK_U54_PRCI
-       bool "PRCI driver for U54 SoCs"
-+      depends on RISCV
-       ---help---
-         Supports Power Reset Clock interface found in U540 SoCs
-
-From d79106eca2349e212c4737c5646002bd864b1593 Mon Sep 17 00:00:00 2001
-From: "Wesley W. Terpstra" <wesley@sifive.com>
-Date: Tue, 13 Feb 2018 19:39:41 -0800
-Subject: [PATCH 5/5] u54-prci: driver for core U54 clocks
-
----
- .../bindings/clock/sifive,u54-prci.txt        | 44 +++++++++++++++++++
- 1 file changed, 44 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/clock/sifive,u54-prci.txt
-
-diff --git a/Documentation/devicetree/bindings/clock/sifive,u54-prci.txt b/Documentation/devicetree/bindings/clock/sifive,u54-prci.txt
-new file mode 100644
-index 0000000000000..88682c5eaebc6
---- /dev/null
-+++ b/Documentation/devicetree/bindings/clock/sifive,u54-prci.txt
-@@ -0,0 +1,44 @@
-+SiFive U54 SoC clocks
-+
-+This binding uses the common clock binding:
-+    Documentation/devicetree/bindings/clock/clock-bindings.txt
-+
-+The U54 PRCI controller generates clocks for the U54 SoC. There is
-+a core PLL that sets the processor frequency and PLLs for ethernet
-+and DDR. It takes an input clock from the board, typically an oscillator
-+or crystal.
-+
-+Required properties:
-+- compatible: Should be "sifive,aloeprci0"
-+- #clock-cells:       Should be <1>
-+- reg:                Specifies base physical address and size of the registers
-+- clocks:     phandles to the parent clock used as input
-+
-+Example:
-+
-+      refclk: refclk {
-+              #clock-cells = <0>;
-+              compatible = "fixed-clock";
-+              clock-frequency = <33333333>;
-+              clock-output-names = "xtal";
-+      };
-+
-+      u54: prci@10000000 {
-+              compatible = "sifive,aloeprci0";
-+              reg = <0x0 0x10000000 0x0 0x1000>;
-+              clocks = <&refclk>;
-+              #clock-cells = <1>;
-+      };
-+
-+      tlclk: tlclk {
-+              compatible = "fixed-factor-clock";
-+              clocks = <&u54 0>; /* Core frequency */
-+              #clock-cells = <0>;
-+              clock-div = <2>;
-+              clock-mult = <1>;
-+      };
-+
-+      ethernet@10090000 {
-+              ...
-+              clocks = <&prci 1>; /* TX clock */
-+      };
-diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
-index ae40cbe770f05..017d8d12551b6 100644
---- a/drivers/clk/Makefile
-+++ b/drivers/clk/Makefile
-@@ -89,6 +89,7 @@ obj-$(CONFIG_COMMON_CLK_QCOM)                += qcom/
- obj-y                                 += renesas/
- obj-$(CONFIG_ARCH_ROCKCHIP)           += rockchip/
- obj-$(CONFIG_COMMON_CLK_SAMSUNG)      += samsung/
-+obj-y                                 += sifive/
- obj-$(CONFIG_ARCH_SIRF)                       += sirf/
- obj-$(CONFIG_ARCH_SOCFPGA)            += socfpga/
- obj-$(CONFIG_PLAT_SPEAR)              += spear/
diff --git a/target/linux/riscv64/patches/003-clk-gemgxl.patch b/target/linux/riscv64/patches/003-clk-gemgxl.patch
deleted file mode 100644 (file)
index c44befc..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-From 13317fd60728d24988fb8f5682bfaafe401b3a15 Mon Sep 17 00:00:00 2001
-From: "Wesley W. Terpstra" <wesley@sifive.com>
-Date: Tue, 6 Feb 2018 11:03:07 -0800
-Subject: [PATCH] gemgxl-mgmt: implement clock switch for GEM tx_clk
-
-Signed-off-by: Palmer Dabbelt <palmer@sifive.com>
----
-
-diff --git a/Documentation/devicetree/bindings/clock/sifive,gemgxl-mgmt.txt b/Documentation/devicetree/bindings/clock/sifive,gemgxl-mgmt.txt
-new file mode 100644
-index 0000000000000..349489e33edaa
---- /dev/null
-+++ b/Documentation/devicetree/bindings/clock/sifive,gemgxl-mgmt.txt
-@@ -0,0 +1,26 @@
-+TX clock switch for GEMGXL in U540 SoCs
-+
-+This binding uses the common clock binding:
-+    Documentation/devicetree/bindings/clock/clock-bindings.txt
-+
-+The U54 includes a clock mux to control the ethernet TX frequenecy. It
-+switches between the local TX clock (125MHz) and PHY TX clocks. This is
-+necessary to toggle between 1Gb and 100/10Mb speeds.
-+
-+Required properties:
-+- compatible: Should be "sifive,cadencegemgxlmgmt0"
-+- #clock-cells:       Should be <0>
-+- reg:                Specifies base physical address and size of the registers
-+
-+Example:
-+
-+      mgmt: cadence-gemgxl-mgmt@100a00000 {
-+              compatible = "sifive,cadencegemgxlmgmt0";
-+              #clock-cells = <0>;
-+              reg = <0x0 0x100a0000 0x0 0x1000>;
-+      };
-+
-+      ethernet@10090000 {
-+              ...
-+              clocks = <&mgmt>; /* TX clock */
-+      };
-diff --git a/drivers/clk/sifive/Kconfig b/drivers/clk/sifive/Kconfig
-index 0000000000000..284bffb121ebd
---- a/drivers/clk/sifive/Kconfig
-+++ b/drivers/clk/sifive/Kconfig
-@@ -0,0 +1,9 @@
-+config CLK_U54_PRCI
-+      bool "PRCI driver for U54 SoCs"
-+      ---help---
-+        Supports Power Reset Clock interface found in U540 SoCs
-+
-+config CLK_GEMGXL_MGMT
-+      bool "TX clock switch for GEMGXL in U540 SoCs"
-+      ---help---
-+        Supports clock muxing between 10/100Mbit and 1Gbit TX clock on U540 SoCs
-diff --git a/drivers/clk/sifive/Makefile b/drivers/clk/sifive/Makefile
-index 0000000000000..7784d2ee0f446
---- a/drivers/clk/sifive/Makefile
-+++ b/drivers/clk/sifive/Makefile
-@@ -0,0 +1,2 @@
-+obj-$(CONFIG_CLK_U54_PRCI)    += u54-prci.o
-+obj-$(CONFIG_CLK_GEMGXL_MGMT) += gemgxl-mgmt.o
-diff --git a/drivers/clk/sifive/gemgxl-mgmt.c b/drivers/clk/sifive/gemgxl-mgmt.c
-new file mode 100644
-index 0000000000000..00b07580fe3ce
---- /dev/null
-+++ b/drivers/clk/sifive/gemgxl-mgmt.c
-@@ -0,0 +1,129 @@
-+/*
-+ * 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.
-+ *
-+ * Copyright (C) 2018 SiFive, Inc.
-+ */
-+
-+#include <linux/clkdev.h>
-+#include <linux/clk-provider.h>
-+#include <linux/err.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <linux/slab.h>
-+
-+struct sifive_gemgxl_mgmt {
-+      void __iomem *reg;
-+      unsigned long rate;
-+      struct clk_hw hw;
-+};
-+
-+#define to_sifive_gemgxl_mgmt(mgmt) container_of(mgmt, struct sifive_gemgxl_mgmt, hw)
-+
-+static unsigned long sifive_gemgxl_mgmt_recalc_rate(struct clk_hw *hw,
-+                                    unsigned long parent_rate)
-+{
-+      struct sifive_gemgxl_mgmt *mgmt = to_sifive_gemgxl_mgmt(hw);
-+      return mgmt->rate;
-+}
-+
-+static long sifive_gemgxl_mgmt_round_rate(struct clk_hw *hw, unsigned long rate,
-+              unsigned long *parent_rate)
-+{
-+      if (WARN_ON(rate < 2500000)) {
-+              return 2500000;
-+      } else if (rate == 2500000) {
-+              return 2500000;
-+      } else if (WARN_ON(rate < 13750000)) {
-+              return 2500000;
-+      } else if (WARN_ON(rate < 25000000)) {
-+              return 25000000;
-+      } else if (rate == 25000000) {
-+              return 25000000;
-+      } else if (WARN_ON(rate < 75000000)) {
-+              return 25000000;
-+      } else if (WARN_ON(rate < 125000000)) {
-+              return 125000000;
-+      } else if (rate == 125000000) {
-+              return 125000000;
-+      } else {
-+              WARN_ON(rate > 125000000);
-+              return 125000000;
-+      }
-+}
-+
-+static int sifive_gemgxl_mgmt_set_rate(struct clk_hw *hw, unsigned long rate,
-+              unsigned long parent_rate)
-+{
-+      struct sifive_gemgxl_mgmt *mgmt = to_sifive_gemgxl_mgmt(hw);
-+      rate = sifive_gemgxl_mgmt_round_rate(hw, rate, &parent_rate);
-+      iowrite32(rate != 125000000, mgmt->reg);
-+      mgmt->rate = rate;
-+      return 0;
-+}
-+
-+static const struct clk_ops sifive_gemgxl_mgmt_ops = {
-+      .recalc_rate = sifive_gemgxl_mgmt_recalc_rate,
-+      .round_rate = sifive_gemgxl_mgmt_round_rate,
-+      .set_rate = sifive_gemgxl_mgmt_set_rate,
-+};
-+
-+static int sifive_gemgxl_mgmt_probe(struct platform_device *pdev)
-+{
-+      struct clk_init_data init;
-+      struct sifive_gemgxl_mgmt *mgmt;
-+      struct resource *res;
-+      struct clk *clk;
-+
-+      mgmt = devm_kzalloc(&pdev->dev, sizeof(*mgmt), GFP_KERNEL);
-+      if (!mgmt)
-+              return -ENOMEM;
-+
-+      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+      mgmt->reg = devm_ioremap_resource(&pdev->dev, res);
-+      if (IS_ERR(mgmt->reg))
-+              return PTR_ERR(mgmt->reg);
-+
-+      init.name = pdev->dev.of_node->name;
-+      init.ops = &sifive_gemgxl_mgmt_ops;
-+      init.flags = 0;
-+      init.num_parents = 0;
-+
-+      mgmt->rate = 0;
-+      mgmt->hw.init = &init;
-+
-+      clk = clk_register(NULL, &mgmt->hw);
-+      if (IS_ERR(clk))
-+              return PTR_ERR(clk);
-+
-+      of_clk_add_provider(pdev->dev.of_node, of_clk_src_simple_get, clk);
-+
-+      dev_info(&pdev->dev, "Registered clock switch '%s'\n", init.name);
-+
-+      return 0;
-+}
-+
-+static const struct of_device_id sifive_gemgxl_mgmt_of_match[] = {
-+      { .compatible = "sifive,cadencegemgxlmgmt0", },
-+      {}
-+};
-+
-+static struct platform_driver sifive_gemgxl_mgmt_driver = {
-+      .driver = {
-+              .name = "sifive-gemgxl-mgmt",
-+              .of_match_table = sifive_gemgxl_mgmt_of_match,
-+      },
-+      .probe = sifive_gemgxl_mgmt_probe,
-+};
-+
-+static int __init sifive_gemgxl_mgmt_init(void)
-+{
-+      return platform_driver_register(&sifive_gemgxl_mgmt_driver);
-+}
-+core_initcall(sifive_gemgxl_mgmt_init);
diff --git a/target/linux/riscv64/patches/004-spi-sifive.patch b/target/linux/riscv64/patches/004-spi-sifive.patch
deleted file mode 100644 (file)
index 78f6c31..0000000
+++ /dev/null
@@ -1,509 +0,0 @@
-From 1e23d75040e34fa26cacf715acb23a4344825bc2 Mon Sep 17 00:00:00 2001
-From: "Wesley W. Terpstra" <wesley@sifive.com>
-Date: Mon, 5 Feb 2018 17:42:32 -0800
-Subject: [PATCH] spi-sifive: support SiFive SPI controller in Quad-Mode
-
-Signed-off-by: Palmer Dabbelt <palmer@sifive.com>
----
- .../devicetree/bindings/spi/spi-sifive.txt    |  29 ++
- drivers/spi/Kconfig                           |   7 +
- drivers/spi/Makefile                          |   1 +
- drivers/spi/spi-sifive.c                      | 423 ++++++++++++++++++
- 4 files changed, 460 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/spi/spi-sifive.txt
- create mode 100644 drivers/spi/spi-sifive.c
-
-diff --git a/Documentation/devicetree/bindings/spi/spi-sifive.txt b/Documentation/devicetree/bindings/spi/spi-sifive.txt
-new file mode 100644
-index 0000000000000..945543244601b
---- /dev/null
-+++ b/Documentation/devicetree/bindings/spi/spi-sifive.txt
-@@ -0,0 +1,29 @@
-+SiFive SPI controller Device Tree Bindings
-+-------------------------------------------------
-+
-+Required properties:
-+- compatible          : Should be "sifive,spi0"
-+- reg                 : Physical base address and size of SPI registers map
-+                        A second (optional) range can indicate memory mapped flash
-+- interrupts          : Must contain one entry
-+- interrupt-parent    : Must be core interrupt controller
-+- clocks              : Must reference the frequency given to the controller
-+- #address-cells      : Must be '1', indicating which CS to use
-+- #size-cells         : Must be '0'
-+
-+Optional properties:
-+- sifive,buffer-size  : Depth of hardware queues; defaults to 8
-+- sifive,bits-per-word        : Maximum bits per word; defaults to 8
-+
-+Example:
-+      spi: spi@10040000 {
-+              compatible = "sifive,spi0";
-+              reg = <0x0 0x10040000 0x0 0x1000 0x0 0x20000000 0x0 0x10000000>;
-+              interrupt-parent = <&plic>;
-+              interrupts = <51>;
-+              clocks = <&tlclk>;
-+              #address-cells = <1>;
-+              #size-cells = <0>;
-+              sifive,buffer-size = <8>;
-+              sifive,bits-per-word = <8>;
-+      };
-diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
-index ad5d68e1dab7c..f77cd28a84392 100644
---- a/drivers/spi/Kconfig
-+++ b/drivers/spi/Kconfig
-@@ -736,6 +736,13 @@ config SPI_ZYNQMP_GQSPI
-       help
-         Enables Xilinx GQSPI controller driver for Zynq UltraScale+ MPSoC.
-+config SPI_SIFIVE
-+        tristate "SiFive SPI controller"
-+        depends on HAS_IOMEM
-+      select SPI_BITBANG
-+        help
-+          This exposes the SPI controller IP from SiFive.
-+
- #
- # Add new SPI master controllers in alphabetical order above this line
- #
-diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
-index cb1f4378b87c0..5c8e8866b16f8 100644
---- a/drivers/spi/Makefile
-+++ b/drivers/spi/Makefile
-@@ -106,6 +106,7 @@ obj-$(CONFIG_SPI_XILINX)           += spi-xilinx.o
- obj-$(CONFIG_SPI_XLP)                 += spi-xlp.o
- obj-$(CONFIG_SPI_XTENSA_XTFPGA)               += spi-xtensa-xtfpga.o
- obj-$(CONFIG_SPI_ZYNQMP_GQSPI)                += spi-zynqmp-gqspi.o
-+obj-$(CONFIG_SPI_SIFIVE)              += spi-sifive.o
- # SPI slave protocol handlers
- obj-$(CONFIG_SPI_SLAVE_TIME)          += spi-slave-time.o
-diff --git a/drivers/spi/spi-sifive.c b/drivers/spi/spi-sifive.c
-new file mode 100644
-index 0000000000000..208566a9888d7
---- /dev/null
-+++ b/drivers/spi/spi-sifive.c
-@@ -0,0 +1,423 @@
-+/*
-+ * SiFive SPI controller driver (master mode only)
-+ *
-+ * Author: SiFive, Inc.
-+ *    sifive@sifive.com
-+ *
-+ * 2018 (c) SiFive Software, Inc.
-+
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/module.h>
-+#include <linux/interrupt.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <linux/spi/spi.h>
-+#include <linux/io.h>
-+#include <linux/log2.h>
-+
-+#define SIFIVE_SPI_MAX_CS     32
-+
-+#define SIFIVE_SPI_NAME "sifive_spi"
-+
-+#define SIFIVE_SPI_DEFAULT_DEPTH 8
-+#define SIFIVE_SPI_DEFAULT_BITS       8
-+
-+#define XSPI_SCDR_OFFSET      0x000   /* Serial Clock Divisor Register */
-+#define XSPI_SCD_SCALE_MASK   0xFFF
-+
-+#define XSPI_SCMR_OFFSET        0x004   /* Serial Clock Mode Register */
-+#define XSPI_SCM_CPHA         1
-+#define XSPI_SCM_CPOL         2
-+#define XSPI_SCM_MODE_MASK     (XSPI_SCM_CPHA | XSPI_SCM_CPOL)
-+
-+#define XSPI_CSIDR_OFFSET       0x010
-+#define XSPI_CSDR_OFFSET        0x014
-+#define XSPI_CSMR_OFFSET        0x018
-+#define XSPI_CSM_MODE_AUTO      0
-+#define XSPI_CSM_MODE_HOLD      2
-+#define XSPI_CSM_MODE_OFF       3
-+
-+#define XSPI_DC0R_OFFSET        0x028
-+#define XSPI_CS_TO_SCK_MASK     0xFF
-+#define XSPI_SCK_TO_CS_MASK     (0xFF << 16)
-+#define XSPI_DC1R_OFFSET        0x02C
-+#define XSPI_MIN_CS_IATIME_MASK 0xFF
-+#define XSPI_MAX_IF_DELAY_MASK  (0xFF << 16)
-+
-+#define XSPI_FFR_OFFSET         0x040
-+#define XSPI_FF_SINGLE          0
-+#define XSPI_FF_DUAL            1
-+#define XSPI_FF_QUAD            2
-+#define XSPI_FF_SPI_MASK        0x3
-+#define XSPI_FF_LSB_FIRST       4
-+#define XSPI_FF_TX_DIR          8
-+#define XSPI_FF_BPF_MASK        (0xFF << 16)
-+
-+#define XSPI_TXDR_OFFSET      0x048   /* Data Transmit Register */
-+#define XSPI_TXD_FIFO_FULL      (8U << 28)
-+#define XSPI_RXDR_OFFSET      0x04C   /* Data Receive Register */
-+#define XSPI_RXD_FIFO_EMPTY     (8U << 28)
-+#define XSPI_DATA_MASK          0xFF
-+#define XSPI_DATA_SHIFT         8
-+
-+#define XSPI_TXWMR_OFFSET       0x050   /* TX FIFO Watermark Register */
-+#define XSPI_RXWMR_OFFSET       0x054   /* RX FIFO Watermark Register */
-+
-+#define XSPI_FCTRL_OFFSET     0x60
-+
-+#define XSPI_IPR_OFFSET               0x074   /* Interrupt Pendings Register */
-+#define XSPI_IER_OFFSET               0x070   /* Interrupt Enable Register */
-+#define XSPI_TXWM_INTR          0x1
-+#define XSPI_RXWM_INTR          0x2
-+
-+struct sifive_spi {
-+      void __iomem    *regs;          /* virt. address of the control registers */
-+      struct clk      *clk;           /* bus clock */
-+      int             irq;            /* watermark irq */
-+      int             buffer_size;    /* buffer size in words */
-+      u32             cs_inactive;    /* Level of the CS pins when inactive*/
-+      struct completion done;         /* Wake-up from interrupt */
-+};
-+
-+static void sifive_spi_write(struct sifive_spi *spi, int offset, u32 value)
-+{
-+      iowrite32(value, spi->regs + offset);
-+}
-+
-+static u32 sifive_spi_read(struct sifive_spi *spi, int offset)
-+{
-+      return ioread32(spi->regs + offset);
-+}
-+
-+static void sifive_spi_init(struct sifive_spi *spi)
-+{
-+      /* Watermark interrupts are disabled by default */
-+      sifive_spi_write(spi, XSPI_IER_OFFSET, 0);
-+
-+      /* Default watermark FIFO threshold values */
-+      sifive_spi_write(spi, XSPI_TXWMR_OFFSET, 1);
-+      sifive_spi_write(spi, XSPI_RXWMR_OFFSET, 0);
-+
-+      /* Set CS/SCK Delays and Inactive Time to defaults */
-+
-+      /* Exit specialized memory-mapped SPI flash mode */
-+      sifive_spi_write(spi, XSPI_FCTRL_OFFSET, 0);
-+}
-+
-+static void sifive_spi_prep_device(struct sifive_spi *spi, struct spi_device *device)
-+{
-+      u32 cr;
-+
-+      /* Update the chip select polarity */
-+      if (device->mode & SPI_CS_HIGH)
-+              spi->cs_inactive &= ~BIT(device->chip_select);
-+      else
-+              spi->cs_inactive |= BIT(device->chip_select);
-+      sifive_spi_write(spi, XSPI_CSDR_OFFSET, spi->cs_inactive);
-+
-+      /* Select the correct device */
-+      sifive_spi_write(spi, XSPI_CSIDR_OFFSET, device->chip_select);
-+
-+      /* Switch clock mode bits */
-+      cr = sifive_spi_read(spi, XSPI_SCMR_OFFSET) & ~XSPI_SCM_MODE_MASK;
-+      if (device->mode & SPI_CPHA)
-+              cr |= XSPI_SCM_CPHA;
-+      if (device->mode & SPI_CPOL)
-+              cr |= XSPI_SCM_CPOL;
-+      sifive_spi_write(spi, XSPI_SCMR_OFFSET, cr);
-+}
-+
-+static int sifive_spi_prep_transfer(struct sifive_spi *spi, struct spi_device *device, struct spi_transfer *t)
-+{
-+      u32 hz, scale, cr;
-+      int mode;
-+
-+      /* Calculate and program the clock rate */
-+      hz = t->speed_hz ? t->speed_hz : device->max_speed_hz;
-+      scale = (DIV_ROUND_UP(clk_get_rate(spi->clk) >> 1, hz) - 1) & XSPI_SCD_SCALE_MASK;
-+      sifive_spi_write(spi, XSPI_SCDR_OFFSET, scale);
-+
-+      /* Modify the SPI protocol mode */
-+      cr = sifive_spi_read(spi, XSPI_FFR_OFFSET);
-+
-+      /* LSB first? */
-+      cr &= ~XSPI_FF_LSB_FIRST;
-+      if (device->mode & SPI_LSB_FIRST)
-+              cr |= XSPI_FF_LSB_FIRST;
-+
-+      /* SINGLE/DUAL/QUAD? */
-+      mode = max((int)t->rx_nbits, (int)t->tx_nbits);
-+      cr &= ~XSPI_FF_SPI_MASK;
-+      switch (mode) {
-+              case SPI_NBITS_QUAD: cr |= XSPI_FF_QUAD;   break;
-+              case SPI_NBITS_DUAL: cr |= XSPI_FF_DUAL;   break;
-+              default:             cr |= XSPI_FF_SINGLE; break;
-+      }
-+
-+      /* SPI direction */
-+      cr &= ~XSPI_FF_TX_DIR;
-+      if (!t->rx_buf)
-+              cr |= XSPI_FF_TX_DIR;
-+
-+      sifive_spi_write(spi, XSPI_FFR_OFFSET, cr);
-+
-+      /* We will want to poll if the time we need to wait is less than the context switching time.
-+       * Let's call that threshold 5us. The operation will take:
-+       *    (8/mode) * buffer_size / hz <= 5 * 10^-6
-+       *    1600000 * buffer_size <= hz * mode
-+       */
-+      return 1600000 * spi->buffer_size <= hz * mode;
-+}
-+
-+static void sifive_spi_tx(struct sifive_spi *spi, const u8* tx_ptr)
-+{
-+      BUG_ON((sifive_spi_read(spi, XSPI_TXDR_OFFSET) & XSPI_TXD_FIFO_FULL) != 0);
-+      sifive_spi_write(spi, XSPI_TXDR_OFFSET, *tx_ptr & XSPI_DATA_MASK);
-+}
-+
-+static void sifive_spi_rx(struct sifive_spi *spi, u8* rx_ptr)
-+{
-+        u32 data = sifive_spi_read(spi, XSPI_RXDR_OFFSET);
-+        BUG_ON((data & XSPI_RXD_FIFO_EMPTY) != 0);
-+        *rx_ptr = data & XSPI_DATA_MASK;
-+}
-+
-+static void sifive_spi_wait(struct sifive_spi *spi, int bit, int poll)
-+{
-+      if (poll) {
-+              u32 cr;
-+              do cr = sifive_spi_read(spi, XSPI_IPR_OFFSET);
-+              while (!(cr & bit));
-+      } else {
-+              reinit_completion(&spi->done);
-+              sifive_spi_write(spi, XSPI_IER_OFFSET, bit);
-+              wait_for_completion(&spi->done);
-+      }
-+}
-+
-+static void sifive_spi_execute(struct sifive_spi *spi, struct spi_transfer *t, int poll)
-+{
-+      int remaining_words = t->len;
-+      const u8* tx_ptr = t->tx_buf;
-+      u8* rx_ptr = t->rx_buf;
-+
-+      while (remaining_words) {
-+              int n_words, tx_words, rx_words;
-+              n_words = min(remaining_words, spi->buffer_size);
-+
-+              /* Enqueue n_words for transmission */
-+              for (tx_words = 0; tx_words < n_words; ++tx_words)
-+                      sifive_spi_tx(spi, tx_ptr++);
-+
-+              if (rx_ptr) {
-+                      /* Wait for transmission + reception to complete */
-+                      sifive_spi_write(spi, XSPI_RXWMR_OFFSET, n_words-1);
-+                      sifive_spi_wait(spi, XSPI_RXWM_INTR, poll);
-+
-+                      /* Read out all the data from the RX FIFO */
-+                      for (rx_words = 0; rx_words < n_words; ++rx_words)
-+                              sifive_spi_rx(spi, rx_ptr++);
-+              } else {
-+                      /* Wait for transmission to complete */
-+                      sifive_spi_wait(spi, XSPI_TXWM_INTR, poll);
-+              }
-+
-+              remaining_words -= n_words;
-+      }
-+}
-+
-+static int sifive_spi_transfer_one(struct spi_master *master, struct spi_device *device, struct spi_transfer *t)
-+{
-+      struct sifive_spi *spi = spi_master_get_devdata(master);
-+      int poll;
-+
-+      sifive_spi_prep_device(spi, device);
-+      poll = sifive_spi_prep_transfer(spi, device, t);
-+      sifive_spi_execute(spi, t, poll);
-+
-+      return 0;
-+}
-+
-+static void sifive_spi_set_cs(struct spi_device *device, bool is_high)
-+{
-+      struct sifive_spi *spi = spi_master_get_devdata(device->master);
-+
-+      /* Reverse polarity is handled by SCMR/CPOL. Not inverted CS. */
-+      if (device->mode & SPI_CS_HIGH)
-+              is_high = !is_high;
-+
-+      sifive_spi_write(spi, XSPI_CSMR_OFFSET, is_high ? XSPI_CSM_MODE_AUTO : XSPI_CSM_MODE_HOLD);
-+}
-+
-+static irqreturn_t sifive_spi_irq(int irq, void *dev_id)
-+{
-+      struct sifive_spi *spi = dev_id;
-+      u32 ip;
-+
-+      ip = sifive_spi_read(spi, XSPI_IPR_OFFSET) & (XSPI_TXWM_INTR | XSPI_RXWM_INTR);
-+      if (ip != 0) {
-+              /* Disable interrupts until next transfer */
-+              sifive_spi_write(spi, XSPI_IER_OFFSET, 0);
-+              complete(&spi->done);
-+              return IRQ_HANDLED;
-+      }
-+
-+      return IRQ_NONE;
-+}
-+
-+static int sifive_spi_probe(struct platform_device *pdev)
-+{
-+      struct sifive_spi *spi;
-+      struct resource *res;
-+      int ret, num_cs;
-+      u32 cs_bits, buffer_size, bits_per_word;
-+      struct spi_master *master;
-+
-+      master = spi_alloc_master(&pdev->dev, sizeof(struct sifive_spi));
-+      if (!master) {
-+              dev_err(&pdev->dev, "out of memory\n");
-+              return -ENOMEM;
-+      }
-+
-+      spi = spi_master_get_devdata(master);
-+      init_completion(&spi->done);
-+      platform_set_drvdata(pdev, master);
-+
-+      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+      spi->regs = devm_ioremap_resource(&pdev->dev, res);
-+      if (IS_ERR(spi->regs)) {
-+              dev_err(&pdev->dev, "Unable to map IO resources\n");
-+              ret = PTR_ERR(spi->regs);
-+              goto put_master;
-+      }
-+
-+      spi->clk = devm_clk_get(&pdev->dev, NULL);
-+      if (IS_ERR(spi->clk)) {
-+              dev_err(&pdev->dev, "Unable to find bus clock\n");
-+              ret = PTR_ERR(spi->clk);
-+              goto put_master;
-+      }
-+
-+      spi->irq = platform_get_irq(pdev, 0);
-+      if (spi->irq < 0) {
-+              dev_err(&pdev->dev, "Unable to find interrupt\n");
-+              ret = spi->irq;
-+              goto put_master;
-+      }
-+
-+      /* Optional parameters */
-+      ret = of_property_read_u32(pdev->dev.of_node, "sifive,buffer-size", &buffer_size);
-+      if (ret < 0)
-+              spi->buffer_size = SIFIVE_SPI_DEFAULT_DEPTH;
-+      else
-+              spi->buffer_size = buffer_size;
-+
-+      ret = of_property_read_u32(pdev->dev.of_node, "sifive,bits-per-word", &bits_per_word);
-+      if (ret < 0)
-+              bits_per_word = SIFIVE_SPI_DEFAULT_BITS;
-+
-+      /* Spin up the bus clock before hitting registers */
-+      ret = clk_prepare_enable(spi->clk);
-+      if (ret) {
-+              dev_err(&pdev->dev, "Unable to enable bus clock\n");
-+              goto put_master;
-+      }
-+
-+      /* probe the number of CS lines */
-+      spi->cs_inactive = sifive_spi_read(spi, XSPI_CSDR_OFFSET);
-+      sifive_spi_write(spi, XSPI_CSDR_OFFSET, 0xffffffffU);
-+      cs_bits = sifive_spi_read(spi, XSPI_CSDR_OFFSET);
-+      sifive_spi_write(spi, XSPI_CSDR_OFFSET, spi->cs_inactive);
-+      if (!cs_bits) {
-+              dev_err(&pdev->dev, "Could not auto probe CS lines\n");
-+              ret = -EINVAL;
-+              goto put_master;
-+      }
-+
-+      num_cs = ilog2(cs_bits) + 1;
-+      if (num_cs > SIFIVE_SPI_MAX_CS) {
-+              dev_err(&pdev->dev, "Invalid number of spi slaves\n");
-+              ret = -EINVAL;
-+              goto put_master;
-+      }
-+
-+      /* Define our master */
-+      master->bus_num = pdev->id;
-+      master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_CS_HIGH |
-+                          SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD;
-+      master->flags = SPI_CONTROLLER_MUST_TX | SPI_MASTER_GPIO_SS;
-+      master->dev.of_node = pdev->dev.of_node;
-+      master->bits_per_word_mask = SPI_BPW_MASK(bits_per_word);
-+      master->num_chipselect = num_cs;
-+      master->transfer_one = sifive_spi_transfer_one;
-+      master->set_cs = sifive_spi_set_cs;
-+
-+      /* If mmc_spi sees a dma_mask, it starts using dma mapped buffers.
-+       * Probably it should rely on the SPI core auto mapping instead.
-+       */
-+      pdev->dev.dma_mask = 0;
-+
-+      /* Configure the SPI master hardware */
-+      sifive_spi_init(spi);
-+
-+      /* Register for SPI Interrupt */
-+      ret = devm_request_irq(&pdev->dev, spi->irq, sifive_spi_irq, 0,
-+                              dev_name(&pdev->dev), spi);
-+      if (ret) {
-+              dev_err(&pdev->dev, "Unable to bind to interrupt\n");
-+              goto put_master;
-+      }
-+
-+      dev_info(&pdev->dev, "mapped; irq=%d, cs=%d\n",
-+              spi->irq, master->num_chipselect);
-+
-+      ret = devm_spi_register_master(&pdev->dev, master);
-+      if (ret < 0) {
-+              dev_err(&pdev->dev, "spi_register_master failed\n");
-+              goto put_master;
-+      }
-+
-+      return 0;
-+
-+put_master:
-+      spi_master_put(master);
-+
-+      return ret;
-+}
-+
-+static int sifive_spi_remove(struct platform_device *pdev)
-+{
-+      struct spi_master *master = platform_get_drvdata(pdev);
-+      struct sifive_spi *spi = spi_master_get_devdata(master);
-+
-+      /* Disable all the interrupts just in case */
-+      sifive_spi_write(spi, XSPI_IER_OFFSET, 0);
-+      spi_master_put(master);
-+
-+      return 0;
-+}
-+
-+static const struct of_device_id sifive_spi_of_match[] = {
-+      { .compatible = "sifive,spi0", },
-+      {}
-+};
-+MODULE_DEVICE_TABLE(of, sifive_spi_of_match);
-+
-+static struct platform_driver sifive_spi_driver = {
-+      .probe = sifive_spi_probe,
-+      .remove = sifive_spi_remove,
-+      .driver = {
-+              .name = SIFIVE_SPI_NAME,
-+              .of_match_table = sifive_spi_of_match,
-+      },
-+};
-+module_platform_driver(sifive_spi_driver);
-+
-+MODULE_AUTHOR("SiFive, Inc. <sifive@sifive.com>");
-+MODULE_DESCRIPTION("SiFive SPI driver");
-+MODULE_LICENSE("GPL");
diff --git a/target/linux/riscv64/patches/005-spi-is25wp256d.patch b/target/linux/riscv64/patches/005-spi-is25wp256d.patch
deleted file mode 100644 (file)
index 68851b4..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-From c6e4a154bd008655dd69a850275d5cb082a7304b Mon Sep 17 00:00:00 2001
-From: "Wesley W. Terpstra" <wesley@sifive.com>
-Date: Mon, 5 Feb 2018 17:44:19 -0800
-Subject: [PATCH] spi-nor: add support for is25wp{32,64,128,256}
-
-Signed-off-by: Palmer Dabbelt <palmer@sifive.com>
----
- drivers/mtd/spi-nor/spi-nor.c | 47 ++++++++++++++++++++++++++++++++++-
- include/linux/mtd/spi-nor.h   |  2 ++
- 2 files changed, 48 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
-index d9c368c441948..e9a3557a3c237 100644
---- a/drivers/mtd/spi-nor/spi-nor.c
-+++ b/drivers/mtd/spi-nor/spi-nor.c
-@@ -1072,6 +1072,9 @@ static const struct flash_info spi_nor_ids[] = {
-                       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-       { "is25wp128",  INFO(0x9d7018, 0, 64 * 1024, 256,
-                       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-+      { "is25wp256d", INFO(0x9d7019, 0, 32 * 1024, 1024,
-+                      SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES)
-+      },
-       /* Macronix */
-       { "mx25l512e",   INFO(0xc22010, 0, 64 * 1024,   1, SECT_4K) },
-@@ -1515,6 +1518,45 @@ static int macronix_quad_enable(struct spi_nor *nor)
-       return 0;
- }
-+/**
-+ * issi_unlock() - clear BP[0123] write-protection.
-+ * @nor:      pointer to a 'struct spi_nor'
-+ *
-+ * Bits [2345] of the Status Register are BP[0123].
-+ * ISSI chips use a different block protection scheme than other chips.
-+ * Just disable the write-protect unilaterally.
-+ *
-+ * Return: 0 on success, -errno otherwise.
-+ */
-+static int issi_unlock(struct spi_nor *nor)
-+{
-+      int ret, val;
-+      u8 mask = SR_BP0 | SR_BP1 | SR_BP2 | SR_BP3;
-+
-+      val = read_sr(nor);
-+      if (val < 0)
-+              return val;
-+      if (!(val & mask))
-+              return 0;
-+
-+      write_enable(nor);
-+
-+      write_sr(nor, val & ~mask);
-+
-+      ret = spi_nor_wait_till_ready(nor);
-+      if (ret)
-+              return ret;
-+
-+      ret = read_sr(nor);
-+      if (ret > 0 && !(ret & mask)) {
-+              dev_info(nor->dev, "ISSI Block Protection Bits cleared\n");
-+              return 0;
-+      } else {
-+              dev_err(nor->dev, "ISSI Block Protection Bits not cleared\n");
-+              return -EINVAL;
-+      }
-+}
-+
- /*
-  * Write status Register and configuration register with 2 bytes
-  * The first byte will be written to the status register, while the
-@@ -2747,6 +2789,9 @@ static int spi_nor_init(struct spi_nor *nor)
-               spi_nor_wait_till_ready(nor);
-       }
-+      if (JEDEC_MFR(nor->info) == SNOR_MFR_ISSI)
-+              issi_unlock(nor);
-+
-       if (nor->quad_enable) {
-               err = nor->quad_enable(nor);
-               if (err) {
-@@ -2926,7 +2971,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
-       if (ret)
-               return ret;
--      if (nor->addr_width) {
-+      if (nor->addr_width && JEDEC_MFR(info) != SNOR_MFR_ISSI) {
-               /* already configured from SFDP */
-       } else if (info->addr_width) {
-               nor->addr_width = info->addr_width;
-diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
-index e60da0d34cc14..da422a37d3837 100644
---- a/include/linux/mtd/spi-nor.h
-+++ b/include/linux/mtd/spi-nor.h
-@@ -23,6 +23,7 @@
- #define SNOR_MFR_ATMEL                CFI_MFR_ATMEL
- #define SNOR_MFR_GIGADEVICE   0xc8
- #define SNOR_MFR_INTEL                CFI_MFR_INTEL
-+#define SNOR_MFR_ISSI         0x9d
- #define SNOR_MFR_MICRON               CFI_MFR_ST /* ST Micro <--> Micron */
- #define SNOR_MFR_MACRONIX     CFI_MFR_MACRONIX
- #define SNOR_MFR_SPANSION     CFI_MFR_AMD
-@@ -121,6 +122,7 @@
- #define SR_BP0                        BIT(2)  /* Block protect 0 */
- #define SR_BP1                        BIT(3)  /* Block protect 1 */
- #define SR_BP2                        BIT(4)  /* Block protect 2 */
-+#define SR_BP3                        BIT(5)  /* Block protect 3 (on ISSI chips) */
- #define SR_TB                 BIT(5)  /* Top/Bottom protect */
- #define SR_SRWD                       BIT(7)  /* SR write protect */
- /* Spansion/Cypress specific status bits */
diff --git a/target/linux/riscv64/patches/006-uart-sifive-serial-driver.patch b/target/linux/riscv64/patches/006-uart-sifive-serial-driver.patch
deleted file mode 100644 (file)
index 9779f9f..0000000
+++ /dev/null
@@ -1,1128 +0,0 @@
-From 6f1c41357974f377c4707a9b77125dd9cc9c2873 Mon Sep 17 00:00:00 2001
-From: "Wesley W. Terpstra" <wesley@sifive.com>
-Date: Fri, 16 Mar 2018 11:34:26 -0700
-Subject: [PATCH] serial/sifive: initial driver from Paul Walmsley
-
----
- drivers/tty/serial/Kconfig       |   23 +
- drivers/tty/serial/Makefile      |    1 +
- drivers/tty/serial/sifive.c      | 1051 ++++++++++++++++++++++++++++++
- include/uapi/linux/serial_core.h |    3 +
- 4 files changed, 1078 insertions(+)
- create mode 100644 drivers/tty/serial/sifive.c
-
-diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
-index df8bd0c7b97db..94a6de4b7dec4 100644
---- a/drivers/tty/serial/Kconfig
-+++ b/drivers/tty/serial/Kconfig
-@@ -1060,6 +1060,29 @@ config SERIAL_OMAP_CONSOLE
-         your boot loader about how to pass options to the kernel at
-         boot time.)
-+config SERIAL_SIFIVE
-+      tristate "SiFive UART support"
-+      depends on OF
-+      select SERIAL_CORE
-+      help
-+        If you have a SiFive Freedom U500 or similar SoC, enable this to
-+        support the SiFive UART.
-+
-+config SERIAL_SIFIVE_CONSOLE
-+      bool "Console on SiFive UART"
-+      depends on SERIAL_SIFIVE=y
-+      select SERIAL_CORE_CONSOLE
-+      help
-+        Select this option if you would like to use a SiFive UART as the
-+        system console.
-+
-+        Even if you say Y here, the currently visible virtual console
-+        (/dev/tty0) will still be used as the system console by default, but
-+        you can alter that using a kernel command line option such as
-+        "console=ttySIx". (Try "man bootparam" or see the documentation of
-+        your boot loader about how to pass options to the kernel at
-+        boot time.)
-+
- config SERIAL_LANTIQ
-       bool "Lantiq serial driver"
-       depends on LANTIQ
-diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
-index daac675612dff..7e906d3c04558 100644
---- a/drivers/tty/serial/Makefile
-+++ b/drivers/tty/serial/Makefile
-@@ -89,6 +89,7 @@ obj-$(CONFIG_SERIAL_MVEBU_UART)      += mvebu-uart.o
- obj-$(CONFIG_SERIAL_PIC32)    += pic32_uart.o
- obj-$(CONFIG_SERIAL_MPS2_UART)        += mps2-uart.o
- obj-$(CONFIG_SERIAL_OWL)      += owl-uart.o
-+obj-$(CONFIG_SERIAL_SIFIVE)   += sifive.o
- # GPIOLIB helpers for modem control lines
- obj-$(CONFIG_SERIAL_MCTRL_GPIO)       += serial_mctrl_gpio.o
-diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c
-new file mode 100644
-index 0000000000000..588fb31cc94d0
---- /dev/null
-+++ b/drivers/tty/serial/sifive.c
-@@ -0,0 +1,1051 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * SiFive UART driver
-+ * Copyright (C) 2018 Paul Walmsley <paul@pwsan.com>
-+ *
-+ * Based partially on drivers/tty/serial/pxa.c, drivers/pwm/pwm-sifive.c,
-+ * and drivers/tty/serial/omap-serial.c
-+ *
-+ * See Chapter 19 "Universal Asynchronous Receiver/Transmitter (UART)" of
-+ * SiFive FE310-G000 v2p3.
-+ *
-+ * The SiFive UART design is not 8250-compatible.  The following common
-+ * features are not supported:
-+ * - Word lengths other than 8 bits
-+ * - Break handling
-+ * - Parity
-+ * - Flow control
-+ * - Modem signals (DSR, RI, etc.)
-+ * On the other hand, the design is free from the baggage of the classical 8250
-+ * programming model.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * 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.
-+ */
-+
-+/* XXX Magic SYSRQ support - is it possible to implement? */
-+/* XXX ignore_status_mask */
-+/* XXX Ensure operations are spinlocked that need to be spinlocked */
-+
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/console.h>
-+#include <linux/serial_reg.h>
-+#include <linux/delay.h>
-+#include <linux/slab.h>
-+#include <linux/tty.h>
-+#include <linux/tty_flip.h>
-+#include <linux/platform_device.h>
-+#include <linux/io.h>
-+#include <linux/clk.h>
-+#include <linux/serial_core.h>
-+#include <linux/irq.h>
-+#include <linux/of.h>
-+#include <linux/of_irq.h>
-+
-+/*
-+ * Register offsets
-+ */
-+
-+/* TXDATA */
-+#define SIFIVE_SERIAL_TXDATA_OFFS             0x0
-+#define SIFIVE_SERIAL_TXDATA_FULL_SHIFT               31
-+#define SIFIVE_SERIAL_TXDATA_FULL_MASK                (1 << SIFIVE_SERIAL_TXDATA_FULL_SHIFT)
-+#define SIFIVE_SERIAL_TXDATA_DATA_SHIFT               0
-+#define SIFIVE_SERIAL_TXDATA_DATA_MASK                (0xff << SIFIVE_SERIAL_TXDATA_DATA_SHIFT)
-+
-+/* RXDATA */
-+#define SIFIVE_SERIAL_RXDATA_OFFS             0x4
-+#define SIFIVE_SERIAL_RXDATA_EMPTY_SHIFT      31
-+#define SIFIVE_SERIAL_RXDATA_EMPTY_MASK               (1 << SIFIVE_SERIAL_RXDATA_EMPTY_SHIFT)
-+#define SIFIVE_SERIAL_RXDATA_DATA_SHIFT               0
-+#define SIFIVE_SERIAL_RXDATA_DATA_MASK                (0xff << SIFIVE_SERIAL_RXDATA_DATA_SHIFT)
-+
-+/* TXCTRL */
-+#define SIFIVE_SERIAL_TXCTRL_OFFS             0x8
-+#define SIFIVE_SERIAL_TXCTRL_TXCNT_SHIFT      16
-+#define SIFIVE_SERIAL_TXCTRL_TXCNT_MASK               (0x7 << SIFIVE_SERIAL_TXCTRL_TXCNT_SHIFT)
-+#define SIFIVE_SERIAL_TXCTRL_NSTOP_SHIFT      1
-+#define SIFIVE_SERIAL_TXCTRL_NSTOP_MASK               (1 << SIFIVE_SERIAL_TXCTRL_NSTOP_SHIFT)
-+#define SIFIVE_SERIAL_TXCTRL_TXEN_SHIFT               0
-+#define SIFIVE_SERIAL_TXCTRL_TXEN_MASK                (1 << SIFIVE_SERIAL_TXCTRL_TXEN_SHIFT)
-+
-+/* RXCTRL */
-+#define SIFIVE_SERIAL_RXCTRL_OFFS             0xC
-+#define SIFIVE_SERIAL_RXCTRL_RXCNT_SHIFT      16
-+#define SIFIVE_SERIAL_RXCTRL_RXCNT_MASK               (0x7 << SIFIVE_SERIAL_TXCTRL_TXCNT_SHIFT)
-+#define SIFIVE_SERIAL_RXCTRL_RXEN_SHIFT               0
-+#define SIFIVE_SERIAL_RXCTRL_RXEN_MASK                (1 << SIFIVE_SERIAL_RXCTRL_RXEN_SHIFT)
-+
-+/* IE */
-+#define SIFIVE_SERIAL_IE_OFFS                 0x10
-+#define SIFIVE_SERIAL_IE_RXWM_SHIFT           1
-+#define SIFIVE_SERIAL_IE_RXWM_MASK            (1 << SIFIVE_SERIAL_IE_RXWM_SHIFT)
-+#define SIFIVE_SERIAL_IE_TXWM_SHIFT           0
-+#define SIFIVE_SERIAL_IE_TXWM_MASK            (1 << SIFIVE_SERIAL_IE_TXWM_SHIFT)
-+
-+/* IP */
-+#define SIFIVE_SERIAL_IP_OFFS                 0x14
-+#define SIFIVE_SERIAL_IP_RXWM_SHIFT           1
-+#define SIFIVE_SERIAL_IP_RXWM_MASK            (1 << SIFIVE_SERIAL_IP_RXWM_SHIFT)
-+#define SIFIVE_SERIAL_IP_TXWM_SHIFT           0
-+#define SIFIVE_SERIAL_IP_TXWM_MASK            (1 << SIFIVE_SERIAL_IP_TXWM_SHIFT)
-+
-+/* DIV */
-+#define SIFIVE_SERIAL_DIV_OFFS                        0x18
-+#define SIFIVE_SERIAL_DIV_DIV_SHIFT           0
-+#define SIFIVE_SERIAL_DIV_DIV_MASK            (0xffff << SIFIVE_SERIAL_IP_DIV_SHIFT)
-+
-+/*
-+ * Config macros
-+ */
-+
-+/* SIFIVE_SERIAL_MAX_PORTS: maximum number of UARTs possible on a device */
-+/* XXX Move to Kconfig? */
-+#define SIFIVE_SERIAL_MAX_PORTS                       10
-+
-+/* SIFIVE_SERIAL_NAME: our driver's name that we pass to the operating system */
-+#define SIFIVE_SERIAL_NAME                    "sifive-serial"
-+
-+/* SIFIVE_TTY_PREFIX: tty name prefix for SiFive serial ports */
-+#define SIFIVE_TTY_PREFIX                     "ttySI"
-+
-+/*
-+ *
-+ */
-+
-+/**
-+ * sifive_serial_port - driver-specific data extension to struct uart_port
-+ * @port: struct uart_port embedded in this struct
-+ * @dev: struct device *
-+ * @ier: shadowed copy of the interrupt enable register
-+ * @clkin_rate: input clock to the UART IP block.
-+ * @bit_rate: UART serial line rate (e.g., 115200 bps)
-+ * @clk_notifier: clock rate change notifier for upstream clock changes
-+ */
-+struct sifive_serial_port {
-+      struct uart_port        port;
-+      struct device           *dev;
-+      unsigned char           ier;
-+      unsigned long           clkin_rate;
-+      unsigned long           bit_rate;
-+      struct clk              *clk;
-+      struct notifier_block   clk_notifier;
-+};
-+
-+/*
-+ * Structure container-of macros
-+ */
-+
-+#define port_to_sifive_serial_port(p) (container_of((p), \
-+                                                  struct sifive_serial_port, \
-+                                                  port))
-+
-+#define notifier_to_sifive_serial_port(nb) (container_of((nb), \
-+                                                       struct sifive_serial_port, \
-+                                                       clk_notifier))
-+
-+/*
-+ * Forward declarations
-+ */
-+static void sifive_serial_stop_tx(struct uart_port *port);
-+
-+/*
-+ * Internal functions
-+ */
-+
-+/**
-+ * sifive_serial_early_write() - write to a UART register (early)
-+ * @port: pointer to a struct uart_port record
-+ * @offs: register address offset from the IP block base address
-+ * @v: value to write to the register
-+ *
-+ * Given a pointer @port to a struct uart_port record, write the value @v to the
-+ * IP block register address offset @offs.  This function is intended for early
-+ * console use.
-+ */
-+static void sifive_serial_early_write(struct uart_port *port, u16 offs, u32 v)
-+{
-+      writel(v, port->membase + offs);
-+}
-+
-+/**
-+ * sifive_serial_early_read() - read from a UART register (early)
-+ * @port: pointer to a struct uart_port record
-+ * @offs: register address offset from the IP block base address
-+ *
-+ * Given a pointer @port to a struct uart_port record, read the contents of the
-+ * IP block register located at offset @offs from the IP block base and return
-+ * it.  This function is intended for early console use.
-+ *
-+ * Returns: the register value read from the UART.
-+ */
-+static u32 sifive_serial_early_read(struct uart_port *port, u16 offs)
-+{
-+      return readl(port->membase + offs);
-+}
-+
-+/**
-+ * sifive_serial_write() - write to a UART register
-+ * @ssp: pointer to a struct sifive_serial_port record
-+ * @offs: register address offset from the IP block base address
-+ * @v: value to write to the register
-+ *
-+ * Write the value @v to the IP block register located at offset @offs from the
-+ * IP block base, given a pointer @ssp to a struct sifive_serial_port record.
-+ */
-+static void sifive_serial_write(struct sifive_serial_port *ssp, u16 offs, u32 v)
-+{
-+      sifive_serial_early_write(&ssp->port, offs, v);
-+}
-+
-+/**
-+ * sifive_serial_read() - read from a UART register
-+ * @ssp: pointer to a struct sifive_serial_port record
-+ * @offs: register address offset from the IP block base address
-+ *
-+ * Read the contents of the IP block register located at offset @offs from the
-+ * IP block base, given a pointer @ssp to a struct sifive_serial_port record.
-+ *
-+ * Returns: the value of the UART register
-+ */
-+static u32 sifive_serial_read(struct sifive_serial_port *ssp, u16 offs)
-+{
-+      return sifive_serial_early_read(&ssp->port, offs);
-+}
-+
-+/**
-+ * sifive_serial_is_txfifo_full() - is the TXFIFO full?
-+ * @ssp: pointer to a struct sifive_serial_port
-+ *
-+ * Read the transmit FIFO "full" bit, returning a non-zero value if the
-+ * TX FIFO is full, or zero if space remains.  Intended to be used to prevent
-+ * writes to the TX FIFO when it's full.
-+ *
-+ * Returns: SIFIVE_SERIAL_TXDATA_FULL_MASK (non-zero) if the transmit FIFO
-+ * is full, or 0 if space remains.
-+ */
-+static int sifive_serial_is_txfifo_full(struct sifive_serial_port *ssp)
-+{
-+      return sifive_serial_read(ssp, SIFIVE_SERIAL_TXDATA_OFFS) &
-+              SIFIVE_SERIAL_TXDATA_FULL_MASK;
-+}
-+
-+/**
-+ * sifive_serial_transmit_char() - enqueue a byte to transmit onto the TX FIFO
-+ * @ssp: pointer to a struct sifive_serial_port
-+ * @ch: character to transmit
-+ *
-+ * Enqueue a byte @ch onto the transmit FIFO, given a pointer @ssp to the
-+ * struct sifive_serial_port * to transmit on.  Caller should first check to
-+ * ensure that the TXFIFO has space; see sifive_serial_is_txfifo_full().
-+ */
-+static void sifive_serial_transmit_char(struct sifive_serial_port *ssp, int ch)
-+{
-+      sifive_serial_write(ssp, SIFIVE_SERIAL_TXDATA_OFFS, ch);
-+}
-+
-+/**
-+ * sifive_serial_transmit_chars() - enqueue multiple bytes onto the TX FIFO
-+ * @ssp: pointer to a struct sifive_serial_port
-+ *
-+ * Transfer up to a TX FIFO size's worth of characters from the Linux serial
-+ * transmit buffer to the SiFive UART TX FIFO.
-+ */
-+static void sifive_serial_transmit_chars(struct sifive_serial_port *ssp)
-+{
-+      struct circ_buf *xmit = &ssp->port.state->xmit;
-+      int count;
-+
-+      if (ssp->port.x_char) {
-+              sifive_serial_transmit_char(ssp, ssp->port.x_char);
-+              ssp->port.icount.tx++;
-+              ssp->port.x_char = 0;
-+              return;
-+      }
-+      if (uart_circ_empty(xmit) || uart_tx_stopped(&ssp->port)) {
-+              sifive_serial_stop_tx(&ssp->port);
-+              return;
-+      }
-+      count = ssp->port.fifosize;
-+      do {
-+              sifive_serial_transmit_char(ssp, xmit->buf[xmit->tail]);
-+              xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-+              ssp->port.icount.tx++;
-+              if (uart_circ_empty(xmit))
-+                      break;
-+      } while (--count > 0);
-+
-+      if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-+              uart_write_wakeup(&ssp->port);
-+
-+      if (uart_circ_empty(xmit))
-+              sifive_serial_stop_tx(&ssp->port);
-+}
-+
-+/**
-+ * sifive_serial_enable_txwm() - enable transmit watermark interrupts
-+ * @ssp: pointer to a struct sifive_serial_port
-+ *
-+ * Enable interrupt generation when the transmit FIFO watermark is reached
-+ * on the UART referred to by @ssp.
-+ */
-+static void sifive_serial_enable_txwm(struct sifive_serial_port *ssp)
-+{
-+      if (ssp->ier & SIFIVE_SERIAL_IE_TXWM_MASK)
-+              return;
-+
-+      ssp->ier |= SIFIVE_SERIAL_IE_TXWM_MASK;
-+      sifive_serial_write(ssp, SIFIVE_SERIAL_IE_OFFS, ssp->ier);
-+}
-+
-+/**
-+ * sifive_serial_enable_rxwm() - enable receive watermark interrupts
-+ * @ssp: pointer to a struct sifive_serial_port
-+ *
-+ * Enable interrupt generation when the receive FIFO watermark is reached
-+ * on the UART referred to by @ssp.
-+ */
-+static void sifive_serial_enable_rxwm(struct sifive_serial_port *ssp)
-+{
-+      if (ssp->ier & SIFIVE_SERIAL_IE_RXWM_MASK)
-+              return;
-+
-+      ssp->ier |= SIFIVE_SERIAL_IE_RXWM_MASK;
-+      sifive_serial_write(ssp, SIFIVE_SERIAL_IE_OFFS, ssp->ier);
-+}
-+
-+/**
-+ * sifive_serial_disable_txwm() - disable transmit watermark interrupts
-+ * @ssp: pointer to a struct sifive_serial_port
-+ *
-+ * Disable interrupt generation when the transmit FIFO watermark is reached
-+ * on the UART referred to by @ssp.
-+ */
-+static void sifive_serial_disable_txwm(struct sifive_serial_port *ssp)
-+{
-+      if (!(ssp->ier & SIFIVE_SERIAL_IE_TXWM_MASK))
-+              return;
-+
-+      ssp->ier &= ~SIFIVE_SERIAL_IE_TXWM_MASK;
-+      sifive_serial_write(ssp, SIFIVE_SERIAL_IE_OFFS, ssp->ier);
-+}
-+
-+/**
-+ * sifive_serial_disable_rxwm() - disable receive watermark interrupts
-+ * @ssp: pointer to a struct sifive_serial_port
-+ *
-+ * Disable interrupt generation when the receive FIFO watermark is reached
-+ * on the UART referred to by @ssp.
-+ */
-+static void sifive_serial_disable_rxwm(struct sifive_serial_port *ssp)
-+{
-+      if (!(ssp->ier & SIFIVE_SERIAL_IE_RXWM_MASK))
-+              return;
-+
-+      ssp->ier &= ~SIFIVE_SERIAL_IE_RXWM_MASK;
-+      sifive_serial_write(ssp, SIFIVE_SERIAL_IE_OFFS, ssp->ier);
-+}
-+
-+/**
-+ * sifive_serial_receive_char() - receive a byte from the UART
-+ * @ssp: pointer to a struct sifive_serial_port
-+ * @is_empty: char pointer to return whether the RX FIFO is empty
-+ *
-+ * Try to read a byte from the SiFive UART RX FIFO, referenced by
-+ * @ssp, and to return it.  Also returns the RX FIFO empty bit in
-+ * the char pointed to by @ch.  The caller must pass the byte back to the
-+ * Linux serial layer if needed.
-+ *
-+ * Returns: the byte read from the UART RX FIFO.
-+ */
-+static char sifive_serial_receive_char(struct sifive_serial_port *ssp,
-+                                     char *is_empty)
-+{
-+      u32 v;
-+      u8 ch;
-+
-+      v = sifive_serial_read(ssp, SIFIVE_SERIAL_RXDATA_OFFS);
-+
-+      if (!is_empty)
-+              WARN_ON(1);
-+      else
-+              *is_empty = (v & SIFIVE_SERIAL_RXDATA_EMPTY_MASK) >>
-+                      SIFIVE_SERIAL_RXDATA_EMPTY_SHIFT;
-+
-+      ch = (v & SIFIVE_SERIAL_RXDATA_DATA_MASK) >>
-+              SIFIVE_SERIAL_RXDATA_DATA_SHIFT;
-+
-+      return ch;
-+}
-+
-+/**
-+ * sifive_serial_receive_chars() - receive multiple bytes from the UART
-+ * @ssp: pointer to a struct sifive_serial_port
-+ *
-+ * Receive up to an RX FIFO's worth of bytes from the SiFive UART referred
-+ * to by @ssp and pass them up to the Linux serial layer.
-+ */
-+static void sifive_serial_receive_chars(struct sifive_serial_port *ssp)
-+{
-+      unsigned char ch;
-+      char is_empty;
-+      int c;
-+
-+      for (c = ssp->port.fifosize; c > 0; --c) {
-+              ch = sifive_serial_receive_char(ssp, &is_empty);
-+              if (is_empty) break;
-+
-+              ssp->port.icount.rx++;
-+              uart_insert_char(&ssp->port, 0, 0, ch, TTY_NORMAL);
-+      }
-+}
-+
-+/**
-+ * sifive_serial_update_div() - calculate the divisor setting by the line rate
-+ * @ssp: pointer to a struct sifive_serial_port
-+ *
-+ * Calculate the appropriate value of the clock divisor for the UART
-+ * referred to by @ssp and the target line rate referred to by @bps, and
-+ * return it.
-+ */
-+static void sifive_serial_update_div(struct sifive_serial_port *ssp)
-+{
-+      u16 div = DIV_ROUND_UP(ssp->clkin_rate, ssp->bit_rate) - 1;
-+      /* XXX check for div out of spec */
-+      sifive_serial_write(ssp, SIFIVE_SERIAL_DIV_OFFS, div);
-+}
-+
-+/**
-+ * sifive_serial_update_bit_rate() - set the UART "baud rate"
-+ * @ssp: pointer to a struct sifive_serial_port
-+ * @rate: new target bit rate
-+ *
-+ * Calculate the UART divisor value for the target bit rate @rate for the
-+ * SiFive UART described by @ssp and program it into the UART.  There may
-+ * be some error between the target bit rate and the actual bit rate implemented
-+ * by the UART due to clock ratio granularity.
-+ */
-+static void sifive_serial_update_bit_rate(struct sifive_serial_port *ssp,
-+                                        unsigned int rate)
-+{
-+      if (ssp->bit_rate == rate)
-+              return;
-+
-+      ssp->bit_rate = rate;
-+      sifive_serial_update_div(ssp);
-+}
-+
-+/**
-+ * sifive_serial_set_stop_bits() - set the number of stop bits
-+ * @ssp: pointer to a struct sifive_serial_port
-+ * @nstop: 1 or 2 (stop bits)
-+ *
-+ * Program the SiFive UART referred to by @ssp to use @nstop stop bits.
-+ */
-+static void sifive_serial_set_stop_bits(struct sifive_serial_port *ssp,
-+                                      char nstop)
-+{
-+      u32 v;
-+
-+      if (nstop < 1 || nstop > 2) {
-+              WARN_ON(1);
-+              return;
-+      }
-+
-+      v = sifive_serial_read(ssp, SIFIVE_SERIAL_TXCTRL_OFFS);
-+      v &= ~SIFIVE_SERIAL_TXCTRL_NSTOP_MASK;
-+      v |= (nstop-1) << SIFIVE_SERIAL_TXCTRL_NSTOP_SHIFT;
-+      sifive_serial_write(ssp, SIFIVE_SERIAL_TXCTRL_OFFS, v);
-+}
-+
-+/**
-+ * sifive_serial_wait_for_xmitr() - wait for an empty slot on the TX FIFO
-+ * @ssp: pointer to a struct sifive_serial_port
-+ *
-+ * Delay while the UART TX FIFO referred to by @ssp is marked as full.
-+ *
-+ * XXX Probably should use a timeout/bailout.
-+ */
-+static inline void sifive_serial_wait_for_xmitr(struct sifive_serial_port *ssp)
-+{
-+      while (sifive_serial_is_txfifo_full(ssp))
-+              udelay(1); /* XXX Should vary by bps rate */
-+}
-+
-+/*
-+ * Linux serial API functions
-+ */
-+
-+static void sifive_serial_stop_tx(struct uart_port *port)
-+{
-+      struct sifive_serial_port *ssp = port_to_sifive_serial_port(port);
-+
-+      sifive_serial_disable_txwm(ssp);
-+}
-+
-+static void sifive_serial_stop_rx(struct uart_port *port)
-+{
-+      struct sifive_serial_port *ssp = port_to_sifive_serial_port(port);
-+
-+      sifive_serial_disable_rxwm(ssp);
-+}
-+
-+static void sifive_serial_start_tx(struct uart_port *port)
-+{
-+      struct sifive_serial_port *ssp = port_to_sifive_serial_port(port);
-+
-+      sifive_serial_enable_txwm(ssp);
-+}
-+
-+static irqreturn_t sifive_serial_irq(int irq, void *dev_id)
-+{
-+      struct sifive_serial_port *ssp = dev_id;
-+      irqreturn_t r = IRQ_NONE;
-+      int c = ssp->port.fifosize;
-+      u32 ip;
-+
-+      spin_lock(&ssp->port.lock);
-+
-+      do {
-+              ip = sifive_serial_read(ssp, SIFIVE_SERIAL_IP_OFFS);
-+              if (!ip)
-+                      break;
-+
-+              r = IRQ_HANDLED;
-+
-+              if (ip & SIFIVE_SERIAL_IP_RXWM_MASK)
-+                      sifive_serial_receive_chars(ssp);
-+              if (ip & SIFIVE_SERIAL_IP_TXWM_MASK)
-+                      sifive_serial_transmit_chars(ssp);
-+      } while (c--);
-+
-+      spin_unlock(&ssp->port.lock);
-+
-+      tty_flip_buffer_push(&ssp->port.state->port);
-+
-+      return r;
-+}
-+
-+static unsigned int sifive_serial_tx_empty(struct uart_port *port)
-+{
-+      struct sifive_serial_port *ssp = port_to_sifive_serial_port(port);
-+
-+      return !sifive_serial_is_txfifo_full(ssp);
-+}
-+
-+static unsigned int sifive_serial_get_mctrl(struct uart_port *port)
-+{
-+      return 0; /* XXX -EINVAL? */
-+}
-+
-+static void sifive_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
-+{
-+      // dev_err(port->dev, "set_mctrl not supported\n");
-+}
-+
-+static void sifive_serial_break_ctl(struct uart_port *port, int break_state)
-+{
-+      dev_err(port->dev, "sending break not supported\n");
-+}
-+
-+static int sifive_serial_startup(struct uart_port *port)
-+{
-+      struct sifive_serial_port *ssp = port_to_sifive_serial_port(port);
-+
-+      sifive_serial_enable_rxwm(ssp);
-+
-+      return 0;
-+}
-+
-+static void sifive_serial_shutdown(struct uart_port *port)
-+{
-+      struct sifive_serial_port *ssp = port_to_sifive_serial_port(port);
-+
-+      sifive_serial_disable_rxwm(ssp);
-+      sifive_serial_disable_txwm(ssp);
-+}
-+
-+/**
-+ * sifive_serial_clk_notifier() - clock post-rate-change notifier
-+ * @nb: pointer to the struct notifier_block, from the notifier code
-+ * @event: event mask from the notifier code
-+ * @data: pointer to the struct clk_notifier_data from the notifier code
-+ *
-+ * On the H5U SoC, the UART IP block is derived from the CPU clock source
-+ * after a synchronous divide-by-two divider, so any CPU clock rate change
-+ * requires the UART baud rate to be updated.  This presumably could corrupt any
-+ * serial word currently being transmitted or received.  It would probably
-+ * be better to stop receives and transmits, then complete the baud rate
-+ * change, then re-enable them.
-+ */
-+static int sifive_serial_clk_notifier(struct notifier_block *nb,
-+                                    unsigned long event, void *data)
-+{
-+      struct clk_notifier_data *cnd = data;
-+      struct sifive_serial_port *ssp = notifier_to_sifive_serial_port(nb);
-+
-+      if (event == POST_RATE_CHANGE && ssp->clkin_rate != cnd->new_rate) {
-+              ssp->clkin_rate = cnd->new_rate;
-+              sifive_serial_update_div(ssp);
-+      }
-+
-+      return NOTIFY_OK;
-+}
-+
-+static void sifive_serial_set_termios(struct uart_port *port,
-+                                    struct ktermios *termios,
-+                                    struct ktermios *old)
-+{
-+      struct sifive_serial_port *ssp = port_to_sifive_serial_port(port);
-+      int rate;
-+      char nstop;
-+
-+      if ((termios->c_cflag & CSIZE) != CS8) {
-+              dev_err(ssp->port.dev, "only 8-bit words supported\n");
-+              return;
-+      }
-+
-+      /* Set number of stop bits */
-+      nstop = (termios->c_cflag & CSTOPB) ? 2 : 1;
-+      sifive_serial_set_stop_bits(ssp, nstop);
-+
-+      /* Set line rate */
-+      rate = uart_get_baud_rate(port, termios, old, 0, ssp->clkin_rate / 16);
-+      sifive_serial_update_bit_rate(ssp, rate);
-+
-+      /* XXX Enable FIFOs with watermark 1 */
-+
-+#if 0
-+      spin_lock_irqsave(&ssp->port.lock, flags);
-+#endif
-+
-+      /*
-+       * Update the per-port timeout.
-+       */
-+      uart_update_timeout(port, termios->c_cflag, rate);
-+
-+      /* XXX */
-+      ssp->port.read_status_mask = 0;
-+      if (termios->c_iflag & INPCK) {
-+              dev_err(ssp->port.dev, "INPCK flag not supported\n");
-+              return;
-+      }
-+      if (termios->c_iflag & (BRKINT | PARMRK)) {
-+              dev_err(ssp->port.dev, "BRKINT/PARMRK flag not supported\n");
-+              return;
-+      }
-+
-+#if 0
-+      /*
-+       * ignore all characters if CREAD is not set
-+       */
-+      if ((termios->c_cflag & CREAD) == 0)
-+              ssp->port.ignore_status_mask |= UART_LSR_DR;
-+#endif
-+
-+      /* XXX enable interrupts */
-+}
-+
-+static void sifive_serial_release_port(struct uart_port *port)
-+{
-+}
-+
-+static int sifive_serial_request_port(struct uart_port *port)
-+{
-+      return 0;
-+}
-+
-+static void sifive_serial_config_port(struct uart_port *port, int flags)
-+{
-+      struct sifive_serial_port *ssp = port_to_sifive_serial_port(port);
-+
-+      ssp->port.type = PORT_SIFIVE_H5U;
-+}
-+
-+static int sifive_serial_verify_port(struct uart_port *port,
-+                                   struct serial_struct *ser)
-+{
-+      return -EINVAL;
-+}
-+
-+static const char *sifive_serial_type(struct uart_port *port)
-+{
-+      return port->type == PORT_SIFIVE_H5U ? SIFIVE_SERIAL_NAME : NULL;
-+}
-+
-+/*
-+ * Polling support
-+ */
-+
-+#ifdef CONFIG_CONSOLE_POLL
-+
-+static void sifive_serial_poll_put_char(struct uart_port *port,
-+                                      unsigned char ch)
-+{
-+      struct sifive_serial_port *ssp = port_to_sifive_serial_port(port);
-+
-+      sifive_serial_wait_for_xmitr(ssp);
-+      sifive_serial_write(ssp, SIFIVE_SERIAL_TXDATA_OFFS, ch);
-+}
-+
-+static int sifive_serial_poll_get_char(struct uart_port *port)
-+{
-+      struct sifive_serial_port *ssp = port_to_sifive_serial_port(port);
-+      char is_empty, ch;
-+
-+      ch = sifive_serial_receive_char(ssp, &is_empty);
-+      if (is_empty)
-+              return NO_POLL_CHAR;
-+
-+      return ch;
-+}
-+
-+#endif /* CONFIG_CONSOLE_POLL */
-+
-+/*
-+ * Earlyconsole support
-+ */
-+
-+#ifdef CONFIG_SERIAL_EARLYCON
-+static void early_sifive_serial_putc(struct uart_port *port, int c)
-+{
-+      while (sifive_serial_early_read(port, SIFIVE_SERIAL_TXDATA_OFFS) &
-+             SIFIVE_SERIAL_TXDATA_FULL_MASK)
-+              cpu_relax();
-+
-+      sifive_serial_early_write(port, SIFIVE_SERIAL_TXDATA_OFFS, c);
-+}
-+
-+void early_sifive_serial_write(struct console *console, const char *s,
-+                             unsigned int count)
-+{
-+      struct earlycon_device *device = console->data;
-+      struct uart_port *port = &device->port;
-+
-+      uart_console_write(port, s, count, early_sifive_serial_putc);
-+}
-+
-+static int __init early_sifive_serial_setup(struct earlycon_device *device,
-+                                          const char *options)
-+{
-+      struct uart_port *port = &device->port;
-+
-+      if (!(port->membase || port->iobase))
-+              return -ENODEV;
-+
-+      device->con->write = early_sifive_serial_write;
-+      return 0;
-+}
-+
-+OF_EARLYCON_DECLARE(sifive, "sifive,freedom-uart", early_sifive_serial_setup);
-+#endif /* CONFIG_SERIAL_EARLYCON */
-+
-+/*
-+ * Linux console interface
-+ */
-+
-+#ifdef CONFIG_SERIAL_SIFIVE_CONSOLE
-+
-+static struct sifive_serial_port *sifive_serial_console_ports[SIFIVE_SERIAL_MAX_PORTS];
-+
-+static void sifive_serial_console_putchar(struct uart_port *port, int ch)
-+{
-+      struct sifive_serial_port *ssp = port_to_sifive_serial_port(port);
-+
-+      sifive_serial_wait_for_xmitr(ssp);
-+      sifive_serial_transmit_char(ssp, ch);
-+}
-+
-+static void sifive_serial_console_write(struct console *co, const char *s,
-+                                      unsigned int count)
-+{
-+      struct sifive_serial_port *ssp = sifive_serial_console_ports[co->index];
-+      unsigned long flags;
-+      unsigned int ier;
-+      int locked = 1;
-+
-+      if (!ssp) return;
-+
-+      local_irq_save(flags);
-+      if (ssp->port.sysrq)
-+              locked = 0;
-+      else if (oops_in_progress)
-+              locked = spin_trylock(&ssp->port.lock);
-+      else
-+              spin_lock(&ssp->port.lock);
-+
-+      ier = sifive_serial_read(ssp, SIFIVE_SERIAL_IE_OFFS);
-+      sifive_serial_write(ssp, SIFIVE_SERIAL_IE_OFFS, 0);
-+
-+      uart_console_write(&ssp->port, s, count, sifive_serial_console_putchar);
-+
-+      sifive_serial_write(ssp, SIFIVE_SERIAL_IE_OFFS, ier);
-+
-+      if (locked)
-+              spin_unlock(&ssp->port.lock);
-+      local_irq_restore(flags);
-+}
-+
-+static int __init sifive_serial_console_setup(struct console *co, char *options)
-+{
-+      struct sifive_serial_port *ssp;
-+      int baud = 115200;
-+      int bits = 8;
-+      int parity = 'n';
-+      int flow = 'n';
-+
-+      ssp = sifive_serial_console_ports[co->index];
-+      if (!ssp)
-+              return -ENODEV;
-+
-+      if (options)
-+              uart_parse_options(options, &baud, &parity, &bits, &flow);
-+
-+      return uart_set_options(&ssp->port, co, baud, parity, bits, flow);
-+}
-+
-+static struct uart_driver sifive_serial_uart_driver;
-+
-+static struct console sifive_serial_console = {
-+      .name           = SIFIVE_TTY_PREFIX,
-+      .write          = sifive_serial_console_write,
-+      .device         = uart_console_device,
-+      .setup          = sifive_serial_console_setup,
-+      .flags          = CON_PRINTBUFFER,
-+      .index          = -1,
-+      .data           = &sifive_serial_uart_driver,
-+};
-+
-+static void sifive_serial_add_console_port(struct sifive_serial_port *ssp)
-+{
-+      sifive_serial_console_ports[ssp->port.line] = ssp;
-+}
-+
-+static void sifive_serial_remove_console_port(struct sifive_serial_port *ssp)
-+{
-+      sifive_serial_console_ports[ssp->port.line] = 0;
-+}
-+
-+#define SIFIVE_SERIAL_CONSOLE (&sifive_serial_console)
-+
-+#else
-+
-+#define SIFIVE_SERIAL_CONSOLE NULL
-+
-+static inline void sifive_serial_add_console_port(struct sifive_serial_port *ssp)
-+{}
-+static void sifive_serial_remove_console_port(struct sifive_serial_port *ssp)
-+{}
-+
-+#endif
-+
-+static const struct uart_ops sifive_serial_uops = {
-+      .tx_empty       = sifive_serial_tx_empty,
-+      .set_mctrl      = sifive_serial_set_mctrl,
-+      .get_mctrl      = sifive_serial_get_mctrl,
-+      .stop_tx        = sifive_serial_stop_tx,
-+      .start_tx       = sifive_serial_start_tx,
-+      .stop_rx        = sifive_serial_stop_rx,
-+      .break_ctl      = sifive_serial_break_ctl,
-+      .startup        = sifive_serial_startup,
-+      .shutdown       = sifive_serial_shutdown,
-+      .set_termios    = sifive_serial_set_termios,
-+      .type           = sifive_serial_type,
-+      .release_port   = sifive_serial_release_port,
-+      .request_port   = sifive_serial_request_port,
-+      .config_port    = sifive_serial_config_port,
-+      .verify_port    = sifive_serial_verify_port,
-+#ifdef CONFIG_CONSOLE_POLL
-+      .poll_put_char  = sifive_serial_poll_put_char,
-+      .poll_get_char  = sifive_serial_poll_get_char,
-+#endif
-+};
-+
-+static struct uart_driver sifive_serial_uart_driver = {
-+      .owner          = THIS_MODULE,
-+      .driver_name    = SIFIVE_SERIAL_NAME,
-+      .dev_name       = "ttySI",
-+      .nr             = SIFIVE_SERIAL_MAX_PORTS,
-+      .cons           = SIFIVE_SERIAL_CONSOLE,
-+};
-+
-+static int sifive_serial_probe(struct platform_device *pdev)
-+{
-+      struct sifive_serial_port *ssp;
-+      struct resource *mem;
-+      struct clk *clk;
-+      void __iomem *base;
-+      int irq, id, r;
-+
-+      irq = platform_get_irq(pdev, 0);
-+      if (irq < 0) {
-+              dev_err(&pdev->dev, "could not acquire interrupt\n");
-+              return -EPROBE_DEFER;
-+      }
-+
-+      mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+      base = devm_ioremap_resource(&pdev->dev, mem);
-+      if (IS_ERR(base)) {
-+              dev_err(&pdev->dev, "could not acquire device memory\n");
-+              return PTR_ERR(base);
-+      }
-+
-+      clk = devm_clk_get(&pdev->dev, NULL);
-+      if (IS_ERR(clk)) {
-+              dev_err(&pdev->dev, "unable to find controller clock\n");
-+              return PTR_ERR(clk);
-+      }
-+
-+      id = of_alias_get_id(pdev->dev.of_node, "serial");
-+      if (id < 0) {
-+              dev_err(&pdev->dev, "missing aliases entry\n");
-+              return id;
-+      }
-+
-+#ifdef CONFIG_SERIAL_SIFIVE_CONSOLE
-+      if (id > SIFIVE_SERIAL_MAX_PORTS) {
-+              dev_err(&pdev->dev, "too many UARTs (%d)\n", id);
-+              return -EINVAL;
-+      }
-+#endif
-+
-+      ssp = devm_kzalloc(&pdev->dev, sizeof(*ssp), GFP_KERNEL);
-+      if (!ssp)
-+              return -ENOMEM;
-+
-+      ssp->port.dev = &pdev->dev;
-+      ssp->port.type = PORT_SIFIVE_H5U;
-+      ssp->port.iotype = UPIO_MEM;
-+      ssp->port.irq = irq;
-+      ssp->port.fifosize = 8;
-+      ssp->port.ops = &sifive_serial_uops;
-+      ssp->port.line = id;
-+      ssp->port.mapbase = mem->start;
-+      ssp->port.membase = base;
-+      ssp->dev = &pdev->dev;
-+      ssp->clk = clk;
-+      ssp->clk_notifier.notifier_call = sifive_serial_clk_notifier;
-+
-+      r = clk_notifier_register(ssp->clk, &ssp->clk_notifier);
-+      if (r) {
-+              dev_err(&pdev->dev, "could not register clock notifier: %d\n",
-+                      r);
-+              goto probe_out1;
-+      }
-+
-+      /* Setup clock divider */
-+      ssp->clkin_rate = clk_get_rate(ssp->clk);
-+      ssp->bit_rate = 115200;
-+      sifive_serial_update_div(ssp);
-+
-+      platform_set_drvdata(pdev, ssp);
-+
-+      /* Enable transmits and set the watermark level to 1 */
-+      sifive_serial_write(ssp, SIFIVE_SERIAL_TXCTRL_OFFS,
-+                          (1 << SIFIVE_SERIAL_TXCTRL_TXCNT_SHIFT) |
-+                          SIFIVE_SERIAL_TXCTRL_TXEN_MASK);
-+
-+      /* Enable receives and set the watermark level to 0 */
-+      sifive_serial_write(ssp, SIFIVE_SERIAL_RXCTRL_OFFS,
-+                          (0 << SIFIVE_SERIAL_RXCTRL_RXCNT_SHIFT) |
-+                          SIFIVE_SERIAL_RXCTRL_RXEN_MASK);
-+
-+      r = request_irq(ssp->port.irq, sifive_serial_irq, ssp->port.irqflags,
-+                      dev_name(&pdev->dev), ssp);
-+      if (r) {
-+              dev_err(&pdev->dev, "could not attach interrupt: %d\n", r);
-+              goto probe_out2;
-+      }
-+
-+      r = uart_add_one_port(&sifive_serial_uart_driver, &ssp->port);
-+      if (r != 0) {
-+              dev_err(&pdev->dev, "could not add uart: %d\n", r);
-+              goto probe_out3;
-+      }
-+
-+      sifive_serial_add_console_port(ssp);
-+
-+      return 0;
-+
-+probe_out3:
-+      free_irq(ssp->port.irq, ssp);
-+probe_out2:
-+      clk_notifier_unregister(ssp->clk, &ssp->clk_notifier);
-+probe_out1:
-+      return r;
-+}
-+
-+static int sifive_serial_remove(struct platform_device *dev)
-+{
-+      struct sifive_serial_port *ssp = platform_get_drvdata(dev);
-+
-+      sifive_serial_remove_console_port(ssp);
-+      uart_remove_one_port(&sifive_serial_uart_driver, &ssp->port);
-+      free_irq(ssp->port.irq, ssp);
-+      clk_notifier_unregister(ssp->clk, &ssp->clk_notifier);
-+
-+      return 0;
-+}
-+
-+static const struct of_device_id sifive_serial_of_match[] = {
-+      { .compatible = "sifive,uart0" },
-+      {},
-+};
-+MODULE_DEVICE_TABLE(of, sifive_serial_match);
-+
-+static struct platform_driver sifive_serial_platform_driver = {
-+      .probe          = sifive_serial_probe,
-+      .remove         = sifive_serial_remove,
-+      .driver         = {
-+              .name   = SIFIVE_SERIAL_NAME,
-+              .of_match_table = of_match_ptr(sifive_serial_of_match),
-+      },
-+};
-+
-+static int __init sifive_serial_init(void)
-+{
-+      struct tty_driver *tty_drv;
-+      int r;
-+
-+      r = uart_register_driver(&sifive_serial_uart_driver);
-+      if (r) goto init_out1;
-+
-+      tty_drv = sifive_serial_uart_driver.tty_driver;
-+      if (!tty_drv) goto init_out2;
-+
-+      /* change default terminal settings for SiFive uarts */
-+      tty_drv->init_termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
-+      tty_drv->init_termios.c_ispeed = 115200;
-+      tty_drv->init_termios.c_ospeed = 115200;
-+
-+      r = platform_driver_register(&sifive_serial_platform_driver);
-+      if (r) goto init_out2;
-+
-+      return 0;
-+
-+init_out2:
-+      uart_unregister_driver(&sifive_serial_uart_driver);
-+init_out1:
-+      return r;
-+}
-+
-+static void __exit sifive_serial_exit(void)
-+{
-+      platform_driver_unregister(&sifive_serial_platform_driver);
-+      uart_unregister_driver(&sifive_serial_uart_driver);
-+}
-+
-+module_init(sifive_serial_init);
-+module_exit(sifive_serial_exit);
-+
-+MODULE_DESCRIPTION("SiFive UART serial driver");
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Paul Walmsley <paul@pwsan.com>");
-diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
-index dce5f9dae1210..86973c3854145 100644
---- a/include/uapi/linux/serial_core.h
-+++ b/include/uapi/linux/serial_core.h
-@@ -281,4 +281,7 @@
- /* MediaTek BTIF */
- #define PORT_MTK_BTIF 117
-+/* SiFive UART */
-+#define PORT_SIFIVE_H5U       118
-+
- #endif /* _UAPILINUX_SERIAL_CORE_H */
diff --git a/target/linux/riscv64/patches/007-gpio-sifive-support-GPIO-on-SiFive-SoCs.patch b/target/linux/riscv64/patches/007-gpio-sifive-support-GPIO-on-SiFive-SoCs.patch
deleted file mode 100644 (file)
index ce41ece..0000000
+++ /dev/null
@@ -1,409 +0,0 @@
-From 28447771a2dddf9c083e1eefa5848d03e83496c7 Mon Sep 17 00:00:00 2001
-From: "Wesley W. Terpstra" <wesley@sifive.com>
-Date: Wed, 21 Feb 2018 15:43:02 -0800
-Subject: [PATCH 07/11] gpio-sifive: support GPIO on SiFive SoCs
-
----
- .../devicetree/bindings/gpio/gpio-sifive.txt       |  28 ++
- drivers/gpio/Kconfig                               |   7 +
- drivers/gpio/Makefile                              |   1 +
- drivers/gpio/gpio-sifive.c                         | 322 +++++++++++++++++++++
- 4 files changed, 358 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/gpio/gpio-sifive.txt
- create mode 100644 drivers/gpio/gpio-sifive.c
-
-diff --git a/Documentation/devicetree/bindings/gpio/gpio-sifive.txt b/Documentation/devicetree/bindings/gpio/gpio-sifive.txt
-new file mode 100644
-index 00000000..bf41eed8
---- /dev/null
-+++ b/Documentation/devicetree/bindings/gpio/gpio-sifive.txt
-@@ -0,0 +1,28 @@
-+SiFive GPIO controller bindings
-+
-+Required properties:
-+- compatible:
-+  - "sifive,gpio0"
-+- reg: Physical base address and length of the controller's registers.
-+- #gpio-cells : Should be 2
-+  - The first cell is the gpio offset number.
-+  - The second cell indicates the polarity of the GPIO
-+- gpio-controller : Marks the device node as a GPIO controller.
-+- interrupt-controller: Mark the device node as an interrupt controller
-+- #interrupt-cells : Should be 2.
-+  - The first cell is the GPIO offset number within the GPIO controller.
-+  - The second cell is the edge/level to use for interrupt generation.
-+- interrupts: Specify the interrupts, one per GPIO
-+
-+Example:
-+
-+gpio: gpio@10060000 {
-+      compatible = "sifive,gpio0";
-+      interrupt-parent = <&plic>;
-+      interrupts = <7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22>;
-+      reg = <0x0 0x10060000 0x0 0x1000>;
-+      gpio-controller;
-+      #gpio-cells = <2>;
-+      interrupt-controller;
-+      #interrupt-cells = <2>;
-+};
-diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
-index 4f52c3a8..7755f49e 100644
---- a/drivers/gpio/Kconfig
-+++ b/drivers/gpio/Kconfig
-@@ -439,6 +439,13 @@ config GPIO_REG
-         A 32-bit single register GPIO fixed in/out implementation.  This
-         can be used to represent any register as a set of GPIO signals.
-+config GPIO_SIFIVE
-+      bool "SiFive GPIO support"
-+      depends on OF_GPIO
-+      select GPIOLIB_IRQCHIP
-+      help
-+        Say yes here to support the GPIO device on SiFive SoCs.
-+
- config GPIO_SPEAR_SPICS
-       bool "ST SPEAr13xx SPI Chip Select as GPIO support"
-       depends on PLAT_SPEAR
-diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
-index c256aff6..244a3696 100644
---- a/drivers/gpio/Makefile
-+++ b/drivers/gpio/Makefile
-@@ -111,6 +111,7 @@ obj-$(CONFIG_GPIO_REG)             += gpio-reg.o
- obj-$(CONFIG_ARCH_SA1100)     += gpio-sa1100.o
- obj-$(CONFIG_GPIO_SCH)                += gpio-sch.o
- obj-$(CONFIG_GPIO_SCH311X)    += gpio-sch311x.o
-+obj-$(CONFIG_GPIO_SIFIVE)     += gpio-sifive.o
- obj-$(CONFIG_GPIO_SODAVILLE)  += gpio-sodaville.o
- obj-$(CONFIG_GPIO_SPEAR_SPICS)        += gpio-spear-spics.o
- obj-$(CONFIG_GPIO_SPRD)               += gpio-sprd.o
-diff --git a/drivers/gpio/gpio-sifive.c b/drivers/gpio/gpio-sifive.c
-new file mode 100644
-index 00000000..6482ebbc
---- /dev/null
-+++ b/drivers/gpio/gpio-sifive.c
-@@ -0,0 +1,322 @@
-+/*
-+ * SiFive GPIO driver
-+ *
-+ * Copyright (C) 2018 SiFive, Inc.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ */
-+#include <linux/bitops.h>
-+#include <linux/device.h>
-+#include <linux/errno.h>
-+#include <linux/of_irq.h>
-+#include <linux/gpio/driver.h>
-+#include <linux/irqchip/chained_irq.h>
-+#include <linux/init.h>
-+#include <linux/of.h>
-+#include <linux/pinctrl/consumer.h>
-+#include <linux/platform_device.h>
-+#include <linux/pm.h>
-+#include <linux/slab.h>
-+#include <linux/spinlock.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 MAX_GPIO      32
-+
-+struct sifive_gpio {
-+      raw_spinlock_t          lock;
-+      void __iomem            *base;
-+      struct gpio_chip        gc;
-+      unsigned long           enabled;
-+      unsigned                trigger[MAX_GPIO];
-+      unsigned int            irq_parent[MAX_GPIO];
-+      struct sifive_gpio      *self_ptr[MAX_GPIO];
-+};
-+
-+static void sifive_assign_bit(void __iomem *ptr, int offset, int value)
-+{
-+      // It's frustrating that we are not allowed to use the device atomics
-+      // which are GUARANTEED to be supported by this device on RISC-V
-+      u32 bit = BIT(offset), old = ioread32(ptr);
-+      if (value)
-+              iowrite32(old | bit, ptr);
-+      else
-+              iowrite32(old & ~bit, ptr);
-+}
-+
-+static int sifive_direction_input(struct gpio_chip *gc, unsigned offset)
-+{
-+      struct sifive_gpio *chip = gpiochip_get_data(gc);
-+      unsigned long flags;
-+
-+      if (offset >= gc->ngpio)
-+              return -EINVAL;
-+
-+      raw_spin_lock_irqsave(&chip->lock, flags);
-+      sifive_assign_bit(chip->base + GPIO_OUTPUT_EN, offset, 0);
-+      sifive_assign_bit(chip->base + GPIO_INPUT_EN,  offset, 1);
-+      raw_spin_unlock_irqrestore(&chip->lock, flags);
-+
-+      return 0;
-+}
-+
-+static int sifive_direction_output(struct gpio_chip *gc, unsigned offset, int value)
-+{
-+      struct sifive_gpio *chip = gpiochip_get_data(gc);
-+      unsigned long flags;
-+
-+      if (offset >= gc->ngpio)
-+              return -EINVAL;
-+
-+      raw_spin_lock_irqsave(&chip->lock, flags);
-+      sifive_assign_bit(chip->base + GPIO_INPUT_EN,   offset, 0);
-+      sifive_assign_bit(chip->base + GPIO_OUTPUT_VAL, offset, value);
-+      sifive_assign_bit(chip->base + GPIO_OUTPUT_EN,  offset, 1);
-+      raw_spin_unlock_irqrestore(&chip->lock, flags);
-+
-+      return 0;
-+}
-+
-+static int sifive_get_direction(struct gpio_chip *gc, unsigned offset)
-+{
-+      struct sifive_gpio *chip = gpiochip_get_data(gc);
-+
-+      if (offset >= gc->ngpio)
-+              return -EINVAL;
-+
-+      return !(ioread32(chip->base + GPIO_OUTPUT_EN) & BIT(offset));
-+}
-+
-+static int sifive_get_value(struct gpio_chip *gc, unsigned offset)
-+{
-+      struct sifive_gpio *chip = gpiochip_get_data(gc);
-+
-+      if (offset >= gc->ngpio)
-+              return -EINVAL;
-+
-+      return !!(ioread32(chip->base + GPIO_INPUT_VAL) & BIT(offset));
-+}
-+
-+static void sifive_set_value(struct gpio_chip *gc, unsigned offset, int value)
-+{
-+      struct sifive_gpio *chip = gpiochip_get_data(gc);
-+      unsigned long flags;
-+
-+      if (offset >= gc->ngpio)
-+              return;
-+
-+      raw_spin_lock_irqsave(&chip->lock, flags);
-+      sifive_assign_bit(chip->base + GPIO_OUTPUT_VAL, offset, value);
-+      raw_spin_unlock_irqrestore(&chip->lock, flags);
-+}
-+
-+static void sifive_set_ie(struct sifive_gpio *chip, int offset)
-+{
-+      unsigned long flags;
-+      unsigned trigger;
-+
-+      raw_spin_lock_irqsave(&chip->lock, flags);
-+      trigger = (chip->enabled & BIT(offset)) ? chip->trigger[offset] : 0;
-+      sifive_assign_bit(chip->base + GPIO_RISE_IE, offset, trigger & IRQ_TYPE_EDGE_RISING);
-+      sifive_assign_bit(chip->base + GPIO_FALL_IE, offset, trigger & IRQ_TYPE_EDGE_FALLING);
-+      sifive_assign_bit(chip->base + GPIO_HIGH_IE, offset, trigger & IRQ_TYPE_LEVEL_HIGH);
-+      sifive_assign_bit(chip->base + GPIO_LOW_IE,  offset, trigger & IRQ_TYPE_LEVEL_LOW);
-+      raw_spin_unlock_irqrestore(&chip->lock, flags);
-+}
-+
-+static int sifive_irq_set_type(struct irq_data *d, unsigned trigger)
-+{
-+      struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-+      struct sifive_gpio *chip = gpiochip_get_data(gc);
-+      int offset = irqd_to_hwirq(d);
-+
-+      if (offset < 0 || offset >= gc->ngpio)
-+              return -EINVAL;
-+
-+      chip->trigger[offset] = trigger;
-+      sifive_set_ie(chip, offset);
-+      return 0;
-+}
-+
-+/* chained_irq_{enter,exit} already mask the parent */
-+static void sifive_irq_mask(struct irq_data *d) { }
-+static void sifive_irq_unmask(struct irq_data *d) { }
-+
-+static void sifive_irq_enable(struct irq_data *d)
-+{
-+      struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-+      struct sifive_gpio *chip = gpiochip_get_data(gc);
-+      int offset = irqd_to_hwirq(d) % MAX_GPIO; // must not fail
-+      u32 bit = BIT(offset);
-+
-+      /* Switch to input */
-+      sifive_direction_input(gc, offset);
-+
-+      /* Clear any sticky pending interrupts */
-+      iowrite32(bit, chip->base + GPIO_RISE_IP);
-+      iowrite32(bit, chip->base + GPIO_FALL_IP);
-+      iowrite32(bit, chip->base + GPIO_HIGH_IP);
-+      iowrite32(bit, chip->base + GPIO_LOW_IP);
-+
-+      /* Enable interrupts */
-+      assign_bit(offset, &chip->enabled, 1);
-+      sifive_set_ie(chip, offset);
-+}
-+
-+static void sifive_irq_disable(struct irq_data *d)
-+{
-+      struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-+      struct sifive_gpio *chip = gpiochip_get_data(gc);
-+      int offset = irqd_to_hwirq(d) % MAX_GPIO; // must not fail
-+
-+      assign_bit(offset, &chip->enabled, 0);
-+      sifive_set_ie(chip, offset);
-+}
-+
-+static struct irq_chip sifive_irqchip = {
-+      .name           = "sifive-gpio",
-+      .irq_set_type   = sifive_irq_set_type,
-+      .irq_mask       = sifive_irq_mask,
-+      .irq_unmask     = sifive_irq_unmask,
-+      .irq_enable     = sifive_irq_enable,
-+      .irq_disable    = sifive_irq_disable,
-+};
-+
-+static void sifive_irq_handler(struct irq_desc *desc)
-+{
-+      struct irq_chip *irqchip = irq_desc_get_chip(desc);
-+      struct sifive_gpio **self_ptr = irq_desc_get_handler_data(desc);
-+      struct sifive_gpio *chip = *self_ptr;
-+      int offset = self_ptr - &chip->self_ptr[0];
-+      u32 bit = BIT(offset);
-+
-+      chained_irq_enter(irqchip, desc);
-+
-+      /* Re-arm the edge triggers so don't miss the next one */
-+      iowrite32(bit, chip->base + GPIO_RISE_IP);
-+      iowrite32(bit, chip->base + GPIO_FALL_IP);
-+
-+      generic_handle_irq(irq_find_mapping(chip->gc.irq.domain, offset));
-+
-+      /* Re-arm the level triggers after handling to prevent spurious refire */
-+      iowrite32(bit, chip->base + GPIO_HIGH_IP);
-+      iowrite32(bit, chip->base + GPIO_LOW_IP);
-+
-+      chained_irq_exit(irqchip, desc);
-+}
-+
-+static int sifive_gpio_probe(struct platform_device *pdev)
-+{
-+      struct device *dev = &pdev->dev;
-+      struct device_node *node = pdev->dev.of_node;
-+      struct sifive_gpio *chip;
-+      struct resource *res;
-+      int gpio, irq, ret, ngpio;
-+
-+      chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
-+      if (!chip) {
-+              dev_err(dev, "out of memory\n");
-+              return -ENOMEM;
-+      }
-+
-+      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+      chip->base = devm_ioremap_resource(dev, res);
-+      if (IS_ERR(chip->base)) {
-+              dev_err(dev, "failed to allocate device memory\n");
-+              return PTR_ERR(chip->base);
-+      }
-+
-+      ngpio = of_irq_count(node);
-+      if (ngpio >= MAX_GPIO) {
-+              dev_err(dev, "too many interrupts\n");
-+              return -EINVAL;
-+      }
-+
-+      raw_spin_lock_init(&chip->lock);
-+      chip->gc.direction_input = sifive_direction_input;
-+      chip->gc.direction_output = sifive_direction_output;
-+      chip->gc.get_direction = sifive_get_direction;
-+      chip->gc.get = sifive_get_value;
-+      chip->gc.set = sifive_set_value;
-+      chip->gc.base = -1;
-+      chip->gc.ngpio = ngpio;
-+      chip->gc.label = dev_name(dev);
-+      chip->gc.parent = dev;
-+      chip->gc.owner = THIS_MODULE;
-+
-+      ret = gpiochip_add_data(&chip->gc, chip);
-+      if (ret)
-+              return ret;
-+
-+      /* Disable all GPIO interrupts before enabling parent interrupts */
-+      iowrite32(0, chip->base + GPIO_RISE_IE);
-+      iowrite32(0, chip->base + GPIO_FALL_IE);
-+      iowrite32(0, chip->base + GPIO_HIGH_IE);
-+      iowrite32(0, chip->base + GPIO_LOW_IE);
-+      chip->enabled = 0;
-+
-+      ret = gpiochip_irqchip_add(&chip->gc, &sifive_irqchip, 0, handle_simple_irq, IRQ_TYPE_NONE);
-+      if (ret) {
-+              dev_err(dev, "could not add irqchip\n");
-+              gpiochip_remove(&chip->gc);
-+              return ret;
-+      }
-+
-+      chip->gc.irq.num_parents = ngpio;
-+      chip->gc.irq.parents = &chip->irq_parent[0];
-+      chip->gc.irq.map = &chip->irq_parent[0];
-+
-+      for (gpio = 0; gpio < ngpio; ++gpio) {
-+              irq = platform_get_irq(pdev, gpio);
-+              if (irq < 0) {
-+                      dev_err(dev, "invalid IRQ\n");
-+                      gpiochip_remove(&chip->gc);
-+                      return -ENODEV;
-+              }
-+
-+              chip->irq_parent[gpio] = irq;
-+              chip->self_ptr[gpio] = chip;
-+              chip->trigger[gpio] = IRQ_TYPE_LEVEL_HIGH;
-+      }
-+
-+      for (gpio = 0; gpio < ngpio; ++gpio) {
-+              irq = chip->irq_parent[gpio];
-+              irq_set_chained_handler_and_data(irq, sifive_irq_handler, &chip->self_ptr[gpio]);
-+              irq_set_parent(irq_find_mapping(chip->gc.irq.domain, gpio), irq);
-+      }
-+
-+      platform_set_drvdata(pdev, chip);
-+      dev_info(dev, "SiFive GPIO chip registered %d GPIOs\n", ngpio);
-+
-+      return 0;
-+}
-+
-+static const struct of_device_id sifive_gpio_match[] = {
-+      {
-+              .compatible = "sifive,gpio0",
-+      },
-+      { },
-+};
-+
-+static struct platform_driver sifive_gpio_driver = {
-+      .probe          = sifive_gpio_probe,
-+      .driver = {
-+              .name   = "sifive_gpio",
-+              .of_match_table = of_match_ptr(sifive_gpio_match),
-+      },
-+};
-+builtin_platform_driver(sifive_gpio_driver)
--- 
-2.7.4
-