瀏覽代碼

linux-mainline: Update to the 5.2 kernel release

Update to the 5.2 kernel release. This includes a large number of
upstream patches for the Unleashed. Due to the large defconfig changes
let's drop the 5.1 support when we upgrade.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Alistair Francis 4 年之前
父節點
當前提交
246f51d9b0
共有 19 個文件被更改,包括 1231 次插入3632 次删除
  1. 1 0
      recipes-kernel/linux/files/0001-Revert-riscv-Use-latest-system-call-ABI.patch
  2. 39 0
      recipes-kernel/linux/files/freedom-u540/0001-macb-bindings-doc-add-sifive-fu540-c000-binding.patch
  3. 0 1174
      recipes-kernel/linux/files/freedom-u540/0001-tty-serial-add-driver-for-the-SiFive-UART.patch
  4. 0 236
      recipes-kernel/linux/files/freedom-u540/0002-gemgxl-mgmt-implement-clock-switch-for-GEM-tx_clk.patch
  5. 189 0
      recipes-kernel/linux/files/freedom-u540/0002-macb-Add-support-for-SiFive-FU540-C000.patch
  6. 62 0
      recipes-kernel/linux/files/freedom-u540/0003-riscv-dts-Add-DT-node-for-SiFive-FU540-Ethernet-cont.patch
  7. 0 63
      recipes-kernel/linux/files/freedom-u540/0003-u54-prci-driver-for-core-U54-clocks.patch
  8. 821 0
      recipes-kernel/linux/files/freedom-u540/0004-PCI-microsemi-Add-host-driver-for-Microsemi-PCIe-con.patch
  9. 0 333
      recipes-kernel/linux/files/freedom-u540/0004-u54-prci-driver-for-core-U54-clocks.patch
  10. 50 0
      recipes-kernel/linux/files/freedom-u540/0005-Microsemi-PCIe-expansion-board-DT-entry.patch
  11. 0 409
      recipes-kernel/linux/files/freedom-u540/0005-gpio-sifive-support-GPIO-on-SiFive-SoCs.patch
  12. 5 4
      recipes-kernel/linux/files/freedom-u540/0006-HACK-Revert-of-device-Really-only-set-bus-DMA-mask-w.patch
  13. 0 342
      recipes-kernel/linux/files/freedom-u540/0006-pwm-sifive-add-a-driver-for-SiFive-SoC-PWM.patch
  14. 1 0
      recipes-kernel/linux/files/freedom-u540/0007-HACK-radeon-Don-t-set-PCI-DMA-mask.patch
  15. 0 39
      recipes-kernel/linux/files/freedom-u540/0007-RISC-V-Networking-fix-Hack.patch
  16. 0 829
      recipes-kernel/linux/files/freedom-u540/0008-pcie-microsemi-Add-support-for-the-Vera-board-root-c.patch
  17. 31 169
      recipes-kernel/linux/files/freedom-u540/defconfig
  18. 0 34
      recipes-kernel/linux/linux-mainline_5.1.bb
  19. 32 0
      recipes-kernel/linux/linux-mainline_5.2.bb

+ 1 - 0
recipes-kernel/linux/files/0001-Revert-riscv-Use-latest-system-call-ABI.patch

@@ -10,6 +10,7 @@ so let's revert it. This revert can be reverted when the glibc
 submission is updated to work on the 5.1 kernel.
 
 Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
+Upstream-Status: Inappropriate [enable feature]
 ---
  arch/riscv/Kconfig                   | 1 +
  arch/riscv/include/uapi/asm/unistd.h | 5 ++++-

+ 39 - 0
recipes-kernel/linux/files/freedom-u540/0001-macb-bindings-doc-add-sifive-fu540-c000-binding.patch

@@ -0,0 +1,39 @@
+From a4a5f99e31e85a6f159c62f224e826ed38f027e9 Mon Sep 17 00:00:00 2001
+From: Yash Shah <yash.shah@sifive.com>
+Date: Tue, 18 Jun 2019 13:26:07 +0530
+Subject: [PATCH 1/6] macb: bindings doc: add sifive fu540-c000 binding
+
+Add the compatibility string documentation for SiFive FU540-C0000
+interface.
+On the FU540, this driver also needs to read and write registers in a
+management IP block that monitors or drives boundary signals for the
+GEMGXL IP block that are not directly mapped to GEMGXL registers.
+Therefore, add additional range to "reg" property for SiFive GEMGXL
+management IP registers.
+
+Signed-off-by: Yash Shah <yash.shah@sifive.com>
+Reviewed-by: Paul Walmsley <paul.walmsley@sifive.com>
+Upstream-Status: Accepted [5.3]
+---
+ Documentation/devicetree/bindings/net/macb.txt | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/Documentation/devicetree/bindings/net/macb.txt b/Documentation/devicetree/bindings/net/macb.txt
+index 9c5e94482b5f..63c73fafe26d 100644
+--- a/Documentation/devicetree/bindings/net/macb.txt
++++ b/Documentation/devicetree/bindings/net/macb.txt
+@@ -15,8 +15,11 @@ Required properties:
+   Use "atmel,sama5d4-gem" for the GEM IP (10/100) available on Atmel sama5d4 SoCs.
+   Use "cdns,zynq-gem" Xilinx Zynq-7xxx SoC.
+   Use "cdns,zynqmp-gem" for Zynq Ultrascale+ MPSoC.
++  Use "sifive,fu540-macb" for SiFive FU540-C000 SoC.
+   Or the generic form: "cdns,emac".
+ - reg: Address and length of the register set for the device
++	For "sifive,fu540-macb", second range is required to specify the
++	address and length of the registers for GEMGXL Management block.
+ - interrupts: Should contain macb interrupt
+ - phy-mode: See ethernet.txt file in the same directory.
+ - clock-names: Tuple listing input clock names.
+-- 
+2.22.0
+

+ 0 - 1174
recipes-kernel/linux/files/freedom-u540/0001-tty-serial-add-driver-for-the-SiFive-UART.patch

@@ -1,1174 +0,0 @@
-From 322175de5296868fa55aa911ea7ba936a985a29a Mon Sep 17 00:00:00 2001
-From: Paul Walmsley <paul.walmsley@sifive.com>
-Date: Sat, 20 Oct 2018 03:10:47 -0700
-Subject: [PATCH 01/10] tty: serial: add driver for the SiFive UART
-
-Add a serial driver for the SiFive UART, found on SiFive FU540 devices
-(among others).
-
-The underlying serial IP block is relatively basic, and currently does
-not support serial break detection.  Further information on the IP
-block can be found in the documentation and Chisel sources:
-
-https://static.dev.sifive.com/FU540-C000-v1.0.pdf
-
-https://github.com/sifive/sifive-blocks/tree/master/src/main/scala/devices/uart
-
-This driver was written in collaboration with Wesley Terpstra
-<wesley@sifive.com>.
-
-Boot-tested on a SiFive HiFive Unleashed A00 board.
-
-Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-Cc: Jiri Slaby <jslaby@suse.com>
-Cc: Palmer Dabbelt <palmer@sifive.com>
-Cc: Wesley Terpstra <wesley@sifive.com>
-Cc: linux-serial@vger.kernel.org
-Cc: linux-riscv@lists.infradead.org
-Cc: linux-kernel@vger.kernel.org
-Cc: Julia Lawall <julia.lawall@lip6.fr>
-Signed-off-by: Paul Walmsley <paul.walmsley@sifive.com>
-Signed-off-by: Paul Walmsley <paul@pwsan.com>
----
- drivers/tty/serial/Kconfig       |   24 +
- drivers/tty/serial/Makefile      |    1 +
- drivers/tty/serial/sifive.c      | 1067 ++++++++++++++++++++++++++++++
- include/uapi/linux/serial_core.h |    3 +
- 4 files changed, 1095 insertions(+)
- create mode 100644 drivers/tty/serial/sifive.c
-
-diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
-index 72966bc0ac76..561e053b690a 100644
---- a/drivers/tty/serial/Kconfig
-+++ b/drivers/tty/serial/Kconfig
-@@ -1095,6 +1095,30 @@ 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
-+	  Select this option if you are building a kernel for a device that
-+	  contains a SiFive UART IP block.  This type of UART is present on
-+	  SiFive FU540 SoCs, among others.
-+
-+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=ttySIFx". (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 40b702aaa85e..2aff1d07d08b 100644
---- a/drivers/tty/serial/Makefile
-+++ b/drivers/tty/serial/Makefile
-@@ -92,6 +92,7 @@ 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_RDA)	+= rda-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 000000000000..80c06039fb57
---- /dev/null
-+++ b/drivers/tty/serial/sifive.c
-@@ -0,0 +1,1067 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * SiFive UART driver
-+ * Copyright (C) 2018 Paul Walmsley <paul@pwsan.com>
-+ * Copyright (C) 2018 SiFive
-+ *
-+ * 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.
-+ *
-+ * Based partially on:
-+ * - drivers/tty/serial/pxa.c
-+ * - drivers/tty/serial/amba-pl011.c
-+ * - drivers/tty/serial/uartlite.c
-+ * - drivers/tty/serial/omap-serial.c
-+ * - drivers/pwm/pwm-sifive.c
-+ *
-+ * See the following sources for further documentation:
-+ * - Chapter 19 "Universal Asynchronous Receiver/Transmitter (UART)" of
-+ *   SiFive FE310-G000 v2p3
-+ * - The tree/master/src/main/scala/devices/uart directory of
-+ *   https://github.com/sifive/sifive-blocks/
-+ *
-+ * 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 8250
-+ * programming model.
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/console.h>
-+#include <linux/delay.h>
-+#include <linux/init.h>
-+#include <linux/io.h>
-+#include <linux/irq.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/of_irq.h>
-+#include <linux/platform_device.h>
-+#include <linux/serial_core.h>
-+#include <linux/serial_reg.h>
-+#include <linux/slab.h>
-+#include <linux/tty.h>
-+#include <linux/tty_flip.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 on a device that can
-+ *                          host a serial console
-+ */
-+#define SIFIVE_SERIAL_MAX_PORTS			8
-+
-+/*
-+ * SIFIVE_DEFAULT_BAUD_RATE: default baud rate that the driver should
-+ *                           configure itself to use
-+ */
-+#define SIFIVE_DEFAULT_BAUD_RATE		115200
-+
-+/* 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			"ttySIF"
-+
-+/* SIFIVE_TX_FIFO_DEPTH: depth of the TX FIFO (in bytes) */
-+#define SIFIVE_TX_FIFO_DEPTH			8
-+
-+/* SIFIVE_RX_FIFO_DEPTH: depth of the TX FIFO (in bytes) */
-+#define SIFIVE_RX_FIFO_DEPTH			8
-+
-+#if (SIFIVE_TX_FIFO_DEPTH != SIFIVE_RX_FIFO_DEPTH)
-+#error Driver does not support configurations with different TX, RX FIFO sizes
-+#endif
-+
-+/*
-+ *
-+ */
-+
-+/**
-+ * 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.
-+ * @baud_rate: UART serial line rate (e.g., 115200 baud)
-+ * @clk_notifier: clock rate change notifier for upstream clock changes
-+ *
-+ * Configuration data specific to this SiFive UART.
-+ */
-+struct sifive_serial_port {
-+	struct uart_port	port;
-+	struct device		*dev;
-+	unsigned char		ier;
-+	unsigned long		clkin_rate;
-+	unsigned long		baud_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
-+ */
-+
-+/**
-+ * __ssp_early_writel() - write to a SiFive serial port 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.
-+ *
-+ * Context: Intended to be used only by the earlyconsole code.
-+ */
-+static void __ssp_early_writel(u32 v, u16 offs, struct uart_port *port)
-+{
-+	writel_relaxed(v, port->membase + offs);
-+}
-+
-+/**
-+ * __ssp_early_readl() - read from a SiFive serial port 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.
-+ *
-+ * Context: Intended to be called only by the earlyconsole code or by
-+ *          __ssp_readl() or __ssp_writel() (in this driver)
-+ *
-+ * Returns: the register value read from the UART.
-+ */
-+static u32 __ssp_early_readl(struct uart_port *port, u16 offs)
-+{
-+	return readl_relaxed(port->membase + offs);
-+}
-+
-+/**
-+ * __ssp_writel() - write to a SiFive serial port register
-+ * @v: value to write to the register
-+ * @offs: register address offset from the IP block base address
-+ * @ssp: pointer to a struct sifive_serial_port record
-+ *
-+ * 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.
-+ *
-+ * Context: Any context.
-+ */
-+static void __ssp_writel(u32 v, u16 offs, struct sifive_serial_port *ssp)
-+{
-+	__ssp_early_writel(v, offs, &ssp->port);
-+}
-+
-+/**
-+ * __ssp_readl() - read from a SiFive serial port 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.
-+ *
-+ * Context: Any context.
-+ *
-+ * Returns: the value of the UART register
-+ */
-+static u32 __ssp_readl(struct sifive_serial_port *ssp, u16 offs)
-+{
-+	return __ssp_early_readl(&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 __ssp_readl(ssp, SIFIVE_SERIAL_TXDATA_OFFS) &
-+		SIFIVE_SERIAL_TXDATA_FULL_MASK;
-+}
-+
-+/**
-+ * __ssp_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().
-+ *
-+ * Context: Any context.
-+ */
-+static void __ssp_transmit_char(struct sifive_serial_port *ssp, int ch)
-+{
-+	__ssp_writel(ch, SIFIVE_SERIAL_TXDATA_OFFS, ssp);
-+}
-+
-+/**
-+ * __ssp_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.
-+ *
-+ * Context: Any context.  Expects @ssp->port.lock to be held by caller.
-+ */
-+static void __ssp_transmit_chars(struct sifive_serial_port *ssp)
-+{
-+	struct circ_buf *xmit = &ssp->port.state->xmit;
-+	int count;
-+
-+	if (ssp->port.x_char) {
-+		__ssp_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 = SIFIVE_TX_FIFO_DEPTH;
-+	do {
-+		__ssp_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);
-+}
-+
-+/**
-+ * __ssp_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 SiFive UART referred to by @ssp.
-+ */
-+static void __ssp_enable_txwm(struct sifive_serial_port *ssp)
-+{
-+	if (ssp->ier & SIFIVE_SERIAL_IE_TXWM_MASK)
-+		return;
-+
-+	ssp->ier |= SIFIVE_SERIAL_IE_TXWM_MASK;
-+	__ssp_writel(ssp->ier, SIFIVE_SERIAL_IE_OFFS, ssp);
-+}
-+
-+/**
-+ * __ssp_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 SiFive UART referred to by @ssp.
-+ */
-+static void __ssp_enable_rxwm(struct sifive_serial_port *ssp)
-+{
-+	if (ssp->ier & SIFIVE_SERIAL_IE_RXWM_MASK)
-+		return;
-+
-+	ssp->ier |= SIFIVE_SERIAL_IE_RXWM_MASK;
-+	__ssp_writel(ssp->ier, SIFIVE_SERIAL_IE_OFFS, ssp);
-+}
-+
-+/**
-+ * __ssp_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 __ssp_disable_txwm(struct sifive_serial_port *ssp)
-+{
-+	if (!(ssp->ier & SIFIVE_SERIAL_IE_TXWM_MASK))
-+		return;
-+
-+	ssp->ier &= ~SIFIVE_SERIAL_IE_TXWM_MASK;
-+	__ssp_writel(ssp->ier, SIFIVE_SERIAL_IE_OFFS, ssp);
-+}
-+
-+/**
-+ * __ssp_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 __ssp_disable_rxwm(struct sifive_serial_port *ssp)
-+{
-+	if (!(ssp->ier & SIFIVE_SERIAL_IE_RXWM_MASK))
-+		return;
-+
-+	ssp->ier &= ~SIFIVE_SERIAL_IE_RXWM_MASK;
-+	__ssp_writel(ssp->ier, SIFIVE_SERIAL_IE_OFFS, ssp);
-+}
-+
-+/**
-+ * __ssp_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 __ssp_receive_char(struct sifive_serial_port *ssp, char *is_empty)
-+{
-+	u32 v;
-+	u8 ch;
-+
-+	v = __ssp_readl(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;
-+}
-+
-+/**
-+ * __ssp_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.
-+ *
-+ * Context: Expects ssp->port.lock to be held by caller.
-+ */
-+static void __ssp_receive_chars(struct sifive_serial_port *ssp)
-+{
-+	unsigned char ch;
-+	char is_empty;
-+	int c;
-+
-+	for (c = SIFIVE_RX_FIFO_DEPTH; c > 0; --c) {
-+		ch = __ssp_receive_char(ssp, &is_empty);
-+		if (is_empty)
-+			break;
-+
-+		ssp->port.icount.rx++;
-+		uart_insert_char(&ssp->port, 0, 0, ch, TTY_NORMAL);
-+	}
-+
-+	spin_unlock(&ssp->port.lock);
-+	tty_flip_buffer_push(&ssp->port.state->port);
-+	spin_lock(&ssp->port.lock);
-+}
-+
-+/**
-+ * __ssp_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
-+ * and target line rate referred to by @ssp and write it into the
-+ * hardware.
-+ */
-+static void __ssp_update_div(struct sifive_serial_port *ssp)
-+{
-+	u16 div;
-+
-+	div = DIV_ROUND_UP(ssp->clkin_rate, ssp->baud_rate) - 1;
-+
-+	__ssp_writel(div, SIFIVE_SERIAL_DIV_OFFS, ssp);
-+}
-+
-+/**
-+ * __ssp_update_baud_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 __ssp_update_baud_rate(struct sifive_serial_port *ssp,
-+				   unsigned int rate)
-+{
-+	if (ssp->baud_rate == rate)
-+		return;
-+
-+	ssp->baud_rate = rate;
-+	__ssp_update_div(ssp);
-+}
-+
-+/**
-+ * __ssp_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 __ssp_set_stop_bits(struct sifive_serial_port *ssp, char nstop)
-+{
-+	u32 v;
-+
-+	if (nstop < 1 || nstop > 2) {
-+		WARN_ON(1);
-+		return;
-+	}
-+
-+	v = __ssp_readl(ssp, SIFIVE_SERIAL_TXCTRL_OFFS);
-+	v &= ~SIFIVE_SERIAL_TXCTRL_NSTOP_MASK;
-+	v |= (nstop - 1) << SIFIVE_SERIAL_TXCTRL_NSTOP_SHIFT;
-+	__ssp_writel(v, SIFIVE_SERIAL_TXCTRL_OFFS, ssp);
-+}
-+
-+/**
-+ * __ssp_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.
-+ *
-+ * Context: Any context.
-+ */
-+static void __maybe_unused __ssp_wait_for_xmitr(struct sifive_serial_port *ssp)
-+{
-+	while (sifive_serial_is_txfifo_full(ssp))
-+		udelay(1); /* XXX Could probably be more intelligent here */
-+}
-+
-+/*
-+ * 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);
-+
-+	__ssp_disable_txwm(ssp);
-+}
-+
-+static void sifive_serial_stop_rx(struct uart_port *port)
-+{
-+	struct sifive_serial_port *ssp = port_to_sifive_serial_port(port);
-+
-+	__ssp_disable_rxwm(ssp);
-+}
-+
-+static void sifive_serial_start_tx(struct uart_port *port)
-+{
-+	struct sifive_serial_port *ssp = port_to_sifive_serial_port(port);
-+
-+	__ssp_enable_txwm(ssp);
-+}
-+
-+static irqreturn_t sifive_serial_irq(int irq, void *dev_id)
-+{
-+	struct sifive_serial_port *ssp = dev_id;
-+	u32 ip;
-+
-+	spin_lock(&ssp->port.lock);
-+
-+	ip = __ssp_readl(ssp, SIFIVE_SERIAL_IP_OFFS);
-+	if (!ip) {
-+		spin_unlock(&ssp->port.lock);
-+		return IRQ_NONE;
-+	}
-+
-+	if (ip & SIFIVE_SERIAL_IP_RXWM_MASK)
-+		__ssp_receive_chars(ssp);
-+	if (ip & SIFIVE_SERIAL_IP_TXWM_MASK)
-+		__ssp_transmit_chars(ssp);
-+
-+	spin_unlock(&ssp->port.lock);
-+
-+	return IRQ_HANDLED;
-+}
-+
-+static unsigned int sifive_serial_tx_empty(struct uart_port *port)
-+{
-+	return TIOCSER_TEMT;
-+}
-+
-+static unsigned int sifive_serial_get_mctrl(struct uart_port *port)
-+{
-+	return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR;
-+}
-+
-+static void sifive_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
-+{
-+	/* IP block does not support these signals */
-+}
-+
-+static void sifive_serial_break_ctl(struct uart_port *port, int break_state)
-+{
-+	/* IP block does not support sending a break */
-+}
-+
-+static int sifive_serial_startup(struct uart_port *port)
-+{
-+	struct sifive_serial_port *ssp = port_to_sifive_serial_port(port);
-+
-+	__ssp_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);
-+
-+	__ssp_disable_rxwm(ssp);
-+	__ssp_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 V0 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;
-+		__ssp_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);
-+	unsigned long flags;
-+	u32 v, old_v;
-+	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;
-+	__ssp_set_stop_bits(ssp, nstop);
-+
-+	/* Set line rate */
-+	rate = uart_get_baud_rate(port, termios, old, 0, ssp->clkin_rate / 16);
-+	__ssp_update_baud_rate(ssp, rate);
-+
-+	spin_lock_irqsave(&ssp->port.lock, flags);
-+
-+	/*
-+	 * Update the per-port timeout.
-+	 */
-+	uart_update_timeout(port, termios->c_cflag, rate);
-+
-+	ssp->port.read_status_mask = 0;
-+	if (termios->c_iflag & INPCK) {
-+		dev_err(ssp->port.dev, "INPCK flag not supported\n");
-+		goto ssst_out;
-+	}
-+	if (termios->c_iflag & (BRKINT | PARMRK)) {
-+		dev_err(ssp->port.dev, "BRKINT/PARMRK flag not supported\n");
-+		goto ssst_out;
-+	}
-+
-+	/*
-+	 * ignore all characters if CREAD is not set
-+	 */
-+	v = __ssp_readl(ssp, SIFIVE_SERIAL_RXCTRL_OFFS);
-+	old_v = v;
-+	if ((termios->c_cflag & CREAD) == 0)
-+		v &= SIFIVE_SERIAL_RXCTRL_RXEN_MASK;
-+	else
-+		v |= SIFIVE_SERIAL_RXCTRL_RXEN_MASK;
-+	if (v != old_v)
-+		__ssp_writel(v, SIFIVE_SERIAL_RXCTRL_OFFS, ssp);
-+
-+ssst_out:
-+	spin_unlock_irqrestore(&ssp->port.lock, flags);
-+}
-+
-+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_V0;
-+}
-+
-+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_V0 ? "SiFive UART v0" : NULL;
-+}
-+
-+/*
-+ * Early console support
-+ */
-+
-+#ifdef CONFIG_SERIAL_EARLYCON
-+static void early_sifive_serial_putc(struct uart_port *port, int c)
-+{
-+	while (__ssp_early_readl(port, SIFIVE_SERIAL_TXDATA_OFFS) &
-+	       SIFIVE_SERIAL_TXDATA_FULL_MASK)
-+		cpu_relax();
-+
-+	__ssp_early_writel(c, SIFIVE_SERIAL_TXDATA_OFFS, port);
-+}
-+
-+static void early_sifive_serial_write(struct console *con, const char *s,
-+				      unsigned int n)
-+{
-+	struct earlycon_device *dev = con->data;
-+	struct uart_port *port = &dev->port;
-+
-+	uart_console_write(port, s, n, early_sifive_serial_putc);
-+}
-+
-+static int __init early_sifive_serial_setup(struct earlycon_device *dev,
-+					    const char *options)
-+{
-+	struct uart_port *port = &dev->port;
-+
-+	if (!port->membase)
-+		return -ENODEV;
-+
-+	dev->con->write = early_sifive_serial_write;
-+
-+	return 0;
-+}
-+
-+OF_EARLYCON_DECLARE(sifive, "sifive,uart0", early_sifive_serial_setup);
-+OF_EARLYCON_DECLARE(sifive, "sifive,fu540-c000-uart0",
-+		    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);
-+
-+	__ssp_wait_for_xmitr(ssp);
-+	__ssp_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 = __ssp_readl(ssp, SIFIVE_SERIAL_IE_OFFS);
-+	__ssp_writel(0, SIFIVE_SERIAL_IE_OFFS, ssp);
-+
-+	uart_console_write(&ssp->port, s, count, sifive_serial_console_putchar);
-+
-+	__ssp_writel(ier, SIFIVE_SERIAL_IE_OFFS, ssp);
-+
-+	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 = SIFIVE_DEFAULT_BAUD_RATE;
-+	int bits = 8;
-+	int parity = 'n';
-+	int flow = 'n';
-+
-+	if (co->index < 0 || co->index >= SIFIVE_SERIAL_MAX_PORTS)
-+		return -ENODEV;
-+
-+	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 int __init sifive_console_init(void)
-+{
-+	register_console(&sifive_serial_console);
-+	return 0;
-+}
-+
-+console_initcall(sifive_console_init);
-+
-+static void __ssp_add_console_port(struct sifive_serial_port *ssp)
-+{
-+	sifive_serial_console_ports[ssp->port.line] = ssp;
-+}
-+
-+static void __ssp_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 __ssp_add_console_port(struct sifive_serial_port *ssp)
-+{}
-+static void __ssp_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,
-+};
-+
-+static struct uart_driver sifive_serial_uart_driver = {
-+	.owner		= THIS_MODULE,
-+	.driver_name	= SIFIVE_SERIAL_NAME,
-+	.dev_name	= SIFIVE_TTY_PREFIX,
-+	.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_V0;
-+	ssp->port.iotype = UPIO_MEM;
-+	ssp->port.irq = irq;
-+	ssp->port.fifosize = SIFIVE_TX_FIFO_DEPTH;
-+	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;
-+	}
-+
-+	/* Set up clock divider */
-+	ssp->clkin_rate = clk_get_rate(ssp->clk);
-+	ssp->baud_rate = SIFIVE_DEFAULT_BAUD_RATE;
-+	__ssp_update_div(ssp);
-+
-+	platform_set_drvdata(pdev, ssp);
-+
-+	/* Enable transmits and set the watermark level to 1 */
-+	__ssp_writel((1 << SIFIVE_SERIAL_TXCTRL_TXCNT_SHIFT) |
-+		     SIFIVE_SERIAL_TXCTRL_TXEN_MASK,
-+		     SIFIVE_SERIAL_TXCTRL_OFFS, ssp);
-+
-+	/* Enable receives and set the watermark level to 0 */
-+	__ssp_writel((0 << SIFIVE_SERIAL_RXCTRL_RXCNT_SHIFT) |
-+		     SIFIVE_SERIAL_RXCTRL_RXEN_MASK,
-+		     SIFIVE_SERIAL_RXCTRL_OFFS, ssp);
-+
-+	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;
-+	}
-+
-+	__ssp_add_console_port(ssp);
-+
-+	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;
-+	}
-+
-+	return 0;
-+
-+probe_out3:
-+	__ssp_remove_console_port(ssp);
-+	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);
-+
-+	__ssp_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,fu540-c000-uart0" },
-+	{ .compatible = "sifive,uart0" },
-+	{},
-+};
-+MODULE_DEVICE_TABLE(of, sifive_serial_of_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)
-+{
-+	int r;
-+
-+	r = uart_register_driver(&sifive_serial_uart_driver);
-+	if (r)
-+		goto init_out1;
-+
-+	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 6009ee2c2e99..d3bb0d447c0b 100644
---- a/include/uapi/linux/serial_core.h
-+++ b/include/uapi/linux/serial_core.h
-@@ -287,4 +287,7 @@
- /* RDA UART */
- #define PORT_RDA	118
- 
-+/* SiFive UART */
-+#define PORT_SIFIVE_V0	118
-+
- #endif /* _UAPILINUX_SERIAL_CORE_H */
--- 
-2.21.0
-

+ 0 - 236
recipes-kernel/linux/files/freedom-u540/0002-gemgxl-mgmt-implement-clock-switch-for-GEM-tx_clk.patch

@@ -1,236 +0,0 @@
-From 3d9d2c51f1c4780deafb2fcaf4c5ad14b8ae9e68 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 02/10] gemgxl-mgmt: implement clock switch for GEM tx_clk
-
-Signed-off-by: Palmer Dabbelt <palmer@sifive.com>
----
- .../bindings/clock/sifive,gemgxl-mgmt.txt     |  26 ++++
- drivers/clk/Kconfig                           |   1 +
- drivers/clk/Makefile                          |   1 +
- drivers/clk/sifive/Kconfig                    |   9 ++
- drivers/clk/sifive/Makefile                   |   2 +
- drivers/clk/sifive/gemgxl-mgmt.c              | 129 ++++++++++++++++++
- 6 files changed, 168 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/clock/sifive,gemgxl-mgmt.txt
- create mode 100644 drivers/clk/sifive/Kconfig
- create mode 100644 drivers/clk/sifive/Makefile
- create mode 100644 drivers/clk/sifive/gemgxl-mgmt.c
-
-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 000000000000..349489e33eda
---- /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/Kconfig b/drivers/clk/Kconfig
-index e705aab9e38b..49d72e084eac 100644
---- a/drivers/clk/Kconfig
-+++ b/drivers/clk/Kconfig
-@@ -309,6 +309,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"
-diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
-index 1db133652f0c..62ba714e34b1 100644
---- a/drivers/clk/Makefile
-+++ b/drivers/clk/Makefile
-@@ -93,6 +93,7 @@ obj-$(CONFIG_COMMON_CLK_QCOM)		+= qcom/
- obj-y					+= renesas/
- obj-$(CONFIG_ARCH_ROCKCHIP)		+= rockchip/
- obj-$(CONFIG_COMMON_CLK_SAMSUNG)	+= samsung/
-+obj-y					+= sifive/
- obj-$(CONFIG_ARCH_SIRF)			+= sirf/
- obj-$(CONFIG_ARCH_SOCFPGA)		+= socfpga/
- obj-$(CONFIG_PLAT_SPEAR)		+= spear/
-diff --git a/drivers/clk/sifive/Kconfig b/drivers/clk/sifive/Kconfig
-new file mode 100644
-index 000000000000..284bffb121eb
---- /dev/null
-+++ 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
-new file mode 100644
-index 000000000000..7784d2ee0f44
---- /dev/null
-+++ 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 000000000000..00b07580fe3c
---- /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);
--- 
-2.21.0
-

