MAINTAINER:=Zoltan HERPAI <wigyori@uid0.hu>
KERNEL_PATCHVER:=4.19
+KERNEL_TESTING_PATCHVER:=5.4
include $(INCLUDE_DIR)/target.mk
--- /dev/null
+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
+++ /dev/null
-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
-
+++ /dev/null
-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/
+++ /dev/null
-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);
+++ /dev/null
-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");
+++ /dev/null
-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 */
+++ /dev/null
-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 */
+++ /dev/null
-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
-