DEVICE_TYPE:=developerboard
MAINTAINER:=Zoltan HERPAI <wigyori@uid0.hu>, Alex Guo <xfguo@xfguo.org>
-KERNEL_PATCHVER:=4.17
+KERNEL_PATCHVER:=4.18
include $(INCLUDE_DIR)/target.mk
--- /dev/null
+CONFIG_64BIT=y
+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
+CONFIG_ARCH_HAS_PTE_SPECIAL=y
+# CONFIG_ARCH_RV32I is not set
+CONFIG_ARCH_RV64I=y
+CONFIG_ARCH_WANT_FRAME_POINTERS=y
+# CONFIG_ASIX_PHY is not set
+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_ATH5K_PCI is not set
+# CONFIG_AUTOFS_FS is not set
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_MQ_PCI=y
+CONFIG_BLK_MQ_VIRTIO=y
+CONFIG_BLK_SCSI_REQUEST=y
+# CONFIG_BPFILTER is not set
+CONFIG_CAVIUM_PTP=y
+CONFIG_CC_HAS_SANCOV_TRACE_PC=y
+CONFIG_CC_HAS_STACKPROTECTOR_NONE=y
+CONFIG_CC_IS_GCC=y
+CONFIG_CLANG_VERSION=0
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_CLZ_TAB=y
+CONFIG_CMDLINE="earlyprintk root=/dev/mmcblk0p2 rootwait"
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMODEL_MEDANY=y
+# CONFIG_CMODEL_MEDLOW is not set
+CONFIG_COMMON_CLK=y
+# CONFIG_COMMON_CLK_SI544 is not set
+CONFIG_COMPAT_BRK=y
+CONFIG_COREDUMP=y
+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
+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_AEAD=y
+CONFIG_CRYPTO_AEAD2=y
+# CONFIG_CRYPTO_AEGIS128 is not set
+# CONFIG_CRYPTO_AEGIS128L is not set
+# CONFIG_CRYPTO_AEGIS256 is not set
+CONFIG_CRYPTO_AKCIPHER=y
+CONFIG_CRYPTO_AKCIPHER2=y
+# CONFIG_CRYPTO_CFB is not set
+CONFIG_CRYPTO_CRC32C=y
+CONFIG_CRYPTO_DRBG=y
+CONFIG_CRYPTO_DRBG_HMAC=y
+CONFIG_CRYPTO_DRBG_MENU=y
+CONFIG_CRYPTO_ECHAINIV=y
+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_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_MORUS1280 is not set
+# CONFIG_CRYPTO_MORUS640 is not set
+CONFIG_CRYPTO_NULL=y
+CONFIG_CRYPTO_NULL2=y
+CONFIG_CRYPTO_RNG=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_RNG_DEFAULT=y
+CONFIG_CRYPTO_RSA=y
+CONFIG_CRYPTO_SHA256=y
+# CONFIG_CRYPTO_SM3 is not set
+# CONFIG_CRYPTO_SM4 is not set
+# CONFIG_CRYPTO_SPECK is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_ZSTD is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_FS is not set
+CONFIG_DEBUG_SECTION_MISMATCH=y
+CONFIG_DECOMPRESS_GZIP=y
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEVMEM=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_DMA_DIRECT_OPS=y
+CONFIG_DNOTIFY=y
+# CONFIG_DP83822_PHY is not set
+# CONFIG_DP83TC811_PHY is not set
+CONFIG_DTC=y
+CONFIG_E1000E=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_ELF_CORE=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_EXPORTFS=y
+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_FIXED_PHY=y
+CONFIG_FRAME_POINTER=y
+CONFIG_FRAME_WARN=2048
+CONFIG_FS_IOMAP=y
+CONFIG_FS_MBCACHE=y
+CONFIG_FUTEX_PI=y
+CONFIG_GCC_VERSION=80100
+# CONFIG_GEMINI_ETHERNET is not set
+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_PCI_IOMAP=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_GPIOLIB_FASTPATH_LIMIT=512
+# CONFIG_GPIO_HLWD is not set
+# CONFIG_GPIO_MAX3191X is not set
+# CONFIG_GPIO_MB86S7X is not set
+# CONFIG_GPIO_PCIE_IDIO_24 is not set
+# CONFIG_GUP_BENCHMARK is not set
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+CONFIG_HAVE_64BIT_ALIGNED_ACCESS=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_CLK_PREPARE=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
+CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
+CONFIG_HAVE_NET_DSA=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
+CONFIG_HID=y
+# CONFIG_HID_ELAN is not set
+CONFIG_HID_GENERIC=y
+# CONFIG_HID_GOOGLE_HAMMER is not set
+# CONFIG_HID_JABRA is not set
+# CONFIG_HID_REDRAGON is not set
+# CONFIG_HID_STEAM is not set
+CONFIG_HVC_DRIVER=y
+CONFIG_HVC_RISCV_SBI=y
+CONFIG_HZ_PERIODIC=y
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_HELPER_AUTO=y
+CONFIG_I2C_OCORES=y
+# CONFIG_ICE is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_INPUT=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_WORK=y
+CONFIG_JBD2=y
+CONFIG_KALLSYMS=y
+CONFIG_KEYS=y
+# CONFIG_LAN743X is not set
+# CONFIG_LEDS_CR0014114 is not set
+# CONFIG_LEDS_LM3692X is not set
+# CONFIG_LEDS_MLXREG is not set
+# CONFIG_LEDS_TRIGGER_ACTIVITY is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+CONFIG_LIBFDT=y
+CONFIG_LOCALVERSION_AUTO=y
+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_DEVICE=y
+# CONFIG_MDIO_MSCC_MIIM is not set
+CONFIG_MEMFD_CREATE=y
+# CONFIG_MICROCHIP_T1_PHY is not set
+CONFIG_MICROSEMI_PHY=y
+# CONFIG_MISC_RTSX_PCI is not set
+# CONFIG_MISC_RTSX_USB is not set
+CONFIG_MMC=y
+CONFIG_MMC_BLOCK=y
+# CONFIG_MMC_CQHCI is not set
+CONFIG_MMC_SPI=y
+# CONFIG_MMC_TIFM_SD is not set
+CONFIG_MODULES_USE_ELF_RELA=y
+CONFIG_MODULE_SECTIONS=y
+CONFIG_MPILIB=y
+CONFIG_MQ_IOSCHED_DEADLINE=y
+CONFIG_MQ_IOSCHED_KYBER=y
+CONFIG_MTD_M25P80=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_MTD_SPI_NOR_USE_4K_SECTORS=y
+# CONFIG_MTK_MMC is not set
+CONFIG_NAMESPACES=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NET_FAILOVER=y
+CONFIG_NET_FLOW_LIMIT=y
+CONFIG_NET_NS=y
+CONFIG_NET_PACKET_ENGINE=y
+CONFIG_NET_PTP_CLASSIFY=y
+# CONFIG_NET_SCH_CBS is not set
+CONFIG_NET_VENDOR_CORTINA=y
+CONFIG_NET_VENDOR_MICROSEMI=y
+CONFIG_NET_VENDOR_NI=y
+CONFIG_NET_VENDOR_SOCIONEXT=y
+CONFIG_NLS=y
+CONFIG_NO_BOOTMEM=y
+CONFIG_NR_CPUS=8
+CONFIG_NVMEM=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_OID_REGISTRY=y
+CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y
+# CONFIG_OVERLAY_FS_XINO_AUTO is not set
+CONFIG_PADATA=y
+CONFIG_PAGE_OFFSET=0xffffffe000000000
+CONFIG_PANIC_TIMEOUT=0
+CONFIG_PCI=y
+# CONFIG_PCIE_CADENCE_HOST is not set
+CONFIG_PCI_DEBUG=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_DOMAINS_GENERIC=y
+CONFIG_PCI_MSI=y
+CONFIG_PGTABLE_LEVELS=3
+CONFIG_PHYLIB=y
+CONFIG_PHYS_ADDR_T_64BIT=y
+# CONFIG_PHY_MAPPHONE_MDM6600 is not set
+CONFIG_PID_NS=y
+CONFIG_PKCS7_MESSAGE_PARSER=y
+CONFIG_PLUGIN_HOSTCC=""
+CONFIG_PPS=y
+CONFIG_PRINTK_TIME=y
+CONFIG_PTP_1588_CLOCK=y
+CONFIG_PWM=y
+CONFIG_PWM_SYSFS=y
+CONFIG_R8169=y
+CONFIG_RATIONAL=y
+CONFIG_RCU_NEED_SEGCBLIST=y
+CONFIG_RCU_STALL_COMMON=y
+CONFIG_RCU_TRACE=y
+CONFIG_RD_GZIP=y
+CONFIG_REGMAP=y
+CONFIG_REGMAP_I2C=y
+CONFIG_REGMAP_SPI=y
+# CONFIG_RENESAS_PHY is not set
+CONFIG_RFKILL_LEDS=y
+CONFIG_RFS_ACCEL=y
+CONFIG_RISCV=y
+CONFIG_RISCV_INTC=y
+CONFIG_RISCV_ISA_A=y
+CONFIG_RISCV_ISA_C=y
+CONFIG_RISCV_PLIC=y
+CONFIG_RISCV_TIMER=y
+# CONFIG_RPMSG_VIRTIO is not set
+CONFIG_RPS=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DRV_ISL12026 is not set
+# CONFIG_RTC_DRV_PCF85363 is not set
+CONFIG_RTC_I2C_AND_SPI=y
+# CONFIG_RUNTIME_TESTING_MENU is not set
+CONFIG_SATA_AHCI=y
+CONFIG_SATA_MOBILE_LPM_POLICY=0
+CONFIG_SATA_PMP=y
+CONFIG_SATA_SIL24=y
+CONFIG_SCHED_DEBUG=y
+CONFIG_SCSI=y
+# CONFIG_SECONDARY_TRUSTED_KEYRING is not set
+CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SGL_ALLOC=y
+CONFIG_SG_POOL=y
+# CONFIG_SIOX is not set
+# CONFIG_SLIMBUS is not set
+CONFIG_SLUB_DEBUG=y
+CONFIG_SMP=y
+# CONFIG_SOUNDWIRE is not set
+CONFIG_SPARSE_IRQ=y
+CONFIG_SPI=y
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_MASTER=y
+CONFIG_SPI_MEM=y
+CONFIG_SRCU=y
+CONFIG_STACKTRACE=y
+CONFIG_SWIOTLB=y
+CONFIG_SWPHY=y
+CONFIG_SYSCTL_EXCEPTION_TRACE=y
+CONFIG_SYSFS_SYSCALL=y
+# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set
+CONFIG_SYSTEM_TRUSTED_KEYRING=y
+CONFIG_THREAD_INFO_IN_TASK=y
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TIMER_OF=y
+CONFIG_TIMER_PROBE=y
+CONFIG_TRACE_CLOCK=y
+CONFIG_TREE_RCU=y
+CONFIG_TREE_SRCU=y
+CONFIG_TUNE_GENERIC=y
+# CONFIG_TYPEC is not set
+CONFIG_UEVENT_HELPER_PATH=""
+# CONFIG_UNISYSSPAR is not set
+CONFIG_USB=y
+CONFIG_USB_COMMON=y
+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_DBGCAP 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_VGA_ARB=y
+CONFIG_VGA_ARB_MAX_GPUS=16
+CONFIG_VIRTIO=y
+CONFIG_VIRTIO_BLK=y
+CONFIG_VIRTIO_CONSOLE=y
+CONFIG_VIRTIO_MENU=y
+CONFIG_VIRTIO_MMIO=y
+# CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES is not set
+CONFIG_VIRTIO_NET=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_WLAN_VENDOR_ADMTEK=y
+CONFIG_WLAN_VENDOR_ATH=y
+CONFIG_WLAN_VENDOR_ATMEL=y
+CONFIG_WLAN_VENDOR_BROADCOM=y
+CONFIG_WLAN_VENDOR_CISCO=y
+CONFIG_WLAN_VENDOR_INTEL=y
+CONFIG_WLAN_VENDOR_INTERSIL=y
+CONFIG_WLAN_VENDOR_MARVELL=y
+CONFIG_WLAN_VENDOR_MEDIATEK=y
+CONFIG_WLAN_VENDOR_QUANTENNA=y
+CONFIG_WLAN_VENDOR_RALINK=y
+CONFIG_WLAN_VENDOR_REALTEK=y
+CONFIG_WLAN_VENDOR_RSI=y
+CONFIG_WLAN_VENDOR_ST=y
+CONFIG_WLAN_VENDOR_TI=y
+CONFIG_WLAN_VENDOR_ZYDAS=y
+CONFIG_X509_CERTIFICATE_PARSER=y
+# CONFIG_XDP_SOCKETS is not set
+# CONFIG_XILINX_VCU is not set
+CONFIG_XPS=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZONE_DMA32=y
--- /dev/null
+config RISCV64_SD_BOOT_PARTSIZE
+ int "Boot (SD Card) filesystem partition size (in MB)"
+ depends on TARGET_riscv64
+ default 32
+
#
-# Copyright (C) 2007-2015 OpenWrt.org
+# Copyright (C) 2010 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
-
-JFFS2_BLOCKSIZE=256k
-
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/image.mk
+#define Build/Clean
+# $(MAKE) -C bbl clean
+#endef
+
+#define Build/Compile
+# $(MAKE) -C bbl compile
+#endef
define Image/Prepare
- $(LINUX_DIR)/scripts/dtc/dtc -O dtb -R 4 -S 0x20000 $(DTS_DIR)/canyonlands.dts > $(KDIR)/openwrt-canyonlands.dtb
+ # sneak in a cleanup here
+ $(MAKE) -C bbl clean
+ cp $(KDIR)/vmlinux.elf $(BIN_DIR)/$(IMG_PREFIX)-vmlinux.elf
endef
-define Image/BuildKernel
- cp $(KDIR)/uImage $(BIN_DIR)/$(IMG_PREFIX)-uImage
+define Image/Build/riscv-sdcard
+ ./gen_riscv64_sdcard_img.sh \
+ $(BIN_DIR)/sdcard.img \
+ $(BIN_DIR)/bbl.bin \
+ $(KDIR)/root.$(1) \
+ $(CONFIG_RISCV64_SD_BOOT_PARTSIZE) \
+ $(CONFIG_TARGET_ROOTFS_PARTSIZE)
+# $(STAGING_DIR_IMAGE)/$(DEVICE_NAME)-u-boot-with-spl.bin
endef
define Image/Build
- $(call Image/Build/$(1),$(1))
-endef
-
-define Image/Build/jffs2-256k
- ( \
- dd if=$(KDIR)/uImage bs=2048k conv=sync; \
- dd if=$(KDIR)/root.$(1) bs=256k conv=sync; \
- ) > $(BIN_DIR)/$(IMG_PREFIX)-jffs2.img
-endef
-
-define Image/Build/squashfs
- $(call prepare_generic_squashfs,$(KDIR)/root.squashfs)
- ( \
- dd if=$(KDIR)/cuImage.taishan bs=256k conv=sync; \
- dd if=$(KDIR)/root.$(1) bs=256k conv=sync; \
- ) > $(BIN_DIR)/$(IMG_PREFIX)-taishan-$(1).img
- ( \
- dd if=$(KDIR)/uImage bs=1920k conv=sync; \
- dd if=$(KDIR)/openwrt-canyonlands.dtb bs=128k conv=sync; \
- dd if=$(KDIR)/root.$(1) bs=256k conv=sync; \
- ) > $(BIN_DIR)/$(IMG_PREFIX)-canyonlands-$(1).img
+ echo "BUILD: $(1)"
+ echo "PROFILE: $(PROFILE)"
+ $(MAKE) -C bbl compile
+# cp $(BIN_DIR)/bbl.bin
+# cp $(KDIR)/root.$(1) $(BIN_DIR)/$(IMG_PREFIX)-$(1).img
+ $(call Image/Build/riscv-sdcard,$(1),$(IMG_PREFIX)-$(PROFILE)-sdcard.img)
+
+# rm -f $@.boot
endef
$(eval $(call BuildImage))
--- /dev/null
+#
+# Copyright (C) 2018 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=bbl
+PKG_RELEASE:=1
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_DATE:=2018-08-16
+PKG_SOURCE_URL:=https://github.com/riscv/riscv-pk.git
+PKG_SOURCE_VERSION:=706cc77c369fd3e4734b5a6aa813d421347f1814
+PKG_MIRROR_HASH:=440a1544258caca1edc1b7d8e89c085438fdcbe010465b5d55ff93b01dd519f3
+
+include $(INCLUDE_DIR)/package.mk
+
+CONFIGURE_ARGS += \
+ --enable-logo \
+ --with-arch=rv64imafdc \
+ --with-abi=lp64d \
+ --with-payload=$(KERNEL_BUILD_DIR)/vmlinux \
+ --prefix=$(KERNEL_BUILD_DIR) \
+ --srcdir=..
+
+define Build/Configure
+ mkdir -p $(PKG_BUILD_DIR)/work
+ (cd $(PKG_BUILD_DIR)/work; ../configure $(CONFIGURE_ARGS) );
+endef
+
+#mabi=lp64d -march=rv64imafdc
+
+define Build/Compile
+ $(MAKE) -C $(PKG_BUILD_DIR)/work bbl
+ $(TARGET_CROSS)objcopy -S -O binary --change-addresses -0x80000000 $(PKG_BUILD_DIR)/work/bbl $(BIN_DIR)/bbl.bin
+endef
+
+$(eval $(call Build/DefaultTargets))
--- /dev/null
+--- a/Makefile.in.old 2018-08-15 11:46:11.000000000 +0200
++++ b/Makefile.in 2018-08-16 19:50:21.961398086 +0200
+@@ -61,7 +61,8 @@
+ march := -march=@WITH_ARCH@
+ endif
+ is_32bit := $(findstring 32,$(march))
+-mabi := -mabi=$(if $(is_32bit),ilp32,lp64)
++#mabi := -mabi=$(if $(is_32bit),ilp32,lp64)
++mabi := @WITH_ABI@
+
+ # Installation directories
+
--- /dev/null
+--- a/configure.ac.old 2018-08-15 11:46:11.000000000 +0200
++++ b/configure.ac 2018-08-16 19:52:37.140188650 +0200
+@@ -83,6 +83,9 @@
+ AC_ARG_WITH([arch], AS_HELP_STRING([--with-arch], [Set the RISC-V architecture]),
+ [AC_SUBST([WITH_ARCH], $with_arch, [Specify architecture to build the project])])
+
++AC_ARG_WITH([abi], AS_HELP_STRING([--with-abi], [Set the RISC-V ABI]),
++ [AC_SUBST([WITH_ABI], $with_abi, [Specify ABI to build the project])])
++
+ AC_ARG_ENABLE([print-device-tree], AS_HELP_STRING([--enable-print-device-tree], [Print DTS when booting]))
+ AS_IF([test "x$enable_print_device_tree" == "xyes"], [
+ AC_DEFINE([PK_PRINT_DEVICE_TREE],,[Define if the DTS is to be displayed])
--- /dev/null
+--- a/Makefile.in.old 2018-08-15 11:46:11.000000000 +0200
++++ b/Makefile.in 2018-08-16 19:50:21.961398086 +0200
+@@ -61,7 +61,8 @@
+ march := -march=@WITH_ARCH@
+ endif
+ is_32bit := $(findstring 32,$(march))
+-mabi := -mabi=$(if $(is_32bit),ilp32,lp64)
++#mabi := -mabi=$(if $(is_32bit),ilp32,lp64)
++mabi := -mabi=lp64d
+
+ # Installation directories
+
--- /dev/null
+#!/usr/bin/env bash
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+set -ex
+[ $# -eq 5 ] || {
+ echo "SYNTAX: $0 <file> <bbl image> <rootfs image> <bbl size> <rootfs size> <u-boot image>"
+ exit 1
+}
+
+BBL_UUID="2E54B353-1271-4842-806F-E436D6AF6985"
+LINUX_UUID="0FC63DAF-8483-4772-8E79-3D69D8477DE4"
+
+OUTPUT="$1"
+BOOTFS="$2"
+ROOTFS="$3"
+BOOTFSSIZE="$4"
+ROOTFSSIZE="$5"
+#UBOOT="$6"
+
+FULLSIZE="$(($BOOTFSSIZE+$ROOTFSSIZE+1))"
+echo "Full size is: ${FULLSIZE}M"
+
+ROOTFSOFFSET="$(($BOOTFSSIZE*1048576 / 512 + 2048))"
+echo "Rootfs offset is: $ROOTFSOFFSET"
+
+dd if=/dev/zero of=$OUTPUT bs=1M count=$FULLSIZE
+
+sgdisk --clear \
+ --new=1:2048:${BOOTFSSIZE}M --change-name=1:bootloader --typecode=1:${BBL_UUID} \
+ --new=2:${ROOTFSOFFSET}: --change-name=2:root --typecode=2:${LINUX_UUID} \
+ $OUTPUT
+
+dd bs=512 if="$BOOTFS" of="$OUTPUT" seek=2048 conv=notrunc
+dd bs=512 if="$ROOTFS" of="$OUTPUT" seek="$ROOTFSOFFSET" conv=notrunc
--- /dev/null
+From 6de0b16fb7a2cea47e9a75534b4ec59f36998616 Mon Sep 17 00:00:00 2001
+From: "Wesley W. Terpstra" <wesley@sifive.com>
+Date: Fri, 12 May 2017 16:01:18 -0700
+Subject: [PATCH 01/11] base: fix order of OF initialization
+
+This fixes: [ 0.010000] cpu cpu0: Error -2 creating of_node link
+... which you get for every CPU on all architectures with a OF cpu/ node.
+
+This affects riscv, nios, etc.
+
+Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>
+---
+ drivers/base/init.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/base/init.c b/drivers/base/init.c
+index dd85b05..908e652 100644
+--- a/drivers/base/init.c
++++ b/drivers/base/init.c
+@@ -30,9 +30,9 @@ void __init driver_init(void)
+ /* These are also core pieces, but must come after the
+ * core core pieces.
+ */
++ of_core_init();
+ platform_bus_init();
+ cpu_dev_init();
+ memory_dev_init();
+ container_dev_init();
+- of_core_init();
+ }
+--
+2.1.4
+
--- /dev/null
+From 7866ef38a00cd390596a67e19d23d8ffd6058732 Mon Sep 17 00:00:00 2001
+From: Palmer Dabbelt <palmer@sifive.com>
+Date: Tue, 21 Nov 2017 15:29:07 -0800
+Subject: [PATCH 02/11] dt-bindings: Correct RISC-V's timebase-frequency
+
+Someone must have read the device tree specification incorrectly,
+because we were putting timebase-frequency in the wrong place. This
+corrects the issue, moving it from
+
+/ {
+ cpus {
+ timebase-frequency = X;
+ }
+}
+
+to
+
+/ {
+ cpus {
+ cpu@0 {
+ timebase-frequency = X;
+ }
+ }
+}
+
+This is great, because the timer's frequency should really be a per-cpu
+quantity on RISC-V systems since there's a timer per CPU. This should
+lead to some cleanups in our timer driver.
+
+CC: Wesley Terpstra <wesley@sifive.com>
+Signed-off-by: Palmer Dabbelt <palmer@sifive.com>
+---
+ Documentation/devicetree/bindings/riscv/cpus.txt | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/Documentation/devicetree/bindings/riscv/cpus.txt b/Documentation/devicetree/bindings/riscv/cpus.txt
+index adf7b7a..b0b038d 100644
+--- a/Documentation/devicetree/bindings/riscv/cpus.txt
++++ b/Documentation/devicetree/bindings/riscv/cpus.txt
+@@ -93,9 +93,9 @@ Linux is allowed to run on.
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+- timebase-frequency = <1000000>;
+ cpu@0 {
+ clock-frequency = <1600000000>;
++ timebase-frequency = <1000000>;
+ compatible = "sifive,rocket0", "riscv";
+ device_type = "cpu";
+ i-cache-block-size = <64>;
+@@ -113,6 +113,7 @@ Linux is allowed to run on.
+ };
+ cpu@1 {
+ clock-frequency = <1600000000>;
++ timebase-frequency = <1000000>;
+ compatible = "sifive,rocket0", "riscv";
+ d-cache-block-size = <64>;
+ d-cache-sets = <64>;
+@@ -145,6 +146,7 @@ Example: Spike ISA Simulator with 1 Hart
+ This device tree matches the Spike ISA golden model as run with `spike -p1`.
+
+ cpus {
++ timebase-frequency = <1000000>;
+ cpu@0 {
+ device_type = "cpu";
+ reg = <0x00000000>;
+--
+2.1.4
+
--- /dev/null
+From fd7aef2aae3b2d250f0c04224b3c85646c2e9c56 Mon Sep 17 00:00:00 2001
+From: Palmer Dabbelt <palmer@sifive.com>
+Date: Mon, 20 Nov 2017 11:26:36 -0800
+Subject: [PATCH 03/11] dt-bindings: Add an enable method to RISC-V
+
+RISC-V doesn't currently specify a mechanism for enabling or disabling
+CPUs. Instead, we assume that all CPUs are enabled on boot, and if
+someone wants to save power we instead put a CPU to sleep via a WFI
+loop. Future systems may have an explicit mechanism for putting a CPU
+to sleep, so we're standardizing the device tree entry for when that
+happens.
+
+We're not defining a spin-table based interface to the firmware, as the
+plan is to handle this entirely within the kernel instead.
+
+CC: Mark Rutland <mark.rutland@arm.com>
+Signed-off-by: Palmer Dabbelt <palmer@sifive.com>
+---
+ Documentation/devicetree/bindings/riscv/cpus.txt | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/Documentation/devicetree/bindings/riscv/cpus.txt b/Documentation/devicetree/bindings/riscv/cpus.txt
+index b0b038d..6aa9cd0 100644
+--- a/Documentation/devicetree/bindings/riscv/cpus.txt
++++ b/Documentation/devicetree/bindings/riscv/cpus.txt
+@@ -82,6 +82,15 @@ described below.
+ Value type: <string>
+ Definition: Contains the RISC-V ISA string of this hart. These
+ ISA strings are defined by the RISC-V ISA manual.
++ - cpu-enable-method:
++ Usage: optional
++ Value type: <stringlist>
++ Definition: When absent, default is either "always-disabled"
++ "always-enabled", depending on the current state
++ of the CPU.
++ Must be one of:
++ * "always-disabled": This CPU cannot be enabled.
++ * "always-enabled": This CPU cannot be disabled.
+
+ Example: SiFive Freedom U540G Development Kit
+ ---------------------------------------------
+--
+2.1.4
+
--- /dev/null
+From 577949829e04d23f58ef4ad5c448689c2ed70a49 Mon Sep 17 00:00:00 2001
+From: Palmer Dabbelt <palmer@dabbelt.com>
+Date: Fri, 8 Dec 2017 15:10:35 -0800
+Subject: [PATCH 04/11] RISC-V: Add early printk support via the SBI console
+
+This code lives entirely within the RISC-V arch code. I've left it
+within an "#ifdef CONFIG_EARLY_PRINTK" despite always having
+EARLY_PRINTK support on RISC-V just in case someone wants to remove
+it.
+
+Signed-off-by: Palmer Dabbelt <palmer@sifive.com>
+---
+ arch/riscv/kernel/setup.c | 27 +++++++++++++++++++++++++++
+ 1 file changed, 27 insertions(+)
+
+diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c
+index f0d2070..2e56af3 100644
+--- a/arch/riscv/kernel/setup.c
++++ b/arch/riscv/kernel/setup.c
+@@ -39,6 +39,27 @@
+ #include <asm/tlbflush.h>
+ #include <asm/thread_info.h>
+
++#ifdef CONFIG_EARLY_PRINTK
++static void sbi_console_write(struct console *co, const char *buf,
++ unsigned int n)
++{
++ int i;
++
++ for (i = 0; i < n; ++i) {
++ if (buf[i] == '\n')
++ sbi_console_putchar('\r');
++ sbi_console_putchar(buf[i]);
++ }
++}
++
++struct console riscv_sbi_early_console_dev __initdata = {
++ .name = "early",
++ .write = sbi_console_write,
++ .flags = CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME,
++ .index = -1
++};
++#endif
++
+ #ifdef CONFIG_DUMMY_CONSOLE
+ struct screen_info screen_info = {
+ .orig_video_lines = 30,
+@@ -195,6 +216,12 @@ static void __init setup_bootmem(void)
+
+ void __init setup_arch(char **cmdline_p)
+ {
++#ifdef CONFIG_EARLY_PRINTK
++ if (likely(!early_console)) {
++ early_console = &riscv_sbi_early_console_dev;
++ register_console(early_console);
++ }
++#endif
+ *cmdline_p = boot_command_line;
+
+ parse_early_param();
+--
+2.1.4
+
--- /dev/null
+From b3b48cbc8a19fc3e3abd3ae9b5d271c12a1a0b87 Mon Sep 17 00:00:00 2001
+From: Christoph Hellwig <hch@lst.de>
+Date: Wed, 25 Jul 2018 08:11:13 +0200
+Subject: [PATCH 05/11] RISC-V: simplify software interrupt / IPI code
+
+Rename handle_ipi to riscv_software_interrupt, drop the unused return
+value and provide a stub for the !SMP build. This allows simplifying
+the upcoming interrupt controller driver by not providing a wrapper
+for it.
+
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+---
+ arch/riscv/include/asm/smp.h | 13 +++++++++++--
+ arch/riscv/kernel/smp.c | 6 ++----
+ 2 files changed, 13 insertions(+), 6 deletions(-)
+
+diff --git a/arch/riscv/include/asm/smp.h b/arch/riscv/include/asm/smp.h
+index 85e4220..80ecb95 100644
+--- a/arch/riscv/include/asm/smp.h
++++ b/arch/riscv/include/asm/smp.h
+@@ -44,8 +44,17 @@ void arch_send_call_function_single_ipi(int cpu);
+ */
+ #define raw_smp_processor_id() (*((int*)((char*)get_current() + TASK_TI_CPU)))
+
+-/* Interprocessor interrupt handler */
+-irqreturn_t handle_ipi(void);
++/* Software interrupt handler */
++void riscv_software_interrupt(void);
++
++#else /* CONFIG_SMP */
++
++/*
++ * We currently only use software interrupts to pass inter-processor
++ * interrupts, so if a non-SMP system gets a software interrupt then we
++ * don't know what to do.
++ */
++#define riscv_software_interrupt() WARN_ON()
+
+ #endif /* CONFIG_SMP */
+
+diff --git a/arch/riscv/kernel/smp.c b/arch/riscv/kernel/smp.c
+index 6d39624..906fe21 100644
+--- a/arch/riscv/kernel/smp.c
++++ b/arch/riscv/kernel/smp.c
+@@ -45,7 +45,7 @@ int setup_profiling_timer(unsigned int multiplier)
+ return -EINVAL;
+ }
+
+-irqreturn_t handle_ipi(void)
++void riscv_software_interrupt(void)
+ {
+ unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits;
+
+@@ -60,7 +60,7 @@ irqreturn_t handle_ipi(void)
+
+ ops = xchg(pending_ipis, 0);
+ if (ops == 0)
+- return IRQ_HANDLED;
++ return;
+
+ if (ops & (1 << IPI_RESCHEDULE))
+ scheduler_ipi();
+@@ -73,8 +73,6 @@ irqreturn_t handle_ipi(void)
+ /* Order data access and bit testing. */
+ mb();
+ }
+-
+- return IRQ_HANDLED;
+ }
+
+ static void
+--
+2.1.4
+
--- /dev/null
+From 422e21b7ab41a21d7342b01fea7d1c6b91d986d8 Mon Sep 17 00:00:00 2001
+From: Christoph Hellwig <hch@lst.de>
+Date: Wed, 25 Jul 2018 08:23:21 +0200
+Subject: [PATCH 06/11] RISC-V: remove INTERRUPT_CAUSE_* defines from asm/irq.h
+
+These are only of use to the local irq controller driver, so add them in
+that driver implementation instead, which will be submitted soon.
+
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+---
+ arch/riscv/include/asm/irq.h | 4 ----
+ 1 file changed, 4 deletions(-)
+
+diff --git a/arch/riscv/include/asm/irq.h b/arch/riscv/include/asm/irq.h
+index 4dee9d4..93eb75e 100644
+--- a/arch/riscv/include/asm/irq.h
++++ b/arch/riscv/include/asm/irq.h
+@@ -17,10 +17,6 @@
+
+ #define NR_IRQS 0
+
+-#define INTERRUPT_CAUSE_SOFTWARE 1
+-#define INTERRUPT_CAUSE_TIMER 5
+-#define INTERRUPT_CAUSE_EXTERNAL 9
+-
+ void riscv_timer_interrupt(void);
+
+ #include <asm-generic/irq.h>
+--
+2.1.4
+
--- /dev/null
+From e07e6be7ef8b44155aebac95dde19a39498ebd00 Mon Sep 17 00:00:00 2001
+From: Palmer Dabbelt <palmer@dabbelt.com>
+Date: Tue, 19 Jun 2018 17:34:53 +0200
+Subject: [PATCH 07/11] irqchip: RISC-V Local Interrupt Controller Driver
+
+This patch adds a driver that manages the local interrupts on each
+RISC-V hart, as specifiec by the RISC-V supervisor level ISA manual.
+The local interrupt controller manages software interrupts, timer
+interrupts, and hardware interrupts (which are routed via the
+platform level interrupt controller). Per-hart local interrupt
+controllers are found on all RISC-V systems.
+
+Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>
+[hch: Kconfig simplifications, various cleanups]
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+---
+ drivers/irqchip/Kconfig | 4 +
+ drivers/irqchip/Makefile | 1 +
+ drivers/irqchip/irq-riscv-intc.c | 197 +++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 202 insertions(+)
+ create mode 100644 drivers/irqchip/irq-riscv-intc.c
+
+diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
+index e9233db..8460fdce 100644
+--- a/drivers/irqchip/Kconfig
++++ b/drivers/irqchip/Kconfig
+@@ -372,3 +372,7 @@ config QCOM_PDC
+ IRQs for Qualcomm Technologies Inc (QTI) mobile chips.
+
+ endmenu
++
++config RISCV_INTC
++ def_bool y
++ depends on RISCV
+diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
+index 15f268f..74e333c 100644
+--- a/drivers/irqchip/Makefile
++++ b/drivers/irqchip/Makefile
+@@ -87,3 +87,4 @@ obj-$(CONFIG_MESON_IRQ_GPIO) += irq-meson-gpio.o
+ obj-$(CONFIG_GOLDFISH_PIC) += irq-goldfish-pic.o
+ obj-$(CONFIG_NDS32) += irq-ativic32.o
+ obj-$(CONFIG_QCOM_PDC) += qcom-pdc.o
++obj-$(CONFIG_RISCV_INTC) += irq-riscv-intc.o
+diff --git a/drivers/irqchip/irq-riscv-intc.c b/drivers/irqchip/irq-riscv-intc.c
+new file mode 100644
+index 0000000..883efaa
+--- /dev/null
++++ b/drivers/irqchip/irq-riscv-intc.c
+@@ -0,0 +1,197 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2012 Regents of the University of California
++ * Copyright (C) 2017 SiFive
++ */
++#include <linux/irq.h>
++#include <linux/irqchip.h>
++#include <linux/irqdomain.h>
++#include <linux/interrupt.h>
++#include <linux/of.h>
++#include <linux/smp.h>
++#include <asm/sbi.h>
++
++#define NR_RISCV_IRQS (8 * sizeof(uintptr_t))
++
++/*
++ * Possible interrupt causes:
++ */
++#define INTERRUPT_CAUSE_SOFTWARE 1
++#define INTERRUPT_CAUSE_TIMER 5
++#define INTERRUPT_CAUSE_EXTERNAL 9
++
++/*
++ * The high order bit of the trap cause register is always set for
++ * interrupts, which allows us to differentiate them from exceptions
++ * quickly. The INTERRUPT_CAUSE_* macros don't contain that bit, so we
++ * need to mask it off.
++ */
++#define INTERRUPT_CAUSE_MASK (1UL << (NR_RISCV_IRQS - 1))
++
++struct riscv_irq_data {
++ struct irq_chip chip;
++ struct irq_domain *domain;
++ int hart;
++ char name[20];
++};
++
++static DEFINE_PER_CPU(struct riscv_irq_data, riscv_irq_data);
++
++static void riscv_intc_irq(struct pt_regs *regs)
++{
++ struct pt_regs *old_regs = set_irq_regs(regs);
++ unsigned long cause = csr_read(scause);
++ struct irq_domain *domain;
++
++ WARN_ON((cause & INTERRUPT_CAUSE_MASK) == 0);
++ cause &= ~INTERRUPT_CAUSE_MASK;
++
++ irq_enter();
++
++ /*
++ * There are three classes of interrupt: timer, software, and
++ * external devices. We dispatch between them here. External
++ * device interrupts use the generic IRQ mechanisms.
++ */
++ switch (cause) {
++ case INTERRUPT_CAUSE_TIMER:
++ riscv_timer_interrupt();
++ break;
++ case INTERRUPT_CAUSE_SOFTWARE:
++ riscv_software_interrupt();
++ break;
++ default:
++ domain = per_cpu(riscv_irq_data, smp_processor_id()).domain;
++ generic_handle_irq(irq_find_mapping(domain, cause));
++ break;
++ }
++
++ irq_exit();
++ set_irq_regs(old_regs);
++}
++
++static int riscv_irqdomain_map(struct irq_domain *d, unsigned int irq,
++ irq_hw_number_t hwirq)
++{
++ struct riscv_irq_data *data = d->host_data;
++
++ irq_set_chip_and_handler(irq, &data->chip, handle_simple_irq);
++ irq_set_chip_data(irq, data);
++ irq_set_noprobe(irq);
++ irq_set_affinity(irq, cpumask_of(data->hart));
++ return 0;
++}
++
++static const struct irq_domain_ops riscv_irqdomain_ops = {
++ .map = riscv_irqdomain_map,
++ .xlate = irq_domain_xlate_onecell,
++};
++
++/*
++ * On RISC-V systems local interrupts are masked or unmasked by writing the SIE
++ * (Supervisor Interrupt Enable) CSR. As CSRs can only be written on the local
++ * hart, these functions can only be called on the hart that corresponds to the
++ * IRQ chip. They are only called internally to this module, so they BUG_ON if
++ * this condition is violated rather than attempting to handle the error by
++ * forwarding to the target hart, as that's already expected to have been done.
++ */
++static void riscv_irq_mask(struct irq_data *d)
++{
++ struct riscv_irq_data *data = irq_data_get_irq_chip_data(d);
++
++ BUG_ON(smp_processor_id() != data->hart);
++ csr_clear(sie, 1 << d->hwirq);
++}
++
++static void riscv_irq_unmask(struct irq_data *d)
++{
++ struct riscv_irq_data *data = irq_data_get_irq_chip_data(d);
++
++ BUG_ON(smp_processor_id() != data->hart);
++ csr_set(sie, 1 << d->hwirq);
++}
++
++/* Callbacks for twiddling SIE on another hart. */
++static void riscv_irq_enable_helper(void *d)
++{
++ riscv_irq_unmask(d);
++}
++
++static void riscv_irq_disable_helper(void *d)
++{
++ riscv_irq_mask(d);
++}
++
++static void riscv_remote_ctrl(unsigned int cpu, void (*fn)(void *d),
++ struct irq_data *data)
++{
++ smp_call_function_single(cpu, fn, data, true);
++}
++
++static void riscv_irq_enable(struct irq_data *d)
++{
++ struct riscv_irq_data *data = irq_data_get_irq_chip_data(d);
++
++ /*
++ * It's only possible to write SIE on the current hart. This jumps
++ * over to the target hart if it's not the current one. It's invalid
++ * to write SIE on a hart that's not currently running.
++ */
++ if (data->hart == smp_processor_id())
++ riscv_irq_unmask(d);
++ else if (cpu_online(data->hart))
++ riscv_remote_ctrl(data->hart, riscv_irq_enable_helper, d);
++ else
++ WARN_ON_ONCE(1);
++}
++
++static void riscv_irq_disable(struct irq_data *d)
++{
++ struct riscv_irq_data *data = irq_data_get_irq_chip_data(d);
++
++ /*
++ * It's only possible to write SIE on the current hart. This jumps
++ * over to the target hart if it's not the current one. It's invalid
++ * to write SIE on a hart that's not currently running.
++ */
++ if (data->hart == smp_processor_id())
++ riscv_irq_mask(d);
++ else if (cpu_online(data->hart))
++ riscv_remote_ctrl(data->hart, riscv_irq_disable_helper, d);
++ else
++ WARN_ON_ONCE(1);
++}
++
++static int __init riscv_intc_init(struct device_node *node,
++ struct device_node *parent)
++{
++ struct riscv_irq_data *data;
++ int hart;
++
++ hart = riscv_of_processor_hart(node->parent);
++ if (hart < 0)
++ return -EIO;
++
++ data = &per_cpu(riscv_irq_data, hart);
++ snprintf(data->name, sizeof(data->name), "riscv,cpu_intc,%d", hart);
++ data->hart = hart;
++ data->chip.name = data->name;
++ data->chip.irq_mask = riscv_irq_mask;
++ data->chip.irq_unmask = riscv_irq_unmask;
++ data->chip.irq_enable = riscv_irq_enable;
++ data->chip.irq_disable = riscv_irq_disable;
++ data->domain = irq_domain_add_linear(node, NR_RISCV_IRQS,
++ &riscv_irqdomain_ops, data);
++ if (!data->domain)
++ goto error_add_linear;
++
++ set_handle_irq(&riscv_intc_irq);
++ pr_info("%s: %lu local interrupts mapped\n", data->name, NR_RISCV_IRQS);
++ return 0;
++
++error_add_linear:
++ pr_warn("%s: unable to add IRQ domain\n", data->name);
++ return -ENXIO;
++}
++
++IRQCHIP_DECLARE(riscv, "riscv,cpu-intc", riscv_intc_init);
+--
+2.1.4
+
--- /dev/null
+From 1da2fd31207d1687f5edc6ba8f0402bbecc423f2 Mon Sep 17 00:00:00 2001
+From: Palmer Dabbelt <palmer@dabbelt.com>
+Date: Mon, 26 Jun 2017 22:07:50 -0700
+Subject: [PATCH 08/11] dt-bindings: interrupt-controller: RISC-V local
+ interrupt controller docs
+
+This patch adds documentation on the RISC-V local interrupt controller,
+which is a per-hart interrupt controller that manages all interrupts
+entering a RISC-V hart. This interrupt controller is present on all
+RISC-V systems.
+
+Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>
+---
+ .../interrupt-controller/riscv,cpu-intc.txt | 41 ++++++++++++++++++++++
+ 1 file changed, 41 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/interrupt-controller/riscv,cpu-intc.txt
+
+diff --git a/Documentation/devicetree/bindings/interrupt-controller/riscv,cpu-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/riscv,cpu-intc.txt
+new file mode 100644
+index 0000000..61900e2
+--- /dev/null
++++ b/Documentation/devicetree/bindings/interrupt-controller/riscv,cpu-intc.txt
+@@ -0,0 +1,41 @@
++RISC-V Hart-Level Interrupt Controller (HLIC)
++---------------------------------------------
++
++RISC-V cores include Control Status Registers (CSRs) which are local to each
++hart and can be read or written by software. Some of these CSRs are used to
++control local interrupts connected to the core. Every interrupt is ultimately
++routed through a hart's HLIC before it interrupts that hart.
++
++The RISC-V supervisor ISA manual specifies three interrupt sources that are
++attached to every HLIC: software interrupts, the timer interrupt, and external
++interrupts. Software interrupts are used to send IPIs between cores. The
++timer interrupt comes from an architecturally mandated real-time timer that is
++controller via SBI calls and CSR reads. External interrupts connect all other
++device interrupts to the HLIC, which are routed via the platform-level
++interrupt controller (PLIC).
++
++All RISC-V systems that conform to the supervisor ISA specification are
++required to have a HLIC with these three interrupt sources present. Since the
++interrupt map is defined by the ISA it's not listed in the HLIC's device tree
++entry, though external interrupt controllers (like the PLIC, for example) will
++need to define how their interrupts map to the relevant HLICs.
++
++Required properties:
++- compatible : "riscv,cpu-intc"
++- #interrupt-cells : should be <1>
++- interrupt-controller : Identifies the node as an interrupt controller
++
++Furthermore, this interrupt-controller MUST be embedded inside the cpu
++definition of the hart whose CSRs control these local interrupts.
++
++An example device tree entry for a HLIC is show below.
++
++ cpu1: cpu@1 {
++ compatible = "riscv";
++ ...
++ cpu1-intc: interrupt-controller {
++ #interrupt-cells = <1>;
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ };
++ };
+--
+2.1.4
+
--- /dev/null
+From 8e3e7dfba04d314cfbade03237a3ec16f436b779 Mon Sep 17 00:00:00 2001
+From: Palmer Dabbelt <palmer@dabbelt.com>
+Date: Tue, 19 Jun 2018 18:10:08 +0200
+Subject: [PATCH 09/11] irqchip: New RISC-V PLIC Driver
+
+This patch adds a driver for the Platform Level Interrupt Controller
+(PLIC) specified as part of the RISC-V supervisor level ISA manual.
+The PLIC connects global interrupt sources to the local interrupt
+controller on each hart.
+
+Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>
+[hch: various cleanups, fixed typos, added SPDX tag]
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+---
+ drivers/irqchip/Kconfig | 13 ++
+ drivers/irqchip/Makefile | 1 +
+ drivers/irqchip/irq-riscv-plic.c | 295 +++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 309 insertions(+)
+ create mode 100644 drivers/irqchip/irq-riscv-plic.c
+
+diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
+index 8460fdce..d1afac8 100644
+--- a/drivers/irqchip/Kconfig
++++ b/drivers/irqchip/Kconfig
+@@ -376,3 +376,16 @@ endmenu
+ config RISCV_INTC
+ def_bool y
+ depends on RISCV
++
++config RISCV_PLIC
++ bool "Platform-Level Interrupt Controller"
++ depends on RISCV
++ default y
++ help
++ This enables support for the PLIC chip found in standard RISC-V
++ systems. The PLIC controls devices interrupts and connects them to
++ each core's local interrupt controller. Aside from timer and
++ software interrupts, all other interrupt sources (MSI, GPIO, etc)
++ are subordinate to the PLIC.
++
++ If you don't know what to do here, say Y.
+diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
+index 74e333c..7954f4c 100644
+--- a/drivers/irqchip/Makefile
++++ b/drivers/irqchip/Makefile
+@@ -88,3 +88,4 @@ obj-$(CONFIG_GOLDFISH_PIC) += irq-goldfish-pic.o
+ obj-$(CONFIG_NDS32) += irq-ativic32.o
+ obj-$(CONFIG_QCOM_PDC) += qcom-pdc.o
+ obj-$(CONFIG_RISCV_INTC) += irq-riscv-intc.o
++obj-$(CONFIG_RISCV_PLIC) += irq-riscv-plic.o
+diff --git a/drivers/irqchip/irq-riscv-plic.c b/drivers/irqchip/irq-riscv-plic.c
+new file mode 100644
+index 0000000..7b80b73
+--- /dev/null
++++ b/drivers/irqchip/irq-riscv-plic.c
+@@ -0,0 +1,295 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2017 SiFive
++ */
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/irq.h>
++#include <linux/irqchip.h>
++#include <linux/irqchip/chained_irq.h>
++#include <linux/irqdomain.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/of_irq.h>
++#include <linux/platform_device.h>
++#include <linux/spinlock.h>
++
++/*
++ * From the RISC-V Priviledged Spec v1.10:
++ *
++ * Global interrupt sources are assigned small unsigned integer identifiers,
++ * beginning at the value 1. An interrupt ID of 0 is reserved to mean "no
++ * interrupt". Interrupt identifiers are also used to break ties when two or
++ * more interrupt sources have the same assigned priority. Smaller values of
++ * interrupt ID take precedence over larger values of interrupt ID.
++ *
++ * While the RISC-V supervisor spec doesn't define the maximum number of
++ * devices supported by the PLIC, the largest number supported by devices
++ * marked as 'riscv,plic0' (which is the only device type this driver supports,
++ * and is the only extant PLIC as of now) is 1024. As mentioned above, device
++ * 0 is defined to be non-existent so this device really only supports 1023
++ * devices.
++ */
++#define MAX_DEVICES 1024
++#define MAX_CONTEXTS 15872
++
++struct plic_handler {
++ bool present;
++ int contextid;
++ struct plic_data *data;
++};
++
++/*
++ * PLIC devices are named like 'riscv,plic0,%llx', this is enough space to
++ * store that name.
++ */
++#define PLIC_DATA_NAME_SIZE 30
++
++struct plic_data {
++ struct irq_chip chip;
++ struct irq_domain *domain;
++ u32 ndev;
++ void __iomem *reg;
++ int handlers;
++ struct plic_handler *handler;
++ char name[PLIC_DATA_NAME_SIZE];
++ spinlock_t lock;
++};
++
++/*
++ * Each interrupt source has a priority register associated with it.
++ * We always hardwire it to one in Linux.
++ */
++static inline u32 __iomem *plic_priority(struct plic_data *data, int hwirq)
++{
++ return data->reg + hwirq * 0x04;
++}
++
++/*
++ * Each hart context has a vector of interrupt enable bits associated with it.
++ * There is one bit for each interrupt source.
++ */
++static inline u32 __iomem *plic_enable_vector(struct plic_data *data,
++ int contextid)
++{
++ return data->reg + (1 << 13) + contextid * 0x80;
++}
++
++/*
++ * Each hart context has a set of control registers associated with it. Right
++ * now there's only two: a source priority threshold over which the hart will
++ * take an interrupt, and a register to claim interrupts.
++ */
++#define CONTEXT_THRESHOLD 0
++#define CONTEXT_CLAIM 4
++
++static inline u32 __iomem *plic_hart_data(struct plic_data *data,
++ int contextid)
++{
++ return data->reg + (1 << 21) + contextid * 0x1000;
++}
++
++/* Explicit interrupt masking. */
++static void plic_disable(struct plic_data *data, int contextid, int hwirq)
++{
++ u32 __iomem *reg = plic_enable_vector(data, contextid) + (hwirq / 32);
++ u32 mask = ~(1 << (hwirq % 32));
++
++ spin_lock(&data->lock);
++ writel(readl(reg) & mask, reg);
++ spin_unlock(&data->lock);
++}
++
++static void plic_enable(struct plic_data *data, int contextid, int hwirq)
++{
++ u32 __iomem *reg = plic_enable_vector(data, contextid) + (hwirq / 32);
++ u32 bit = 1 << (hwirq % 32);
++
++ spin_lock(&data->lock);
++ writel(readl(reg) | bit, reg);
++ spin_unlock(&data->lock);
++}
++
++/*
++ * There is no need to mask/unmask PLIC interrupts
++ * They are "masked" by reading claim and "unmasked" when writing it back.
++ */
++static void plic_irq_mask(struct irq_data *d)
++{
++}
++
++static void plic_irq_unmask(struct irq_data *d)
++{
++}
++
++static void plic_irq_enable(struct irq_data *d)
++{
++ struct plic_data *data = irq_data_get_irq_chip_data(d);
++ int i;
++
++ writel(1, plic_priority(data, d->hwirq));
++ for (i = 0; i < data->handlers; ++i)
++ if (data->handler[i].present)
++ plic_enable(data, i, d->hwirq);
++}
++
++static void plic_irq_disable(struct irq_data *d)
++{
++ struct plic_data *data = irq_data_get_irq_chip_data(d);
++ int i;
++
++ writel(0, plic_priority(data, d->hwirq));
++ for (i = 0; i < data->handlers; ++i)
++ if (data->handler[i].present)
++ plic_disable(data, i, d->hwirq);
++}
++
++static int plic_irqdomain_map(struct irq_domain *d, unsigned int irq,
++ irq_hw_number_t hwirq)
++{
++ struct plic_data *data = d->host_data;
++
++ irq_set_chip_and_handler(irq, &data->chip, handle_simple_irq);
++ irq_set_chip_data(irq, data);
++ irq_set_noprobe(irq);
++ return 0;
++}
++
++static const struct irq_domain_ops plic_irqdomain_ops = {
++ .map = plic_irqdomain_map,
++ .xlate = irq_domain_xlate_onecell,
++};
++
++/*
++ * Handling an interrupt is a two-step process: first you claim the interrupt
++ * by reading the claim register, then you complete the interrupt by writing
++ * that source ID back to the same claim register. This automatically enables
++ * and disables the interrupt, so there's nothing else to do.
++ */
++static void plic_chained_handle_irq(struct irq_desc *desc)
++{
++ struct plic_handler *handler = irq_desc_get_handler_data(desc);
++ struct irq_chip *chip = irq_desc_get_chip(desc);
++ struct irq_domain *domain = handler->data->domain;
++ void __iomem *ph = plic_hart_data(handler->data, handler->contextid);
++ u32 what;
++
++ chained_irq_enter(chip, desc);
++ while ((what = readl(ph + CONTEXT_CLAIM))) {
++ int irq = irq_find_mapping(domain, what);
++
++ if (irq > 0)
++ generic_handle_irq(irq);
++ else
++ handle_bad_irq(desc);
++ writel(what, ph + CONTEXT_CLAIM);
++ }
++ chained_irq_exit(chip, desc);
++}
++
++static int plic_init(struct device_node *node, struct device_node *parent)
++{
++ struct plic_data *data;
++ struct resource resource;
++ int i, ok = 0;
++ int out = -1;
++
++ data = kzalloc(sizeof(*data), GFP_KERNEL);
++ if (WARN_ON(!data))
++ return -ENOMEM;
++
++ spin_lock_init(&data->lock);
++
++ data->reg = of_iomap(node, 0);
++ if (WARN_ON(!data->reg)) {
++ out = -EIO;
++ goto free_data;
++ }
++
++ of_property_read_u32(node, "riscv,ndev", &data->ndev);
++ if (WARN_ON(!data->ndev)) {
++ out = -EINVAL;
++ goto free_reg;
++ }
++
++ data->handlers = of_irq_count(node);
++ if (WARN_ON(!data->handlers)) {
++ out = -EINVAL;
++ goto free_reg;
++ }
++
++ data->handler =
++ kcalloc(data->handlers, sizeof(*data->handler), GFP_KERNEL);
++ if (WARN_ON(!data->handler)) {
++ out = -ENOMEM;
++ goto free_reg;
++ }
++
++ data->domain = irq_domain_add_linear(node, data->ndev + 1,
++ &plic_irqdomain_ops, data);
++ if (WARN_ON(!data->domain)) {
++ out = -ENOMEM;
++ goto free_handler;
++ }
++
++ of_address_to_resource(node, 0, &resource);
++ snprintf(data->name, sizeof(data->name),
++ "riscv,plic0,%llx", resource.start);
++ data->chip.name = data->name;
++ data->chip.irq_mask = plic_irq_mask;
++ data->chip.irq_unmask = plic_irq_unmask;
++ data->chip.irq_enable = plic_irq_enable;
++ data->chip.irq_disable = plic_irq_disable;
++
++ for (i = 0; i < data->handlers; ++i) {
++ struct plic_handler *handler = &data->handler[i];
++ struct of_phandle_args parent;
++ int parent_irq, hwirq;
++
++ handler->present = false;
++
++ if (of_irq_parse_one(node, i, &parent))
++ continue;
++ /* skip context holes */
++ if (parent.args[0] == -1)
++ continue;
++
++ /* skip any contexts that lead to inactive harts */
++ if (of_device_is_compatible(parent.np, "riscv,cpu-intc") &&
++ parent.np->parent &&
++ riscv_of_processor_hart(parent.np->parent) < 0)
++ continue;
++
++ parent_irq = irq_create_of_mapping(&parent);
++ if (!parent_irq)
++ continue;
++
++ handler->present = true;
++ handler->contextid = i;
++ handler->data = data;
++ /* hwirq prio must be > this to trigger an interrupt */
++ writel(0, plic_hart_data(data, i) + CONTEXT_THRESHOLD);
++
++ for (hwirq = 1; hwirq <= data->ndev; ++hwirq)
++ plic_disable(data, i, hwirq);
++ irq_set_chained_handler_and_data(parent_irq,
++ plic_chained_handle_irq, handler);
++ ++ok;
++ }
++
++ pr_info("%s: mapped %d interrupts to %d/%d handlers\n",
++ data->name, data->ndev, ok, data->handlers);
++ WARN_ON(!ok);
++ return 0;
++
++free_handler:
++ kfree(data->handler);
++free_reg:
++ iounmap(data->reg);
++free_data:
++ kfree(data);
++ return out;
++}
++
++IRQCHIP_DECLARE(plic0, "riscv,plic0", plic_init);
+--
+2.1.4
+
--- /dev/null
+From 634a87822bc9939c99068e72612e3c5df40bff18 Mon Sep 17 00:00:00 2001
+From: Palmer Dabbelt <palmer@dabbelt.com>
+Date: Mon, 26 Jun 2017 22:09:07 -0700
+Subject: [PATCH 10/11] dt-bindings: interrupt-controller: RISC-V PLIC
+ documentation
+
+This patch adds documentation for the platform-level interrupt
+controller (PLIC) found in all RISC-V systems. This interrupt
+controller routes interrupts from all the devices in the system to each
+hart-local interrupt controller.
+
+Note: the DTS bindings for the PLIC aren't set in stone yet, as we might
+want to change how we're specifying holes in the hart list.
+
+Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>
+---
+ .../bindings/interrupt-controller/riscv,plic0.txt | 55 ++++++++++++++++++++++
+ 1 file changed, 55 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/interrupt-controller/riscv,plic0.txt
+
+diff --git a/Documentation/devicetree/bindings/interrupt-controller/riscv,plic0.txt b/Documentation/devicetree/bindings/interrupt-controller/riscv,plic0.txt
+new file mode 100644
+index 0000000..99cd359
+--- /dev/null
++++ b/Documentation/devicetree/bindings/interrupt-controller/riscv,plic0.txt
+@@ -0,0 +1,55 @@
++RISC-V Platform-Level Interrupt Controller (PLIC)
++-------------------------------------------------
++
++The RISC-V supervisor ISA specification allows for the presence of a
++platform-level interrupt controller (PLIC). The PLIC connects all external
++interrupts in the system to all hart contexts in the system, via the external
++interrupt source in each hart's hart-local interrupt controller (HLIC). A hart
++context is a privilege mode in a hardware execution thread. For example, in
++an 4 core system with 2-way SMT, you have 8 harts and probably at least two
++privilege modes per hart; machine mode and supervisor mode.
++
++Each interrupt can be enabled on per-context basis. Any context can claim
++a pending enabled interrupt and then release it once it has been handled.
++
++Each interrupt has a configurable priority. Higher priority interrupts are
++serviced firs. Each context can specify a priority threshold. Interrupts
++with priority below this threshold will not cause the PLIC to raise its
++interrupt line leading to the context.
++
++While the PLIC supports both edge-triggered and level-triggered interrupts,
++interrupt handlers are oblivious to this distinction and therefor it is not
++specific in the PLIC device-tree binding.
++
++While the RISC-V ISA doesn't specify a memory layout for the PLIC, the
++"riscv,plic0" device is a concrete implementation of the PLIC that contains a
++specific memory layout. More details about the memory layout of the
++"riscv,plic0" device can be found as a comment in the device driver, or as part
++of the SiFive U5 Coreplex Series Manual (page 22 of the PDF of version 1.0)
++<https://www.sifive.com/documentation/coreplex/u5-coreplex-series-manual/>
++
++Required properties:
++- compatible : "riscv,plic0"
++- #address-cells : should be <0>
++- #interrupt-cells : should be <1>
++- interrupt-controller : Identifies the node as an interrupt controller
++- reg : Should contain 1 register range (address and length)
++- interrupts-extended : Specifies which contexts are connected to the PLIC,
++ with "-1" specifying that a context is not present.
++
++Example:
++
++ plic: interrupt-controller@c000000 {
++ #address-cells = <0>;
++ #interrupt-cells = <1>;
++ compatible = "riscv,plic0";
++ interrupt-controller;
++ interrupts-extended = <
++ &cpu0-intc 11
++ &cpu1-intc 11 &cpu1-intc 9
++ &cpu2-intc 11 &cpu2-intc 9
++ &cpu3-intc 11 &cpu3-intc 9
++ &cpu4-intc 11 &cpu4-intc 9>;
++ reg = <0xc000000 0x4000000>;
++ riscv,ndev = <10>;
++ };
+--
+2.1.4
+
--- /dev/null
+From 406087706427cdd610ce2dc3fbffa655064944d3 Mon Sep 17 00:00:00 2001
+From: Palmer Dabbelt <palmer@dabbelt.com>
+Date: Tue, 19 Jun 2018 17:36:28 +0200
+Subject: [PATCH 11/11] clocksource: new RISC-V SBI timer driver
+
+The RISC-V ISA defines a per-hart real-time clock and timer, which is
+present on all systems. The clock is accessed via the 'rdtime'
+pseudo-instruction (which reads a CSR), and the timer is set via an SBI
+call.
+
+Signed-off-by: Dmitriy Cherkasov <dmitriy@oss-tech.org>
+Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>
+[hch: remove dead code, add SPDX tags, minor cleanups]
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+---
+ arch/riscv/include/asm/timer.h | 7 +++
+ arch/riscv/kernel/time.c | 9 +---
+ drivers/clocksource/Kconfig | 10 ++++
+ drivers/clocksource/Makefile | 1 +
+ drivers/clocksource/riscv_timer.c | 97 +++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 116 insertions(+), 8 deletions(-)
+ create mode 100644 arch/riscv/include/asm/timer.h
+ create mode 100644 drivers/clocksource/riscv_timer.c
+
+diff --git a/arch/riscv/include/asm/timer.h b/arch/riscv/include/asm/timer.h
+new file mode 100644
+index 0000000..ae20dd9
+--- /dev/null
++++ b/arch/riscv/include/asm/timer.h
+@@ -0,0 +1,7 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++#ifndef _ASM_RISCV_TIMER_H
++#define _ASM_RISCV_TIMER_H
++
++DECLARE_PER_CPU(struct clock_event_device, riscv_clock_event);
++
++#endif /* _ASM_RISCV_TIMER_H */
+diff --git a/arch/riscv/kernel/time.c b/arch/riscv/kernel/time.c
+index 2463fcc..bba28fc 100644
+--- a/arch/riscv/kernel/time.c
++++ b/arch/riscv/kernel/time.c
+@@ -16,19 +16,13 @@
+ #include <linux/clockchips.h>
+ #include <linux/delay.h>
+
+-#ifdef CONFIG_RISCV_TIMER
+-#include <linux/timer_riscv.h>
+-#endif
+-
+ #include <asm/sbi.h>
++#include <asm/timer.h>
+
+ unsigned long riscv_timebase;
+
+-DECLARE_PER_CPU(struct clock_event_device, riscv_clock_event);
+-
+ void riscv_timer_interrupt(void)
+ {
+-#ifdef CONFIG_RISCV_TIMER
+ /*
+ * FIXME: This needs to be cleaned up along with the rest of the IRQ
+ * handling cleanup. See irq.c for more details.
+@@ -36,7 +30,6 @@ void riscv_timer_interrupt(void)
+ struct clock_event_device *evdev = this_cpu_ptr(&riscv_clock_event);
+
+ evdev->event_handler(evdev);
+-#endif
+ }
+
+ void __init init_clockevent(void)
+diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
+index dec0dd8..a57083e 100644
+--- a/drivers/clocksource/Kconfig
++++ b/drivers/clocksource/Kconfig
+@@ -609,4 +609,14 @@ config ATCPIT100_TIMER
+ help
+ This option enables support for the Andestech ATCPIT100 timers.
+
++config RISCV_TIMER
++ bool "Timer for the RISC-V platform"
++ depends on RISCV || COMPILE_TEST
++ select TIMER_PROBE
++ select TIMER_OF
++ help
++ This enables the per-hart timer built into all RISC-V systems, which
++ is accessed via both the SBI and the rdcycle instruction. This is
++ required for all RISC-V systems.
++
+ endmenu
+diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
+index 00caf37..ded31f7 100644
+--- a/drivers/clocksource/Makefile
++++ b/drivers/clocksource/Makefile
+@@ -78,3 +78,4 @@ obj-$(CONFIG_H8300_TPU) += h8300_tpu.o
+ obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o
+ obj-$(CONFIG_X86_NUMACHIP) += numachip.o
+ obj-$(CONFIG_ATCPIT100_TIMER) += timer-atcpit100.o
++obj-$(CONFIG_RISCV_TIMER) += riscv_timer.o
+diff --git a/drivers/clocksource/riscv_timer.c b/drivers/clocksource/riscv_timer.c
+new file mode 100644
+index 0000000..48196b2
+--- /dev/null
++++ b/drivers/clocksource/riscv_timer.c
+@@ -0,0 +1,97 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2012 Regents of the University of California
++ * Copyright (C) 2017 SiFive
++ */
++#include <linux/clocksource.h>
++#include <linux/clockchips.h>
++#include <linux/delay.h>
++#include <asm/sbi.h>
++#include <asm/timer.h>
++
++#define MINDELTA 100
++#define MAXDELTA 0x7fffffff
++
++/*
++ * All RISC-V systems have a timer attached to every hart. These timers can be
++ * read by the 'rdcycle' pseudo instruction, and can use the SBI to setup
++ * events. In order to abstract the architecture-specific timer reading and
++ * setting functions away from the clock event insertion code, we provide
++ * function pointers to the clockevent subsystem that perform two basic
++ * operations: rdtime() reads the timer on the current CPU, and
++ * next_event(delta) sets the next timer event to 'delta' cycles in the future.
++ * As the timers are inherently a per-cpu resource, these callbacks perform
++ * operations on the current hart. There is guaranteed to be exactly one timer
++ * per hart on all RISC-V systems.
++ */
++//DECLARE_PER_CPU(struct clocksource, riscv_clocksource);
++
++static int next_event(unsigned long delta, struct clock_event_device *ce)
++{
++ /*
++ * time_init() allocates a timer for each CPU. Since we're writing the
++ * timer comparison register here we can't allow the timers to cross
++ * harts.
++ */
++ BUG_ON(ce != this_cpu_ptr(&riscv_clock_event));
++ sbi_set_timer(get_cycles64() + delta);
++ return 0;
++}
++
++DEFINE_PER_CPU(struct clock_event_device, riscv_clock_event) = {
++ .name = "riscv_timer_clockevent",
++ .features = CLOCK_EVT_FEAT_ONESHOT,
++ .rating = 100,
++ .set_next_event = next_event,
++};
++
++/*
++ * It is guarnteed that all the timers across all the harts are synchronized
++ * within one tick of each other, so while this could technically go
++ * backwards when hopping between CPUs, practically it won't happen.
++ */
++static unsigned long long rdtime(struct clocksource *cs)
++{
++ return get_cycles64();
++}
++
++DEFINE_PER_CPU(struct clocksource, riscv_clocksource) = {
++ .name = "riscv_clocksource",
++ .rating = 300,
++ .mask = CLOCKSOURCE_MASK(BITS_PER_LONG),
++ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
++ .read = rdtime,
++};
++
++static int hart_of_timer(struct device_node *dev)
++{
++ u32 hart;
++
++ if (!dev)
++ return -1;
++ if (!of_device_is_compatible(dev, "riscv"))
++ return -1;
++ if (of_property_read_u32(dev, "reg", &hart))
++ return -1;
++
++ return hart;
++}
++
++static int timer_riscv_init_dt(struct device_node *n)
++{
++ int cpu_id = hart_of_timer(n);
++ struct clock_event_device *ce = per_cpu_ptr(&riscv_clock_event, cpu_id);
++ struct clocksource *cs = per_cpu_ptr(&riscv_clocksource, cpu_id);
++
++ if (cpu_id == smp_processor_id()) {
++ clocksource_register_hz(cs, riscv_timebase);
++
++ ce->cpumask = cpumask_of(cpu_id);
++ clockevents_config_and_register(ce, riscv_timebase,
++ MINDELTA, MAXDELTA);
++ }
++
++ return 0;
++}
++
++TIMER_OF_DECLARE(riscv_timer, "riscv", timer_riscv_init_dt);
+--
+2.1.4
+