+ 189 - 0
recipes-kernel/linux/files/freedom-u540/0002-macb-Add-support-for-SiFive-FU540-C000.patch

@@ -0,0 +1,189 @@
+From 4181aa6e771dcc09b62eb3495bd09bf151b8bd9d Mon Sep 17 00:00:00 2001
+From: Yash Shah <yash.shah@sifive.com>
+Date: Tue, 18 Jun 2019 13:26:08 +0530
+Subject: [PATCH 2/6] macb: Add support for SiFive FU540-C000
+
+The management IP block is tightly coupled with the Cadence MACB IP
+block on the FU540, and manages many of the boundary signals from the
+MACB IP. This patch only controls the tx_clk input signal to the MACB
+IP. Future patches may add support for monitoring or controlling other
+IP boundary signals.
+
+Signed-off-by: Yash Shah <yash.shah@sifive.com>
+Upstream-Status: Accepted [5.3]
+---
+ drivers/net/ethernet/cadence/macb_main.c | 123 +++++++++++++++++++++++
+ 1 file changed, 123 insertions(+)
+
+diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
+index 262a28ff81fc..111bf51a8405 100644
+--- a/drivers/net/ethernet/cadence/macb_main.c
++++ b/drivers/net/ethernet/cadence/macb_main.c
+@@ -7,6 +7,7 @@
+ 
+ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+ #include <linux/clk.h>
++#include <linux/clk-provider.h>
+ #include <linux/crc32.h>
+ #include <linux/module.h>
+ #include <linux/moduleparam.h>
+@@ -37,6 +38,15 @@
+ #include <linux/pm_runtime.h>
+ #include "macb.h"
+ 
++/* This structure is only used for MACB on SiFive FU540 devices */
++struct sifive_fu540_macb_mgmt {
++	void __iomem *reg;
++	unsigned long rate;
++	struct clk_hw hw;
++};
++
++static struct sifive_fu540_macb_mgmt *mgmt;
++
+ #define MACB_RX_BUFFER_SIZE	128
+ #define RX_BUFFER_MULTIPLE	64  /* bytes */
+ 
+@@ -3943,6 +3953,116 @@ static int at91ether_init(struct platform_device *pdev)
+ 	return 0;
+ }
+ 
++static unsigned long fu540_macb_tx_recalc_rate(struct clk_hw *hw,
++					       unsigned long parent_rate)
++{
++	return mgmt->rate;
++}
++
++static long fu540_macb_tx_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;
++
++	WARN_ON(rate > 125000000);
++
++	return 125000000;
++}
++
++static int fu540_macb_tx_set_rate(struct clk_hw *hw, unsigned long rate,
++				  unsigned long parent_rate)
++{
++	rate = fu540_macb_tx_round_rate(hw, rate, &parent_rate);
++	if (rate != 125000000)
++		iowrite32(1, mgmt->reg);
++	else
++		iowrite32(0, mgmt->reg);
++	mgmt->rate = rate;
++
++	return 0;
++}
++
++static const struct clk_ops fu540_c000_ops = {
++	.recalc_rate = fu540_macb_tx_recalc_rate,
++	.round_rate = fu540_macb_tx_round_rate,
++	.set_rate = fu540_macb_tx_set_rate,
++};
++
++static int fu540_c000_clk_init(struct platform_device *pdev, struct clk **pclk,
++			       struct clk **hclk, struct clk **tx_clk,
++			       struct clk **rx_clk, struct clk **tsu_clk)
++{
++	struct clk_init_data init;
++	int err = 0;
++
++	err = macb_clk_init(pdev, pclk, hclk, tx_clk, rx_clk, tsu_clk);
++	if (err)
++		return err;
++
++	mgmt = devm_kzalloc(&pdev->dev, sizeof(*mgmt), GFP_KERNEL);
++	if (!mgmt)
++		return -ENOMEM;
++
++	init.name = "sifive-gemgxl-mgmt";
++	init.ops = &fu540_c000_ops;
++	init.flags = 0;
++	init.num_parents = 0;
++
++	mgmt->rate = 0;
++	mgmt->hw.init = &init;
++
++	*tx_clk = clk_register(NULL, &mgmt->hw);
++	if (IS_ERR(*tx_clk))
++		return PTR_ERR(*tx_clk);
++
++	err = clk_prepare_enable(*tx_clk);
++	if (err)
++		dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", err);
++	else
++		dev_info(&pdev->dev, "Registered clk switch '%s'\n", init.name);
++
++	return 0;
++}
++
++static int fu540_c000_init(struct platform_device *pdev)
++{
++	struct resource *res;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++	if (!res)
++		return -ENODEV;
++
++	mgmt->reg = ioremap(res->start, resource_size(res));
++	if (!mgmt->reg)
++		return -ENOMEM;
++
++	return macb_init(pdev);
++}
++
++static const struct macb_config fu540_c000_config = {
++	.caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_JUMBO |
++		MACB_CAPS_GEM_HAS_PTP,
++	.dma_burst_length = 16,
++	.clk_init = fu540_c000_clk_init,
++	.init = fu540_c000_init,
++	.jumbo_max_len = 10240,
++};
++
+ static const struct macb_config at91sam9260_config = {
+ 	.caps = MACB_CAPS_USRIO_HAS_CLKEN | MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII,
+ 	.clk_init = macb_clk_init,
+@@ -4032,6 +4152,7 @@ static const struct of_device_id macb_dt_ids[] = {
+ 	{ .compatible = "cdns,emac", .data = &emac_config },
+ 	{ .compatible = "cdns,zynqmp-gem", .data = &zynqmp_config},
+ 	{ .compatible = "cdns,zynq-gem", .data = &zynq_config },
++	{ .compatible = "sifive,fu540-macb", .data = &fu540_c000_config },
+ 	{ /* sentinel */ }
+ };
+ MODULE_DEVICE_TABLE(of, macb_dt_ids);
+@@ -4239,6 +4360,7 @@ static int macb_probe(struct platform_device *pdev)
+ 
+ err_disable_clocks:
+ 	clk_disable_unprepare(tx_clk);
++	clk_unregister(tx_clk);
+ 	clk_disable_unprepare(hclk);
+ 	clk_disable_unprepare(pclk);
+ 	clk_disable_unprepare(rx_clk);
+@@ -4273,6 +4395,7 @@ static int macb_remove(struct platform_device *pdev)
+ 		pm_runtime_dont_use_autosuspend(&pdev->dev);
+ 		if (!pm_runtime_suspended(&pdev->dev)) {
+ 			clk_disable_unprepare(bp->tx_clk);
++			clk_unregister(bp->tx_clk);
+ 			clk_disable_unprepare(bp->hclk);
+ 			clk_disable_unprepare(bp->pclk);
+ 			clk_disable_unprepare(bp->rx_clk);
+-- 
+2.22.0
+

+ 62 - 0
recipes-kernel/linux/files/freedom-u540/0003-riscv-dts-Add-DT-node-for-SiFive-FU540-Ethernet-cont.patch

@@ -0,0 +1,62 @@
+From 9955158a18bd876a2e9b6028d28e930ae71fee93 Mon Sep 17 00:00:00 2001
+From: Yash Shah <yash.shah@sifive.com>
+Date: Fri, 21 Jun 2019 16:23:49 +0530
+Subject: [PATCH 3/6] riscv: dts: Add DT node for SiFive FU540 Ethernet
+ controller driver
+
+DT node for SiFive FU540-C000 GEMGXL Ethernet controller driver added
+
+Signed-off-by: Yash Shah <yash.shah@sifive.com>
+Reviewed-by: Anup Patel <anup@brainfault.org>
+Upstream-Status: Accepted [5.3]
+---
+ arch/riscv/boot/dts/sifive/fu540-c000.dtsi       | 16 ++++++++++++++++
+ .../boot/dts/sifive/hifive-unleashed-a00.dts     |  9 +++++++++
+ 2 files changed, 25 insertions(+)
+
+diff --git a/arch/riscv/boot/dts/sifive/fu540-c000.dtsi b/arch/riscv/boot/dts/sifive/fu540-c000.dtsi
+index 40983491b95f..56e009ad4cbe 100644
+--- a/arch/riscv/boot/dts/sifive/fu540-c000.dtsi
++++ b/arch/riscv/boot/dts/sifive/fu540-c000.dtsi
+@@ -217,5 +217,21 @@
+ 			#size-cells = <0>;
+ 			status = "disabled";
+ 		};
++		eth0: ethernet@10090000 {
++			compatible = "sifive,fu540-macb";
++			interrupt-parent = <&plic0>;
++			interrupts = <53>;
++			reg = <0x0 0x10090000 0x0 0x2000
++			       0x0 0x100a0000 0x0 0x1000>;
++			reg-names = "control";
++			status = "disabled";
++			local-mac-address = [00 00 00 00 00 00];
++			clock-names = "pclk", "hclk";
++			clocks = <&prci PRCI_CLK_GEMGXLPLL>,
++				 <&prci PRCI_CLK_GEMGXLPLL>;
++			#address-cells = <1>;
++			#size-cells = <0>;
++		};
++
+ 	};
+ };
+diff --git a/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts b/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
+index 0b55c53c08c7..85c17a7980cd 100644
+--- a/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
++++ b/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
+@@ -76,3 +76,12 @@
+ 		disable-wp;
+ 	};
+ };
++
++&eth0 {
++	status = "okay";
++	phy-mode = "gmii";
++	phy-handle = <&phy1>;
++	phy1: ethernet-phy@0 {
++		reg = <0>;
++	};
++};
+-- 
+2.22.0
+

+ 0 - 63
recipes-kernel/linux/files/freedom-u540/0003-u54-prci-driver-for-core-U54-clocks.patch

@@ -1,63 +0,0 @@
-From aebd1722fcf2f9e7071ceeca5995a308ca099959 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 03/10] 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 000000000000..88682c5eaebc
---- /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 */
-+	};
--- 
-2.21.0
-

+ 821 - 0
recipes-kernel/linux/files/freedom-u540/0004-PCI-microsemi-Add-host-driver-for-Microsemi-PCIe-con.patch

@@ -0,0 +1,821 @@
+From 85fac9c69c09dd6d288b3a07960040e9aa4eb0ad Mon Sep 17 00:00:00 2001
+From: Daire McNamara <daire.mcnamara@microchip.com>
+Date: Fri, 15 Feb 2019 16:24:24 +0000
+Subject: [PATCH 4/6] PCI: microsemi: Add host driver for Microsemi PCIe
+ controller
+
+This patch adds support to the Microsemi/Microchip PolarFire
+PCIe controller when configured in host (Root Complex) mode.
+
+Signed-off-by: Daire McNamara <daire.mcnamara@microchip.com>
+Upstream-Status: Inappropriate [not author]
+---
+ drivers/pci/controller/Kconfig          |   8 +
+ drivers/pci/controller/Makefile         |   1 +
+ drivers/pci/controller/pcie-microsemi.c | 764 ++++++++++++++++++++++++
+ 3 files changed, 773 insertions(+)
+ create mode 100644 drivers/pci/controller/pcie-microsemi.c
+
+diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
+index 011c57cae4b0..e22364792bca 100644
+--- a/drivers/pci/controller/Kconfig
++++ b/drivers/pci/controller/Kconfig
+@@ -281,5 +281,13 @@ config VMD
+ 	  To compile this driver as a module, choose M here: the
+ 	  module will be called vmd.
+ 
++config PCIE_MICROSEMI
++	bool "Microsemi AXI PCIe host bridge support"
++	depends on PCI_MSI && OF
++	help
++	  Say 'Y' here if you want kernel to support the Microsemi AXI PCIe
++	  Host Bridge driver.
++
++
+ source "drivers/pci/controller/dwc/Kconfig"
+ endmenu
+diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile
+index d56a507495c5..c3b76ff221be 100644
+--- a/drivers/pci/controller/Makefile
++++ b/drivers/pci/controller/Makefile
+@@ -28,6 +28,7 @@ obj-$(CONFIG_PCIE_ROCKCHIP_HOST) += pcie-rockchip-host.o
+ obj-$(CONFIG_PCIE_MEDIATEK) += pcie-mediatek.o
+ obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o
+ obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o
++obj-$(CONFIG_PCIE_MICROSEMI) += pcie-microsemi.o
+ obj-$(CONFIG_VMD) += vmd.o
+ # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
+ obj-y				+= dwc/
+diff --git a/drivers/pci/controller/pcie-microsemi.c b/drivers/pci/controller/pcie-microsemi.c
+new file mode 100644
+index 000000000000..60e185bebc60
+--- /dev/null
++++ b/drivers/pci/controller/pcie-microsemi.c
+@@ -0,0 +1,764 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * PCIe host controller driver for Microsemi AXI PCIe Bridge
++ *
++ * Copyright (c) 2018 - 2019 Microsemi Corporation.
++ *
++ * Based on:
++ *	pcie-rcar.c
++ *	pcie-xilinx.c
++ *	pcie-altera.c
++ */
++
++#include <linux/bitmap.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <linux/irqdomain.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/msi.h>
++#include <linux/of_address.h>
++#include <linux/of_pci.h>
++#include <linux/of_platform.h>
++#include <linux/of_irq.h>
++#include <linux/pci.h>
++#include <linux/platform_device.h>
++
++#include "../pci.h"
++
++/* ECAM definitions */
++#define ECAM_BUS_NUM_SHIFT		20
++#define ECAM_DEV_NUM_SHIFT		12
++
++/* Number of MSI IRQs */
++#define MICROSEMI_NUM_MSI_IRQS		32
++#define MICROSEMI_NUM_MSI_IRQS_CODED	 5
++
++/* PCIe Bridge Phy and Controller Phy offsets */
++#define MICROSEMI_PCIE0_BRIDGE_ADDR	0x00004000u
++#define MICROSEMI_PCIE0_CTRL_ADDR	0x00006000u
++
++#define MICROSEMI_PCIE1_BRIDGE_ADDR	0x00008000u
++#define MICROSEMI_PCIE1_CTRL_ADDR	0x0000a000u
++
++/* PCIe Controller Phy Regs */
++#define MICROSEMI_SEC_ERROR_INT			0x28
++#define SEC_ERROR_INT_TX_RAM_SEC_ERR_INT	GENMASK(3, 0)
++#define SEC_ERROR_INT_RX_RAM_SEC_ERR_INT	GENMASK(7, 4)
++#define SEC_ERROR_INT_PCIE2AXI_RAM_SEC_ERR_INT	GENMASK(11, 8)
++#define SEC_ERROR_INT_AXI2PCIE_RAM_SEC_ERR_INT	GENMASK(15, 12)
++#define MICROSEMI_SEC_ERROR_INT_MASK		0x2c
++#define MICROSEMI_DED_ERROR_INT			0x30
++#define DED_ERROR_INT_TX_RAM_DED_ERR_INT	GENMASK(3, 0)
++#define DED_ERROR_INT_RX_RAM_DED_ERR_INT	GENMASK(7, 4)
++#define DED_ERROR_INT_PCIE2AXI_RAM_DED_ERR_INT	GENMASK(11, 8)
++#define DED_ERROR_INT_AXI2PCIE_RAM_DED_ERR_INT	GENMASK(15, 12)
++#define MICROSEMI_DED_ERROR_INT_MASK		0x34
++#define MICROSEMI_ECC_CONTROL			0x38
++#define ECC_CONTROL_AXI2PCIE_RAM_ECC_BYPASS	BIT(27)
++#define ECC_CONTROL_PCIE2AXI_RAM_ECC_BYPASS	BIT(26)
++#define ECC_CONTROL_RX_RAM_ECC_BYPASS		BIT(25)
++#define ECC_CONTROL_TX_RAM_ECC_BYPASS		BIT(24)
++#define MICROSEMI_LTSSM_STATE			0x5c
++#define MICROSEMI_LTSSM_L0_STATE		0x10
++#define MICROSEMI_PCIE_EVENT_INT		0x14c
++#define PCIE_EVENT_INT_L2_EXIT_INT		BIT(0)
++#define PCIE_EVENT_INT_HOTRST_EXIT_INT		BIT(1)
++#define PCIE_EVENT_INT_DLUP_EXIT_INT		BIT(2)
++#define PCIE_EVENT_INT_L2_EXIT_INT_MASK		BIT(16)
++#define PCIE_EVENT_INT_HOTRST_EXIT_INT_MASK	BIT(17)
++#define PCIE_EVENT_INT_DLUP_EXIT_INT_MASK	BIT(18)
++
++/* PCIe Bridge Phy Regs */
++#define MICROSEMI_PCIE_PCI_IDS_DW1		0x9c
++#define MICROSEMI_IMASK_LOCAL			0x180
++#define MICROSEMI_PCIE_LOCAL_INT_ENABLE		0x0f000000u
++#define MICROSEMI_PCI_INTS			0x0f000000u
++#define MICROSEMI_PM_MSI_INT_SHIFT		24
++#define MICROSEMI_PCIE_ENABLE_MSI		0x10000000u
++#define MICROSEMI_MSI_INT			0x10000000u
++#define MICROSEMI_MSI_INT_SHIFT			28
++#define MICROSEMI_ISTATUS_LOCAL			0x184
++#define MICROSEMI_IMASK_HOST			0x188
++#define MICROSEMI_ISTATUS_HOST			0x18c
++#define MICROSEMI_ISTATUS_MSI			0x194
++
++/* PCIe AXI slave table init defines */
++#define MICROSEMI_ATR0_AXI4_SLV0_SRCADDR_PARAM	0x800u
++#define ATR_SIZE_SHIFT				1
++#define ATR_IMPL_ENABLE				1
++#define MICROSEMI_ATR0_AXI4_SLV0_SRC_ADDR	0x804u
++#define MICROSEMI_ATR0_AXI4_SLV0_TRSL_ADDR_LSB	0x808u
++#define MICROSEMI_ATR0_AXI4_SLV0_TRSL_ADDR_UDW	0x80cu
++#define MICROSEMI_ATR0_AXI4_SLV0_TRSL_PARAM	0x810u
++#define MICROSEMI_PCIE_TX_RX_INTERFACE		0x00000000u
++#define MICROSEMI_PCIE_CONFIG_INTERFACE		0x00000001u
++
++#define MICROSEMI_ATR0_AXI4_SLV_SIZE		32
++
++/* PCIe Master table init defines */
++#define MICROSEMI_ATR0_PCIE_WIN0_SRCADDR_31_12	0x600u
++#define MICROSEMI_ATR0_PCIE_WIN0_SIZE		0x1f
++#define MICROSEMI_ATR0_PCIE_WIN0_SIZE_SHIFT	1
++#define MICROSEMI_ATR0_PCIE_WIN0_SRCADDR_63_32	0x604u
++
++#define MICROSEMI_MSI_MSG_ADDR			0x190u
++
++/* PCIe Config space MSI capability structure */
++#define MSI_CAP_CTRL_OFFSET		0xe0u
++#define MSI_ENABLE			(0x01u << 16)
++#define MSI_ENABLE_MULTI		(MICROSEMI_NUM_MSI_IRQS_CODED << 20)
++#define MSI_MSG_ADDR_OFFSET		0xe4u
++#define MSI_MSG_UPPER_ADDR_OFFSET	0xe8u
++#define MSI_MSG_DATA_OFFSET		0xf0u
++
++/**
++ * struct microsemi_pcie_port - PCIe port information
++ * @pcie_base_addr: IO Mapped Register Base
++ * @axi_base_addr: AMBA Mapped Register Base
++ * @irq: Interrupt number
++ * @root_busno: Root Bus number
++ * @dev: Device pointer
++ * @msi_domain: MSI IRQ domain pointer
++ * @leg_domain: Legacy IRQ domain pointer
++ * @resources: Bus Resources
++ */
++struct microsemi_pcie_port {
++	struct platform_device *pdev;
++	void __iomem *pcie_base_addr;
++	void __iomem *axi_base_addr;
++	void __iomem *bridge_base_addr;
++	void __iomem *ctrl_base_addr;
++	int bridge;
++	u32 irq;
++	u8 root_busno;
++	struct device *dev;
++	struct irq_domain *msi_domain;
++	struct irq_domain *leg_domain;
++	struct list_head resources;
++	struct mutex lock;			/* protect bitmap variable */
++	DECLARE_BITMAP(msi_irq_in_use, MICROSEMI_NUM_MSI_IRQS);
++};
++
++static inline u32 pcie_read(struct microsemi_pcie_port *port, u32 reg)
++{
++	return readl(port->pcie_base_addr + reg);
++}
++
++static inline void pcie_write(struct microsemi_pcie_port *port,
++			      u32 val, u32 reg)
++{
++	writel(val, port->pcie_base_addr + reg);
++}
++
++static void microsemi_pcie_enable(struct microsemi_pcie_port *port)
++{
++	u32 enb;
++
++	enb = readl(port->bridge_base_addr + MICROSEMI_LTSSM_STATE);
++	enb |= MICROSEMI_LTSSM_L0_STATE;
++	writel(enb, port->bridge_base_addr + MICROSEMI_LTSSM_STATE);
++}
++
++/**
++ * microsemi_pcie_valid_device - Check if a valid device is present on bus
++ * @bus: PCI Bus structure
++ * @devfn: device/function
++ *
++ * Return: 'true' on success and 'false' if invalid device is found
++ */
++static bool microsemi_pcie_valid_device(struct pci_bus *bus, unsigned int devfn)
++{
++	struct microsemi_pcie_port *port = bus->sysdata;
++
++	/* Only one device down on each root port */
++	if (bus->number == port->root_busno && devfn > 0)
++		return false;
++
++	return true;
++}
++
++/**
++ * microsemi_pcie_map_bus - Get configuration base
++ * @bus: PCI Bus structure
++ * @devfn: Device/function
++ * @where: Offset from base
++ *
++ * Return: Base address of the configuration space needed to be
++ *	 accessed.
++ */
++static void __iomem *microsemi_pcie_map_bus(struct pci_bus *bus,
++					    unsigned int devfn, int where)
++{
++	struct microsemi_pcie_port *port = bus->sysdata;
++	int relbus;
++
++	if (!microsemi_pcie_valid_device(bus, devfn))
++		return NULL;
++
++	relbus = (bus->number << ECAM_BUS_NUM_SHIFT) |
++		(devfn << ECAM_DEV_NUM_SHIFT);
++
++	return port->pcie_base_addr + relbus + where;
++}
++
++/* PCIe operations */
++static struct pci_ops microsemi_pcie_ops = {
++	.map_bus = microsemi_pcie_map_bus,
++	.read	= pci_generic_config_read,
++	.write	= pci_generic_config_write,
++};
++
++/* MSI functions */
++
++/**
++ * microsemi_pcie_destroy_msi - Free MSI number
++ * @irq: IRQ to be freed
++ */
++static void microsemi_pcie_destroy_msi(unsigned int irq)
++{
++	struct microsemi_pcie_port *port =
++		msi_desc_to_pci_sysdata(irq_get_msi_desc(irq));
++	irq_hw_number_t hwirq = irqd_to_hwirq(irq_get_irq_data(irq));
++
++	if (!port)
++		return;
++
++	if (!test_bit(hwirq, port->msi_irq_in_use))
++		dev_err(port->dev, "trying to free unused MSI%d\n", irq);
++	else
++		clear_bit(hwirq, port->msi_irq_in_use);
++}
++
++/**
++ * microsemi_pcie_assign_msi - Allocate MSI number
++ *
++ * Return: A valid IRQ on success and error value on failure.
++ */
++static int microsemi_pcie_assign_msi(struct microsemi_pcie_port *port)
++{
++	int pos;
++
++	mutex_lock(&port->lock);
++	pos = find_first_zero_bit(port->msi_irq_in_use, MICROSEMI_NUM_MSI_IRQS);
++	if (pos < MICROSEMI_NUM_MSI_IRQS) {
++		set_bit(pos, port->msi_irq_in_use);
++	} else {
++		mutex_unlock(&port->lock);
++		return -ENOSPC;
++	}
++
++	mutex_unlock(&port->lock);
++	return pos;
++}
++
++/**
++ * microsemi_msi_teardown_irq - Destroy the MSI
++ * @chip: MSI Chip descriptor
++ * @irq: MSI IRQ to destroy
++ */
++static void microsemi_msi_teardown_irq(struct msi_controller *chip,
++				       unsigned int irq)
++{
++	microsemi_pcie_destroy_msi(irq);
++	irq_dispose_mapping(irq);
++}
++
++/**
++ * microsemi_pcie_msi_setup_irq - Setup MSI request
++ * @chip: MSI chip pointer
++ * @pdev: PCIe device pointer
++ * @desc: MSI descriptor pointer
++ *
++ * Return: '0' on success and error value on failure
++ */
++static int microsemi_pcie_msi_setup_irq(struct msi_controller *chip,
++					struct pci_dev *pdev,
++					struct msi_desc *desc)
++{
++	struct microsemi_pcie_port *port = pdev->bus->sysdata;
++	unsigned int irq;
++	int hwirq;
++	struct msi_msg msg;
++
++	hwirq = microsemi_pcie_assign_msi(port);
++	if (hwirq < 0)
++		return hwirq;
++
++	irq = irq_create_mapping(port->msi_domain, hwirq);
++	if (!irq)
++		return -EINVAL;
++
++	irq_set_msi_desc(irq, desc);
++
++	msg.address_hi = upper_32_bits(MICROSEMI_MSI_MSG_ADDR);
++	msg.address_lo = lower_32_bits(MICROSEMI_MSI_MSG_ADDR);
++	msg.data = hwirq;
++
++	pci_write_msi_msg(irq, &msg);
++
++	return 0;
++}
++
++/* MSI Chip Descriptor */
++static struct msi_controller microsemi_pcie_msi_chip = {
++	.setup_irq = microsemi_pcie_msi_setup_irq,
++	.teardown_irq = microsemi_msi_teardown_irq,
++};
++
++/* HW Interrupt Chip Descriptor */
++static struct irq_chip microsemi_msi_irq_chip = {
++	.name = "Microsemi PCIe MSI",
++	.irq_enable = pci_msi_unmask_irq,
++	.irq_disable = pci_msi_mask_irq,
++	.irq_mask = pci_msi_mask_irq,
++	.irq_unmask = pci_msi_unmask_irq,
++};
++
++/**
++ * microsemi_pcie_msi_map - Set the handler for the MSI and mark IRQ as valid
++ * @domain: IRQ domain
++ * @irq: Virtual IRQ number
++ * @hwirq: HW interrupt number
++ *
++ * Return: Always returns 0.
++ */
++static int microsemi_pcie_msi_map(struct irq_domain *domain, unsigned int irq,
++				  irq_hw_number_t hwirq)
++{
++	irq_set_chip_and_handler(irq, &microsemi_msi_irq_chip,
++				 handle_simple_irq);
++	irq_set_chip_data(irq, domain->host_data);
++
++	return 0;
++}
++
++/* IRQ Domain operations */
++static const struct irq_domain_ops msi_domain_ops = {
++	.map = microsemi_pcie_msi_map,
++};
++
++/**
++ * microsemi_pcie_enable_msi - Enable MSI support
++ * @port: PCIe port information
++ */
++static void microsemi_pcie_enable_msi(struct microsemi_pcie_port *port)
++{
++	u32 cap_ctrl;
++
++	cap_ctrl = pcie_read(port, MSI_CAP_CTRL_OFFSET);
++
++	pcie_write(port, cap_ctrl | MSI_ENABLE_MULTI |
++		MSI_ENABLE, MSI_CAP_CTRL_OFFSET);
++	pcie_write(port, MICROSEMI_MSI_MSG_ADDR, MSI_MSG_ADDR_OFFSET);
++}
++
++/* INTx Functions */
++
++/**
++ * microsemi_pcie_intx_map - Set the handler for the INTx and mark IRQ as valid
++ * @domain: IRQ domain
++ * @irq: Virtual IRQ number
++ * @hwirq: HW interrupt number
++ *
++ * Return: Always returns 0.
++ */
++static int microsemi_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
++				   irq_hw_number_t hwirq)
++{
++	irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_simple_irq);
++	irq_set_chip_data(irq, domain->host_data);
++
++	return 0;
++}
++
++/* INTx IRQ Domain operations */
++static const struct irq_domain_ops intx_domain_ops = {
++	.map = microsemi_pcie_intx_map,
++	.xlate = pci_irqd_intx_xlate,
++};
++
++/* PCIe HW Functions */
++
++/**
++ * microsemi_pcie_intr_handler - Interrupt Service Handler
++ * @irq: IRQ number
++ * @data: PCIe port information
++ *
++ * Return: IRQ_HANDLED on success and IRQ_NONE on failure
++ */
++static irqreturn_t microsemi_pcie_intr_handler(int irq, void *data)
++{
++	struct microsemi_pcie_port *port = (struct microsemi_pcie_port *)data;
++	struct device *dev = port->dev;
++	unsigned long status;
++	unsigned long msi;
++	u32 bit;
++	u32 virq;
++
++	status = readl(port->bridge_base_addr + MICROSEMI_ISTATUS_LOCAL);
++
++	/* Might be sharing interrupt line.  Check if interrupt is for us */
++	if (!status)
++		return IRQ_NONE;
++
++	status = (status & MICROSEMI_PCI_INTS) >> MICROSEMI_PM_MSI_INT_SHIFT;
++	for_each_set_bit(bit, &status, PCI_NUM_INTX) {
++		/* clear that interrupt bit */
++		writel(1 << (bit + MICROSEMI_PM_MSI_INT_SHIFT),
++		       port->bridge_base_addr + MICROSEMI_ISTATUS_LOCAL);
++		virq = irq_find_mapping(port->leg_domain, bit);
++
++		if (virq)
++			generic_handle_irq(virq);
++		else
++			dev_err(dev, "unexpected IRQ, INT%d\n", bit);
++	}
++
++	status = readl(port->bridge_base_addr + MICROSEMI_ISTATUS_LOCAL);
++	if (status & MICROSEMI_MSI_INT) {
++		/* Clear the ISTATUS MSI bit */
++		writel((1 << MICROSEMI_MSI_INT_SHIFT),
++		       port->bridge_base_addr + MICROSEMI_ISTATUS_LOCAL);
++		msi = readl(port->bridge_base_addr + MICROSEMI_ISTATUS_MSI);
++		for_each_set_bit(bit, &msi, MICROSEMI_NUM_MSI_IRQS) {
++			/* clear that MSI interrupt bit */
++			writel((1 << bit),
++			       port->bridge_base_addr + MICROSEMI_ISTATUS_MSI);
++			virq = irq_find_mapping(port->msi_domain, bit);
++			if (virq)
++				generic_handle_irq(virq);
++			else
++				dev_err(dev, "unexpected IRQ, INT%d\n", bit);
++		}
++	}
++
++	return IRQ_HANDLED;
++}
++
++/**
++ * microsemi_pcie_init_irq_domain - Initialize IRQ domain
++ * @port: PCIe port information
++ *
++ * Return: '0' on success and error value on failure
++ */
++static int microsemi_pcie_init_irq_domain(struct microsemi_pcie_port *port)
++{
++	struct device *dev = port->dev;
++	struct device_node *node = dev->of_node;
++	struct device_node *pcie_intc_node;
++
++	/* Setup INTx */
++	pcie_intc_node = of_get_next_child(node, NULL);
++	if (!pcie_intc_node) {
++		dev_err(dev, "no PCIe INTx node found\n");
++		return -ENODEV;
++	}
++
++	port->leg_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX,
++						 &intx_domain_ops,
++						 port);
++	if (!port->leg_domain) {
++		dev_err(dev, "failed to get a INTx IRQ domain\n");
++		return -ENODEV;
++	}
++
++	/* Setup MSI */
++	if (IS_ENABLED(CONFIG_PCI_MSI)) {
++		port->msi_domain =
++			irq_domain_add_linear(node,
++					      MICROSEMI_NUM_MSI_IRQS,
++					      &msi_domain_ops,
++					      &microsemi_pcie_msi_chip);
++		if (!port->msi_domain) {
++			dev_err(dev, "failed to get an MSI IRQ domain\n");
++			return -ENODEV;
++		}
++		microsemi_pcie_enable_msi(port);
++	}
++
++	/* Enable interrupts */
++	writel(MICROSEMI_PCIE_ENABLE_MSI | MICROSEMI_PCIE_LOCAL_INT_ENABLE,
++	       port->bridge_base_addr + MICROSEMI_IMASK_LOCAL);
++
++	return 0;
++}
++
++/**
++ * microsemi_pcie_init_port - Parse Device tree, Initialize hardware
++ * @port: PCIe port information
++ *
++ * Return: '0' on success and error value on failure
++ */
++static int microsemi_pcie_init_port(struct microsemi_pcie_port *port)
++{
++	struct device *dev = port->dev;
++	struct device_node *node = dev->of_node;
++	struct of_pci_range_parser parser;
++	struct of_pci_range range;
++	struct resource regs;
++	struct resource regs1;
++	resource_size_t size;
++	u32 atr_sz;
++	const char *type;
++	int err;
++	u32 val;
++	int index = 1;
++
++	type = of_get_property(node, "device_type", NULL);
++	if (!type || strcmp(type, "pci")) {
++		dev_err(dev, "invalid \"device_type\" %s\n", type);
++		return -EINVAL;
++	}
++
++	/* Only supporting bridge 1 */
++	port->bridge = 1;
++
++	mutex_init(&port->lock);
++
++	err = of_address_to_resource(node, 0, &regs);
++	if (err) {
++		dev_err(dev, "missing \"reg\" property\n");
++		return err;
++	}
++
++	port->pcie_base_addr = devm_pci_remap_cfg_resource(dev, &regs);
++	if (IS_ERR(port->pcie_base_addr))
++		return PTR_ERR(port->pcie_base_addr);
++
++	err = of_address_to_resource(node, 1, &regs1);
++	if (err) {
++		dev_err(dev, "missing \"reg\" property\n");
++		return err;
++	}
++
++	port->axi_base_addr = devm_ioremap_resource(dev, &regs1);
++	if (IS_ERR(port->axi_base_addr))
++		return PTR_ERR(port->axi_base_addr);
++
++	if (port->bridge == 0) {
++		port->bridge_base_addr = port->axi_base_addr
++			+ MICROSEMI_PCIE0_BRIDGE_ADDR;
++		port->ctrl_base_addr = port->axi_base_addr
++			+ MICROSEMI_PCIE0_CTRL_ADDR;
++	} else {
++		port->bridge_base_addr = port->axi_base_addr
++			+ MICROSEMI_PCIE1_BRIDGE_ADDR;
++		port->ctrl_base_addr = port->axi_base_addr
++			+ MICROSEMI_PCIE1_CTRL_ADDR;
++	}
++
++	port->irq = irq_of_parse_and_map(node, 0);
++
++	err = devm_request_irq(dev, port->irq, microsemi_pcie_intr_handler,
++			       IRQF_SHARED | IRQF_NO_THREAD,
++			       "microsemi-pcie", port);
++	if (err) {
++		dev_err(dev, "unable to request IRQ%d\n", port->irq);
++		return err;
++	}
++
++	microsemi_pcie_enable(port);
++
++	/* Clear and Disable interrupts */
++	val = ECC_CONTROL_AXI2PCIE_RAM_ECC_BYPASS
++		| ECC_CONTROL_PCIE2AXI_RAM_ECC_BYPASS
++		| ECC_CONTROL_RX_RAM_ECC_BYPASS
++		| ECC_CONTROL_TX_RAM_ECC_BYPASS;
++	writel(val, port->ctrl_base_addr + MICROSEMI_ECC_CONTROL);
++
++	val = PCIE_EVENT_INT_L2_EXIT_INT
++		| PCIE_EVENT_INT_HOTRST_EXIT_INT
++		| PCIE_EVENT_INT_DLUP_EXIT_INT
++		| PCIE_EVENT_INT_L2_EXIT_INT_MASK
++		| PCIE_EVENT_INT_HOTRST_EXIT_INT_MASK
++		| PCIE_EVENT_INT_DLUP_EXIT_INT_MASK;
++	writel(val, port->ctrl_base_addr + MICROSEMI_PCIE_EVENT_INT);
++
++	val = SEC_ERROR_INT_TX_RAM_SEC_ERR_INT
++		| SEC_ERROR_INT_RX_RAM_SEC_ERR_INT
++		| SEC_ERROR_INT_PCIE2AXI_RAM_SEC_ERR_INT
++		| SEC_ERROR_INT_AXI2PCIE_RAM_SEC_ERR_INT;
++	writel(val, port->ctrl_base_addr + MICROSEMI_SEC_ERROR_INT);
++	writel(val, port->ctrl_base_addr + MICROSEMI_SEC_ERROR_INT_MASK);
++
++	val = DED_ERROR_INT_TX_RAM_DED_ERR_INT
++		| DED_ERROR_INT_RX_RAM_DED_ERR_INT
++		| DED_ERROR_INT_PCIE2AXI_RAM_DED_ERR_INT
++		| DED_ERROR_INT_AXI2PCIE_RAM_DED_ERR_INT;
++	writel(val, port->ctrl_base_addr + MICROSEMI_DED_ERROR_INT);
++	writel(val, port->ctrl_base_addr + MICROSEMI_DED_ERROR_INT_MASK);
++
++	writel(0x00000000, port->bridge_base_addr + MICROSEMI_IMASK_LOCAL);
++	writel(GENMASK(31, 0),
++	       port->bridge_base_addr + MICROSEMI_ISTATUS_LOCAL);
++	writel(0x00000000, port->bridge_base_addr + MICROSEMI_IMASK_HOST);
++	writel(GENMASK(31, 0), port->bridge_base_addr + MICROSEMI_ISTATUS_HOST);
++
++	/* Configure Address Translation Table 0 for PCIe config space */
++	writel(MICROSEMI_PCIE_CONFIG_INTERFACE,
++	       port->bridge_base_addr + MICROSEMI_ATR0_AXI4_SLV0_TRSL_PARAM);
++
++	size = resource_size(&regs);
++
++	atr_sz = find_first_bit((const unsigned long *)&size, 64) - 1;
++
++	writel(lower_32_bits(regs.start)
++		| atr_sz << ATR_SIZE_SHIFT | ATR_IMPL_ENABLE,
++		port->bridge_base_addr
++		+ MICROSEMI_ATR0_AXI4_SLV0_SRCADDR_PARAM);
++
++	writel(lower_32_bits(regs.start),
++	       port->bridge_base_addr + MICROSEMI_ATR0_AXI4_SLV0_TRSL_ADDR_LSB);
++
++	if (of_pci_range_parser_init(&parser, node)) {
++		dev_err(dev, "missing \"ranges\" property\n");
++		return -EINVAL;
++	}
++
++	for_each_of_pci_range(&parser, &range) {
++		switch (range.flags & IORESOURCE_TYPE_BITS) {
++		case IORESOURCE_MEM:
++			size = range.size;
++			atr_sz =
++				find_first_bit((const unsigned long *)&size, 64)
++				- 1;
++
++			/* Configure Address Translation Table index for PCIe
++			 * mem space
++			 */
++			writel(MICROSEMI_PCIE_TX_RX_INTERFACE,
++			       port->bridge_base_addr
++				+ (index * MICROSEMI_ATR0_AXI4_SLV_SIZE)
++				+ MICROSEMI_ATR0_AXI4_SLV0_TRSL_PARAM);
++
++			writel(lower_32_bits(range.cpu_addr)
++				| (atr_sz << ATR_SIZE_SHIFT)
++				| ATR_IMPL_ENABLE,
++				port->bridge_base_addr
++				+ (index * MICROSEMI_ATR0_AXI4_SLV_SIZE)
++				+ MICROSEMI_ATR0_AXI4_SLV0_SRCADDR_PARAM);
++
++			writel(lower_32_bits(range.pci_addr),
++			       port->bridge_base_addr
++				+ (index * MICROSEMI_ATR0_AXI4_SLV_SIZE)
++				+ MICROSEMI_ATR0_AXI4_SLV0_TRSL_ADDR_LSB);
++
++			break;
++		}
++		index++;
++	}
++
++	writel(readl(port->bridge_base_addr
++		+ MICROSEMI_ATR0_PCIE_WIN0_SRCADDR_31_12)
++		| (MICROSEMI_ATR0_PCIE_WIN0_SIZE
++		<< MICROSEMI_ATR0_PCIE_WIN0_SIZE_SHIFT),
++		port->bridge_base_addr +
++		MICROSEMI_ATR0_PCIE_WIN0_SRCADDR_31_12);
++
++	writel(0x0,
++	       port->bridge_base_addr + MICROSEMI_ATR0_PCIE_WIN0_SRCADDR_63_32);
++
++	writel((readl(port->bridge_base_addr + MICROSEMI_PCIE_PCI_IDS_DW1)
++		& 0xffff)
++		| (PCI_CLASS_BRIDGE_PCI << 16),
++		port->bridge_base_addr + MICROSEMI_PCIE_PCI_IDS_DW1);
++
++	return 0;
++}
++
++/**
++ * microsemi_pcie_probe - Probe function
++ * @pdev: Platform device pointer
++ *
++ * Return: '0' on success and error value on failure
++ */
++static int microsemi_pcie_probe(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct microsemi_pcie_port *port;
++	struct pci_bus *bus, *child;
++	struct pci_host_bridge *bridge;
++	int err;
++	resource_size_t iobase = 0;
++	LIST_HEAD(res);
++
++	if (!dev->of_node)
++		return -ENODEV;
++
++	bridge = devm_pci_alloc_host_bridge(dev, sizeof(*port));
++	if (!bridge)
++		return -ENODEV;
++
++	port = pci_host_bridge_priv(bridge);
++
++	port->dev = dev;
++	port->pdev = pdev;
++
++	err = microsemi_pcie_init_port(port);
++	if (err) {
++		dev_err(dev, "PCIe port initialization failed\n");
++		return err;
++	}
++
++	err = microsemi_pcie_init_irq_domain(port);
++	if (err) {
++		dev_err(dev, "failed creating IRQ domain\n");
++		return err;
++	}
++
++	err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res,
++						    &iobase);
++	if (err) {
++		dev_err(dev, "getting bridge resources failed\n");
++		return err;
++	}
++
++	err = devm_request_pci_bus_resources(dev, &res);
++	if (err)
++		goto error;
++
++	list_splice_init(&res, &bridge->windows);
++	bridge->dev.parent = dev;
++	bridge->sysdata = port;
++	bridge->busnr = 0;
++	bridge->ops = &microsemi_pcie_ops;
++	bridge->map_irq = of_irq_parse_and_map_pci;
++	bridge->swizzle_irq = pci_common_swizzle;
++
++#ifdef CONFIG_PCI_MSI
++	microsemi_pcie_msi_chip.dev = dev;
++	bridge->msi = &microsemi_pcie_msi_chip;
++#endif
++	err = pci_scan_root_bus_bridge(bridge);
++	if (err < 0)
++		goto error;
++
++	bus = bridge->bus;
++
++	pci_assign_unassigned_bus_resources(bus);
++	list_for_each_entry(child, &bus->children, node)
++		pcie_bus_configure_settings(child);
++	pci_bus_add_devices(bus);
++
++	return 0;
++
++error:
++	pci_free_resource_list(&res);
++	return err;
++}
++
++static const struct of_device_id microsemi_pcie_of_match[] = {
++	{ .compatible = "microsemi,ms-pf-axi-pcie-host", },
++	{}
++};
++
++static struct platform_driver microsemi_pcie_driver = {
++	.driver = {
++		.name = "microsemi-pcie",
++		.of_match_table = microsemi_pcie_of_match,
++		.suppress_bind_attrs = true,
++	},
++	.probe = microsemi_pcie_probe,
++};
++builtin_platform_driver(microsemi_pcie_driver);
+-- 
+2.22.0
+

+ 0 - 333
recipes-kernel/linux/files/freedom-u540/0004-u54-prci-driver-for-core-U54-clocks.patch

@@ -1,333 +0,0 @@
-From 883228d88d9ad6edc7ed9a4540926e80a22c560f 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 04/10] u54-prci: driver for core U54 clocks
-
----
- drivers/clk/sifive/u54-prci.c | 314 ++++++++++++++++++++++++++++++++++
- 1 file changed, 314 insertions(+)
- create mode 100644 drivers/clk/sifive/u54-prci.c
-
-diff --git a/drivers/clk/sifive/u54-prci.c b/drivers/clk/sifive/u54-prci.c
-new file mode 100644
-index 000000000000..edc4b7818e71
---- /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);
--- 
-2.21.0
-

+ 50 - 0
recipes-kernel/linux/files/freedom-u540/0005-Microsemi-PCIe-expansion-board-DT-entry.patch

@@ -0,0 +1,50 @@
+From b290b577a77f91233c0e68cab85436a8de2ebbd0 Mon Sep 17 00:00:00 2001
+From: Atish Patra <atish.patra@wdc.com>
+Date: Fri, 21 Jun 2019 12:36:21 -0700
+Subject: [PATCH 5/6] Microsemi PCIe expansion board DT entry.
+
+Signed-off-by: Atish Patra <atish.patra@wdc.com>
+Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
+Upstream-Status: Inappropriate [enable feature]
+---
+ .../sifive/hifive-unleashed-a00-microsemi.dts | 28 +++++++++++++++++++
+ 1 file changed, 28 insertions(+)
+ create mode 100644 arch/riscv/boot/dts/sifive/hifive-unleashed-a00-microsemi.dts
+
+diff --git a/arch/riscv/boot/dts/sifive/hifive-unleashed-a00-microsemi.dts b/arch/riscv/boot/dts/sifive/hifive-unleashed-a00-microsemi.dts
+new file mode 100644
+index 000000000000..4d25606f4e0c
+--- /dev/null
++++ b/arch/riscv/boot/dts/sifive/hifive-unleashed-a00-microsemi.dts
+@@ -0,0 +1,28 @@
++// SPDX-License-Identifier: (GPL-2.0 OR MIT)
++
++#include "hifive-unleashed-a00.dts"
++
++/ {
++	soc {
++		pcie: pcie@2030000000 {
++			#address-cells = <0x3>;
++			#interrupt-cells = <0x1>;
++			#size-cells = <0x2>;
++			compatible = "microsemi,ms-pf-axi-pcie-host";
++			device_type = "pci";
++			bus-range = <0x01 0x7f>;
++			interrupt-map = <0 0 0 1 &ms_pcie_intc 0 0 0 0 2 &ms_pcie_intc 1 0 0 0 3 &ms_pcie_intc 2 0 0 0 4 &ms_pcie_intc 3>;
++			interrupt-map-mask = <0 0 0 7>;
++			interrupt-parent = <&plic0>;
++			interrupts = <32>;
++			ranges = <0x3000000 0x0 0x40000000 0x0 0x40000000 0x0 0x20000000>;
++			reg = <0x20 0x30000000 0x0 0x4000000 0x20 0x0 0x0 0x100000>;
++			reg-names = "control", "apb";
++			ms_pcie_intc: interrupt-controller {
++				#address-cells = <0>;
++				#interrupt-cells = <1>;
++				interrupt-controller;
++			};
++		};
++	};
++};
+-- 
+2.22.0
+

+ 0 - 409
recipes-kernel/linux/files/freedom-u540/0005-gpio-sifive-support-GPIO-on-SiFive-SoCs.patch

@@ -1,409 +0,0 @@
-From 9b081d5eb7cd900b8ed96c1ee01f515de11fb174 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 05/10] 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 000000000000..bf41eed81dbf
---- /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 3f50526a771f..2a0115b0df97 100644
---- a/drivers/gpio/Kconfig
-+++ b/drivers/gpio/Kconfig
-@@ -451,6 +451,13 @@ config GPIO_SAMA5D2_PIOBU
- 	  The difference from regular GPIOs is that they
- 	  maintain their value during backup/self-refresh.
- 
-+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_SIOX
- 	tristate "SIOX GPIO support"
- 	depends on SIOX
-diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
-index 54d55274b93a..660e2e70f05c 100644
---- a/drivers/gpio/Makefile
-+++ b/drivers/gpio/Makefile
-@@ -114,6 +114,7 @@ obj-$(CONFIG_ARCH_SA1100)	+= gpio-sa1100.o
- obj-$(CONFIG_GPIO_SAMA5D2_PIOBU)	+= gpio-sama5d2-piobu.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_SNPS_CREG)	+= gpio-creg-snps.o
- obj-$(CONFIG_GPIO_SODAVILLE)	+= gpio-sodaville.o
- obj-$(CONFIG_GPIO_SPEAR_SPICS)	+= gpio-spear-spics.o
-diff --git a/drivers/gpio/gpio-sifive.c b/drivers/gpio/gpio-sifive.c
-new file mode 100644
-index 000000000000..6482ebbc00ce
---- /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.21.0
-

+ 5 - 4
recipes-kernel/linux/files/freedom-u540/0009-HACK-Revert-of-device-Really-only-set-bus-DMA-mask-w.patch → recipes-kernel/linux/files/freedom-u540/0006-HACK-Revert-of-device-Really-only-set-bus-DMA-mask-w.patch

@@ -1,7 +1,7 @@
-From 9b3b6bc3456ac35aaf99a3182f8a40485abef67b Mon Sep 17 00:00:00 2001
+From 41fce8c7589f76b6cd09d56db0f4ddd971a6dbd6 Mon Sep 17 00:00:00 2001
 From: Alistair Francis <alistair.francis@wdc.com>
 Date: Thu, 21 Feb 2019 16:29:37 -0800
-Subject: [PATCH 09/10] HACK: Revert "of/device: Really only set bus DMA mask
+Subject: [PATCH 6/6] HACK: Revert "of/device: Really only set bus DMA mask
  when appropriate"
 
 This reverts commit 6778be4e520959659b27a441c06a84c9cb009085.
@@ -15,12 +15,13 @@ USB bus when attaching a USB to PCIe card to a RISC-V board:
     xhci_hcd 0000:03:00.0: remove, state 1
 
 Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
+Upstream-Status: Denied
 ---
  drivers/of/device.c | 4 +---
  1 file changed, 1 insertion(+), 3 deletions(-)
 
 diff --git a/drivers/of/device.c b/drivers/of/device.c
-index 3717f2a20d0d..8299f8055da7 100644
+index da8158392010..e1fb703ff603 100644
 --- a/drivers/of/device.c
 +++ b/drivers/of/device.c
 @@ -149,11 +149,9 @@ int of_dma_configure(struct device *dev, struct device_node *np, bool force_dma)
@@ -37,5 +38,5 @@ index 3717f2a20d0d..8299f8055da7 100644
  	coherent = of_dma_is_coherent(np);
  	dev_dbg(dev, "device is%sdma coherent\n",
 -- 
-2.21.0
+2.22.0
 

+ 0 - 342
recipes-kernel/linux/files/freedom-u540/0006-pwm-sifive-add-a-driver-for-SiFive-SoC-PWM.patch

@@ -1,342 +0,0 @@
-From f263b4b12a93490dbb1af78a51a6f06129448226 Mon Sep 17 00:00:00 2001
-From: "Wesley W. Terpstra" <wesley@sifive.com>
-Date: Fri, 2 Mar 2018 14:53:51 -0800
-Subject: [PATCH 06/10] pwm-sifive: add a driver for SiFive SoC PWM
-
----
- .../devicetree/bindings/pwm/pwm-sifive.txt    |  28 ++
- drivers/pwm/Kconfig                           |  10 +
- drivers/pwm/Makefile                          |   1 +
- drivers/pwm/pwm-sifive.c                      | 252 ++++++++++++++++++
- 4 files changed, 291 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/pwm/pwm-sifive.txt
- create mode 100644 drivers/pwm/pwm-sifive.c
-
-diff --git a/Documentation/devicetree/bindings/pwm/pwm-sifive.txt b/Documentation/devicetree/bindings/pwm/pwm-sifive.txt
-new file mode 100644
-index 000000000000..7cea20db58e5
---- /dev/null
-+++ b/Documentation/devicetree/bindings/pwm/pwm-sifive.txt
-@@ -0,0 +1,28 @@
-+SiFive PWM controller
-+
-+Unlike most other PWM controllers, the SiFive PWM controller currently only
-+supports one period for all channels in the PWM. This is set globally in DTS.
-+The period also has significant restrictions on the values it can achieve,
-+which the driver rounds to the nearest achievable frequency.
-+
-+Required properties:
-+- compatible: should be "sifive,pwm0"
-+- reg: physical base address and length of the controller's registers
-+- clocks: The frequency the controller runs at
-+- #pwm-cells: Should be 2.
-+  The first cell is the PWM channel number
-+  The second cell is the PWM polarity
-+- sifive,approx-period: the driver will get as close to this period as it can
-+- interrupts: one interrupt per PWM channel (currently unused in the driver)
-+
-+Examples:
-+
-+pwm:  pwm@10020000 {
-+	compatible = "sifive,pwm0";
-+	reg = <0x0 0x10020000 0x0 0x1000>;
-+	clocks = <&tlclk>;
-+	interrupt-parent = <&plic>;
-+	interrupts = <42 43 44 45>;
-+	#pwm-cells = <2>;
-+	sifive,approx-period = <1000000>;
-+};
-diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
-index 54f8238aac0d..995b9f654d46 100644
---- a/drivers/pwm/Kconfig
-+++ b/drivers/pwm/Kconfig
-@@ -389,6 +389,16 @@ config PWM_SAMSUNG
- 	  To compile this driver as a module, choose M here: the module
- 	  will be called pwm-samsung.
- 
-+config PWM_SIFIVE
-+	tristate "SiFive PWM support"
-+	depends on OF
-+	depends on COMMON_CLK
-+	help
-+	  Generic PWM framework driver for SiFive SoCs.
-+
-+	  To compile this driver as a module, choose M here: the module
-+	  will be called pwm-sifive.
-+
- config PWM_SPEAR
- 	tristate "STMicroelectronics SPEAr PWM support"
- 	depends on PLAT_SPEAR
-diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
-index 448825e892bc..0da3e99b0186 100644
---- a/drivers/pwm/Makefile
-+++ b/drivers/pwm/Makefile
-@@ -38,6 +38,7 @@ obj-$(CONFIG_PWM_RCAR)		+= pwm-rcar.o
- obj-$(CONFIG_PWM_RENESAS_TPU)	+= pwm-renesas-tpu.o
- obj-$(CONFIG_PWM_ROCKCHIP)	+= pwm-rockchip.o
- obj-$(CONFIG_PWM_SAMSUNG)	+= pwm-samsung.o
-+obj-$(CONFIG_PWM_SIFIVE)	+= pwm-sifive.o
- obj-$(CONFIG_PWM_SPEAR)		+= pwm-spear.o
- obj-$(CONFIG_PWM_STI)		+= pwm-sti.o
- obj-$(CONFIG_PWM_STM32)		+= pwm-stm32.o
-diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c
-new file mode 100644
-index 000000000000..93bc0844d23a
---- /dev/null
-+++ b/drivers/pwm/pwm-sifive.c
-@@ -0,0 +1,252 @@
-+/*
-+ * 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 <dt-bindings/pwm/pwm.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/pwm.h>
-+#include <linux/slab.h>
-+#include <linux/clk.h>
-+#include <linux/io.h>
-+
-+#define MAX_PWM			4
-+
-+/* Register offsets */
-+#define REG_PWMCFG		0x0
-+#define REG_PWMCOUNT		0x8
-+#define REG_PWMS		0x10
-+#define	REG_PWMCMP0		0x20
-+
-+/* PWMCFG fields */
-+#define BIT_PWM_SCALE		0
-+#define BIT_PWM_STICKY		8
-+#define BIT_PWM_ZERO_ZMP	9
-+#define BIT_PWM_DEGLITCH	10
-+#define BIT_PWM_EN_ALWAYS	12
-+#define BIT_PWM_EN_ONCE		13
-+#define BIT_PWM0_CENTER		16
-+#define BIT_PWM0_GANG		24
-+#define BIT_PWM0_IP		28
-+
-+#define SIZE_PWMCMP		4
-+#define MASK_PWM_SCALE		0xf
-+
-+struct sifive_pwm_device {
-+	struct pwm_chip		chip;
-+	struct notifier_block	notifier;
-+	struct clk		*clk;
-+	void __iomem		*regs;
-+	int 			irq;
-+	unsigned int		approx_period;
-+	unsigned int		real_period;
-+};
-+
-+static inline struct sifive_pwm_device *chip_to_sifive(struct pwm_chip *c)
-+{
-+	return container_of(c, struct sifive_pwm_device, chip);
-+}
-+
-+static inline struct sifive_pwm_device *notifier_to_sifive(struct notifier_block *nb)
-+{
-+	return container_of(nb, struct sifive_pwm_device, notifier);
-+}
-+
-+static int sifive_pwm_apply(struct pwm_chip *chip, struct pwm_device *dev, struct pwm_state *state)
-+{
-+	struct sifive_pwm_device *pwm = chip_to_sifive(chip);
-+	unsigned int duty_cycle;
-+	u32 frac;
-+
-+	duty_cycle = state->duty_cycle;
-+	if (!state->enabled) duty_cycle = 0;
-+	if (state->polarity == PWM_POLARITY_NORMAL) duty_cycle = state->period - duty_cycle;
-+
-+	frac = ((u64)duty_cycle << 16) / state->period;
-+	frac = min(frac, 0xFFFFU);
-+
-+	iowrite32(frac, pwm->regs + REG_PWMCMP0 + (dev->hwpwm * SIZE_PWMCMP));
-+
-+	if (state->enabled) {
-+		state->period = pwm->real_period;
-+		state->duty_cycle = ((u64)frac * pwm->real_period) >> 16;
-+		if (state->polarity == PWM_POLARITY_NORMAL)
-+			state->duty_cycle = state->period - state->duty_cycle;
-+	}
-+
-+	return 0;
-+}
-+
-+static void sifive_pwm_get_state(struct pwm_chip *chip, struct pwm_device *dev, struct pwm_state *state)
-+{
-+	struct sifive_pwm_device *pwm = chip_to_sifive(chip);
-+	unsigned long duty;
-+
-+	duty = ioread32(pwm->regs + REG_PWMCMP0 + (dev->hwpwm * SIZE_PWMCMP));
-+
-+	state->period     = pwm->real_period;
-+	state->duty_cycle = ((u64)duty * pwm->real_period) >> 16;
-+	state->polarity   = PWM_POLARITY_INVERSED;
-+	state->enabled    = duty > 0;
-+}
-+
-+static const struct pwm_ops sifive_pwm_ops = {
-+	.get_state	= sifive_pwm_get_state,
-+	.apply		= sifive_pwm_apply,
-+	.owner		= THIS_MODULE,
-+};
-+
-+static struct pwm_device *sifive_pwm_xlate(struct pwm_chip *chip, const struct of_phandle_args *args)
-+{
-+	struct sifive_pwm_device *pwm = chip_to_sifive(chip);
-+	struct pwm_device *dev;
-+
-+	if (args->args[0] >= chip->npwm)
-+		return ERR_PTR(-EINVAL);
-+
-+	dev = pwm_request_from_chip(chip, args->args[0], NULL);
-+	if (IS_ERR(dev))
-+		return dev;
-+
-+	/* The period cannot be changed on a per-PWM basis */
-+	dev->args.period   = pwm->real_period;
-+	dev->args.polarity = PWM_POLARITY_NORMAL;
-+	if (args->args[1] & PWM_POLARITY_INVERTED)
-+		dev->args.polarity = PWM_POLARITY_INVERSED;
-+
-+	return dev;
-+}
-+
-+static void sifive_pwm_update_clock(struct sifive_pwm_device *pwm, unsigned long rate)
-+{
-+	/* (1 << (16+scale)) * 10^9/rate = real_period */
-+	unsigned long scalePow = (pwm->approx_period * (u64)rate) / 1000000000;
-+	int scale = ilog2(scalePow) - 16;
-+
-+	scale = clamp(scale, 0, 0xf);
-+	iowrite32((1 << BIT_PWM_EN_ALWAYS) | (scale << BIT_PWM_SCALE), pwm->regs + REG_PWMCFG);
-+
-+	pwm->real_period = (1000000000ULL << (16 + scale)) / rate;
-+}
-+
-+static int sifive_pwm_clock_notifier(struct notifier_block *nb, unsigned long event, void *data)
-+{
-+	struct clk_notifier_data *ndata = data;
-+	struct sifive_pwm_device *pwm = notifier_to_sifive(nb);
-+
-+	if (event == POST_RATE_CHANGE)
-+		sifive_pwm_update_clock(pwm, ndata->new_rate);
-+
-+	return NOTIFY_OK;
-+}
-+
-+static int sifive_pwm_probe(struct platform_device *pdev)
-+{
-+	struct device *dev = &pdev->dev;
-+	struct device_node *node = pdev->dev.of_node;
-+	struct sifive_pwm_device *pwm;
-+	struct pwm_chip *chip;
-+	struct resource *res;
-+	int ret;
-+
-+	pwm = devm_kzalloc(dev, sizeof(*pwm), GFP_KERNEL);
-+	if (!pwm) {
-+		dev_err(dev, "Out of memory\n");
-+		return -ENOMEM;
-+	}
-+
-+	chip = &pwm->chip;
-+	chip->dev = dev;
-+	chip->ops = &sifive_pwm_ops;
-+	chip->of_xlate = sifive_pwm_xlate;
-+	chip->of_pwm_n_cells = 2;
-+	chip->base = -1;
-+
-+	ret = of_property_read_u32(node, "sifive,npwm", &chip->npwm);
-+	if (ret < 0 || chip->npwm > MAX_PWM) chip->npwm = MAX_PWM;
-+
-+	ret = of_property_read_u32(node, "sifive,approx-period", &pwm->approx_period);
-+	if (ret < 0) {
-+		dev_err(dev, "Unable to read sifive,approx-period from DTS\n");
-+		return -ENOENT;
-+	}
-+
-+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+	pwm->regs = devm_ioremap_resource(dev, res);
-+	if (IS_ERR(pwm->regs)) {
-+		dev_err(dev, "Unable to map IO resources\n");
-+		return PTR_ERR(pwm->regs);
-+	}
-+
-+	pwm->clk = devm_clk_get(dev, NULL);
-+	if (IS_ERR(pwm->clk)) {
-+		dev_err(dev, "Unable to find controller clock\n");
-+		return PTR_ERR(pwm->clk);
-+	}
-+
-+	pwm->irq = platform_get_irq(pdev, 0);
-+	if (pwm->irq < 0) {
-+		dev_err(dev, "Unable to find interrupt\n");
-+		return pwm->irq;
-+	}
-+
-+	/* Watch for changes to underlying clock frequency */
-+	pwm->notifier.notifier_call = sifive_pwm_clock_notifier;
-+	clk_notifier_register(pwm->clk, &pwm->notifier);
-+
-+	/* Initialize PWM config */
-+	sifive_pwm_update_clock(pwm, clk_get_rate(pwm->clk));
-+
-+	/* No interrupt handler needed yet */
-+/*
-+	ret = devm_request_irq(dev, pwm->irq, sifive_pwm_irq, 0, dev_name(dev), pwm);
-+	if (ret) {
-+		dev_err(dev, "Unable to bind interrupt\n");
-+		return ret;
-+	}
-+*/
-+
-+	ret = pwmchip_add(chip);
-+	if (ret < 0) {
-+		dev_err(dev, "cannot register PWM: %d\n", ret);
-+		clk_notifier_unregister(pwm->clk, &pwm->notifier);
-+		return ret;
-+	}
-+
-+	platform_set_drvdata(pdev, pwm);
-+	dev_info(dev, "SiFive PWM chip registered %d PWMs\n", chip->npwm);
-+
-+	return 0;
-+}
-+
-+static int sifive_pwm_remove(struct platform_device *dev)
-+{
-+	struct sifive_pwm_device *pwm = platform_get_drvdata(dev);
-+	struct pwm_chip *chip = &pwm->chip;
-+
-+	clk_notifier_unregister(pwm->clk, &pwm->notifier);
-+	return pwmchip_remove(chip);
-+}
-+
-+static const struct of_device_id sifive_pwm_of_match[] = {
-+	{ .compatible = "sifive,pwm0" },
-+	{},
-+};
-+MODULE_DEVICE_TABLE(of, sifive_pwm_of_match);
-+
-+static struct platform_driver sifive_pwm_driver = {
-+	.probe = sifive_pwm_probe,
-+	.remove = sifive_pwm_remove,
-+	.driver = {
-+		.name = "pwm-sifivem",
-+		.of_match_table = of_match_ptr(sifive_pwm_of_match),
-+	},
-+};
-+module_platform_driver(sifive_pwm_driver);
-+
-+MODULE_DESCRIPTION("SiFive PWM driver");
-+MODULE_LICENSE("GPL v2");
--- 
-2.21.0
-

+ 1 - 0
recipes-kernel/linux/files/freedom-u540/0010-HACK-radeon-Don-t-set-PCI-DMA-mask.patch → recipes-kernel/linux/files/freedom-u540/0007-HACK-radeon-Don-t-set-PCI-DMA-mask.patch

@@ -13,6 +13,7 @@ and results with a partially working graphcis card. By not setting a DMA
 mask the messages aren't seen and the GPU works.
 
 Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
+Upstream-Status: Denied
 ---
  drivers/gpu/drm/radeon/radeon_device.c | 11 +++++------
  1 file changed, 5 insertions(+), 6 deletions(-)

+ 0 - 39
recipes-kernel/linux/files/freedom-u540/0007-RISC-V-Networking-fix-Hack.patch

@@ -1,39 +0,0 @@
-From b720ad246b285e678cc16f0c35ef1921ace80043 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 07/10] 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 4be4cc09eb90..a69a95304cb3 100644
---- a/drivers/net/phy/mdio_bus.c
-+++ b/drivers/net/phy/mdio_bus.c
-@@ -57,9 +57,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.21.0
-

+ 0 - 829
recipes-kernel/linux/files/freedom-u540/0008-pcie-microsemi-Add-support-for-the-Vera-board-root-c.patch

@@ -1,829 +0,0 @@
-From 9ecb60c4fd1cd7e85973427527167eaac137bfe9 Mon Sep 17 00:00:00 2001
-From: "Wesley W. Terpstra" <wesley@sifive.com>
-Date: Wed, 25 Apr 2018 12:10:15 -0700
-Subject: [PATCH 08/10] pcie-microsemi: Add support for the Vera-board root
- complex
-
-Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
----
- drivers/pci/controller/Kconfig          |   6 +
- drivers/pci/controller/Makefile         |   1 +
- drivers/pci/controller/pcie-microsemi.c | 778 ++++++++++++++++++++++++
- 3 files changed, 785 insertions(+)
- create mode 100644 drivers/pci/controller/pcie-microsemi.c
-
-diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
-index 6012f3059acd..284cea1b6ba1 100644
---- a/drivers/pci/controller/Kconfig
-+++ b/drivers/pci/controller/Kconfig
-@@ -280,5 +280,11 @@ config VMD
- 	  To compile this driver as a module, choose M here: the
- 	  module will be called vmd.
- 
-+config PCIE_MICROSEMI
-+	bool "Microsemi AXI PCIe host bridge support"
-+	depends on OF || COMPILE_TEST
-+	help
-+	  Say 'Y' here if you want kernel to support the Microsemi AXI PCIe
-+	  Host Bridge driver.
- source "drivers/pci/controller/dwc/Kconfig"
- endmenu
-diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile
-index d56a507495c5..c3b76ff221be 100644
---- a/drivers/pci/controller/Makefile
-+++ b/drivers/pci/controller/Makefile
-@@ -28,6 +28,7 @@ obj-$(CONFIG_PCIE_ROCKCHIP_HOST) += pcie-rockchip-host.o
- obj-$(CONFIG_PCIE_MEDIATEK) += pcie-mediatek.o
- obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o
- obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o
-+obj-$(CONFIG_PCIE_MICROSEMI) += pcie-microsemi.o
- obj-$(CONFIG_VMD) += vmd.o
- # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
- obj-y				+= dwc/
-diff --git a/drivers/pci/controller/pcie-microsemi.c b/drivers/pci/controller/pcie-microsemi.c
-new file mode 100644
-index 000000000000..8e65059e4cf0
---- /dev/null
-+++ b/drivers/pci/controller/pcie-microsemi.c
-@@ -0,0 +1,778 @@
-+/*
-+ * PCIe host controller driver for Microsemi AXI PCIe Bridge
-+ *
-+ * Copyright (c) 2018 - Microsemi.
-+ *
-+ * Based on:
-+ *  pcie-rcar.c
-+ *  pcie-xilinx.c
-+ *  pcie-altera.c
-+ *
-+ * 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.
-+ */
-+
-+#include <linux/bitmap.h>
-+#include <linux/interrupt.h>
-+#include <linux/irq.h>
-+#include <linux/irqdomain.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/msi.h>
-+#include <linux/of_address.h>
-+#include <linux/of_pci.h>
-+#include <linux/of_platform.h>
-+#include <linux/of_irq.h>
-+#include <linux/pci.h>
-+#include <linux/platform_device.h>
-+
-+#include "../pci.h"
-+
-+/* ECAM definitions */
-+#define ECAM_BUS_NUM_SHIFT                  20
-+#define ECAM_DEV_NUM_SHIFT                  12
-+
-+/* Number of MSI IRQs */
-+#define MICROSEMI_NUM_MSI_IRQS              32
-+#define MICROSEMI_NUM_MSI_IRQS_CODED         5
-+
-+/* PCIe Bridge Phy and Controller Phy offsets */
-+#define MICROSEMI_PCIE0_BRIDGE_ADDR                   0x00004000u
-+#define MICROSEMI_PCIE0_CTRL_ADDR                     0x00006000u
-+
-+#define MICROSEMI_PCIE1_BRIDGE_ADDR                   0x00008000u
-+#define MICROSEMI_PCIE1_CTRL_ADDR                     0x0000A000u
-+
-+/* PCIe Controller Phy Regs */
-+#define MICROSEMI_SEC_ERROR_INT                       0x28
-+#define  SEC_ERROR_INT_TX_RAM_SEC_ERR_INT              GENMASK(3,0)
-+#define  SEC_ERROR_INT_RX_RAM_SEC_ERR_INT              GENMASK(7,4)
-+#define  SEC_ERROR_INT_PCIE2AXI_RAM_SEC_ERR_INT        GENMASK(11,8)
-+#define  SEC_ERROR_INT_AXI2PCIE_RAM_SEC_ERR_INT        GENMASK(15,12)
-+#define MICROSEMI_SEC_ERROR_INT_MASK                  0x2c
-+#define MICROSEMI_DED_ERROR_INT                       0x30
-+#define  DED_ERROR_INT_TX_RAM_DED_ERR_INT              GENMASK(3,0)
-+#define  DED_ERROR_INT_RX_RAM_DED_ERR_INT              GENMASK(7,4)
-+#define  DED_ERROR_INT_PCIE2AXI_RAM_DED_ERR_INT        GENMASK(11,8)
-+#define  DED_ERROR_INT_AXI2PCIE_RAM_DED_ERR_INT        GENMASK(15,12)
-+#define MICROSEMI_DED_ERROR_INT_MASK                  0x34
-+#define MICROSEMI_ECC_CONTROL                         0x38
-+#define  ECC_CONTROL_AXI2PCIE_RAM_ECC_BYPASS           BIT(27)
-+#define  ECC_CONTROL_PCIE2AXI_RAM_ECC_BYPASS           BIT(26)
-+#define  ECC_CONTROL_RX_RAM_ECC_BYPASS                 BIT(25)
-+#define  ECC_CONTROL_TX_RAM_ECC_BYPASS                 BIT(24)
-+#define MICROSEMI_LTSSM_STATE                         0x5c
-+#define  MICROSEMI_LTSSM_L0_STATE                      0x10
-+#define MICROSEMI_PCIE_EVENT_INT                      0x14c
-+#define  PCIE_EVENT_INT_L2_EXIT_INT                    BIT(0)
-+#define  PCIE_EVENT_INT_HOTRST_EXIT_INT                BIT(1)
-+#define  PCIE_EVENT_INT_DLUP_EXIT_INT                  BIT(2)
-+#define  PCIE_EVENT_INT_L2_EXIT_INT_MASK               BIT(16)
-+#define  PCIE_EVENT_INT_HOTRST_EXIT_INT_MASK           BIT(17)
-+#define  PCIE_EVENT_INT_DLUP_EXIT_INT_MASK             BIT(18)
-+
-+/* PCIe Bridge Phy Regs */
-+#define MICROSEMI_PCIE_PCI_IDS_DW1                    0x9c
-+#define MICROSEMI_IMASK_LOCAL                         0x180
-+#define  MICROSEMI_PCIE_LOCAL_INT_ENABLE               0x0F000000u
-+#define  MICROSEMI_PCI_INTS                            0x0F000000u
-+#define  MICROSEMI_PM_MSI_INT_SHIFT                    24
-+#define  MICROSEMI_PCIE_ENABLE_MSI                     0x10000000u
-+#define  MICROSEMI_MSI_INT                             0x10000000u
-+#define  MICROSEMI_MSI_INT_SHIFT                       28
-+#define MICROSEMI_ISTATUS_LOCAL                       0x184
-+#define MICROSEMI_IMASK_HOST                          0x188
-+#define MICROSEMI_ISTATUS_HOST                        0x18c
-+#define MICROSEMI_ISTATUS_MSI                         0x194
-+
-+/* PCIe AXI slave table init defines */
-+#define MICROSEMI_ATR0_AXI4_SLV0_SRCADDR_PARAM        0x800u
-+#define  ATR_SIZE_SHIFT                                (1)
-+#define  ATR_IMPL_ENABLE                               (1)
-+#define MICROSEMI_ATR0_AXI4_SLV0_SRC_ADDR             0x804u
-+#define MICROSEMI_ATR0_AXI4_SLV0_TRSL_ADDR_LSB        0x808u
-+#define MICROSEMI_ATR0_AXI4_SLV0_TRSL_ADDR_UDW        0x80cu
-+#define MICROSEMI_ATR0_AXI4_SLV0_TRSL_PARAM           0x810u
-+#define  MICROSEMI_PCIE_TX_RX_INTERFACE                0x00000000u
-+#define  MICROSEMI_PCIE_CONFIG_INTERFACE               0x00000001u
-+
-+
-+#define MICROSEMI_ATR0_AXI4_SLV_SIZE                  (32)
-+
-+/* PCIe Master table init defines */
-+#define MICROSEMI_ATR0_PCIE_WIN0_SRCADDR_31_12        0x600u
-+#define  MICROSEMI_ATR0_PCIE_WIN0_SIZE                 (0x1f)
-+#define  MICROSEMI_ATR0_PCIE_WIN0_SIZE_SHIFT           (1)
-+#define MICROSEMI_ATR0_PCIE_WIN0_SRCADDR_63_32        0x604u
-+
-+#define MICROSEMI_MSI_MSG_ADDR                        0x190u
-+
-+/* PCIe Config space MSI capability structure */
-+#define MSI_CAP_CTRL_OFFSET                 0xE0u
-+#define  MSI_ENABLE                          (0x01u << 16)
-+#define  MSI_ENABLE_MULTI                    (MICROSEMI_NUM_MSI_IRQS_CODED << 20)
-+#define MSI_MSG_ADDR_OFFSET                 0xE4u
-+#define MSI_MSG_UPPER_ADDR_OFFSET           0xE8u
-+#define MSI_MSG_DATA_OFFSET                 0xF0u
-+
-+
-+/**
-+ * struct microsemi_pcie_port - PCIe port information
-+ * @pcie_base_addr: IO Mapped Register Base
-+ * @axi_base_addr: AMBA Mapped Register Base
-+ * @irq: Interrupt number
-+ * @root_busno: Root Bus number
-+ * @dev: Device pointer
-+ * @msi_domain: MSI IRQ domain pointer
-+ * @leg_domain: Legacy IRQ domain pointer
-+ * @resources: Bus Resources
-+ */
-+struct microsemi_pcie_port {
-+        struct platform_device *pdev;
-+        void __iomem *pcie_base_addr;
-+        void __iomem *axi_base_addr;
-+        int bridge;
-+        u32 irq;
-+        u8 root_busno;
-+        struct device *dev;
-+        struct irq_domain *msi_domain;
-+        struct irq_domain *leg_domain;
-+        struct list_head resources;
-+};
-+
-+static DECLARE_BITMAP(msi_irq_in_use, MICROSEMI_NUM_MSI_IRQS);
-+
-+static inline u32 pcie_read(struct microsemi_pcie_port *port, u32 reg)
-+{
-+        return readl(port->pcie_base_addr + reg);
-+}
-+
-+static inline void pcie_write(struct microsemi_pcie_port *port,
-+                                u32 val, u32 reg)
-+{
-+        writel(val, port->pcie_base_addr + reg);
-+}
-+
-+static inline bool microsemi_pcie_link_up(struct microsemi_pcie_port *port)
-+{
-+        void *base_addr;
-+
-+        if(port->bridge == 0)
-+            base_addr = port->axi_base_addr + MICROSEMI_PCIE0_CTRL_ADDR;
-+        else
-+            base_addr = port->axi_base_addr + MICROSEMI_PCIE1_CTRL_ADDR;
-+
-+        return (readl(base_addr + MICROSEMI_LTSSM_STATE)
-+                & MICROSEMI_LTSSM_L0_STATE) ? 1 : 0;
-+}
-+
-+/**
-+ * microsemi_pcie_valid_device - Check if a valid device is present on bus
-+ * @bus: PCI Bus structure
-+ * @devfn: device/function
-+ *
-+ * Return: 'true' on success and 'false' if invalid device is found
-+ */
-+static bool microsemi_pcie_valid_device(struct pci_bus *bus, unsigned int devfn)
-+{
-+        struct microsemi_pcie_port *port = bus->sysdata;
-+
-+        /* Check if link is up when trying to access downstream ports */
-+        if (bus->number != port->root_busno)
-+                if (!microsemi_pcie_link_up(port))
-+                        return false;
-+
-+        /* Only one device down on each root port */
-+        if (bus->number == port->root_busno && devfn > 0)
-+                return false;
-+
-+        return true;
-+}
-+
-+/**
-+ * microsemi_pcie_map_bus - Get configuration base
-+ * @bus: PCI Bus structure
-+ * @devfn: Device/function
-+ * @where: Offset from base
-+ *
-+ * Return: Base address of the configuration space needed to be
-+ *         accessed.
-+ */
-+static void __iomem *microsemi_pcie_map_bus(struct pci_bus *bus,
-+                                            unsigned int devfn, int where)
-+{
-+        struct microsemi_pcie_port *port = bus->sysdata;
-+        int relbus;
-+
-+        if (!microsemi_pcie_valid_device(bus, devfn))
-+                return NULL;
-+
-+        relbus = (bus->number << ECAM_BUS_NUM_SHIFT) |
-+                     (devfn << ECAM_DEV_NUM_SHIFT);
-+
-+        return port->pcie_base_addr + relbus + where;
-+}
-+
-+/* PCIe operations */
-+static struct pci_ops microsemi_pcie_ops = {
-+        .map_bus = microsemi_pcie_map_bus,
-+        .read        = pci_generic_config_read,
-+        .write        = pci_generic_config_write,
-+};
-+
-+/* MSI functions */
-+
-+/**
-+ * microsemi_pcie_destroy_msi - Free MSI number
-+ * @irq: IRQ to be freed
-+ */
-+static void microsemi_pcie_destroy_msi(unsigned int irq)
-+{
-+        struct msi_desc *msi;
-+        struct microsemi_pcie_port *port;
-+        struct irq_data *d = irq_get_irq_data(irq);
-+        irq_hw_number_t hwirq = irqd_to_hwirq(d);
-+
-+        if (!test_bit(hwirq, msi_irq_in_use)) {
-+                msi = irq_get_msi_desc(irq);
-+                port = msi_desc_to_pci_sysdata(msi);
-+                dev_err(port->dev, "Trying to free unused MSI#%d\n", irq);
-+        } else
-+                clear_bit(hwirq, msi_irq_in_use);
-+}
-+
-+/**
-+ * microsemi_pcie_assign_msi - Allocate MSI number
-+ *
-+ * Return: A valid IRQ on success and error value on failure.
-+ */
-+static int microsemi_pcie_assign_msi(void)
-+{
-+        int pos;
-+
-+        pos = find_first_zero_bit(msi_irq_in_use, MICROSEMI_NUM_MSI_IRQS);
-+        if (pos < MICROSEMI_NUM_MSI_IRQS)
-+                set_bit(pos, msi_irq_in_use);
-+        else
-+                return -ENOSPC;
-+
-+        return pos;
-+}
-+
-+/**
-+ * microsemi_msi_teardown_irq - Destroy the MSI
-+ * @chip: MSI Chip descriptor
-+ * @irq: MSI IRQ to destroy
-+ */
-+static void microsemi_msi_teardown_irq(struct msi_controller *chip,
-+                                       unsigned int irq)
-+{
-+        microsemi_pcie_destroy_msi(irq);
-+        irq_dispose_mapping(irq);
-+}
-+
-+/**
-+ * microsemi_pcie_msi_setup_irq - Setup MSI request
-+ * @chip: MSI chip pointer
-+ * @pdev: PCIe device pointer
-+ * @desc: MSI descriptor pointer
-+ *
-+ * Return: '0' on success and error value on failure
-+ */
-+static int microsemi_pcie_msi_setup_irq(struct msi_controller *chip,
-+                                        struct pci_dev *pdev,
-+                                        struct msi_desc *desc)
-+{
-+        struct microsemi_pcie_port *port = pdev->bus->sysdata;
-+        unsigned int irq;
-+        int hwirq;
-+        struct msi_msg msg;
-+
-+        hwirq = microsemi_pcie_assign_msi();
-+        if (hwirq < 0)
-+                return hwirq;
-+
-+        irq = irq_create_mapping(port->msi_domain, hwirq);
-+        if (!irq)
-+                return -EINVAL;
-+
-+        irq_set_msi_desc(irq, desc);
-+
-+        msg.address_hi = upper_32_bits(MICROSEMI_MSI_MSG_ADDR);
-+        msg.address_lo = lower_32_bits(MICROSEMI_MSI_MSG_ADDR);
-+        msg.data = hwirq;
-+
-+        pci_write_msi_msg(irq, &msg);
-+
-+        return 0;
-+}
-+
-+/* MSI Chip Descriptor */
-+static struct msi_controller microsemi_pcie_msi_chip = {
-+        .setup_irq = microsemi_pcie_msi_setup_irq,
-+        .teardown_irq = microsemi_msi_teardown_irq,
-+};
-+
-+/* HW Interrupt Chip Descriptor */
-+static struct irq_chip microsemi_msi_irq_chip = {
-+        .name = "Microsemi PCIe MSI",
-+        .irq_enable = pci_msi_unmask_irq,
-+        .irq_disable = pci_msi_mask_irq,
-+        .irq_mask = pci_msi_mask_irq,
-+        .irq_unmask = pci_msi_unmask_irq,
-+};
-+
-+/**
-+ * microsemi_pcie_msi_map - Set the handler for the MSI and mark IRQ as valid
-+ * @domain: IRQ domain
-+ * @irq: Virtual IRQ number
-+ * @hwirq: HW interrupt number
-+ *
-+ * Return: Always returns 0.
-+ */
-+static int microsemi_pcie_msi_map(struct irq_domain *domain, unsigned int irq,
-+                                  irq_hw_number_t hwirq)
-+{
-+        irq_set_chip_and_handler(irq,
-+                                &microsemi_msi_irq_chip, handle_simple_irq);
-+        irq_set_chip_data(irq, domain->host_data);
-+
-+        return 0;
-+}
-+
-+/* IRQ Domain operations */
-+static const struct irq_domain_ops msi_domain_ops = {
-+        .map = microsemi_pcie_msi_map,
-+};
-+
-+/**
-+ * microsemi_pcie_enable_msi - Enable MSI support
-+ * @port: PCIe port information
-+ */
-+static void microsemi_pcie_enable_msi(struct microsemi_pcie_port *port)
-+{
-+        u32 cap_ctrl;
-+
-+        cap_ctrl = pcie_read(port, MSI_CAP_CTRL_OFFSET);
-+
-+        pcie_write(port, cap_ctrl | MSI_ENABLE_MULTI | 
-+                       MSI_ENABLE, MSI_CAP_CTRL_OFFSET);
-+        pcie_write(port, MICROSEMI_MSI_MSG_ADDR, MSI_MSG_ADDR_OFFSET);
-+}
-+
-+/* INTx Functions */
-+
-+/**
-+ * microsemi_pcie_intx_map - Set the handler for the INTx and mark IRQ as valid
-+ * @domain: IRQ domain
-+ * @irq: Virtual IRQ number
-+ * @hwirq: HW interrupt number
-+ *
-+ * Return: Always returns 0.
-+ */
-+static int microsemi_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
-+                                   irq_hw_number_t hwirq)
-+{
-+        irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_simple_irq);
-+        irq_set_chip_data(irq, domain->host_data);
-+
-+        return 0;
-+}
-+
-+/* INTx IRQ Domain operations */
-+static const struct irq_domain_ops intx_domain_ops = {
-+        .map = microsemi_pcie_intx_map,
-+        .xlate = pci_irqd_intx_xlate,
-+};
-+
-+/* PCIe HW Functions */
-+
-+/**
-+ * microsemi_pcie_intr_handler - Interrupt Service Handler
-+ * @irq: IRQ number
-+ * @data: PCIe port information
-+ *
-+ * Return: IRQ_HANDLED on success and IRQ_NONE on failure
-+ */
-+static irqreturn_t microsemi_pcie_intr_handler(int irq, void *data)
-+{
-+        struct microsemi_pcie_port *port = (struct microsemi_pcie_port *) data;
-+        struct device *dev = port->dev;
-+        unsigned long status;
-+        unsigned long msi;
-+        u32 bit;
-+        u32 virq;
-+        void *base_addr;
-+
-+        if(port->bridge == 0)
-+            base_addr = port->axi_base_addr + MICROSEMI_PCIE0_BRIDGE_ADDR;
-+        else
-+            base_addr = port->axi_base_addr + MICROSEMI_PCIE1_BRIDGE_ADDR;
-+
-+        status = readl(base_addr + MICROSEMI_ISTATUS_LOCAL);
-+
-+        status = (status & MICROSEMI_PCI_INTS) >> MICROSEMI_PM_MSI_INT_SHIFT;
-+        for_each_set_bit(bit, &status, PCI_NUM_INTX) {
-+                /* clear that interrupt bit */
-+                writel(1 << (bit+MICROSEMI_PM_MSI_INT_SHIFT),
-+                         base_addr + MICROSEMI_ISTATUS_LOCAL);
-+                virq = irq_find_mapping(port->leg_domain, bit);
-+
-+                if (virq)
-+                        generic_handle_irq(virq);
-+                else
-+                        dev_err(dev, "unexpected IRQ, INT%d\n", bit);
-+        }
-+
-+        status = readl(base_addr + MICROSEMI_ISTATUS_LOCAL);
-+        if (status & MICROSEMI_MSI_INT) {
-+                // Clear the ISTATUS MSI bit
-+                writel((1 << MICROSEMI_MSI_INT_SHIFT), base_addr + MICROSEMI_ISTATUS_LOCAL);
-+                msi = readl(base_addr + MICROSEMI_ISTATUS_MSI);
-+                for_each_set_bit(bit, &msi, MICROSEMI_NUM_MSI_IRQS) {
-+                        /* clear that MSI interrupt bit */
-+                        writel((1 << bit),
-+                                base_addr + MICROSEMI_ISTATUS_MSI);
-+                        virq = irq_find_mapping(port->msi_domain, bit);
-+                        if (virq)
-+                                generic_handle_irq(virq);
-+                        else
-+                                dev_err(dev, "unexpected IRQ, INT%d\n", bit);
-+                }
-+        }
-+
-+        return IRQ_HANDLED;
-+}
-+
-+/**
-+ * microsemi_pcie_init_irq_domain - Initialize IRQ domain
-+ * @port: PCIe port information
-+ *
-+ * Return: '0' on success and error value on failure
-+ */
-+static int microsemi_pcie_init_irq_domain(struct microsemi_pcie_port *port)
-+{
-+        struct device *dev = port->dev;
-+        struct device_node *node = dev->of_node;
-+        struct device_node *pcie_intc_node;
-+        void *bridge_base_addr;
-+
-+        if(port->bridge == 0) {
-+                bridge_base_addr =  port->axi_base_addr + MICROSEMI_PCIE0_BRIDGE_ADDR;
-+        } else {
-+                bridge_base_addr =  port->axi_base_addr + MICROSEMI_PCIE1_BRIDGE_ADDR;
-+        }
-+
-+        /* Setup INTx */
-+        pcie_intc_node = of_get_next_child(node, NULL);
-+        if (!pcie_intc_node) {
-+                dev_err(dev, "No PCIe Intc node found\n");
-+                return -ENODEV;
-+        }
-+        dev_info(dev, "Intc node foundi %s\n", pcie_intc_node->name);
-+
-+        port->leg_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX,
-+                                                 &intx_domain_ops,
-+                                                 port);
-+        if (!port->leg_domain) {
-+                dev_err(dev, "Failed to get a INTx IRQ domain\n");
-+                return -ENODEV;
-+        }
-+
-+        /* Setup MSI */
-+        if (IS_ENABLED(CONFIG_PCI_MSI)) {
-+                port->msi_domain = irq_domain_add_linear(node,
-+                                                MICROSEMI_NUM_MSI_IRQS,
-+                                                &msi_domain_ops,
-+                                                &microsemi_pcie_msi_chip);
-+                if (!port->msi_domain) {
-+                        dev_err(dev, "Failed to get a MSI IRQ domain\n");
-+                        return -ENODEV;
-+                }
-+                microsemi_pcie_enable_msi(port);
-+        }
-+
-+        /* Enable interrupts */
-+        writel(MICROSEMI_PCIE_ENABLE_MSI | MICROSEMI_PCIE_LOCAL_INT_ENABLE,
-+                bridge_base_addr + MICROSEMI_IMASK_LOCAL);
-+
-+        return 0;
-+}
-+
-+/**
-+ * microsemi_pcie_init_port - Parse Device tree, Initialize hardware
-+ * @port: PCIe port information
-+ *
-+ * Return: '0' on success and error value on failure
-+ */
-+static int microsemi_pcie_init_port(struct microsemi_pcie_port *port)
-+{
-+        struct device *dev = port->dev;
-+        struct device_node *node = dev->of_node;
-+        struct of_pci_range_parser parser;
-+        struct of_pci_range range;
-+        struct resource regs;
-+        struct resource regs1;
-+        resource_size_t size;
-+        u32 atr_sz;
-+        const char *type;
-+        int err;
-+        void *bridge_base_addr;
-+        void *ctrl_base_addr;
-+        u32 val;
-+        int index = 1;
-+
-+        type = of_get_property(node, "device_type", NULL);
-+        if (!type || strcmp(type, "pci")) {
-+                dev_err(dev, "invalid \"device_type\" %s\n", type);
-+                return -EINVAL;
-+        }
-+
-+        /* Only supporting bridge 1 */
-+        port->bridge = 1;
-+
-+        err = of_address_to_resource(node, 0, &regs);
-+        if (err) {
-+                dev_err(dev, "missing \"reg\" property\n");
-+                return err;
-+        }
-+
-+        port->pcie_base_addr = devm_pci_remap_cfg_resource(dev, &regs);
-+        if (IS_ERR(port->pcie_base_addr))
-+                return PTR_ERR(port->pcie_base_addr);
-+
-+        err = of_address_to_resource(node, 1, &regs1);
-+        if (err) {
-+                dev_err(dev, "missing \"reg\" property\n");
-+                return err;
-+        }
-+
-+        port->axi_base_addr = devm_ioremap_resource(dev, &regs1);
-+        if (IS_ERR(port->axi_base_addr))
-+                return PTR_ERR(port->axi_base_addr);
-+
-+        if(port->bridge == 0) {
-+                bridge_base_addr =  port->axi_base_addr + MICROSEMI_PCIE0_BRIDGE_ADDR;
-+                ctrl_base_addr = port->axi_base_addr + MICROSEMI_PCIE0_CTRL_ADDR;
-+        } else {
-+                bridge_base_addr =  port->axi_base_addr + MICROSEMI_PCIE1_BRIDGE_ADDR;
-+                ctrl_base_addr = port->axi_base_addr + MICROSEMI_PCIE1_CTRL_ADDR;
-+        }
-+
-+        port->irq = irq_of_parse_and_map(node, 0);
-+
-+        err = devm_request_irq(dev, port->irq, microsemi_pcie_intr_handler,
-+                               IRQF_SHARED | IRQF_NO_THREAD,
-+                               "microsemi-pcie", port);
-+        if (err) {
-+                dev_err(dev, "unable to request irq %d\n", port->irq);
-+                return err;
-+        }
-+
-+        /* Clear and Disable interrupts */
-+        val = ECC_CONTROL_AXI2PCIE_RAM_ECC_BYPASS
-+            | ECC_CONTROL_PCIE2AXI_RAM_ECC_BYPASS
-+            | ECC_CONTROL_RX_RAM_ECC_BYPASS
-+            | ECC_CONTROL_TX_RAM_ECC_BYPASS;
-+        writel(val, ctrl_base_addr + MICROSEMI_ECC_CONTROL);
-+
-+        val = PCIE_EVENT_INT_L2_EXIT_INT
-+            | PCIE_EVENT_INT_HOTRST_EXIT_INT
-+            | PCIE_EVENT_INT_DLUP_EXIT_INT
-+            | PCIE_EVENT_INT_L2_EXIT_INT_MASK
-+            | PCIE_EVENT_INT_HOTRST_EXIT_INT_MASK
-+            | PCIE_EVENT_INT_DLUP_EXIT_INT_MASK;
-+        writel(val, ctrl_base_addr + MICROSEMI_PCIE_EVENT_INT);
-+
-+        val = SEC_ERROR_INT_TX_RAM_SEC_ERR_INT
-+            | SEC_ERROR_INT_RX_RAM_SEC_ERR_INT
-+            | SEC_ERROR_INT_PCIE2AXI_RAM_SEC_ERR_INT
-+            | SEC_ERROR_INT_AXI2PCIE_RAM_SEC_ERR_INT;
-+        writel(val, ctrl_base_addr + MICROSEMI_SEC_ERROR_INT);
-+        writel(val, ctrl_base_addr + MICROSEMI_SEC_ERROR_INT_MASK);
-+
-+        val = DED_ERROR_INT_TX_RAM_DED_ERR_INT
-+            | DED_ERROR_INT_RX_RAM_DED_ERR_INT
-+            | DED_ERROR_INT_PCIE2AXI_RAM_DED_ERR_INT
-+            | DED_ERROR_INT_AXI2PCIE_RAM_DED_ERR_INT;
-+        writel(val, ctrl_base_addr + MICROSEMI_DED_ERROR_INT);
-+        writel(val, ctrl_base_addr + MICROSEMI_DED_ERROR_INT_MASK);
-+
-+        writel(0x00000000, bridge_base_addr + MICROSEMI_IMASK_LOCAL);
-+        writel(GENMASK(31,0), bridge_base_addr + MICROSEMI_ISTATUS_LOCAL);
-+        writel(0x00000000, bridge_base_addr + MICROSEMI_IMASK_HOST);
-+        writel(GENMASK(31,0), bridge_base_addr + MICROSEMI_ISTATUS_HOST);
-+
-+        dev_info(dev, "interrupt disabled\n");
-+
-+        /* Configure Address Translation Table 0 for pcie config space */
-+        writel(MICROSEMI_PCIE_CONFIG_INTERFACE,
-+                bridge_base_addr + MICROSEMI_ATR0_AXI4_SLV0_TRSL_PARAM);
-+
-+        size = resource_size(&regs);
-+
-+        atr_sz = find_first_bit((const unsigned long *)&size, 64) - 1;
-+
-+        writel(lower_32_bits(regs.start) | atr_sz << ATR_SIZE_SHIFT | ATR_IMPL_ENABLE,
-+                bridge_base_addr + MICROSEMI_ATR0_AXI4_SLV0_SRCADDR_PARAM);
-+
-+        //writel(upper_32_bits(regs.start),
-+        //    bridge_base_addr + MICROSEMI_ATR0_AXI4_SLV0_SRC_ADDR);
-+
-+        writel(lower_32_bits(regs.start),
-+                bridge_base_addr + MICROSEMI_ATR0_AXI4_SLV0_TRSL_ADDR_LSB);
-+
-+        //writel(upper_32_bits(regs.start),
-+        //        bridge_base_addr + MICROSEMI_ATR0_AXI4_SLV0_TRSL_ADDR_UDW);
-+
-+        if (of_pci_range_parser_init(&parser, node)) {
-+                dev_err(dev, "missing \"ranges\" property\n");
-+                return -EINVAL;
-+        }
-+
-+
-+        for_each_of_pci_range(&parser, &range) {
-+                switch (range.flags & IORESOURCE_TYPE_BITS) {
-+                case IORESOURCE_MEM:
-+                    size = range.size;
-+                    atr_sz = find_first_bit((const unsigned long *)&size, 64) - 1;
-+
-+                    /* Configure Address Translation Table index for pcie mem space */
-+                    writel(MICROSEMI_PCIE_TX_RX_INTERFACE,
-+                        bridge_base_addr + (index * MICROSEMI_ATR0_AXI4_SLV_SIZE ) + 
-+                        MICROSEMI_ATR0_AXI4_SLV0_TRSL_PARAM);
-+
-+                    writel(lower_32_bits(range.cpu_addr) | atr_sz << ATR_SIZE_SHIFT | ATR_IMPL_ENABLE,
-+                        bridge_base_addr + (index * MICROSEMI_ATR0_AXI4_SLV_SIZE ) + 
-+                        MICROSEMI_ATR0_AXI4_SLV0_SRCADDR_PARAM);
-+
-+                    //writel(upper_32_bits(range.cpu_addr),
-+                    //    bridge_base_addr + (index * MICROSEMI_ATR0_AXI4_SLV_SIZE ) + 
-+                    //    MICROSEMI_ATR0_AXI4_SLV0_SRC_ADDR);
-+
-+                    writel(lower_32_bits(range.pci_addr),
-+                        bridge_base_addr + (index * MICROSEMI_ATR0_AXI4_SLV_SIZE ) + 
-+                        MICROSEMI_ATR0_AXI4_SLV0_TRSL_ADDR_LSB);
-+
-+                    //writel(upper_32_bits(range.pci_addr),
-+                    //    bridge_base_addr + (index * MICROSEMI_ATR0_AXI4_SLV_SIZE ) + 
-+                    //    MICROSEMI_ATR0_AXI4_SLV0_TRSL_ADDR_UDW);
-+
-+                    break;
-+                }
-+                index++;
-+        }
-+
-+        writel(readl(bridge_base_addr + MICROSEMI_ATR0_PCIE_WIN0_SRCADDR_31_12)
-+                | MICROSEMI_ATR0_PCIE_WIN0_SIZE << MICROSEMI_ATR0_PCIE_WIN0_SIZE_SHIFT,
-+                bridge_base_addr + MICROSEMI_ATR0_PCIE_WIN0_SRCADDR_31_12);
-+
-+        writel(0x0, bridge_base_addr + MICROSEMI_ATR0_PCIE_WIN0_SRCADDR_63_32);
-+
-+        writel((readl(bridge_base_addr + MICROSEMI_PCIE_PCI_IDS_DW1) & 0xffff)
-+                | (PCI_CLASS_BRIDGE_PCI << 16),
-+                bridge_base_addr + MICROSEMI_PCIE_PCI_IDS_DW1);
-+
-+        return 0;
-+}
-+
-+/**
-+ * microsemi_pcie_probe - Probe function
-+ * @pdev: Platform device pointer
-+ *
-+ * Return: '0' on success and error value on failure
-+ */
-+static int microsemi_pcie_probe(struct platform_device *pdev)
-+{
-+        struct device *dev = &pdev->dev;
-+        struct microsemi_pcie_port *port;
-+        struct pci_bus *bus, *child;
-+        struct pci_host_bridge *bridge;
-+        int err;
-+        resource_size_t iobase = 0;
-+        LIST_HEAD(res);
-+
-+        if (!dev->of_node)
-+                return -ENODEV;
-+
-+        bridge = devm_pci_alloc_host_bridge(dev, sizeof(*port));
-+        if (!bridge)
-+                return -ENODEV;
-+
-+        port = pci_host_bridge_priv(bridge);
-+
-+        port->dev = dev;
-+        port->pdev = pdev;
-+
-+        err = microsemi_pcie_init_port(port);
-+        if (err) {
-+                dev_err(dev, "Pcie port initialization failed\n");
-+                return err;
-+        }
-+
-+
-+        err = microsemi_pcie_init_irq_domain(port);
-+        if (err) {
-+                dev_err(dev, "Failed creating IRQ Domain\n");
-+                return err;
-+        }
-+
-+        err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res,
-+                                                    &iobase);
-+        if (err) {
-+                dev_err(dev, "Getting bridge resources failed\n");
-+                return err;
-+        }
-+
-+        err = devm_request_pci_bus_resources(dev, &res);
-+        if (err)
-+                goto error;
-+
-+
-+        list_splice_init(&res, &bridge->windows);
-+        bridge->dev.parent = dev;
-+        bridge->sysdata = port;
-+        bridge->busnr = 0;
-+        bridge->ops = &microsemi_pcie_ops;
-+        bridge->map_irq = of_irq_parse_and_map_pci;
-+        bridge->swizzle_irq = pci_common_swizzle;
-+
-+#ifdef CONFIG_PCI_MSI
-+        microsemi_pcie_msi_chip.dev = dev;
-+        bridge->msi = &microsemi_pcie_msi_chip;
-+#endif
-+        err = pci_scan_root_bus_bridge(bridge);
-+        dev_info(dev, "pci_scan_root_bus_bridge done\n");
-+        if (err < 0)
-+                goto error;
-+
-+        bus = bridge->bus;
-+
-+        pci_assign_unassigned_bus_resources(bus);
-+        list_for_each_entry(child, &bus->children, node)
-+                pcie_bus_configure_settings(child);
-+        pci_bus_add_devices(bus);
-+
-+        return 0;
-+
-+error:
-+        pci_free_resource_list(&res);
-+        return err;
-+}
-+
-+static const struct of_device_id microsemi_pcie_of_match[] = {
-+        { .compatible = "ms-pf,axi-pcie-host", },
-+        {}
-+};
-+
-+static struct platform_driver microsemi_pcie_driver = {
-+        .driver = {
-+                .name = "microsemi-pcie",
-+                .of_match_table = microsemi_pcie_of_match,
-+                .suppress_bind_attrs = true,
-+        },
-+        .probe = microsemi_pcie_probe,
-+};
-+builtin_platform_driver(microsemi_pcie_driver);
--- 
-2.21.0
-

+ 31 - 169
recipes-kernel/linux/files/freedom-u540/defconfig

@@ -1,8 +1,5 @@
-CONFIG_LOCALVERSION="-riscv"
-CONFIG_DEFAULT_HOSTNAME="ucbvax"
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
-# CONFIG_CROSS_MEMORY_ATTACH is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_CGROUPS=y
@@ -12,18 +9,14 @@ CONFIG_CGROUP_BPF=y
 CONFIG_NAMESPACES=y
 CONFIG_USER_NS=y
 CONFIG_CHECKPOINT_RESTORE=y
-CONFIG_BLK_DEV_INITRD=y
+CONFIG_EXPERT=y
 CONFIG_BPF_SYSCALL=y
-CONFIG_EMBEDDED=y
 CONFIG_SMP=y
-CONFIG_HZ_100=y
-CONFIG_CMDLINE="earlycon=sbi root=/dev/mmcblk0p3 rootwait"
+CONFIG_CMDLINE="earlycon=sbi earlycon=sbi root=/dev/mmcblk0p3 rootwait console=ttySIF0 console=tty0"
+CONFIG_CMDLINE_FORCE=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
 CONFIG_BLK_DEV_ZONED=y
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_COMPACTION is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -34,230 +27,99 @@ CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 CONFIG_IP_PNP_BOOTP=y
 CONFIG_IP_PNP_RARP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
 CONFIG_NETLINK_DIAG=y
 CONFIG_PCI=y
 CONFIG_PCIEPORTBUS=y
-CONFIG_HOTPLUG_PCI_PCIE=y
-CONFIG_PCIE_ECRC=y
-CONFIG_PCIE_DPC=y
-CONFIG_PCIE_PTM=y
 CONFIG_PCI_DEBUG=y
-CONFIG_PCI_REALLOC_ENABLE_AUTO=y
-CONFIG_PCI_IOV=y
-CONFIG_PCI_PRI=y
-CONFIG_PCI_PASID=y
-CONFIG_HOTPLUG_PCI=y
-CONFIG_HOTPLUG_PCI_CPCI=y
-CONFIG_HOTPLUG_PCI_SHPC=y
 CONFIG_PCI_HOST_GENERIC=y
 CONFIG_PCIE_MICROSEMI=y
-CONFIG_PCI_ENDPOINT=y
 CONFIG_PCI_SW_SWITCHTEC=y
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_EXTRA_FIRMWARE="radeon/BTC_rlc.bin radeon/CAICOS_mc.bin radeon/CAICOS_me.bin radeon/CAICOS_pfp.bin radeon/CAICOS_smc.bin radeon/SUMO_uvd.bin"
-CONFIG_MTD=y
-CONFIG_MTD_BLOCK_RO=y
-CONFIG_MTD_M25P80=y
-CONFIG_MTD_SPI_NOR=y
 CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_NBD=y
 CONFIG_VIRTIO_BLK=y
 CONFIG_BLK_DEV_NVME=y
+CONFIG_NVME_MULTIPATH=y
 CONFIG_NVME_FC=y
 CONFIG_NVME_TARGET=y
-CONFIG_EEPROM_AT24=y
+CONFIG_NVME_TARGET_LOOP=y
+CONFIG_NVME_TARGET_FC=y
+CONFIG_NVME_TARGET_FCLOOP=y
+CONFIG_NVME_TARGET_TCP=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_BLK_DEV_SR=y
-CONFIG_SCSI_VIRTIO=y
 CONFIG_ATA=y
 CONFIG_SATA_AHCI=y
 CONFIG_SATA_AHCI_PLATFORM=y
-CONFIG_SATA_SIL24=y
 CONFIG_SATA_MV=y
+CONFIG_SATA_SIL=y
 CONFIG_TARGET_CORE=y
+CONFIG_TCM_IBLOCK=y
+CONFIG_TCM_FILEIO=y
+CONFIG_ISCSI_TARGET=y
 CONFIG_NETDEVICES=y
 CONFIG_VIRTIO_NET=y
-# CONFIG_NET_VENDOR_AURORA is not set
 CONFIG_MACB=y
 CONFIG_E1000E=y
 CONFIG_R8169=y
 CONFIG_MICROSEMI_PHY=y
 CONFIG_INPUT_MOUSEDEV=y
 CONFIG_INPUT_EVDEV=y
-CONFIG_INPUT_EVBUG=y
-CONFIG_INPUT_JOYSTICK=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_MOUSE_PS2 is not set
 CONFIG_INPUT_TABLET=y
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_USB_COMPOSITE=y
-CONFIG_INPUT_MISC=y
-CONFIG_INPUT_AD714X=y
-CONFIG_SERIO_PCIPS2=y
-CONFIG_SERIO_RAW=y
-CONFIG_SERIO_GPIO_PS2=y
-CONFIG_USERIO=y
+CONFIG_SERIO_LIBPS2=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_SERIAL_8250_PCI is not set
-CONFIG_SERIAL_8250_RT288X=y
 CONFIG_SERIAL_OF_PLATFORM=y
 CONFIG_SERIAL_EARLYCON_RISCV_SBI=y
-CONFIG_SERIAL_JSM=y
 CONFIG_SERIAL_SIFIVE=y
 CONFIG_SERIAL_SIFIVE_CONSOLE=y
-CONFIG_SERIAL_SCCNXP=m
-CONFIG_SERIAL_SC16IS7XX=m
-CONFIG_SERIAL_SC16IS7XX_SPI=y
-CONFIG_SERIAL_ARC=m
-CONFIG_SERIAL_RP2=m
-CONFIG_SERIAL_FSL_LPUART=m
-CONFIG_SERIAL_CONEXANT_DIGICOLOR=m
-CONFIG_SERIAL_DEV_BUS=y
-CONFIG_VIRTIO_CONSOLE=y
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C_OCORES=y
+CONFIG_HVC_RISCV_SBI=y
 CONFIG_SPI=y
 CONFIG_SPI_SIFIVE=y
-CONFIG_PPS=y
 # CONFIG_PTP_1588_CLOCK is not set
-CONFIG_GPIOLIB=y
-CONFIG_GPIO_SYSFS=y
-CONFIG_GPIO_SIFIVE=y
-CONFIG_POWER_RESET=y
-CONFIG_POWER_RESET_GPIO_RESTART=y
-CONFIG_PMBUS=y
-CONFIG_MEDIA_SUPPORT=y
-CONFIG_MEDIA_CAMERA_SUPPORT=y
-CONFIG_MEDIA_CONTROLLER=y
-CONFIG_VIDEO_V4L2_SUBDEV_API=y
-CONFIG_VIDEO_ADV_DEBUG=y
-CONFIG_MEDIA_USB_SUPPORT=y
-CONFIG_USB_GSPCA=y
-CONFIG_MEDIA_PCI_SUPPORT=y
-CONFIG_V4L_PLATFORM_DRIVERS=y
-CONFIG_V4L_MEM2MEM_DRIVERS=y
 CONFIG_DRM=y
-CONFIG_DRM_DP_AUX_CHARDEV=y
 CONFIG_DRM_RADEON=y
-CONFIG_DRM_AMDGPU=y
-CONFIG_DRM_AMD_ACP=y
-CONFIG_DRM_UDL=y
-CONFIG_DRM_CIRRUS_QEMU=y
-CONFIG_DRM_QXL=y
-CONFIG_DRM_BOCHS=y
-CONFIG_DRM_VIRTIO_GPU=y
-CONFIG_DRM_PANEL_LVDS=y
-CONFIG_DRM_PANEL_SIMPLE=y
-CONFIG_DRM_DUMB_VGA_DAC=y
-CONFIG_DRM_TINYDRM=y
-CONFIG_FB_FOREIGN_ENDIAN=y
-CONFIG_FB_CIRRUS=y
-CONFIG_FB_RADEON=y
-CONFIG_FB_ATY128=y
-CONFIG_FB_ATY=y
-CONFIG_FB_SIMPLE=y
-# CONFIG_LCD_CLASS_DEVICE is not set
 CONFIG_LOGO=y
 CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND_USB_AUDIO=y
-CONFIG_HIDRAW=y
-CONFIG_UHID=y
-CONFIG_HID_PID=y
-CONFIG_USB_HIDDEV=y
-CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
-CONFIG_USB_DYNAMIC_MINORS=y
-CONFIG_USB_MON=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_PLATFORM=y
 CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_EHCI_ROOT_HUB_TT=y
 CONFIG_USB_EHCI_HCD_PLATFORM=y
-CONFIG_USB_ACM=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
 CONFIG_USB_STORAGE=y
-CONFIG_USB_STORAGE_DEBUG=y
-CONFIG_USB_STORAGE_ENE_UB6250=y
 CONFIG_USB_UAS=y
-CONFIG_USB_SERIAL=y
-CONFIG_USB_SERIAL_CONSOLE=y
-CONFIG_USB_SERIAL_GENERIC=y
-CONFIG_USB_SERIAL_SIMPLE=y
-CONFIG_USB_SERIAL_FTDI_SIO=y
-CONFIG_USB_GPIO_VBUS=y
-CONFIG_USB_GADGET=y
-CONFIG_U_SERIAL_CONSOLE=y
-CONFIG_USB_FOTG210_UDC=y
-CONFIG_USB_GR_UDC=y
-CONFIG_USB_CONFIGFS=y
-CONFIG_USB_CONFIGFS_SERIAL=y
-CONFIG_USB_CONFIGFS_ACM=y
-CONFIG_USB_CONFIGFS_OBEX=y
-CONFIG_USB_CONFIGFS_NCM=y
-CONFIG_USB_CONFIGFS_ECM=y
-CONFIG_USB_CONFIGFS_ECM_SUBSET=y
-CONFIG_USB_CONFIGFS_F_LB_SS=y
-CONFIG_USB_CONFIGFS_F_UAC1=y
-CONFIG_USB_CONFIGFS_F_UAC1_LEGACY=y
-CONFIG_USB_CONFIGFS_F_UAC2=y
-CONFIG_USB_CONFIGFS_F_MIDI=y
-CONFIG_USB_CONFIGFS_F_HID=y
-CONFIG_USB_CONFIGFS_F_UVC=y
-CONFIG_USB_AUDIO=m
-CONFIG_GADGET_UAC1=y
-CONFIG_GADGET_UAC1_LEGACY=y
-CONFIG_USB_ETH=m
-CONFIG_USB_GADGET_TARGET=m
-CONFIG_USB_G_SERIAL=m
-CONFIG_USB_MIDI_GADGET=m
-CONFIG_USB_CDC_COMPOSITE=m
-CONFIG_USB_G_ACM_MS=m
-CONFIG_USB_G_MULTI=m
-CONFIG_USB_G_MULTI_CDC=y
-CONFIG_USB_G_HID=m
-CONFIG_USB_G_DBGP=m
-CONFIG_USB_ULPI_BUS=y
 CONFIG_MMC=y
 CONFIG_MMC_SPI=y
-CONFIG_VIRTIO_PCI=y
-# CONFIG_VIRTIO_PCI_LEGACY is not set
-CONFIG_VIRTIO_BALLOON=y
-CONFIG_VIRTIO_INPUT=y
+CONFIG_DMADEVICES=y
 CONFIG_VIRTIO_MMIO=y
-CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
-CONFIG_CLK_U54_PRCI=y
-CONFIG_CLK_GEMGXL_MGMT=y
-# CONFIG_IOMMU_SUPPORT is not set
-CONFIG_PWM=y
-CONFIG_PWM_SIFIVE=y
+CONFIG_CLK_SIFIVE=y
+CONFIG_CLK_SIFIVE_FU540_PRCI=y
 CONFIG_SIFIVE_PLIC=y
 CONFIG_EXT3_FS=y
 CONFIG_EXT4_FS_POSIX_ACL=y
-CONFIG_XFS_FS=y
+CONFIG_F2FS_FS=y
+CONFIG_F2FS_FS_SECURITY=y
 CONFIG_AUTOFS4_FS=y
-CONFIG_FUSE_FS=y
 CONFIG_MSDOS_FS=y
 CONFIG_VFAT_FS=y
-# CONFIG_PROC_PAGE_MONITOR is not set
 CONFIG_TMPFS=y
 CONFIG_TMPFS_POSIX_ACL=y
-# CONFIG_MISC_FILESYSTEMS is not set
-# CONFIG_NETWORK_FILESYSTEMS is not set
-CONFIG_KEYS=y
-CONFIG_CRYPTO_RSA=y
-CONFIG_CRYPTO_ECHAINIV=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_V4_1=y
+CONFIG_NFS_V4_2=y
+CONFIG_ROOT_NFS=y
 CONFIG_CRYPTO_USER_API_HASH=y
-# CONFIG_CRYPTO_HW is not set
-CONFIG_ASYMMETRIC_KEY_TYPE=y
-CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y
-CONFIG_X509_CERTIFICATE_PARSER=y
-CONFIG_PKCS7_MESSAGE_PARSER=y
-CONFIG_SYSTEM_TRUSTED_KEYRING=y
+CONFIG_CRYPTO_DEV_VIRTIO=y
+CONFIG_XZ_DEC=y
 CONFIG_PRINTK_TIME=y
-CONFIG_STRIP_ASM_SYMS=y
-CONFIG_DEBUG_SECTION_MISMATCH=y
-CONFIG_STACKTRACE=y
 # CONFIG_RCU_TRACE is not set

+ 0 - 34
recipes-kernel/linux/linux-mainline_5.1.bb

@@ -1,34 +0,0 @@
-require recipes-kernel/linux/linux-mainline-common.inc
-
-LINUX_VERSION ?= "5.1.x"
-KERNEL_VERSION_SANITY_SKIP="1"
-
-BRANCH = "linux-5.1.y"
-SRCREV = "${AUTOREV}"
-SRC_URI = " \
-    git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git;branch=${BRANCH} \
-"
-
-# Out of tree patches required for HiFive Unleashed
-SRC_URI_append_freedom-u540 = " \
-    file://0001-tty-serial-add-driver-for-the-SiFive-UART.patch \
-    file://0002-gemgxl-mgmt-implement-clock-switch-for-GEM-tx_clk.patch \
-    file://0003-u54-prci-driver-for-core-U54-clocks.patch \
-    file://0004-u54-prci-driver-for-core-U54-clocks.patch \
-    file://0005-gpio-sifive-support-GPIO-on-SiFive-SoCs.patch \
-    file://0006-pwm-sifive-add-a-driver-for-SiFive-SoC-PWM.patch \
-    file://0007-RISC-V-Networking-fix-Hack.patch \
-    file://0008-pcie-microsemi-Add-support-for-the-Vera-board-root-c.patch \
-    file://0009-HACK-Revert-of-device-Really-only-set-bus-DMA-mask-w.patch \
-    file://0010-HACK-radeon-Don-t-set-PCI-DMA-mask.patch \
-"
-
-# Fix a breakage with the current 32bit glibc fork
-SRC_URI_append_qemuriscv32 = " file://0001-Revert-riscv-Use-latest-system-call-ABI.patch"
-
-# qemu uses in-tree defconfig
-# freedom-u540 uses out-of-tree defconfig
-SRC_URI_append_freedom-u540 = " file://defconfig"
-
-KBUILD_DEFCONFIG_qemuriscv32 = "rv32_defconfig"
-KBUILD_DEFCONFIG_qemuriscv64 = "defconfig"

+ 32 - 0
recipes-kernel/linux/linux-mainline_5.2.bb

@@ -0,0 +1,32 @@
+require recipes-kernel/linux/linux-mainline-common.inc
+
+LINUX_VERSION ?= "5.2.x"
+KERNEL_VERSION_SANITY_SKIP="1"
+
+BRANCH = "linux-5.2.y"
+SRCREV = "${AUTOREV}"
+SRC_URI = " \
+    git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git;branch=${BRANCH} \
+"
+
+SRC_URI_append_freedom-u540 = " \
+    file://0001-macb-bindings-doc-add-sifive-fu540-c000-binding.patch \
+    file://0002-macb-Add-support-for-SiFive-FU540-C000.patch \
+    file://0003-riscv-dts-Add-DT-node-for-SiFive-FU540-Ethernet-cont.patch \
+    file://0004-PCI-microsemi-Add-host-driver-for-Microsemi-PCIe-con.patch \
+    file://0005-Microsemi-PCIe-expansion-board-DT-entry.patch \
+    file://0006-HACK-Revert-of-device-Really-only-set-bus-DMA-mask-w.patch \
+    file://0007-HACK-radeon-Don-t-set-PCI-DMA-mask.patch \
+"
+
+# Fix a breakage with the current 32bit glibc fork
+SRC_URI_append_qemuriscv32 = " file://0001-Revert-riscv-Use-latest-system-call-ABI.patch"
+
+KERNEL_DEVICETREE_freedom-u540 = "sifive/${RISCV_SBI_FDT}"
+
+# freedom-u540 uses out-of-tree defconfig
+SRC_URI_append_freedom-u540 = " file://defconfig"
+
+# qemu uses in-tree defconfig
+KBUILD_DEFCONFIG_qemuriscv32 = "rv32_defconfig"
+KBUILD_DEFCONFIG_qemuriscv64 = "defconfig"