mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 01/12] clk: add SiFive PRCI clock controller support
@ 2021-04-27 20:22 Ahmad Fatoum
  2021-04-27 20:22 ` [PATCH 02/12] serial: implement SiFive UART support Ahmad Fatoum
                   ` (10 more replies)
  0 siblings, 11 replies; 20+ messages in thread
From: Ahmad Fatoum @ 2021-04-27 20:22 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum, rcz

Import U74 and U54 clock controller support from Linux v5.12.

Unlike Linux, dependency wrpll-cln28hpc.c is compiled in unconditionally.
Linker garbage collection will take care to omit it if unreferenced.

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
 drivers/clk/Kconfig                           |   2 +
 drivers/clk/Makefile                          |   2 +
 drivers/clk/analogbits/Makefile               |   3 +
 drivers/clk/analogbits/wrpll-cln28hpc.c       | 367 +++++++++++
 drivers/clk/sifive/Kconfig                    |  18 +
 drivers/clk/sifive/Makefile                   |   2 +
 drivers/clk/sifive/fu540-prci.c               |  87 +++
 drivers/clk/sifive/fu540-prci.h               |  16 +
 drivers/clk/sifive/fu740-prci.c               | 121 ++++
 drivers/clk/sifive/fu740-prci.h               |  21 +
 drivers/clk/sifive/sifive-prci.c              | 581 ++++++++++++++++++
 drivers/clk/sifive/sifive-prci.h              | 298 +++++++++
 include/linux/clk/analogbits-wrpll-cln28hpc.h |  79 +++
 13 files changed, 1597 insertions(+)
 create mode 100644 drivers/clk/analogbits/Makefile
 create mode 100644 drivers/clk/analogbits/wrpll-cln28hpc.c
 create mode 100644 drivers/clk/sifive/Kconfig
 create mode 100644 drivers/clk/sifive/Makefile
 create mode 100644 drivers/clk/sifive/fu540-prci.c
 create mode 100644 drivers/clk/sifive/fu540-prci.h
 create mode 100644 drivers/clk/sifive/fu740-prci.c
 create mode 100644 drivers/clk/sifive/fu740-prci.h
 create mode 100644 drivers/clk/sifive/sifive-prci.c
 create mode 100644 drivers/clk/sifive/sifive-prci.h
 create mode 100644 include/linux/clk/analogbits-wrpll-cln28hpc.h

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index c05e06565192..d8649c3f9bf0 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -19,3 +19,5 @@ config CLK_SOCFPGA
 	bool
 	select COMMON_CLK_OF_PROVIDER
 	default y if ARCH_SOCFPGA && OFDEVICE
+
+source "drivers/clk/sifive/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 04c797e7e0df..b0be8d1bd89a 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -21,3 +21,5 @@ obj-$(CONFIG_ARCH_STM32MP)	+= clk-stm32mp1.o
 obj-$(CONFIG_MACH_VEXPRESS)	+= vexpress/
 obj-$(CONFIG_MACH_MIPS_LOONGSON)+= loongson/
 obj-$(CONFIG_ARCH_LAYERSCAPE)	+= clk-qoric.o
+obj-y				+= analogbits/
+obj-$(CONFIG_CLK_SIFIVE)	+= sifive/
diff --git a/drivers/clk/analogbits/Makefile b/drivers/clk/analogbits/Makefile
new file mode 100644
index 000000000000..c893283ea529
--- /dev/null
+++ b/drivers/clk/analogbits/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-y	+= wrpll-cln28hpc.o
diff --git a/drivers/clk/analogbits/wrpll-cln28hpc.c b/drivers/clk/analogbits/wrpll-cln28hpc.c
new file mode 100644
index 000000000000..640af533d606
--- /dev/null
+++ b/drivers/clk/analogbits/wrpll-cln28hpc.c
@@ -0,0 +1,367 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018-2019 SiFive, Inc.
+ * Wesley Terpstra
+ * Paul Walmsley
+ *
+ * This library supports configuration parsing and reprogramming of
+ * the CLN28HPC variant of the Analog Bits Wide Range PLL.  The
+ * intention is for this library to be reusable for any device that
+ * integrates this PLL; thus the register structure and programming
+ * details are expected to be provided by a separate IP block driver.
+ *
+ * The bulk of this code is primarily useful for clock configurations
+ * that must operate at arbitrary rates, as opposed to clock configurations
+ * that are restricted by software or manufacturer guidance to a small,
+ * pre-determined set of performance points.
+ *
+ * References:
+ * - Analog Bits "Wide Range PLL Datasheet", version 2015.10.01
+ * - SiFive FU540-C000 Manual v1p0, Chapter 7 "Clocking and Reset"
+ *   https://static.dev.sifive.com/FU540-C000-v1.0.pdf
+ */
+
+#include <linux/kernel.h>
+#include <stdio.h>
+#include <printk.h>
+#include <linux/bug.h>
+#include <linux/err.h>
+#include <linux/log2.h>
+#include <linux/math64.h>
+#include <linux/clk/analogbits-wrpll-cln28hpc.h>
+
+/* MIN_INPUT_FREQ: minimum input clock frequency, in Hz (Fref_min) */
+#define MIN_INPUT_FREQ			7000000
+
+/* MAX_INPUT_FREQ: maximum input clock frequency, in Hz (Fref_max) */
+#define MAX_INPUT_FREQ			600000000
+
+/* MIN_POST_DIVIDE_REF_FREQ: minimum post-divider reference frequency, in Hz */
+#define MIN_POST_DIVR_FREQ		7000000
+
+/* MAX_POST_DIVIDE_REF_FREQ: maximum post-divider reference frequency, in Hz */
+#define MAX_POST_DIVR_FREQ		200000000
+
+/* MIN_VCO_FREQ: minimum VCO frequency, in Hz (Fvco_min) */
+#define MIN_VCO_FREQ			2400000000UL
+
+/* MAX_VCO_FREQ: maximum VCO frequency, in Hz (Fvco_max) */
+#define MAX_VCO_FREQ			4800000000ULL
+
+/* MAX_DIVQ_DIVISOR: maximum output divisor.  Selected by DIVQ = 6 */
+#define MAX_DIVQ_DIVISOR		64
+
+/* MAX_DIVR_DIVISOR: maximum reference divisor.  Selected by DIVR = 63 */
+#define MAX_DIVR_DIVISOR		64
+
+/* MAX_LOCK_US: maximum PLL lock time, in microseconds (tLOCK_max) */
+#define MAX_LOCK_US			70
+
+/*
+ * ROUND_SHIFT: number of bits to shift to avoid precision loss in the rounding
+ *              algorithm
+ */
+#define ROUND_SHIFT			20
+
+/*
+ * Private functions
+ */
+
+/**
+ * __wrpll_calc_filter_range() - determine PLL loop filter bandwidth
+ * @post_divr_freq: input clock rate after the R divider
+ *
+ * Select the value to be presented to the PLL RANGE input signals, based
+ * on the input clock frequency after the post-R-divider @post_divr_freq.
+ * This code follows the recommendations in the PLL datasheet for filter
+ * range selection.
+ *
+ * Return: The RANGE value to be presented to the PLL configuration inputs,
+ *         or a negative return code upon error.
+ */
+static int __wrpll_calc_filter_range(unsigned long post_divr_freq)
+{
+	if (post_divr_freq < MIN_POST_DIVR_FREQ ||
+	    post_divr_freq > MAX_POST_DIVR_FREQ) {
+		WARN(1, "%s: post-divider reference freq out of range: %lu",
+		     __func__, post_divr_freq);
+		return -ERANGE;
+	}
+
+	switch (post_divr_freq) {
+	case 0 ... 10999999:
+		return 1;
+	case 11000000 ... 17999999:
+		return 2;
+	case 18000000 ... 29999999:
+		return 3;
+	case 30000000 ... 49999999:
+		return 4;
+	case 50000000 ... 79999999:
+		return 5;
+	case 80000000 ... 129999999:
+		return 6;
+	}
+
+	return 7;
+}
+
+/**
+ * __wrpll_calc_fbdiv() - return feedback fixed divide value
+ * @c: ptr to a struct wrpll_cfg record to read from
+ *
+ * The internal feedback path includes a fixed by-two divider; the
+ * external feedback path does not.  Return the appropriate divider
+ * value (2 or 1) depending on whether internal or external feedback
+ * is enabled.  This code doesn't test for invalid configurations
+ * (e.g. both or neither of WRPLL_FLAGS_*_FEEDBACK are set); it relies
+ * on the caller to do so.
+ *
+ * Context: Any context.  Caller must protect the memory pointed to by
+ *          @c from simultaneous modification.
+ *
+ * Return: 2 if internal feedback is enabled or 1 if external feedback
+ *         is enabled.
+ */
+static u8 __wrpll_calc_fbdiv(const struct wrpll_cfg *c)
+{
+	return (c->flags & WRPLL_FLAGS_INT_FEEDBACK_MASK) ? 2 : 1;
+}
+
+/**
+ * __wrpll_calc_divq() - determine DIVQ based on target PLL output clock rate
+ * @target_rate: target PLL output clock rate
+ * @vco_rate: pointer to a u64 to store the computed VCO rate into
+ *
+ * Determine a reasonable value for the PLL Q post-divider, based on the
+ * target output rate @target_rate for the PLL.  Along with returning the
+ * computed Q divider value as the return value, this function stores the
+ * desired target VCO rate into the variable pointed to by @vco_rate.
+ *
+ * Context: Any context.  Caller must protect the memory pointed to by
+ *          @vco_rate from simultaneous access or modification.
+ *
+ * Return: a positive integer DIVQ value to be programmed into the hardware
+ *         upon success, or 0 upon error (since 0 is an invalid DIVQ value)
+ */
+static u8 __wrpll_calc_divq(u32 target_rate, u64 *vco_rate)
+{
+	u64 s;
+	u8 divq = 0;
+
+	if (!vco_rate) {
+		WARN_ON(1);
+		goto wcd_out;
+	}
+
+	s = div_u64(MAX_VCO_FREQ, target_rate);
+	if (s <= 1) {
+		divq = 1;
+		*vco_rate = MAX_VCO_FREQ;
+	} else if (s > MAX_DIVQ_DIVISOR) {
+		divq = ilog2(MAX_DIVQ_DIVISOR);
+		*vco_rate = MIN_VCO_FREQ;
+	} else {
+		divq = ilog2(s);
+		*vco_rate = (u64)target_rate << divq;
+	}
+
+wcd_out:
+	return divq;
+}
+
+/**
+ * __wrpll_update_parent_rate() - update PLL data when parent rate changes
+ * @c: ptr to a struct wrpll_cfg record to write PLL data to
+ * @parent_rate: PLL input refclk rate (pre-R-divider)
+ *
+ * Pre-compute some data used by the PLL configuration algorithm when
+ * the PLL's reference clock rate changes.  The intention is to avoid
+ * computation when the parent rate remains constant - expected to be
+ * the common case.
+ *
+ * Returns: 0 upon success or -ERANGE if the reference clock rate is
+ * out of range.
+ */
+static int __wrpll_update_parent_rate(struct wrpll_cfg *c,
+				      unsigned long parent_rate)
+{
+	u8 max_r_for_parent;
+
+	if (parent_rate > MAX_INPUT_FREQ || parent_rate < MIN_POST_DIVR_FREQ)
+		return -ERANGE;
+
+	c->parent_rate = parent_rate;
+	max_r_for_parent = div_u64(parent_rate, MIN_POST_DIVR_FREQ);
+	c->max_r = min_t(u8, MAX_DIVR_DIVISOR, max_r_for_parent);
+
+	c->init_r = DIV_ROUND_UP_ULL(parent_rate, MAX_POST_DIVR_FREQ);
+
+	return 0;
+}
+
+/**
+ * wrpll_configure() - compute PLL configuration for a target rate
+ * @c: ptr to a struct wrpll_cfg record to write into
+ * @target_rate: target PLL output clock rate (post-Q-divider)
+ * @parent_rate: PLL input refclk rate (pre-R-divider)
+ *
+ * Compute the appropriate PLL signal configuration values and store
+ * in PLL context @c.  PLL reprogramming is not glitchless, so the
+ * caller should switch any downstream logic to a different clock
+ * source or clock-gate it before presenting these values to the PLL
+ * configuration signals.
+ *
+ * The caller must pass this function a pre-initialized struct
+ * wrpll_cfg record: either initialized to zero (with the
+ * exception of the .name and .flags fields) or read from the PLL.
+ *
+ * Context: Any context.  Caller must protect the memory pointed to by @c
+ *          from simultaneous access or modification.
+ *
+ * Return: 0 upon success; anything else upon failure.
+ */
+int wrpll_configure_for_rate(struct wrpll_cfg *c, u32 target_rate,
+			     unsigned long parent_rate)
+{
+	unsigned long ratio;
+	u64 target_vco_rate, delta, best_delta, f_pre_div, vco, vco_pre;
+	u32 best_f, f, post_divr_freq;
+	u8 fbdiv, divq, best_r, r;
+	int range;
+
+	if (c->flags == 0) {
+		WARN(1, "%s called with uninitialized PLL config", __func__);
+		return -EINVAL;
+	}
+
+	/* Initialize rounding data if it hasn't been initialized already */
+	if (parent_rate != c->parent_rate) {
+		if (__wrpll_update_parent_rate(c, parent_rate)) {
+			pr_err("%s: PLL input rate is out of range\n",
+			       __func__);
+			return -ERANGE;
+		}
+	}
+
+	c->flags &= ~WRPLL_FLAGS_RESET_MASK;
+
+	/* Put the PLL into bypass if the user requests the parent clock rate */
+	if (target_rate == parent_rate) {
+		c->flags |= WRPLL_FLAGS_BYPASS_MASK;
+		return 0;
+	}
+
+	c->flags &= ~WRPLL_FLAGS_BYPASS_MASK;
+
+	/* Calculate the Q shift and target VCO rate */
+	divq = __wrpll_calc_divq(target_rate, &target_vco_rate);
+	if (!divq)
+		return -1;
+	c->divq = divq;
+
+	/* Precalculate the pre-Q divider target ratio */
+	ratio = div64_u64((target_vco_rate << ROUND_SHIFT), parent_rate);
+
+	fbdiv = __wrpll_calc_fbdiv(c);
+	best_r = 0;
+	best_f = 0;
+	best_delta = MAX_VCO_FREQ;
+
+	/*
+	 * Consider all values for R which land within
+	 * [MIN_POST_DIVR_FREQ, MAX_POST_DIVR_FREQ]; prefer smaller R
+	 */
+	for (r = c->init_r; r <= c->max_r; ++r) {
+		f_pre_div = ratio * r;
+		f = (f_pre_div + (1 << ROUND_SHIFT)) >> ROUND_SHIFT;
+		f >>= (fbdiv - 1);
+
+		post_divr_freq = div_u64(parent_rate, r);
+		vco_pre = fbdiv * post_divr_freq;
+		vco = vco_pre * f;
+
+		/* Ensure rounding didn't take us out of range */
+		if (vco > target_vco_rate) {
+			--f;
+			vco = vco_pre * f;
+		} else if (vco < MIN_VCO_FREQ) {
+			++f;
+			vco = vco_pre * f;
+		}
+
+		delta = abs(target_rate - vco);
+		if (delta < best_delta) {
+			best_delta = delta;
+			best_r = r;
+			best_f = f;
+		}
+	}
+
+	c->divr = best_r - 1;
+	c->divf = best_f - 1;
+
+	post_divr_freq = div_u64(parent_rate, best_r);
+
+	/* Pick the best PLL jitter filter */
+	range = __wrpll_calc_filter_range(post_divr_freq);
+	if (range < 0)
+		return range;
+	c->range = range;
+
+	return 0;
+}
+
+/**
+ * wrpll_calc_output_rate() - calculate the PLL's target output rate
+ * @c: ptr to a struct wrpll_cfg record to read from
+ * @parent_rate: PLL refclk rate
+ *
+ * Given a pointer to the PLL's current input configuration @c and the
+ * PLL's input reference clock rate @parent_rate (before the R
+ * pre-divider), calculate the PLL's output clock rate (after the Q
+ * post-divider).
+ *
+ * Context: Any context.  Caller must protect the memory pointed to by @c
+ *          from simultaneous modification.
+ *
+ * Return: the PLL's output clock rate, in Hz.  The return value from
+ *         this function is intended to be convenient to pass directly
+ *         to the Linux clock framework; thus there is no explicit
+ *         error return value.
+ */
+unsigned long wrpll_calc_output_rate(const struct wrpll_cfg *c,
+				     unsigned long parent_rate)
+{
+	u8 fbdiv;
+	u64 n;
+
+	if (c->flags & WRPLL_FLAGS_EXT_FEEDBACK_MASK) {
+		WARN(1, "external feedback mode not yet supported");
+		return ULONG_MAX;
+	}
+
+	fbdiv = __wrpll_calc_fbdiv(c);
+	n = parent_rate * fbdiv * (c->divf + 1);
+	n = div_u64(n, c->divr + 1);
+	n >>= c->divq;
+
+	return n;
+}
+
+/**
+ * wrpll_calc_max_lock_us() - return the time for the PLL to lock
+ * @c: ptr to a struct wrpll_cfg record to read from
+ *
+ * Return the minimum amount of time (in microseconds) that the caller
+ * must wait after reprogramming the PLL to ensure that it is locked
+ * to the input frequency and stable.  This is likely to depend on the DIVR
+ * value; this is under discussion with the manufacturer.
+ *
+ * Return: the minimum amount of time the caller must wait for the PLL
+ *         to lock (in microseconds)
+ */
+unsigned int wrpll_calc_max_lock_us(const struct wrpll_cfg *c)
+{
+	return MAX_LOCK_US;
+}
diff --git a/drivers/clk/sifive/Kconfig b/drivers/clk/sifive/Kconfig
new file mode 100644
index 000000000000..6b3f4bc60056
--- /dev/null
+++ b/drivers/clk/sifive/Kconfig
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0
+
+menuconfig CLK_SIFIVE
+	bool "SiFive SoC driver support"
+	depends on RISCV || COMPILE_TEST
+	help
+	  SoC drivers for SiFive Linux-capable SoCs.
+
+if CLK_SIFIVE
+
+config CLK_SIFIVE_PRCI
+	bool "PRCI driver for SiFive SoCs"
+	help
+	  Supports the Power Reset Clock interface (PRCI) IP block found in
+	  FU540/FU740 SoCs. If this kernel is meant to run on a SiFive FU540/
+	  FU740 SoCs, enable this driver.
+
+endif
diff --git a/drivers/clk/sifive/Makefile b/drivers/clk/sifive/Makefile
new file mode 100644
index 000000000000..7b06fc04e6b3
--- /dev/null
+++ b/drivers/clk/sifive/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_CLK_SIFIVE_PRCI)	+= sifive-prci.o fu540-prci.o fu740-prci.o
diff --git a/drivers/clk/sifive/fu540-prci.c b/drivers/clk/sifive/fu540-prci.c
new file mode 100644
index 000000000000..e6379dfd6ab6
--- /dev/null
+++ b/drivers/clk/sifive/fu540-prci.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018-2019 SiFive, Inc.
+ * Copyright (C) 2018-2019 Wesley Terpstra
+ * Copyright (C) 2018-2019 Paul Walmsley
+ * Copyright (C) 2020 Zong Li
+ *
+ * The FU540 PRCI implements clock and reset control for the SiFive
+ * FU540-C000 chip.  This driver assumes that it has sole control
+ * over all PRCI resources.
+ *
+ * This driver is based on the PRCI driver written by Wesley Terpstra:
+ * https://github.com/riscv/riscv-linux/commit/999529edf517ed75b56659d456d221b2ee56bb60
+ *
+ * References:
+ * - SiFive FU540-C000 manual v1p0, Chapter 7 "Clocking and Reset"
+ */
+
+#include <dt-bindings/clock/sifive-fu540-prci.h>
+
+#include "fu540-prci.h"
+#include "sifive-prci.h"
+
+/* PRCI integration data for each WRPLL instance */
+
+static struct __prci_wrpll_data __prci_corepll_data = {
+	.cfg0_offs = PRCI_COREPLLCFG0_OFFSET,
+	.cfg1_offs = PRCI_COREPLLCFG1_OFFSET,
+	.enable_bypass = sifive_prci_coreclksel_use_hfclk,
+	.disable_bypass = sifive_prci_coreclksel_use_corepll,
+};
+
+static struct __prci_wrpll_data __prci_ddrpll_data = {
+	.cfg0_offs = PRCI_DDRPLLCFG0_OFFSET,
+	.cfg1_offs = PRCI_DDRPLLCFG1_OFFSET,
+};
+
+static struct __prci_wrpll_data __prci_gemgxlpll_data = {
+	.cfg0_offs = PRCI_GEMGXLPLLCFG0_OFFSET,
+	.cfg1_offs = PRCI_GEMGXLPLLCFG1_OFFSET,
+};
+
+/* Linux clock framework integration */
+
+static const struct clk_ops sifive_fu540_prci_wrpll_clk_ops = {
+	.set_rate = sifive_prci_wrpll_set_rate,
+	.round_rate = sifive_prci_wrpll_round_rate,
+	.recalc_rate = sifive_prci_wrpll_recalc_rate,
+	.enable = sifive_prci_clock_enable,
+	.disable = sifive_prci_clock_disable,
+	.is_enabled = sifive_clk_is_enabled,
+};
+
+static const struct clk_ops sifive_fu540_prci_wrpll_ro_clk_ops = {
+	.recalc_rate = sifive_prci_wrpll_recalc_rate,
+};
+
+static const struct clk_ops sifive_fu540_prci_tlclksel_clk_ops = {
+	.recalc_rate = sifive_prci_tlclksel_recalc_rate,
+};
+
+/* List of clock controls provided by the PRCI */
+struct __prci_clock __prci_init_clocks_fu540[] = {
+	[PRCI_CLK_COREPLL] = {
+		.name = "corepll",
+		.parent_name = "hfclk",
+		.ops = &sifive_fu540_prci_wrpll_clk_ops,
+		.pwd = &__prci_corepll_data,
+	},
+	[PRCI_CLK_DDRPLL] = {
+		.name = "ddrpll",
+		.parent_name = "hfclk",
+		.ops = &sifive_fu540_prci_wrpll_ro_clk_ops,
+		.pwd = &__prci_ddrpll_data,
+	},
+	[PRCI_CLK_GEMGXLPLL] = {
+		.name = "gemgxlpll",
+		.parent_name = "hfclk",
+		.ops = &sifive_fu540_prci_wrpll_clk_ops,
+		.pwd = &__prci_gemgxlpll_data,
+	},
+	[PRCI_CLK_TLCLK] = {
+		.name = "tlclk",
+		.parent_name = "corepll",
+		.ops = &sifive_fu540_prci_tlclksel_clk_ops,
+	},
+};
diff --git a/drivers/clk/sifive/fu540-prci.h b/drivers/clk/sifive/fu540-prci.h
new file mode 100644
index 000000000000..c220677dc010
--- /dev/null
+++ b/drivers/clk/sifive/fu540-prci.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020 SiFive, Inc.
+ * Zong Li
+ */
+
+#ifndef __SIFIVE_CLK_FU540_PRCI_H
+#define __SIFIVE_CLK_FU540_PRCI_H
+
+#include "sifive-prci.h"
+
+#define NUM_CLOCK_FU540	4
+
+extern struct __prci_clock __prci_init_clocks_fu540[NUM_CLOCK_FU540];
+
+#endif /* __SIFIVE_CLK_FU540_PRCI_H */
diff --git a/drivers/clk/sifive/fu740-prci.c b/drivers/clk/sifive/fu740-prci.c
new file mode 100644
index 000000000000..14df75f7f64b
--- /dev/null
+++ b/drivers/clk/sifive/fu740-prci.c
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 SiFive, Inc.
+ * Copyright (C) 2020 Zong Li
+ */
+
+#include <dt-bindings/clock/sifive-fu740-prci.h>
+
+#include "fu540-prci.h"
+#include "sifive-prci.h"
+
+/* PRCI integration data for each WRPLL instance */
+
+static struct __prci_wrpll_data __prci_corepll_data = {
+	.cfg0_offs = PRCI_COREPLLCFG0_OFFSET,
+	.cfg1_offs = PRCI_COREPLLCFG1_OFFSET,
+	.enable_bypass = sifive_prci_coreclksel_use_hfclk,
+	.disable_bypass = sifive_prci_coreclksel_use_final_corepll,
+};
+
+static struct __prci_wrpll_data __prci_ddrpll_data = {
+	.cfg0_offs = PRCI_DDRPLLCFG0_OFFSET,
+	.cfg1_offs = PRCI_DDRPLLCFG1_OFFSET,
+};
+
+static struct __prci_wrpll_data __prci_gemgxlpll_data = {
+	.cfg0_offs = PRCI_GEMGXLPLLCFG0_OFFSET,
+	.cfg1_offs = PRCI_GEMGXLPLLCFG1_OFFSET,
+};
+
+static struct __prci_wrpll_data __prci_dvfscorepll_data = {
+	.cfg0_offs = PRCI_DVFSCOREPLLCFG0_OFFSET,
+	.cfg1_offs = PRCI_DVFSCOREPLLCFG1_OFFSET,
+	.enable_bypass = sifive_prci_corepllsel_use_corepll,
+	.disable_bypass = sifive_prci_corepllsel_use_dvfscorepll,
+};
+
+static struct __prci_wrpll_data __prci_hfpclkpll_data = {
+	.cfg0_offs = PRCI_HFPCLKPLLCFG0_OFFSET,
+	.cfg1_offs = PRCI_HFPCLKPLLCFG1_OFFSET,
+	.enable_bypass = sifive_prci_hfpclkpllsel_use_hfclk,
+	.disable_bypass = sifive_prci_hfpclkpllsel_use_hfpclkpll,
+};
+
+static struct __prci_wrpll_data __prci_cltxpll_data = {
+	.cfg0_offs = PRCI_CLTXPLLCFG0_OFFSET,
+	.cfg1_offs = PRCI_CLTXPLLCFG1_OFFSET,
+};
+
+/* Linux clock framework integration */
+
+static const struct clk_ops sifive_fu740_prci_wrpll_clk_ops = {
+	.set_rate = sifive_prci_wrpll_set_rate,
+	.round_rate = sifive_prci_wrpll_round_rate,
+	.recalc_rate = sifive_prci_wrpll_recalc_rate,
+	.enable = sifive_prci_clock_enable,
+	.disable = sifive_prci_clock_disable,
+	.is_enabled = sifive_clk_is_enabled,
+};
+
+static const struct clk_ops sifive_fu740_prci_wrpll_ro_clk_ops = {
+	.recalc_rate = sifive_prci_wrpll_recalc_rate,
+};
+
+static const struct clk_ops sifive_fu740_prci_tlclksel_clk_ops = {
+	.recalc_rate = sifive_prci_tlclksel_recalc_rate,
+};
+
+static const struct clk_ops sifive_fu740_prci_hfpclkplldiv_clk_ops = {
+	.recalc_rate = sifive_prci_hfpclkplldiv_recalc_rate,
+};
+
+/* List of clock controls provided by the PRCI */
+struct __prci_clock __prci_init_clocks_fu740[] = {
+	[PRCI_CLK_COREPLL] = {
+		.name = "corepll",
+		.parent_name = "hfclk",
+		.ops = &sifive_fu740_prci_wrpll_clk_ops,
+		.pwd = &__prci_corepll_data,
+	},
+	[PRCI_CLK_DDRPLL] = {
+		.name = "ddrpll",
+		.parent_name = "hfclk",
+		.ops = &sifive_fu740_prci_wrpll_ro_clk_ops,
+		.pwd = &__prci_ddrpll_data,
+	},
+	[PRCI_CLK_GEMGXLPLL] = {
+		.name = "gemgxlpll",
+		.parent_name = "hfclk",
+		.ops = &sifive_fu740_prci_wrpll_clk_ops,
+		.pwd = &__prci_gemgxlpll_data,
+	},
+	[PRCI_CLK_DVFSCOREPLL] = {
+		.name = "dvfscorepll",
+		.parent_name = "hfclk",
+		.ops = &sifive_fu740_prci_wrpll_clk_ops,
+		.pwd = &__prci_dvfscorepll_data,
+	},
+	[PRCI_CLK_HFPCLKPLL] = {
+		.name = "hfpclkpll",
+		.parent_name = "hfclk",
+		.ops = &sifive_fu740_prci_wrpll_clk_ops,
+		.pwd = &__prci_hfpclkpll_data,
+	},
+	[PRCI_CLK_CLTXPLL] = {
+		.name = "cltxpll",
+		.parent_name = "hfclk",
+		.ops = &sifive_fu740_prci_wrpll_clk_ops,
+		.pwd = &__prci_cltxpll_data,
+	},
+	[PRCI_CLK_TLCLK] = {
+		.name = "tlclk",
+		.parent_name = "corepll",
+		.ops = &sifive_fu740_prci_tlclksel_clk_ops,
+	},
+	[PRCI_CLK_PCLK] = {
+		.name = "pclk",
+		.parent_name = "hfpclkpll",
+		.ops = &sifive_fu740_prci_hfpclkplldiv_clk_ops,
+	},
+};
diff --git a/drivers/clk/sifive/fu740-prci.h b/drivers/clk/sifive/fu740-prci.h
new file mode 100644
index 000000000000..13ef971f7764
--- /dev/null
+++ b/drivers/clk/sifive/fu740-prci.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020 SiFive, Inc.
+ * Zong Li
+ */
+
+#ifndef __SIFIVE_CLK_FU740_PRCI_H
+#define __SIFIVE_CLK_FU740_PRCI_H
+
+#include "sifive-prci.h"
+
+#define NUM_CLOCK_FU740	8
+
+extern struct __prci_clock __prci_init_clocks_fu740[NUM_CLOCK_FU740];
+
+static const struct prci_clk_desc prci_clk_fu740 = {
+	.clks = __prci_init_clocks_fu740,
+	.num_clks = ARRAY_SIZE(__prci_init_clocks_fu740),
+};
+
+#endif /* __SIFIVE_CLK_FU740_PRCI_H */
diff --git a/drivers/clk/sifive/sifive-prci.c b/drivers/clk/sifive/sifive-prci.c
new file mode 100644
index 000000000000..b452bbf8cc18
--- /dev/null
+++ b/drivers/clk/sifive/sifive-prci.c
@@ -0,0 +1,581 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 SiFive, Inc.
+ * Copyright (C) 2020 Zong Li
+ */
+
+#include <common.h>
+#include <linux/list.h>
+#include <linux/clkdev.h>
+#include <linux/overflow.h>
+#include <printk.h>
+#include <clock.h>
+#include <io.h>
+#include <of.h>
+#include <driver.h>
+#include <init.h>
+#include "sifive-prci.h"
+#include "fu540-prci.h"
+#include "fu740-prci.h"
+
+static const struct prci_clk_desc prci_clk_fu540 = {
+	.clks = __prci_init_clocks_fu540,
+	.num_clks = ARRAY_SIZE(__prci_init_clocks_fu540),
+};
+
+/*
+ * Private functions
+ */
+
+/**
+ * __prci_readl() - read from a PRCI register
+ * @pd: PRCI context
+ * @offs: register offset to read from (in bytes, from PRCI base address)
+ *
+ * Read the register located at offset @offs from the base virtual
+ * address of the PRCI register target described by @pd, and return
+ * the value to the caller.
+ *
+ * Context: Any context.
+ *
+ * Return: the contents of the register described by @pd and @offs.
+ */
+static u32 __prci_readl(struct __prci_data *pd, u32 offs)
+{
+	return readl(pd->va + offs);
+}
+
+static void __prci_writel(u32 v, u32 offs, struct __prci_data *pd)
+{
+	writel(v, pd->va + offs);
+}
+
+/* WRPLL-related private functions */
+
+/**
+ * __prci_wrpll_unpack() - unpack WRPLL configuration registers into parameters
+ * @c: ptr to a struct wrpll_cfg record to write config into
+ * @r: value read from the PRCI PLL configuration register
+ *
+ * Given a value @r read from an FU740 PRCI PLL configuration register,
+ * split it into fields and populate it into the WRPLL configuration record
+ * pointed to by @c.
+ *
+ * The COREPLLCFG0 macros are used below, but the other *PLLCFG0 macros
+ * have the same register layout.
+ *
+ * Context: Any context.
+ */
+static void __prci_wrpll_unpack(struct wrpll_cfg *c, u32 r)
+{
+	u32 v;
+
+	v = r & PRCI_COREPLLCFG0_DIVR_MASK;
+	v >>= PRCI_COREPLLCFG0_DIVR_SHIFT;
+	c->divr = v;
+
+	v = r & PRCI_COREPLLCFG0_DIVF_MASK;
+	v >>= PRCI_COREPLLCFG0_DIVF_SHIFT;
+	c->divf = v;
+
+	v = r & PRCI_COREPLLCFG0_DIVQ_MASK;
+	v >>= PRCI_COREPLLCFG0_DIVQ_SHIFT;
+	c->divq = v;
+
+	v = r & PRCI_COREPLLCFG0_RANGE_MASK;
+	v >>= PRCI_COREPLLCFG0_RANGE_SHIFT;
+	c->range = v;
+
+	c->flags &=
+	    (WRPLL_FLAGS_INT_FEEDBACK_MASK | WRPLL_FLAGS_EXT_FEEDBACK_MASK);
+
+	/* external feedback mode not supported */
+	c->flags |= WRPLL_FLAGS_INT_FEEDBACK_MASK;
+}
+
+/**
+ * __prci_wrpll_pack() - pack PLL configuration parameters into a register value
+ * @c: pointer to a struct wrpll_cfg record containing the PLL's cfg
+ *
+ * Using a set of WRPLL configuration values pointed to by @c,
+ * assemble a PRCI PLL configuration register value, and return it to
+ * the caller.
+ *
+ * Context: Any context.  Caller must ensure that the contents of the
+ *          record pointed to by @c do not change during the execution
+ *          of this function.
+ *
+ * Returns: a value suitable for writing into a PRCI PLL configuration
+ *          register
+ */
+static u32 __prci_wrpll_pack(const struct wrpll_cfg *c)
+{
+	u32 r = 0;
+
+	r |= c->divr << PRCI_COREPLLCFG0_DIVR_SHIFT;
+	r |= c->divf << PRCI_COREPLLCFG0_DIVF_SHIFT;
+	r |= c->divq << PRCI_COREPLLCFG0_DIVQ_SHIFT;
+	r |= c->range << PRCI_COREPLLCFG0_RANGE_SHIFT;
+
+	/* external feedback mode not supported */
+	r |= PRCI_COREPLLCFG0_FSE_MASK;
+
+	return r;
+}
+
+/**
+ * __prci_wrpll_read_cfg0() - read the WRPLL configuration from the PRCI
+ * @pd: PRCI context
+ * @pwd: PRCI WRPLL metadata
+ *
+ * Read the current configuration of the PLL identified by @pwd from
+ * the PRCI identified by @pd, and store it into the local configuration
+ * cache in @pwd.
+ *
+ * Context: Any context.  Caller must prevent the records pointed to by
+ *          @pd and @pwd from changing during execution.
+ */
+static void __prci_wrpll_read_cfg0(struct __prci_data *pd,
+				   struct __prci_wrpll_data *pwd)
+{
+	__prci_wrpll_unpack(&pwd->c, __prci_readl(pd, pwd->cfg0_offs));
+}
+
+/**
+ * __prci_wrpll_write_cfg0() - write WRPLL configuration into the PRCI
+ * @pd: PRCI context
+ * @pwd: PRCI WRPLL metadata
+ * @c: WRPLL configuration record to write
+ *
+ * Write the WRPLL configuration described by @c into the WRPLL
+ * configuration register identified by @pwd in the PRCI instance
+ * described by @c.  Make a cached copy of the WRPLL's current
+ * configuration so it can be used by other code.
+ *
+ * Context: Any context.  Caller must prevent the records pointed to by
+ *          @pd and @pwd from changing during execution.
+ */
+static void __prci_wrpll_write_cfg0(struct __prci_data *pd,
+				    struct __prci_wrpll_data *pwd,
+				    struct wrpll_cfg *c)
+{
+	__prci_writel(__prci_wrpll_pack(c), pwd->cfg0_offs, pd);
+
+	memcpy(&pwd->c, c, sizeof(*c));
+}
+
+/**
+ * __prci_wrpll_write_cfg1() - write Clock enable/disable configuration
+ * into the PRCI
+ * @pd: PRCI context
+ * @pwd: PRCI WRPLL metadata
+ * @enable: Clock enable or disable value
+ */
+static void __prci_wrpll_write_cfg1(struct __prci_data *pd,
+				    struct __prci_wrpll_data *pwd,
+				    u32 enable)
+{
+	__prci_writel(enable, pwd->cfg1_offs, pd);
+}
+
+/*
+ * Linux clock framework integration
+ *
+ * See the Linux clock framework documentation for more information on
+ * these functions.
+ */
+
+unsigned long sifive_prci_wrpll_recalc_rate(struct clk *hw,
+					    unsigned long parent_rate)
+{
+	struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
+	struct __prci_wrpll_data *pwd = pc->pwd;
+
+	return wrpll_calc_output_rate(&pwd->c, parent_rate);
+}
+
+long sifive_prci_wrpll_round_rate(struct clk *hw,
+				  unsigned long rate,
+				  unsigned long *parent_rate)
+{
+	struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
+	struct __prci_wrpll_data *pwd = pc->pwd;
+	struct wrpll_cfg c;
+
+	memcpy(&c, &pwd->c, sizeof(c));
+
+	wrpll_configure_for_rate(&c, rate, *parent_rate);
+
+	return wrpll_calc_output_rate(&c, *parent_rate);
+}
+
+int sifive_prci_wrpll_set_rate(struct clk *hw,
+			       unsigned long rate, unsigned long parent_rate)
+{
+	struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
+	struct __prci_wrpll_data *pwd = pc->pwd;
+	struct __prci_data *pd = pc->pd;
+	int r;
+
+	r = wrpll_configure_for_rate(&pwd->c, rate, parent_rate);
+	if (r)
+		return r;
+
+	if (pwd->enable_bypass)
+		pwd->enable_bypass(pd);
+
+	__prci_wrpll_write_cfg0(pd, pwd, &pwd->c);
+
+	udelay(wrpll_calc_max_lock_us(&pwd->c));
+
+	return 0;
+}
+
+int sifive_clk_is_enabled(struct clk *hw)
+{
+	struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
+	struct __prci_wrpll_data *pwd = pc->pwd;
+	struct __prci_data *pd = pc->pd;
+	u32 r;
+
+	r = __prci_readl(pd, pwd->cfg1_offs);
+
+	if (r & PRCI_COREPLLCFG1_CKE_MASK)
+		return 1;
+	else
+		return 0;
+}
+
+int sifive_prci_clock_enable(struct clk *hw)
+{
+	struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
+	struct __prci_wrpll_data *pwd = pc->pwd;
+	struct __prci_data *pd = pc->pd;
+
+	if (sifive_clk_is_enabled(hw))
+		return 0;
+
+	__prci_wrpll_write_cfg1(pd, pwd, PRCI_COREPLLCFG1_CKE_MASK);
+
+	if (pwd->disable_bypass)
+		pwd->disable_bypass(pd);
+
+	return 0;
+}
+
+void sifive_prci_clock_disable(struct clk *hw)
+{
+	struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
+	struct __prci_wrpll_data *pwd = pc->pwd;
+	struct __prci_data *pd = pc->pd;
+	u32 r;
+
+	if (pwd->enable_bypass)
+		pwd->enable_bypass(pd);
+
+	r = __prci_readl(pd, pwd->cfg1_offs);
+	r &= ~PRCI_COREPLLCFG1_CKE_MASK;
+
+	__prci_wrpll_write_cfg1(pd, pwd, r);
+}
+
+/* TLCLKSEL clock integration */
+
+unsigned long sifive_prci_tlclksel_recalc_rate(struct clk *hw,
+					       unsigned long parent_rate)
+{
+	struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
+	struct __prci_data *pd = pc->pd;
+	u32 v;
+	u8 div;
+
+	v = __prci_readl(pd, PRCI_CLKMUXSTATUSREG_OFFSET);
+	v &= PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK;
+	div = v ? 1 : 2;
+
+	return div_u64(parent_rate, div);
+}
+
+/* HFPCLK clock integration */
+
+unsigned long sifive_prci_hfpclkplldiv_recalc_rate(struct clk *hw,
+						   unsigned long parent_rate)
+{
+	struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
+	struct __prci_data *pd = pc->pd;
+	u32 div = __prci_readl(pd, PRCI_HFPCLKPLLDIV_OFFSET);
+
+	return div_u64(parent_rate, div + 2);
+}
+
+/*
+ * Core clock mux control
+ */
+
+/**
+ * sifive_prci_coreclksel_use_hfclk() - switch the CORECLK mux to output HFCLK
+ * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg
+ *
+ * Switch the CORECLK mux to the HFCLK input source; return once complete.
+ *
+ * Context: Any context.  Caller must prevent concurrent changes to the
+ *          PRCI_CORECLKSEL_OFFSET register.
+ */
+void sifive_prci_coreclksel_use_hfclk(struct __prci_data *pd)
+{
+	u32 r;
+
+	r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
+	r |= PRCI_CORECLKSEL_CORECLKSEL_MASK;
+	__prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
+
+	r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);	/* barrier */
+}
+
+/**
+ * sifive_prci_coreclksel_use_corepll() - switch the CORECLK mux to output
+ * COREPLL
+ * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg
+ *
+ * Switch the CORECLK mux to the COREPLL output clock; return once complete.
+ *
+ * Context: Any context.  Caller must prevent concurrent changes to the
+ *          PRCI_CORECLKSEL_OFFSET register.
+ */
+void sifive_prci_coreclksel_use_corepll(struct __prci_data *pd)
+{
+	u32 r;
+
+	r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
+	r &= ~PRCI_CORECLKSEL_CORECLKSEL_MASK;
+	__prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
+
+	r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);	/* barrier */
+}
+
+/**
+ * sifive_prci_coreclksel_use_final_corepll() - switch the CORECLK mux to output
+ * FINAL_COREPLL
+ * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg
+ *
+ * Switch the CORECLK mux to the final COREPLL output clock; return once
+ * complete.
+ *
+ * Context: Any context.  Caller must prevent concurrent changes to the
+ *          PRCI_CORECLKSEL_OFFSET register.
+ */
+void sifive_prci_coreclksel_use_final_corepll(struct __prci_data *pd)
+{
+	u32 r;
+
+	r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
+	r &= ~PRCI_CORECLKSEL_CORECLKSEL_MASK;
+	__prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
+
+	r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);	/* barrier */
+}
+
+/**
+ * sifive_prci_corepllsel_use_dvfscorepll() - switch the COREPLL mux to
+ * output DVFS_COREPLL
+ * @pd: struct __prci_data * for the PRCI containing the COREPLL mux reg
+ *
+ * Switch the COREPLL mux to the DVFSCOREPLL output clock; return once complete.
+ *
+ * Context: Any context.  Caller must prevent concurrent changes to the
+ *          PRCI_COREPLLSEL_OFFSET register.
+ */
+void sifive_prci_corepllsel_use_dvfscorepll(struct __prci_data *pd)
+{
+	u32 r;
+
+	r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET);
+	r |= PRCI_COREPLLSEL_COREPLLSEL_MASK;
+	__prci_writel(r, PRCI_COREPLLSEL_OFFSET, pd);
+
+	r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET);	/* barrier */
+}
+
+/**
+ * sifive_prci_corepllsel_use_corepll() - switch the COREPLL mux to
+ * output COREPLL
+ * @pd: struct __prci_data * for the PRCI containing the COREPLL mux reg
+ *
+ * Switch the COREPLL mux to the COREPLL output clock; return once complete.
+ *
+ * Context: Any context.  Caller must prevent concurrent changes to the
+ *          PRCI_COREPLLSEL_OFFSET register.
+ */
+void sifive_prci_corepllsel_use_corepll(struct __prci_data *pd)
+{
+	u32 r;
+
+	r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET);
+	r &= ~PRCI_COREPLLSEL_COREPLLSEL_MASK;
+	__prci_writel(r, PRCI_COREPLLSEL_OFFSET, pd);
+
+	r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET);	/* barrier */
+}
+
+/**
+ * sifive_prci_hfpclkpllsel_use_hfclk() - switch the HFPCLKPLL mux to
+ * output HFCLK
+ * @pd: struct __prci_data * for the PRCI containing the HFPCLKPLL mux reg
+ *
+ * Switch the HFPCLKPLL mux to the HFCLK input source; return once complete.
+ *
+ * Context: Any context.  Caller must prevent concurrent changes to the
+ *          PRCI_HFPCLKPLLSEL_OFFSET register.
+ */
+void sifive_prci_hfpclkpllsel_use_hfclk(struct __prci_data *pd)
+{
+	u32 r;
+
+	r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET);
+	r |= PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_MASK;
+	__prci_writel(r, PRCI_HFPCLKPLLSEL_OFFSET, pd);
+
+	r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET);	/* barrier */
+}
+
+/**
+ * sifive_prci_hfpclkpllsel_use_hfpclkpll() - switch the HFPCLKPLL mux to
+ * output HFPCLKPLL
+ * @pd: struct __prci_data * for the PRCI containing the HFPCLKPLL mux reg
+ *
+ * Switch the HFPCLKPLL mux to the HFPCLKPLL output clock; return once complete.
+ *
+ * Context: Any context.  Caller must prevent concurrent changes to the
+ *          PRCI_HFPCLKPLLSEL_OFFSET register.
+ */
+void sifive_prci_hfpclkpllsel_use_hfpclkpll(struct __prci_data *pd)
+{
+	u32 r;
+
+	r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET);
+	r &= ~PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_MASK;
+	__prci_writel(r, PRCI_HFPCLKPLLSEL_OFFSET, pd);
+
+	r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET);	/* barrier */
+}
+
+/**
+ * __prci_register_clocks() - register clock controls in the PRCI
+ * @dev: Linux struct device
+ * @pd: The pointer for PRCI per-device instance data
+ * @desc: The pointer for the information of clocks of each SoCs
+ *
+ * Register the list of clock controls described in __prci_init_clocks[] with
+ * the Linux clock framework.
+ *
+ * Return: 0 upon success or a negative error code upon failure.
+ */
+static int __prci_register_clocks(struct device_d *dev, struct __prci_data *pd,
+				  const struct prci_clk_desc *desc)
+{
+	struct __prci_clock *pic;
+	int parent_count, i, r;
+
+	parent_count = of_clk_get_parent_count(dev->device_node);
+	if (parent_count != EXPECTED_CLK_PARENT_COUNT) {
+		dev_err(dev, "expected only two parent clocks, found %d\n",
+			parent_count);
+		return -EINVAL;
+	}
+
+	/* Register PLLs */
+	for (i = 0; i < desc->num_clks; ++i) {
+		pic = &(desc->clks[i]);
+
+		pic->hw.name = pic->name;
+		pic->hw.parent_names = &pic->parent_name;
+		pic->hw.num_parents = 1;
+		pic->hw.ops = pic->ops;
+
+		pic->pd = pd;
+
+		if (pic->pwd)
+			__prci_wrpll_read_cfg0(pd, pic->pwd);
+
+		r = clk_register(&pic->hw);
+		if (r) {
+			dev_warn(dev, "Failed to register clock %s: %d\n",
+				 pic->hw.name, r);
+			return r;
+		}
+
+		r = clk_register_clkdev(&pic->hw, pic->name, dev_name(dev));
+		if (r) {
+			dev_warn(dev, "Failed to register clkdev for %s: %d\n",
+				 pic->hw.name, r);
+			return r;
+		}
+
+		pd->hw_clks.clks[i] = &pic->hw;
+	}
+
+	pd->hw_clks.clk_num = i;
+
+	r = of_clk_add_provider(dev->device_node, of_clk_src_onecell_get,
+				&pd->hw_clks);
+	if (r) {
+		dev_err(dev, "could not add hw_provider: %d\n", r);
+		return r;
+	}
+
+	return 0;
+}
+
+/**
+ * sifive_prci_init() - initialize prci data and check parent count
+ * @dev: platform device pointer for the prci
+ *
+ * Return: 0 upon success or a negative error code upon failure.
+ */
+static int sifive_prci_probe(struct device_d *dev)
+{
+	struct resource *res;
+	struct __prci_data *pd;
+	const struct prci_clk_desc *desc;
+	int r;
+
+	desc = device_get_match_data(dev);
+
+	pd = malloc(sizeof(*pd));
+	if (!pd)
+		return -ENOMEM;
+
+	pd->hw_clks.clk_num = desc->num_clks;
+	pd->hw_clks.clks = calloc(pd->hw_clks.clk_num, sizeof(*pd->hw_clks.clks));
+	if (!pd->hw_clks.clks)
+		return -ENOMEM;
+
+	res = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(res))
+		return PTR_ERR(res);
+
+	pd->va = IOMEM(res->start);
+
+	r = __prci_register_clocks(dev, pd, desc);
+	if (r) {
+		dev_err(dev, "could not register clocks: %d\n", r);
+		return r;
+	}
+
+	dev_dbg(dev, "SiFive PRCI probed\n");
+
+	return 0;
+}
+
+static const struct of_device_id sifive_prci_of_match[] = {
+	{.compatible = "sifive,fu540-c000-prci", .data = &prci_clk_fu540},
+	{.compatible = "sifive,fu740-c000-prci", .data = &prci_clk_fu740},
+	{}
+};
+
+static struct driver_d sifive_prci_driver = {
+	.name = "sifive-clk-prci",
+	.of_compatible = sifive_prci_of_match,
+	.probe = sifive_prci_probe,
+};
+core_platform_driver(sifive_prci_driver);
diff --git a/drivers/clk/sifive/sifive-prci.h b/drivers/clk/sifive/sifive-prci.h
new file mode 100644
index 000000000000..d8515538185c
--- /dev/null
+++ b/drivers/clk/sifive/sifive-prci.h
@@ -0,0 +1,298 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018-2019 SiFive, Inc.
+ * Wesley Terpstra
+ * Paul Walmsley
+ * Zong Li
+ */
+
+#ifndef __SIFIVE_CLK_SIFIVE_PRCI_H
+#define __SIFIVE_CLK_SIFIVE_PRCI_H
+
+#include <linux/clk/analogbits-wrpll-cln28hpc.h>
+#include <linux/clk.h>
+
+/*
+ * EXPECTED_CLK_PARENT_COUNT: how many parent clocks this driver expects:
+ *     hfclk and rtcclk
+ */
+#define EXPECTED_CLK_PARENT_COUNT 2
+
+/*
+ * Register offsets and bitmasks
+ */
+
+/* COREPLLCFG0 */
+#define PRCI_COREPLLCFG0_OFFSET		0x4
+#define PRCI_COREPLLCFG0_DIVR_SHIFT	0
+#define PRCI_COREPLLCFG0_DIVR_MASK	(0x3f << PRCI_COREPLLCFG0_DIVR_SHIFT)
+#define PRCI_COREPLLCFG0_DIVF_SHIFT	6
+#define PRCI_COREPLLCFG0_DIVF_MASK	(0x1ff << PRCI_COREPLLCFG0_DIVF_SHIFT)
+#define PRCI_COREPLLCFG0_DIVQ_SHIFT	15
+#define PRCI_COREPLLCFG0_DIVQ_MASK	(0x7 << PRCI_COREPLLCFG0_DIVQ_SHIFT)
+#define PRCI_COREPLLCFG0_RANGE_SHIFT	18
+#define PRCI_COREPLLCFG0_RANGE_MASK	(0x7 << PRCI_COREPLLCFG0_RANGE_SHIFT)
+#define PRCI_COREPLLCFG0_BYPASS_SHIFT	24
+#define PRCI_COREPLLCFG0_BYPASS_MASK	(0x1 << PRCI_COREPLLCFG0_BYPASS_SHIFT)
+#define PRCI_COREPLLCFG0_FSE_SHIFT	25
+#define PRCI_COREPLLCFG0_FSE_MASK	(0x1 << PRCI_COREPLLCFG0_FSE_SHIFT)
+#define PRCI_COREPLLCFG0_LOCK_SHIFT	31
+#define PRCI_COREPLLCFG0_LOCK_MASK	(0x1 << PRCI_COREPLLCFG0_LOCK_SHIFT)
+
+/* COREPLLCFG1 */
+#define PRCI_COREPLLCFG1_OFFSET		0x8
+#define PRCI_COREPLLCFG1_CKE_SHIFT	31
+#define PRCI_COREPLLCFG1_CKE_MASK	(0x1 << PRCI_COREPLLCFG1_CKE_SHIFT)
+
+/* DDRPLLCFG0 */
+#define PRCI_DDRPLLCFG0_OFFSET		0xc
+#define PRCI_DDRPLLCFG0_DIVR_SHIFT	0
+#define PRCI_DDRPLLCFG0_DIVR_MASK	(0x3f << PRCI_DDRPLLCFG0_DIVR_SHIFT)
+#define PRCI_DDRPLLCFG0_DIVF_SHIFT	6
+#define PRCI_DDRPLLCFG0_DIVF_MASK	(0x1ff << PRCI_DDRPLLCFG0_DIVF_SHIFT)
+#define PRCI_DDRPLLCFG0_DIVQ_SHIFT	15
+#define PRCI_DDRPLLCFG0_DIVQ_MASK	(0x7 << PRCI_DDRPLLCFG0_DIVQ_SHIFT)
+#define PRCI_DDRPLLCFG0_RANGE_SHIFT	18
+#define PRCI_DDRPLLCFG0_RANGE_MASK	(0x7 << PRCI_DDRPLLCFG0_RANGE_SHIFT)
+#define PRCI_DDRPLLCFG0_BYPASS_SHIFT	24
+#define PRCI_DDRPLLCFG0_BYPASS_MASK	(0x1 << PRCI_DDRPLLCFG0_BYPASS_SHIFT)
+#define PRCI_DDRPLLCFG0_FSE_SHIFT	25
+#define PRCI_DDRPLLCFG0_FSE_MASK	(0x1 << PRCI_DDRPLLCFG0_FSE_SHIFT)
+#define PRCI_DDRPLLCFG0_LOCK_SHIFT	31
+#define PRCI_DDRPLLCFG0_LOCK_MASK	(0x1 << PRCI_DDRPLLCFG0_LOCK_SHIFT)
+
+/* DDRPLLCFG1 */
+#define PRCI_DDRPLLCFG1_OFFSET		0x10
+#define PRCI_DDRPLLCFG1_CKE_SHIFT	31
+#define PRCI_DDRPLLCFG1_CKE_MASK	(0x1 << PRCI_DDRPLLCFG1_CKE_SHIFT)
+
+/* GEMGXLPLLCFG0 */
+#define PRCI_GEMGXLPLLCFG0_OFFSET	0x1c
+#define PRCI_GEMGXLPLLCFG0_DIVR_SHIFT	0
+#define PRCI_GEMGXLPLLCFG0_DIVR_MASK	(0x3f << PRCI_GEMGXLPLLCFG0_DIVR_SHIFT)
+#define PRCI_GEMGXLPLLCFG0_DIVF_SHIFT	6
+#define PRCI_GEMGXLPLLCFG0_DIVF_MASK	(0x1ff << PRCI_GEMGXLPLLCFG0_DIVF_SHIFT)
+#define PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT	15
+#define PRCI_GEMGXLPLLCFG0_DIVQ_MASK	(0x7 << PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT)
+#define PRCI_GEMGXLPLLCFG0_RANGE_SHIFT	18
+#define PRCI_GEMGXLPLLCFG0_RANGE_MASK	(0x7 << PRCI_GEMGXLPLLCFG0_RANGE_SHIFT)
+#define PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT	24
+#define PRCI_GEMGXLPLLCFG0_BYPASS_MASK	(0x1 << PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT)
+#define PRCI_GEMGXLPLLCFG0_FSE_SHIFT	25
+#define PRCI_GEMGXLPLLCFG0_FSE_MASK	(0x1 << PRCI_GEMGXLPLLCFG0_FSE_SHIFT)
+#define PRCI_GEMGXLPLLCFG0_LOCK_SHIFT	31
+#define PRCI_GEMGXLPLLCFG0_LOCK_MASK	(0x1 << PRCI_GEMGXLPLLCFG0_LOCK_SHIFT)
+
+/* GEMGXLPLLCFG1 */
+#define PRCI_GEMGXLPLLCFG1_OFFSET	0x20
+#define PRCI_GEMGXLPLLCFG1_CKE_SHIFT	31
+#define PRCI_GEMGXLPLLCFG1_CKE_MASK	(0x1 << PRCI_GEMGXLPLLCFG1_CKE_SHIFT)
+
+/* CORECLKSEL */
+#define PRCI_CORECLKSEL_OFFSET			0x24
+#define PRCI_CORECLKSEL_CORECLKSEL_SHIFT	0
+#define PRCI_CORECLKSEL_CORECLKSEL_MASK					\
+		(0x1 << PRCI_CORECLKSEL_CORECLKSEL_SHIFT)
+
+/* DEVICESRESETREG */
+#define PRCI_DEVICESRESETREG_OFFSET				0x28
+#define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT		0
+#define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_MASK			\
+		(0x1 << PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT)
+#define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT		1
+#define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_MASK				\
+		(0x1 << PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT)
+#define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT		2
+#define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_MASK				\
+		(0x1 << PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT)
+#define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT		3
+#define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_MASK				\
+		(0x1 << PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT)
+#define PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT			5
+#define PRCI_DEVICESRESETREG_GEMGXL_RST_N_MASK				\
+		(0x1 << PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT)
+#define PRCI_DEVICESRESETREG_CHIPLINK_RST_N_SHIFT		6
+#define PRCI_DEVICESRESETREG_CHIPLINK_RST_N_MASK			\
+		(0x1 << PRCI_DEVICESRESETREG_CHIPLINK_RST_N_SHIFT)
+
+/* CLKMUXSTATUSREG */
+#define PRCI_CLKMUXSTATUSREG_OFFSET				0x2c
+#define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT		1
+#define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK			\
+		(0x1 << PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT)
+
+/* CLTXPLLCFG0 */
+#define PRCI_CLTXPLLCFG0_OFFSET		0x30
+#define PRCI_CLTXPLLCFG0_DIVR_SHIFT	0
+#define PRCI_CLTXPLLCFG0_DIVR_MASK	(0x3f << PRCI_CLTXPLLCFG0_DIVR_SHIFT)
+#define PRCI_CLTXPLLCFG0_DIVF_SHIFT	6
+#define PRCI_CLTXPLLCFG0_DIVF_MASK	(0x1ff << PRCI_CLTXPLLCFG0_DIVF_SHIFT)
+#define PRCI_CLTXPLLCFG0_DIVQ_SHIFT	15
+#define PRCI_CLTXPLLCFG0_DIVQ_MASK	(0x7 << PRCI_CLTXPLLCFG0_DIVQ_SHIFT)
+#define PRCI_CLTXPLLCFG0_RANGE_SHIFT	18
+#define PRCI_CLTXPLLCFG0_RANGE_MASK	(0x7 << PRCI_CLTXPLLCFG0_RANGE_SHIFT)
+#define PRCI_CLTXPLLCFG0_BYPASS_SHIFT	24
+#define PRCI_CLTXPLLCFG0_BYPASS_MASK	(0x1 << PRCI_CLTXPLLCFG0_BYPASS_SHIFT)
+#define PRCI_CLTXPLLCFG0_FSE_SHIFT	25
+#define PRCI_CLTXPLLCFG0_FSE_MASK	(0x1 << PRCI_CLTXPLLCFG0_FSE_SHIFT)
+#define PRCI_CLTXPLLCFG0_LOCK_SHIFT	31
+#define PRCI_CLTXPLLCFG0_LOCK_MASK	(0x1 << PRCI_CLTXPLLCFG0_LOCK_SHIFT)
+
+/* CLTXPLLCFG1 */
+#define PRCI_CLTXPLLCFG1_OFFSET		0x34
+#define PRCI_CLTXPLLCFG1_CKE_SHIFT	31
+#define PRCI_CLTXPLLCFG1_CKE_MASK	(0x1 << PRCI_CLTXPLLCFG1_CKE_SHIFT)
+
+/* DVFSCOREPLLCFG0 */
+#define PRCI_DVFSCOREPLLCFG0_OFFSET	0x38
+
+/* DVFSCOREPLLCFG1 */
+#define PRCI_DVFSCOREPLLCFG1_OFFSET	0x3c
+#define PRCI_DVFSCOREPLLCFG1_CKE_SHIFT	31
+#define PRCI_DVFSCOREPLLCFG1_CKE_MASK	(0x1 << PRCI_DVFSCOREPLLCFG1_CKE_SHIFT)
+
+/* COREPLLSEL */
+#define PRCI_COREPLLSEL_OFFSET			0x40
+#define PRCI_COREPLLSEL_COREPLLSEL_SHIFT	0
+#define PRCI_COREPLLSEL_COREPLLSEL_MASK					\
+		(0x1 << PRCI_COREPLLSEL_COREPLLSEL_SHIFT)
+
+/* HFPCLKPLLCFG0 */
+#define PRCI_HFPCLKPLLCFG0_OFFSET		0x50
+#define PRCI_HFPCLKPLL_CFG0_DIVR_SHIFT		0
+#define PRCI_HFPCLKPLL_CFG0_DIVR_MASK					\
+		(0x3f << PRCI_HFPCLKPLLCFG0_DIVR_SHIFT)
+#define PRCI_HFPCLKPLL_CFG0_DIVF_SHIFT		6
+#define PRCI_HFPCLKPLL_CFG0_DIVF_MASK					\
+		(0x1ff << PRCI_HFPCLKPLLCFG0_DIVF_SHIFT)
+#define PRCI_HFPCLKPLL_CFG0_DIVQ_SHIFT		15
+#define PRCI_HFPCLKPLL_CFG0_DIVQ_MASK					\
+		(0x7 << PRCI_HFPCLKPLLCFG0_DIVQ_SHIFT)
+#define PRCI_HFPCLKPLL_CFG0_RANGE_SHIFT		18
+#define PRCI_HFPCLKPLL_CFG0_RANGE_MASK					\
+		(0x7 << PRCI_HFPCLKPLLCFG0_RANGE_SHIFT)
+#define PRCI_HFPCLKPLL_CFG0_BYPASS_SHIFT	24
+#define PRCI_HFPCLKPLL_CFG0_BYPASS_MASK					\
+		(0x1 << PRCI_HFPCLKPLLCFG0_BYPASS_SHIFT)
+#define PRCI_HFPCLKPLL_CFG0_FSE_SHIFT		25
+#define PRCI_HFPCLKPLL_CFG0_FSE_MASK					\
+		(0x1 << PRCI_HFPCLKPLLCFG0_FSE_SHIFT)
+#define PRCI_HFPCLKPLL_CFG0_LOCK_SHIFT		31
+#define PRCI_HFPCLKPLL_CFG0_LOCK_MASK					\
+		(0x1 << PRCI_HFPCLKPLLCFG0_LOCK_SHIFT)
+
+/* HFPCLKPLLCFG1 */
+#define PRCI_HFPCLKPLLCFG1_OFFSET		0x54
+#define PRCI_HFPCLKPLLCFG1_CKE_SHIFT		31
+#define PRCI_HFPCLKPLLCFG1_CKE_MASK					\
+		(0x1 << PRCI_HFPCLKPLLCFG1_CKE_SHIFT)
+
+/* HFPCLKPLLSEL */
+#define PRCI_HFPCLKPLLSEL_OFFSET		0x58
+#define PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_SHIFT	0
+#define PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_MASK				\
+		(0x1 << PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_SHIFT)
+
+/* HFPCLKPLLDIV */
+#define PRCI_HFPCLKPLLDIV_OFFSET		0x5c
+
+/* PRCIPLL */
+#define PRCI_PRCIPLL_OFFSET			0xe0
+
+/* PROCMONCFG */
+#define PRCI_PROCMONCFG_OFFSET			0xf0
+
+/*
+ * Private structures
+ */
+
+/**
+ * struct __prci_data - per-device-instance data
+ * @va: base virtual address of the PRCI IP block
+ * @hw_clks: encapsulates struct clk_hw records
+ *
+ * PRCI per-device instance data
+ */
+struct __prci_data {
+	void __iomem *va;
+	struct clk_onecell_data hw_clks;
+};
+
+/**
+ * struct __prci_wrpll_data - WRPLL configuration and integration data
+ * @c: WRPLL current configuration record
+ * @enable_bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL)
+ * @disable_bypass: fn ptr to code to not bypass the WRPLL (or NULL)
+ * @cfg0_offs: WRPLL CFG0 register offset (in bytes) from the PRCI base address
+ * @cfg1_offs: WRPLL CFG1 register offset (in bytes) from the PRCI base address
+ *
+ * @enable_bypass and @disable_bypass are used for WRPLL instances
+ * that contain a separate external glitchless clock mux downstream
+ * from the PLL.  The WRPLL internal bypass mux is not glitchless.
+ */
+struct __prci_wrpll_data {
+	struct wrpll_cfg c;
+	void (*enable_bypass)(struct __prci_data *pd);
+	void (*disable_bypass)(struct __prci_data *pd);
+	u8 cfg0_offs;
+	u8 cfg1_offs;
+};
+
+/**
+ * struct __prci_clock - describes a clock device managed by PRCI
+ * @name: user-readable clock name string - should match the manual
+ * @parent_name: parent name for this clock
+ * @ops: struct clk_ops for the Linux clock framework to use for control
+ * @hw: Linux-private clock data
+ * @pwd: WRPLL-specific data, associated with this clock (if not NULL)
+ * @pd: PRCI-specific data associated with this clock (if not NULL)
+ *
+ * PRCI clock data.  Used by the PRCI driver to register PRCI-provided
+ * clocks to the Linux clock infrastructure.
+ */
+struct __prci_clock {
+	const char *name;
+	const char *parent_name;
+	const struct clk_ops *ops;
+	struct clk hw;
+	struct __prci_wrpll_data *pwd;
+	struct __prci_data *pd;
+};
+
+#define clk_hw_to_prci_clock(pwd) container_of(pwd, struct __prci_clock, hw)
+
+/*
+ * struct prci_clk_desc - describes the information of clocks of each SoCs
+ * @clks: point to a array of __prci_clock
+ * @num_clks: the number of element of clks
+ */
+struct prci_clk_desc {
+	struct __prci_clock *clks;
+	size_t num_clks;
+};
+
+/* Core clock mux control */
+void sifive_prci_coreclksel_use_hfclk(struct __prci_data *pd);
+void sifive_prci_coreclksel_use_corepll(struct __prci_data *pd);
+void sifive_prci_coreclksel_use_final_corepll(struct __prci_data *pd);
+void sifive_prci_corepllsel_use_dvfscorepll(struct __prci_data *pd);
+void sifive_prci_corepllsel_use_corepll(struct __prci_data *pd);
+void sifive_prci_hfpclkpllsel_use_hfclk(struct __prci_data *pd);
+void sifive_prci_hfpclkpllsel_use_hfpclkpll(struct __prci_data *pd);
+
+/* Linux clock framework integration */
+long sifive_prci_wrpll_round_rate(struct clk *hw, unsigned long rate,
+				  unsigned long *parent_rate);
+int sifive_prci_wrpll_set_rate(struct clk *hw, unsigned long rate,
+			       unsigned long parent_rate);
+int sifive_clk_is_enabled(struct clk *hw);
+int sifive_prci_clock_enable(struct clk *hw);
+void sifive_prci_clock_disable(struct clk *hw);
+unsigned long sifive_prci_wrpll_recalc_rate(struct clk *hw,
+					    unsigned long parent_rate);
+unsigned long sifive_prci_tlclksel_recalc_rate(struct clk *hw,
+					       unsigned long parent_rate);
+unsigned long sifive_prci_hfpclkplldiv_recalc_rate(struct clk *hw,
+						   unsigned long parent_rate);
+
+#endif /* __SIFIVE_CLK_SIFIVE_PRCI_H */
diff --git a/include/linux/clk/analogbits-wrpll-cln28hpc.h b/include/linux/clk/analogbits-wrpll-cln28hpc.h
new file mode 100644
index 000000000000..03279097e138
--- /dev/null
+++ b/include/linux/clk/analogbits-wrpll-cln28hpc.h
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018-2019 SiFive, Inc.
+ * Wesley Terpstra
+ * Paul Walmsley
+ */
+
+#ifndef __LINUX_CLK_ANALOGBITS_WRPLL_CLN28HPC_H
+#define __LINUX_CLK_ANALOGBITS_WRPLL_CLN28HPC_H
+
+#include <linux/types.h>
+
+/* DIVQ_VALUES: number of valid DIVQ values */
+#define DIVQ_VALUES				6
+
+/*
+ * Bit definitions for struct wrpll_cfg.flags
+ *
+ * WRPLL_FLAGS_BYPASS_FLAG: if set, the PLL is either in bypass, or should be
+ *	programmed to enter bypass
+ * WRPLL_FLAGS_RESET_FLAG: if set, the PLL is in reset
+ * WRPLL_FLAGS_INT_FEEDBACK_FLAG: if set, the PLL is configured for internal
+ *	feedback mode
+ * WRPLL_FLAGS_EXT_FEEDBACK_FLAG: if set, the PLL is configured for external
+ *	feedback mode (not yet supported by this driver)
+ */
+#define WRPLL_FLAGS_BYPASS_SHIFT		0
+#define WRPLL_FLAGS_BYPASS_MASK		BIT(WRPLL_FLAGS_BYPASS_SHIFT)
+#define WRPLL_FLAGS_RESET_SHIFT		1
+#define WRPLL_FLAGS_RESET_MASK		BIT(WRPLL_FLAGS_RESET_SHIFT)
+#define WRPLL_FLAGS_INT_FEEDBACK_SHIFT	2
+#define WRPLL_FLAGS_INT_FEEDBACK_MASK	BIT(WRPLL_FLAGS_INT_FEEDBACK_SHIFT)
+#define WRPLL_FLAGS_EXT_FEEDBACK_SHIFT	3
+#define WRPLL_FLAGS_EXT_FEEDBACK_MASK	BIT(WRPLL_FLAGS_EXT_FEEDBACK_SHIFT)
+
+/**
+ * struct wrpll_cfg - WRPLL configuration values
+ * @divr: reference divider value (6 bits), as presented to the PLL signals
+ * @divf: feedback divider value (9 bits), as presented to the PLL signals
+ * @divq: output divider value (3 bits), as presented to the PLL signals
+ * @flags: PLL configuration flags.  See above for more information
+ * @range: PLL loop filter range.  See below for more information
+ * @output_rate_cache: cached output rates, swept across DIVQ
+ * @parent_rate: PLL refclk rate for which values are valid
+ * @max_r: maximum possible R divider value, given @parent_rate
+ * @init_r: initial R divider value to start the search from
+ *
+ * @divr, @divq, @divq, @range represent what the PLL expects to see
+ * on its input signals.  Thus @divr and @divf are the actual divisors
+ * minus one.  @divq is a power-of-two divider; for example, 1 =
+ * divide-by-2 and 6 = divide-by-64.  0 is an invalid @divq value.
+ *
+ * When initially passing a struct wrpll_cfg record, the
+ * record should be zero-initialized with the exception of the @flags
+ * field.  The only flag bits that need to be set are either
+ * WRPLL_FLAGS_INT_FEEDBACK or WRPLL_FLAGS_EXT_FEEDBACK.
+ */
+struct wrpll_cfg {
+	u8 divr;
+	u8 divq;
+	u8 range;
+	u8 flags;
+	u16 divf;
+/* private: */
+	u32 output_rate_cache[DIVQ_VALUES];
+	unsigned long parent_rate;
+	u8 max_r;
+	u8 init_r;
+};
+
+int wrpll_configure_for_rate(struct wrpll_cfg *c, u32 target_rate,
+			     unsigned long parent_rate);
+
+unsigned int wrpll_calc_max_lock_us(const struct wrpll_cfg *c);
+
+unsigned long wrpll_calc_output_rate(const struct wrpll_cfg *c,
+				     unsigned long parent_rate);
+
+#endif /* __LINUX_CLK_ANALOGBITS_WRPLL_CLN28HPC_H */
-- 
2.29.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 02/12] serial: implement SiFive UART support
  2021-04-27 20:22 [PATCH 01/12] clk: add SiFive PRCI clock controller support Ahmad Fatoum
@ 2021-04-27 20:22 ` Ahmad Fatoum
  2021-04-27 20:23 ` [PATCH 03/12] debug_ll: support <asm/debug_ll.h> to get rid of mach directories Ahmad Fatoum
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Ahmad Fatoum @ 2021-04-27 20:22 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum, rcz

Import serial driver from Linux v5.11.

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
 drivers/serial/Kconfig         |   9 ++
 drivers/serial/Makefile        |   1 +
 drivers/serial/serial_sifive.c | 171 +++++++++++++++++++++++++++++++++
 3 files changed, 181 insertions(+)
 create mode 100644 drivers/serial/serial_sifive.c

diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index db924efa02a6..b9750d1774f8 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -164,4 +164,13 @@ config VIRTIO_CONSOLE
 
 	  Also serves as a general-purpose serial device for data
 	  transfer between the guest and host.
+
+config SERIAL_SIFIVE
+	tristate "SiFive UART support"
+	depends on OFDEVICE
+	help
+	  Select this option if you are building barebox for a device that
+	  contains a SiFive UART IP block.  This type of UART is present on
+	  SiFive FU540 SoCs, among others.
+
 endmenu
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 7ff41cd5c744..5120b1737664 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -23,3 +23,4 @@ obj-$(CONFIG_DRIVER_SERIAL_EFI_STDIO)		+= efi-stdio.o
 obj-$(CONFIG_DRIVER_SERIAL_DIGIC)		+= serial_digic.o
 obj-$(CONFIG_DRIVER_SERIAL_LPUART)		+= serial_lpuart.o
 obj-$(CONFIG_VIRTIO_CONSOLE)			+= virtio_console.o
+obj-$(CONFIG_SERIAL_SIFIVE)			+= serial_sifive.o
diff --git a/drivers/serial/serial_sifive.c b/drivers/serial/serial_sifive.c
new file mode 100644
index 000000000000..45f7c2bc9ace
--- /dev/null
+++ b/drivers/serial/serial_sifive.c
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Anup Patel <anup@brainfault.org>
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <malloc.h>
+#include <io.h>
+#include <of.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#define UART_TXFIFO_FULL	0x80000000
+#define UART_RXFIFO_EMPTY	0x80000000
+#define UART_RXFIFO_DATA	0x000000ff
+#define UART_TXCTRL_TXEN	0x1
+#define UART_RXCTRL_RXEN	0x1
+
+/* IP register */
+#define UART_IP_RXWM            0x2
+
+struct sifive_serial_regs {
+	u32 txfifo;
+	u32 rxfifo;
+	u32 txctrl;
+	u32 rxctrl;
+	u32 ie;
+	u32 ip;
+	u32 div;
+};
+
+struct sifive_serial_priv {
+	unsigned long freq;
+	struct sifive_serial_regs __iomem *regs;
+	struct console_device cdev;
+};
+
+#define to_priv(cdev) container_of(cdev, struct sifive_serial_priv, cdev)
+
+/**
+ * Find minimum divisor divides in_freq to max_target_hz;
+ * Based on uart driver n SiFive FSBL.
+ *
+ * f_baud = f_in / (div + 1) => div = (f_in / f_baud) - 1
+ * The nearest integer solution requires rounding up as to not exceed
+ * max_target_hz.
+ * div  = ceil(f_in / f_baud) - 1
+ *	= floor((f_in - 1 + f_baud) / f_baud) - 1
+ * This should not overflow as long as (f_in - 1 + f_baud) does not exceed
+ * 2^32 - 1, which is unlikely since we represent frequencies in kHz.
+ */
+static inline unsigned int uart_min_clk_divisor(unsigned long in_freq,
+						unsigned long max_target_hz)
+{
+	unsigned long quotient =
+			(in_freq + max_target_hz - 1) / (max_target_hz);
+	/* Avoid underflow */
+	if (quotient == 0)
+		return 0;
+	else
+		return quotient - 1;
+}
+
+static void sifive_serial_init(struct sifive_serial_regs __iomem *regs)
+{
+	writel(UART_TXCTRL_TXEN, &regs->txctrl);
+	writel(UART_RXCTRL_RXEN, &regs->rxctrl);
+	writel(0, &regs->ie);
+}
+
+static int sifive_serial_setbrg(struct console_device *cdev, int baudrate)
+{
+	struct sifive_serial_priv *priv = to_priv(cdev);
+
+	writel((uart_min_clk_divisor(priv->freq, baudrate)), &priv->regs->div);
+
+	return 0;
+}
+
+static int sifive_serial_getc(struct console_device *cdev)
+{
+	struct sifive_serial_regs __iomem *regs = to_priv(cdev)->regs;
+	u32 ch;
+
+	do {
+		ch = readl(&regs->rxfifo);
+	} while (ch & UART_RXFIFO_EMPTY);
+
+	return ch & UART_RXFIFO_DATA;
+}
+
+static void sifive_serial_putc(struct console_device *cdev, const char ch)
+{
+	struct sifive_serial_regs __iomem *regs = to_priv(cdev)->regs;
+
+	// TODO: how to check for !empty to utilize fifo?
+	while (readl(&regs->txfifo) & UART_TXFIFO_FULL)
+		;
+
+	writel(ch, &regs->txfifo);
+}
+
+static int sifive_serial_tstc(struct console_device *cdev)
+{
+	struct sifive_serial_regs __iomem *regs = to_priv(cdev)->regs;
+
+	return readl(&regs->ip) & UART_IP_RXWM;
+}
+
+static void sifive_serial_flush(struct console_device *cdev)
+{
+	struct sifive_serial_regs __iomem *regs = to_priv(cdev)->regs;
+
+	while (readl(&regs->txfifo) & UART_TXFIFO_FULL)
+		;
+}
+
+static int sifive_serial_probe(struct device_d *dev)
+{
+	struct sifive_serial_priv *priv;
+	struct resource *iores;
+	struct clk *clk;
+	u32 freq;
+	int ret;
+
+	clk = clk_get(dev, NULL);
+	if (!IS_ERR(clk)) {
+		freq = clk_get_rate(clk);
+	} else {
+		dev_dbg(dev, "failed to get clock. Fallback to device tree.\n");
+
+		ret = of_property_read_u32(dev->device_node, "clock-frequency", &freq);
+		if (ret) {
+			dev_warn(dev, "unknown clock frequency\n");
+			return ret;
+		}
+	}
+
+	iores = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(iores))
+		return PTR_ERR(iores);
+
+	priv = xzalloc(sizeof(*priv));
+
+	priv->freq = freq;
+	priv->regs = IOMEM(iores->start);
+
+	priv->cdev.dev = dev;
+	priv->cdev.putc = sifive_serial_putc;
+	priv->cdev.getc = sifive_serial_getc;
+	priv->cdev.tstc = sifive_serial_tstc;
+	priv->cdev.flush = sifive_serial_flush;
+	priv->cdev.setbrg = sifive_serial_setbrg,
+
+	sifive_serial_init(priv->regs);
+
+	return console_register(&priv->cdev);
+}
+
+static __maybe_unused struct of_device_id sifive_serial_dt_ids[] = {
+	{ .compatible = "sifive,uart0" },
+	{ /* sentinel */ }
+};
+
+static struct driver_d serial_sifive_driver = {
+	.name   = "serial_sifive",
+	.probe  = sifive_serial_probe,
+	.of_compatible = sifive_serial_dt_ids,
+};
+console_platform_driver(serial_sifive_driver);
-- 
2.29.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 03/12] debug_ll: support <asm/debug_ll.h> to get rid of mach directories
  2021-04-27 20:22 [PATCH 01/12] clk: add SiFive PRCI clock controller support Ahmad Fatoum
  2021-04-27 20:22 ` [PATCH 02/12] serial: implement SiFive UART support Ahmad Fatoum
@ 2021-04-27 20:23 ` Ahmad Fatoum
  2021-04-27 20:23 ` [PATCH 04/12] RISC-V: support multi-image for all machines Ahmad Fatoum
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Ahmad Fatoum @ 2021-04-27 20:23 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum, rcz

Linux support has no arch/riscv/mach-* directories. If we can get rid of
them, we could multi-image build all images at once. Only thing holding
us back is <mach/debug_ll.h>. Add <asm/debug_ll.h> as alternative.

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
 common/Kconfig     | 4 ++++
 include/debug_ll.h | 4 ++++
 2 files changed, 8 insertions(+)

diff --git a/common/Kconfig b/common/Kconfig
index bddf802d3bb4..b10fb45b722d 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -1462,6 +1462,10 @@ endmenu
 config HAS_DEBUG_LL
 	bool
 
+config HAS_ASM_DEBUG_LL
+	bool
+	select HAS_DEBUG_LL
+
 config DDR_SPD
 	bool
 	select CRC_ITU_T
diff --git a/include/debug_ll.h b/include/debug_ll.h
index 5bd1afe6ac73..735033b314cc 100644
--- a/include/debug_ll.h
+++ b/include/debug_ll.h
@@ -12,6 +12,9 @@
 #define   __INCLUDE_DEBUG_LL_H__
 
 #ifdef CONFIG_HAS_DEBUG_LL
+#ifdef CONFIG_HAS_ASM_DEBUG_LL
+#include <asm/debug_ll.h>
+#else
 /*
  * mach/debug_ll.h should implement PUTC_LL. This can be a macro or a static
  * inline function. Note that several SoCs expect the UART to be initialized
@@ -21,6 +24,7 @@
  */
 #include <mach/debug_ll.h>
 #endif
+#endif
 
 #if defined (CONFIG_DEBUG_LL)
 
-- 
2.29.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 04/12] RISC-V: support multi-image for all machines
  2021-04-27 20:22 [PATCH 01/12] clk: add SiFive PRCI clock controller support Ahmad Fatoum
  2021-04-27 20:22 ` [PATCH 02/12] serial: implement SiFive UART support Ahmad Fatoum
  2021-04-27 20:23 ` [PATCH 03/12] debug_ll: support <asm/debug_ll.h> to get rid of mach directories Ahmad Fatoum
@ 2021-04-27 20:23 ` Ahmad Fatoum
  2021-05-03 11:33   ` Sascha Hauer
  2021-04-27 20:23 ` [PATCH 05/12] RISC-V: erizo: restrict to RV32I Ahmad Fatoum
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 20+ messages in thread
From: Ahmad Fatoum @ 2021-04-27 20:23 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum, rcz

We already got rid of arch/riscv/mach-virt. Now do the same for
arch/riscv/mach-erizo. This will enable us to build images for all
RISC-V boards at once.

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
 arch/riscv/Kconfig                         | 31 ++--------------------
 arch/riscv/Kconfig.socs                    | 24 +++++++++++++++++
 arch/riscv/Makefile                        |  2 +-
 arch/riscv/configs/erizo_generic_defconfig |  1 +
 arch/riscv/configs/virt32_defconfig        |  2 +-
 arch/riscv/configs/virt64_defconfig        |  2 +-
 arch/riscv/mach-erizo/Kconfig              | 11 --------
 7 files changed, 30 insertions(+), 43 deletions(-)
 create mode 100644 arch/riscv/Kconfig.socs
 delete mode 100644 arch/riscv/mach-erizo/Kconfig

diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index c0583f31536b..a4aa799acf01 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -19,31 +19,6 @@ config ARCH_TEXT_BASE
 	hex
 	default 0x0
 
-menu "Machine selection"
-
-choice
-	prompt "System type"
-	default MACH_ERIZO
-
-config MACH_ERIZO
-	bool "erizo family"
-	select ARCH_RV32I
-	select HAS_DEBUG_LL
-	select HAS_NMON
-	select USE_COMPRESSED_DTB
-	select RISCV_M_MODE
-	select RISCV_TIMER
-
-config MACH_VIRT
-	bool "virt family"
-	select BOARD_RISCV_GENERIC_DT
-	select CLINT_TIMER
-	help
-	  Generates an image tht can be be booted by QEMU. The image is called
-	  barebox-dt-2nd.img
-
-endchoice
-
 choice
 	prompt "Base ISA"
 	default ARCH_RV32I
@@ -63,6 +38,8 @@ config ARCH_RV64I
 
 endchoice
 
+source "arch/riscv/Kconfig.socs"
+
 config CPU_SUPPORTS_32BIT_KERNEL
 	bool
 
@@ -82,8 +59,6 @@ config 64BIT
 	select ARCH_DMA_ADDR_T_64BIT
 	select PHYS_ADDR_T_64BIT
 
-source "arch/riscv/mach-erizo/Kconfig"
-
 config BOARD_RISCV_GENERIC_DT
 	select BOARD_GENERIC_DT
 	bool "Build generic RISC-V device tree 2nd stage image"
@@ -93,8 +68,6 @@ config BOARD_RISCV_GENERIC_DT
 	  in a1 like the Kernel does, so it could be used anywhere where a Kernel
 	  image could be used. The image will be called images/barebox-dt-2nd.img
 
-endmenu
-
 menu "RISC-V specific settings"
 
 config RISCV_OPTIMZED_STRING_FUNCTIONS
diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
new file mode 100644
index 000000000000..b0e38d8f2cca
--- /dev/null
+++ b/arch/riscv/Kconfig.socs
@@ -0,0 +1,24 @@
+menu "SoC selection"
+
+config SOC_ERIZO
+	bool "Erizo SoC"
+	select ARCH_RV32I
+	select HAS_DEBUG_LL
+	select HAS_NMON
+	select USE_COMPRESSED_DTB
+	select RISCV_M_MODE
+	select RISCV_TIMER
+
+config BOARD_ERIZO_GENERIC
+	depends on SOC_ERIZO
+	def_bool y
+
+config SOC_VIRT
+	bool "QEMU Virt Machine"
+	select BOARD_RISCV_GENERIC_DT
+	select CLINT_TIMER
+	help
+	  Generates an image tht can be be booted by QEMU. The image is called
+	  barebox-dt-2nd.img
+
+endmenu
diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
index 1a41d15477b5..09a94d69b220 100644
--- a/arch/riscv/Makefile
+++ b/arch/riscv/Makefile
@@ -19,7 +19,7 @@ LDFLAGS_pbl += $(riscv-ldflags-y)
 cflags-y += $(riscv-cflags-y)
 LDFLAGS_barebox += -nostdlib
 
-machine-$(CONFIG_MACH_ERIZO)	:= erizo
+machine-$(CONFIG_SOC_ERIZO)	:= erizo
 
 LDFLAGS_barebox += $(riscv-ldflags-y)
 
diff --git a/arch/riscv/configs/erizo_generic_defconfig b/arch/riscv/configs/erizo_generic_defconfig
index 839b652ab53d..247a17913048 100644
--- a/arch/riscv/configs/erizo_generic_defconfig
+++ b/arch/riscv/configs/erizo_generic_defconfig
@@ -1,3 +1,4 @@
+CONFIG_SOC_ERIZO=y
 # CONFIG_GLOBALVAR is not set
 CONFIG_STACK_SIZE=0x20000
 CONFIG_MALLOC_SIZE=0x100000
diff --git a/arch/riscv/configs/virt32_defconfig b/arch/riscv/configs/virt32_defconfig
index 83e3ca1bade8..218fee57b711 100644
--- a/arch/riscv/configs/virt32_defconfig
+++ b/arch/riscv/configs/virt32_defconfig
@@ -1,4 +1,4 @@
-CONFIG_MACH_VIRT=y
+CONFIG_SOC_VIRT=y
 CONFIG_RISCV_OPTIMZED_STRING_FUNCTIONS=y
 CONFIG_STACK_SIZE=0x20000
 CONFIG_MALLOC_SIZE=0x0
diff --git a/arch/riscv/configs/virt64_defconfig b/arch/riscv/configs/virt64_defconfig
index 17ce16637d96..04a4f1e2f4cb 100644
--- a/arch/riscv/configs/virt64_defconfig
+++ b/arch/riscv/configs/virt64_defconfig
@@ -1,4 +1,4 @@
-CONFIG_MACH_VIRT=y
+CONFIG_SOC_VIRT=y
 CONFIG_ARCH_RV64I=y
 CONFIG_RISCV_OPTIMZED_STRING_FUNCTIONS=y
 CONFIG_STACK_SIZE=0x20000
diff --git a/arch/riscv/mach-erizo/Kconfig b/arch/riscv/mach-erizo/Kconfig
deleted file mode 100644
index 2400b4437b10..000000000000
--- a/arch/riscv/mach-erizo/Kconfig
+++ /dev/null
@@ -1,11 +0,0 @@
-if MACH_ERIZO
-
-choice
-	prompt "Board type"
-
-config BOARD_ERIZO_GENERIC
-	bool "erizo generic board"
-
-endchoice
-
-endif
-- 
2.29.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 05/12] RISC-V: erizo: restrict to RV32I
  2021-04-27 20:22 [PATCH 01/12] clk: add SiFive PRCI clock controller support Ahmad Fatoum
                   ` (2 preceding siblings ...)
  2021-04-27 20:23 ` [PATCH 04/12] RISC-V: support multi-image for all machines Ahmad Fatoum
@ 2021-04-27 20:23 ` Ahmad Fatoum
  2021-04-27 20:23 ` [PATCH 06/12] RISC-V: erizo: drop mach-erizo directory Ahmad Fatoum
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Ahmad Fatoum @ 2021-04-27 20:23 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum, rcz

Erizo is a RISC-V 32-bit softcore. Because ARCH_RV32I can be selected
independently, a 64-bit barebox images could be built, but the image
produced would be useless. Avoid this by not showing the SOC_ERIZO
prompt when compiling for 64-bit.

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
 arch/riscv/Kconfig.socs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
index b0e38d8f2cca..093bca33806c 100644
--- a/arch/riscv/Kconfig.socs
+++ b/arch/riscv/Kconfig.socs
@@ -2,7 +2,7 @@ menu "SoC selection"
 
 config SOC_ERIZO
 	bool "Erizo SoC"
-	select ARCH_RV32I
+	depends on ARCH_RV32I
 	select HAS_DEBUG_LL
 	select HAS_NMON
 	select USE_COMPRESSED_DTB
-- 
2.29.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 06/12] RISC-V: erizo: drop mach-erizo directory
  2021-04-27 20:22 [PATCH 01/12] clk: add SiFive PRCI clock controller support Ahmad Fatoum
                   ` (3 preceding siblings ...)
  2021-04-27 20:23 ` [PATCH 05/12] RISC-V: erizo: restrict to RV32I Ahmad Fatoum
@ 2021-04-27 20:23 ` Ahmad Fatoum
  2021-05-05 10:18   ` Antony Pavlov
  2021-04-27 20:23 ` [PATCH 07/12] RISC-V: add SBI based cpuinfo Ahmad Fatoum
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 20+ messages in thread
From: Ahmad Fatoum @ 2021-04-27 20:23 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum, rcz

With the recent changes, we can now delete mach-erizo. Do so.

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
 arch/riscv/Kconfig.socs                        |  2 +-
 arch/riscv/Makefile                            | 13 -------------
 .../include/mach => include/asm}/debug_ll.h    | 18 +++++++-----------
 arch/riscv/mach-erizo/Makefile                 |  3 ---
 common/Kconfig                                 |  5 +++++
 5 files changed, 13 insertions(+), 28 deletions(-)
 rename arch/riscv/{mach-erizo/include/mach => include/asm}/debug_ll.h (57%)
 delete mode 100644 arch/riscv/mach-erizo/Makefile

diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
index 093bca33806c..ea5ae0a6e9b5 100644
--- a/arch/riscv/Kconfig.socs
+++ b/arch/riscv/Kconfig.socs
@@ -3,7 +3,7 @@ menu "SoC selection"
 config SOC_ERIZO
 	bool "Erizo SoC"
 	depends on ARCH_RV32I
-	select HAS_DEBUG_LL
+	select HAS_ASM_DEBUG_LL
 	select HAS_NMON
 	select USE_COMPRESSED_DTB
 	select RISCV_M_MODE
diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
index 09a94d69b220..0b1278936d91 100644
--- a/arch/riscv/Makefile
+++ b/arch/riscv/Makefile
@@ -19,8 +19,6 @@ LDFLAGS_pbl += $(riscv-ldflags-y)
 cflags-y += $(riscv-cflags-y)
 LDFLAGS_barebox += -nostdlib
 
-machine-$(CONFIG_SOC_ERIZO)	:= erizo
-
 LDFLAGS_barebox += $(riscv-ldflags-y)
 
 ifndef CONFIG_MODULES
@@ -31,21 +29,10 @@ endif
 
 KBUILD_BINARY := barebox.bin
 
-machdirs := $(patsubst %,arch/riscv/mach-%/,$(machine-y))
-
-KBUILD_CPPFLAGS += $(patsubst %,-I$(srctree)/%include,$(machdirs))
-
 archprepare: maketools
 
 PHONY += maketools
 
-ifneq ($(machine-y),)
-MACH  := arch/riscv/mach-$(machine-y)/
-else
-MACH  :=
-endif
-
-common-y += $(MACH)
 common-y += arch/riscv/boards/
 common-y += arch/riscv/cpu/
 common-y += arch/riscv/lib/
diff --git a/arch/riscv/mach-erizo/include/mach/debug_ll.h b/arch/riscv/include/asm/debug_ll.h
similarity index 57%
rename from arch/riscv/mach-erizo/include/mach/debug_ll.h
rename to arch/riscv/include/asm/debug_ll.h
index a20acfcdfb79..755ed09786d5 100644
--- a/arch/riscv/mach-erizo/include/mach/debug_ll.h
+++ b/arch/riscv/include/asm/debug_ll.h
@@ -1,18 +1,10 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (C) 2017 Antony Pavlov <antonynpavlov@gmail.com>
- *
- * This file is part of barebox.
- *
- * 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.
- *
  */
 
-#ifndef __MACH_ERIZO_DEBUG_LL__
-#define __MACH_ERIZO_DEBUG_LL__
+#ifndef __ASM_DEBUG_LL__
+#define __ASM_DEBUG_LL__
 
 /** @file
  *  This File contains declaration for early output support
@@ -20,6 +12,8 @@
 
 #include <linux/kconfig.h>
 
+#ifdef CONFIG_DEBUG_ERIZO
+
 #define DEBUG_LL_UART_ADDR	0x90000000
 #define DEBUG_LL_UART_SHIFT	2
 #define DEBUG_LL_UART_IOSIZE32
@@ -30,4 +24,6 @@
 
 #include <asm/debug_ll_ns16550.h>
 
-#endif /* __MACH_ERIZO_DEBUG_LL__ */
+#endif
+
+#endif /* __ASM_DEBUG_LL__ */
diff --git a/arch/riscv/mach-erizo/Makefile b/arch/riscv/mach-erizo/Makefile
deleted file mode 100644
index d9c51e74c379..000000000000
--- a/arch/riscv/mach-erizo/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-# just to build a built-in.o. Otherwise compilation fails when no o-files is
-# created.
-obj- += dummy.o
diff --git a/common/Kconfig b/common/Kconfig
index b10fb45b722d..6d7a1c6b0494 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -1342,6 +1342,11 @@ config DEBUG_RPI3_MINI_UART
 	help
 	  Say Y here if you want low-level debugging support on
 	  RaspberryPi 3 board mini UART.
+
+config DEBUG_ERIZO
+	bool "Erizo ns16550 port"
+	depends on SOC_ERIZO
+
 endchoice
 
 config DEBUG_IMX_UART_PORT
-- 
2.29.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 07/12] RISC-V: add SBI based cpuinfo
  2021-04-27 20:22 [PATCH 01/12] clk: add SiFive PRCI clock controller support Ahmad Fatoum
                   ` (4 preceding siblings ...)
  2021-04-27 20:23 ` [PATCH 06/12] RISC-V: erizo: drop mach-erizo directory Ahmad Fatoum
@ 2021-04-27 20:23 ` Ahmad Fatoum
  2021-04-27 20:23 ` [PATCH 08/12] gpio: gpio-generic-platform: remove unused non-DT support Ahmad Fatoum
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Ahmad Fatoum @ 2021-04-27 20:23 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum, rcz

SBI appeared to be especially useful to implement a generic console
driver. However, SBI v0.2 removes these services without substitute.

We might find other use for it later, but for now, add the bare minimum
of querying the version of the running SBI implementation.

The cpuinfo command is intentionally kept generic. It can later be
extended to support CONFIG_RISCV_M_MODE as well.

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
 arch/riscv/include/asm/sbi.h | 32 +++++++++++++++----
 arch/riscv/lib/Makefile      |  2 ++
 arch/riscv/lib/cpuinfo.c     | 45 ++++++++++++++++++++++++++
 arch/riscv/lib/sbi.c         | 62 ++++++++++++++++++++++++++++++++++++
 commands/Kconfig             |  7 ++++
 5 files changed, 142 insertions(+), 6 deletions(-)
 create mode 100644 arch/riscv/lib/cpuinfo.c
 create mode 100644 arch/riscv/lib/sbi.c

diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h
index 99895d9c3bdd..ab1fc9a128e5 100644
--- a/arch/riscv/include/asm/sbi.h
+++ b/arch/riscv/include/asm/sbi.h
@@ -89,11 +89,32 @@ struct sbiret {
 	long value;
 };
 
-void sbi_init(void);
-struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,
-			unsigned long arg1, unsigned long arg2,
-			unsigned long arg3, unsigned long arg4,
-			unsigned long arg5);
+static inline struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,
+				      unsigned long arg1, unsigned long arg2,
+				      unsigned long arg3, unsigned long arg4,
+				      unsigned long arg5)
+{
+	struct sbiret ret;
+
+	register uintptr_t a0 asm ("a0") = (uintptr_t)(arg0);
+	register uintptr_t a1 asm ("a1") = (uintptr_t)(arg1);
+	register uintptr_t a2 asm ("a2") = (uintptr_t)(arg2);
+	register uintptr_t a3 asm ("a3") = (uintptr_t)(arg3);
+	register uintptr_t a4 asm ("a4") = (uintptr_t)(arg4);
+	register uintptr_t a5 asm ("a5") = (uintptr_t)(arg5);
+	register uintptr_t a6 asm ("a6") = (uintptr_t)(fid);
+	register uintptr_t a7 asm ("a7") = (uintptr_t)(ext);
+	asm volatile ("ecall"
+		      : "+r" (a0), "+r" (a1)
+		      : "r" (a2), "r" (a3), "r" (a4), "r" (a5), "r" (a6), "r" (a7)
+		      : "memory");
+	ret.error = a0;
+	ret.value = a1;
+
+	return ret;
+}
+
+long __sbi_base_ecall(int fid);
 
 void sbi_console_putchar(int ch);
 int sbi_console_getchar(void);
@@ -148,6 +169,5 @@ static inline unsigned long sbi_minor_version(void)
 int sbi_err_map_linux_errno(int err);
 #else /* CONFIG_RISCV_SBI */
 static inline int sbi_remote_fence_i(const unsigned long *hart_mask) { return -1; }
-static inline void sbi_init(void) {}
 #endif /* CONFIG_RISCV_SBI */
 #endif /* _ASM_RISCV_SBI_H */
diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile
index a4eaa1005d44..49750d576ae1 100644
--- a/arch/riscv/lib/Makefile
+++ b/arch/riscv/lib/Makefile
@@ -6,3 +6,5 @@ obj-y += dtb.o
 obj-pbl-y += sections.o setupc.o reloc.o sections.o runtime-offset.o
 obj-$(CONFIG_HAS_ARCH_SJLJ) += setjmp.o longjmp.o
 obj-$(CONFIG_RISCV_OPTIMZED_STRING_FUNCTIONS) += memcpy.o memset.o memmove.o
+obj-$(CONFIG_RISCV_SBI) += sbi.o
+obj-$(CONFIG_CMD_RISCV_CPUINFO) += cpuinfo.o
diff --git a/arch/riscv/lib/cpuinfo.c b/arch/riscv/lib/cpuinfo.c
new file mode 100644
index 000000000000..21b99a990a1a
--- /dev/null
+++ b/arch/riscv/lib/cpuinfo.c
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <common.h>
+#include <command.h>
+#include <asm/sbi.h>
+
+static const char *implementations[] = {
+	[0] = "\"Berkeley Boot Loader (BBL)\" ",
+	[1] = "\"OpenSBI\" ",
+	[2] = "\"Xvisor\" ",
+	[3] = "\"KVM\" ",
+	[4] = "\"RustSBI\" ",
+	[5] = "\"Diosix\" ",
+};
+
+static int do_cpuinfo(int argc, char *argv[])
+{
+	const char *implementation = "";
+	unsigned long impid;
+
+	printf("SBI specification v%lu.%lu detected\n",
+	       sbi_major_version(), sbi_minor_version());
+
+	if (sbi_spec_is_0_1())
+		return 0;
+
+	impid = __sbi_base_ecall(SBI_EXT_BASE_GET_IMP_ID);
+	if (impid < ARRAY_SIZE(implementations))
+		implementation = implementations[impid];
+
+	printf("SBI implementation ID=0x%lx %sVersion=0x%lx\n",
+	       impid, implementation, __sbi_base_ecall(SBI_EXT_BASE_GET_IMP_VERSION));
+
+	printf("SBI Machine VENDORID=0x%lx ARCHID=0x%lx MIMPID=0x%lx\n",
+	       __sbi_base_ecall(SBI_EXT_BASE_GET_MVENDORID),
+	       __sbi_base_ecall(SBI_EXT_BASE_GET_MARCHID),
+	       __sbi_base_ecall(SBI_EXT_BASE_GET_MIMPID));
+
+	return 0;
+}
+
+BAREBOX_CMD_START(cpuinfo)
+	.cmd            = do_cpuinfo,
+BAREBOX_CMD_DESC("show CPU information")
+BAREBOX_CMD_GROUP(CMD_GRP_INFO)
+	BAREBOX_CMD_END
diff --git a/arch/riscv/lib/sbi.c b/arch/riscv/lib/sbi.c
new file mode 100644
index 000000000000..973c9d9d0f1e
--- /dev/null
+++ b/arch/riscv/lib/sbi.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SBI initialilization and all extension implementation.
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ */
+
+#include <asm/sbi.h>
+#include <linux/export.h>
+#include <errno.h>
+#include <init.h>
+
+/* default SBI version is 0.1 */
+unsigned long sbi_spec_version = SBI_SPEC_VERSION_DEFAULT;
+EXPORT_SYMBOL(sbi_spec_version);
+
+int sbi_err_map_linux_errno(int err)
+{
+	switch (err) {
+	case SBI_SUCCESS:
+		return 0;
+	case SBI_ERR_DENIED:
+		return -EPERM;
+	case SBI_ERR_INVALID_PARAM:
+		return -EINVAL;
+	case SBI_ERR_INVALID_ADDRESS:
+		return -EFAULT;
+	case SBI_ERR_NOT_SUPPORTED:
+	case SBI_ERR_FAILURE:
+	default:
+		return -ENOTSUPP;
+	};
+}
+EXPORT_SYMBOL(sbi_err_map_linux_errno);
+
+long __sbi_base_ecall(int fid)
+{
+	struct sbiret ret;
+
+	ret = sbi_ecall(SBI_EXT_BASE, fid, 0, 0, 0, 0, 0, 0);
+	if (!ret.error)
+		return ret.value;
+	else
+		return sbi_err_map_linux_errno(ret.error);
+}
+
+static inline long sbi_get_spec_version(void)
+{
+	return __sbi_base_ecall(SBI_EXT_BASE_GET_SPEC_VERSION);
+}
+
+static int sbi_init(void)
+{
+	int ret;
+
+	ret = sbi_get_spec_version();
+	if (ret > 0)
+		sbi_spec_version = ret;
+	return 0;
+
+}
+core_initcall(sbi_init);
diff --git a/commands/Kconfig b/commands/Kconfig
index b3937fdd8df8..5ae3cb3dd145 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -44,6 +44,13 @@ config CMD_ARM_CPUINFO
 	  D-cache: 8192 bytes (linelen = 8)
 	  Control register: M C W P D L I V RR DT IT U XP
 
+config CMD_RISCV_CPUINFO
+	bool "cpuinfo command"
+	default y
+	depends on RISCV_SBI
+	help
+	  Show SBI info about RISC-V CPU
+
 config CMD_DEVINFO
 	tristate
 	default y
-- 
2.29.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 08/12] gpio: gpio-generic-platform: remove unused non-DT support
  2021-04-27 20:22 [PATCH 01/12] clk: add SiFive PRCI clock controller support Ahmad Fatoum
                   ` (5 preceding siblings ...)
  2021-04-27 20:23 ` [PATCH 07/12] RISC-V: add SBI based cpuinfo Ahmad Fatoum
@ 2021-04-27 20:23 ` Ahmad Fatoum
  2021-04-27 20:23 ` [PATCH 09/12] gpio: generic: sync with upstream Linux gpio-mmio driver Ahmad Fatoum
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Ahmad Fatoum @ 2021-04-27 20:23 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum, rcz

We have nothing in-tree matching against either "basic-mmio-gpio"
or "basic-mmio-gpio-be" and none should be added, because new platforms
should probe from device tree. Remove the unused the non-DT support.

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
 drivers/gpio/gpio-generic.c | 22 +---------------------
 1 file changed, 1 insertion(+), 21 deletions(-)

diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c
index 8259b799f9a7..f381ddbf4e79 100644
--- a/drivers/gpio/gpio-generic.c
+++ b/drivers/gpio/gpio-generic.c
@@ -337,7 +337,6 @@ static int bgpio_dev_probe(struct device_d *dev)
 	unsigned long flags = 0;
 	int err;
 	struct bgpio_chip *bgc;
-	struct bgpio_pdata *pdata = dev->platform_data;
 
 	r = dev_get_resource_by_name(dev, IORESOURCE_MEM, "dat");
 	if (IS_ERR(r))
@@ -373,12 +372,6 @@ static int bgpio_dev_probe(struct device_d *dev)
 	if (err)
 		return err;
 
-	if (pdata) {
-		bgc->gc.base = pdata->base;
-		if (pdata->ngpio > 0)
-			bgc->gc.ngpio = pdata->ngpio;
-	}
-
 	dev->priv = bgc;
 
 	return gpiochip_add(&bgc->gc);
@@ -391,18 +384,6 @@ static void bgpio_dev_remove(struct device_d *dev)
 	bgpio_remove(bgc);
 }
 
-static struct platform_device_id bgpio_id_table[] = {
-	{
-		.name		= "basic-mmio-gpio",
-		.driver_data	= 0,
-	},
-	{
-		.name		= "basic-mmio-gpio-be",
-		.driver_data	= BGPIOF_BIG_ENDIAN,
-	},
-	{ }
-};
-
 static struct of_device_id __maybe_unused bgpio_of_match[] = {
 	{
 		.compatible = "wd,mbl-gpio",
@@ -413,8 +394,7 @@ static struct of_device_id __maybe_unused bgpio_of_match[] = {
 
 static struct driver_d bgpio_driver = {
 	.name		= "basic-mmio-gpio",
-	.id_table	= bgpio_id_table,
-	.of_compatible	= DRV_OF_COMPAT(bgpio_of_match),
+	.of_compatible	= bgpio_of_match,
 	.probe		= bgpio_dev_probe,
 	.remove		= bgpio_dev_remove,
 };
-- 
2.29.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 09/12] gpio: generic: sync with upstream Linux gpio-mmio driver
  2021-04-27 20:22 [PATCH 01/12] clk: add SiFive PRCI clock controller support Ahmad Fatoum
                   ` (6 preceding siblings ...)
  2021-04-27 20:23 ` [PATCH 08/12] gpio: gpio-generic-platform: remove unused non-DT support Ahmad Fatoum
@ 2021-04-27 20:23 ` Ahmad Fatoum
  2021-05-06 23:45   ` Antony Pavlov
  2021-04-27 20:23 ` [PATCH 10/12] gpio: add SiFive GPIO controller support Ahmad Fatoum
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 20+ messages in thread
From: Ahmad Fatoum @ 2021-04-27 20:23 UTC (permalink / raw)
  To: barebox; +Cc: Steffen Trumtrar, Ahmad Fatoum, rcz

The gpio-mmio driver in Linux v5.12 has evolved quite a bit since the
last sync. It now supports big endian byte order, 64-bit registers as
well as controllers that have both a dirin and dirout register.

The latter is particularly interesting, because it's required for the
SiFive GPIO controller ported in a later patch.

This commit also touches gpio-mpc8xxx used on the LS1046A.
Because bit and byte endianness can now be configured separately,
the driver needs adjustment. We don't seem to support any boards
that have the peripheral as little-endian, but this is fixed by this
commit. Comparing other bgpio_init users with Linux shows no need for
further fixups.

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
Cc: Steffen Trumtrar <s.trumtrar@pengutronix.de>
Cc: Antony Pavlov <antonynpavlov@gmail.com>

Would be great if you could test this.
---
 drivers/gpio/gpio-generic.c     | 431 ++++++++++++++++++++++++--------
 drivers/gpio/gpio-mpc8xxx.c     |   6 +-
 include/io.h                    |   2 +
 include/linux/basic_mmio_gpio.h |  14 +-
 4 files changed, 337 insertions(+), 116 deletions(-)

diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c
index f381ddbf4e79..713085267a15 100644
--- a/drivers/gpio/gpio-generic.c
+++ b/drivers/gpio/gpio-generic.c
@@ -7,63 +7,117 @@
  */
 
 #include <init.h>
-#include <malloc.h>
 #include <linux/err.h>
+#include <linux/bug.h>
+#include <linux/kernel.h>
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <errno.h>
 #include <linux/log2.h>
-#include <linux/err.h>
+#include <linux/ioport.h>
+#include <io.h>
 #include <linux/basic_mmio_gpio.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <driver.h>
+#include <of.h>
+#include <of_device.h>
 
-static void bgpio_write8(void __iomem *reg, unsigned int data)
+static void bgpio_write8(void __iomem *reg, unsigned long data)
 {
 	writeb(data, reg);
 }
 
-static unsigned int bgpio_read8(void __iomem *reg)
+static unsigned long bgpio_read8(void __iomem *reg)
 {
 	return readb(reg);
 }
 
-static void bgpio_write16(void __iomem *reg, unsigned int data)
+static void bgpio_write16(void __iomem *reg, unsigned long data)
 {
 	writew(data, reg);
 }
 
-static unsigned int bgpio_read16(void __iomem *reg)
+static unsigned long bgpio_read16(void __iomem *reg)
 {
 	return readw(reg);
 }
 
-static void bgpio_write32(void __iomem *reg, unsigned int data)
+static void bgpio_write32(void __iomem *reg, unsigned long data)
 {
 	writel(data, reg);
 }
 
-static unsigned int bgpio_read32(void __iomem *reg)
+static unsigned long bgpio_read32(void __iomem *reg)
 {
 	return readl(reg);
 }
 
-static unsigned int bgpio_pin2mask(struct bgpio_chip *bgc, unsigned int pin)
+#if BITS_PER_LONG >= 64
+static void bgpio_write64(void __iomem *reg, unsigned long data)
+{
+	writeq(data, reg);
+}
+
+static unsigned long bgpio_read64(void __iomem *reg)
+{
+	return readq(reg);
+}
+#endif /* BITS_PER_LONG >= 64 */
+
+static void bgpio_write16be(void __iomem *reg, unsigned long data)
+{
+	iowrite16be(data, reg);
+}
+
+static unsigned long bgpio_read16be(void __iomem *reg)
+{
+	return ioread16be(reg);
+}
+
+static void bgpio_write32be(void __iomem *reg, unsigned long data)
+{
+	iowrite32be(data, reg);
+}
+
+static unsigned long bgpio_read32be(void __iomem *reg)
+{
+	return ioread32be(reg);
+}
+
+static unsigned long bgpio_line2mask(struct bgpio_chip *bgc, unsigned int line)
 {
-	return 1 << pin;
+	if (bgc->be_bits)
+		return BIT(bgc->bits - 1 - line);
+	return BIT(line);
 }
 
-static unsigned int bgpio_pin2mask_be(struct bgpio_chip *bgc, unsigned int pin)
+static int bgpio_get_set(struct gpio_chip *gc, unsigned int gpio)
 {
-	return 1 << (bgc->bits - 1 - pin);
+	struct bgpio_chip *bgc = to_bgpio_chip(gc);
+	unsigned long pinmask = bgpio_line2mask(bgc, gpio);
+	bool dir = !!(bgc->dir & pinmask);
+
+	if (dir)
+		return !!(bgc->read_reg(bgc->reg_set) & pinmask);
+	else
+		return !!(bgc->read_reg(bgc->reg_dat) & pinmask);
 }
 
 static int bgpio_get(struct gpio_chip *gc, unsigned int gpio)
 {
 	struct bgpio_chip *bgc = to_bgpio_chip(gc);
+	return !!(bgc->read_reg(bgc->reg_dat) & bgpio_line2mask(bgc, gpio));
+}
 
-	return !!(bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio));
+static void bgpio_set_none(struct gpio_chip *gc, unsigned int gpio, int val)
+{
 }
 
 static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
 {
 	struct bgpio_chip *bgc = to_bgpio_chip(gc);
-	unsigned int mask = bgc->pin2mask(bgc, gpio);
+	unsigned long mask = bgpio_line2mask(bgc, gpio);
 
 	if (val)
 		bgc->data |= mask;
@@ -77,7 +131,7 @@ static void bgpio_set_with_clear(struct gpio_chip *gc, unsigned int gpio,
 				 int val)
 {
 	struct bgpio_chip *bgc = to_bgpio_chip(gc);
-	unsigned int mask = bgc->pin2mask(bgc, gpio);
+	unsigned long mask = bgpio_line2mask(bgc, gpio);
 
 	if (val)
 		bgc->write_reg(bgc->reg_set, mask);
@@ -88,7 +142,7 @@ static void bgpio_set_with_clear(struct gpio_chip *gc, unsigned int gpio,
 static void bgpio_set_set(struct gpio_chip *gc, unsigned int gpio, int val)
 {
 	struct bgpio_chip *bgc = to_bgpio_chip(gc);
-	unsigned int mask = bgc->pin2mask(bgc, gpio);
+	unsigned long mask = bgpio_line2mask(bgc, gpio);
 
 	if (val)
 		bgc->data |= mask;
@@ -103,6 +157,12 @@ static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio)
 	return 0;
 }
 
+static int bgpio_dir_out_err(struct gpio_chip *gc, unsigned int gpio,
+				int val)
+{
+	return -EINVAL;
+}
+
 static int bgpio_simple_dir_out(struct gpio_chip *gc, unsigned int gpio,
 				int val)
 {
@@ -115,69 +175,115 @@ static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
 {
 	struct bgpio_chip *bgc = to_bgpio_chip(gc);
 
-	bgc->dir &= ~bgc->pin2mask(bgc, gpio);
-	bgc->write_reg(bgc->reg_dir, bgc->dir);
+	bgc->dir &= ~bgpio_line2mask(bgc, gpio);
+
+	if (bgc->reg_dir_in)
+		bgc->write_reg(bgc->reg_dir_in, ~bgc->dir);
+	if (bgc->reg_dir_out)
+		bgc->write_reg(bgc->reg_dir_out, bgc->dir);
 
 	return 0;
 }
 
-static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio)
 {
 	struct bgpio_chip *bgc = to_bgpio_chip(gc);
 
-	gc->ops->set(gc, gpio, val);
+	/* Return 0 if output, 1 if input */
+	if (bgc->dir_unreadable) {
+		if (bgc->dir & bgpio_line2mask(bgc, gpio))
+			return GPIOF_DIR_OUT;
+		return GPIOF_DIR_IN;
+	}
 
-	bgc->dir |= bgc->pin2mask(bgc, gpio);
-	bgc->write_reg(bgc->reg_dir, bgc->dir);
+	if (bgc->reg_dir_out) {
+		if (bgc->read_reg(bgc->reg_dir_out) & bgpio_line2mask(bgc, gpio))
+			return GPIOF_DIR_OUT;
+		return GPIOF_DIR_IN;
+	}
 
-	return 0;
+	if (bgc->reg_dir_in)
+		if (!(bgc->read_reg(bgc->reg_dir_in) & bgpio_line2mask(bgc, gpio)))
+			return GPIOF_DIR_OUT;
+
+	return GPIOF_DIR_IN;
 }
 
-static int bgpio_dir_in_inv(struct gpio_chip *gc, unsigned int gpio)
+static void bgpio_dir_out(struct bgpio_chip *bgc, unsigned int gpio, int val)
 {
-	struct bgpio_chip *bgc = to_bgpio_chip(gc);
-
-	bgc->dir |= bgc->pin2mask(bgc, gpio);
-	bgc->write_reg(bgc->reg_dir, bgc->dir);
+	bgc->dir |= bgpio_line2mask(bgc, gpio);
 
-	return 0;
+	if (bgc->reg_dir_in)
+		bgc->write_reg(bgc->reg_dir_in, ~bgc->dir);
+	if (bgc->reg_dir_out)
+		bgc->write_reg(bgc->reg_dir_out, bgc->dir);
 }
 
-static int bgpio_dir_out_inv(struct gpio_chip *gc, unsigned int gpio, int val)
+static int bgpio_dir_out_dir_first(struct gpio_chip *gc, unsigned int gpio,
+				   int val)
 {
 	struct bgpio_chip *bgc = to_bgpio_chip(gc);
 
+	bgpio_dir_out(bgc, gpio, val);
 	gc->ops->set(gc, gpio, val);
+	return 0;
+}
 
-	bgc->dir &= ~bgc->pin2mask(bgc, gpio);
-	bgc->write_reg(bgc->reg_dir, bgc->dir);
+static int bgpio_dir_out_val_first(struct gpio_chip *gc, unsigned int gpio,
+				   int val)
+{
+	struct bgpio_chip *bgc = to_bgpio_chip(gc);
 
+	gc->ops->set(gc, gpio, val);
+	bgpio_dir_out(bgc, gpio, val);
 	return 0;
 }
 
-static int bgpio_setup_accessors(struct device_d *dev, struct bgpio_chip *bgc,
-				 bool be)
+static int bgpio_setup_accessors(struct device_d *dev,
+				 struct bgpio_chip *bgc,
+				 bool byte_be)
 {
+
 	switch (bgc->bits) {
 	case 8:
 		bgc->read_reg	= bgpio_read8;
 		bgc->write_reg	= bgpio_write8;
 		break;
 	case 16:
-		bgc->read_reg	= bgpio_read16;
-		bgc->write_reg	= bgpio_write16;
+		if (byte_be) {
+			bgc->read_reg	= bgpio_read16be;
+			bgc->write_reg	= bgpio_write16be;
+		} else {
+			bgc->read_reg	= bgpio_read16;
+			bgc->write_reg	= bgpio_write16;
+		}
 		break;
 	case 32:
-		bgc->read_reg	= bgpio_read32;
-		bgc->write_reg	= bgpio_write32;
+		if (byte_be) {
+			bgc->read_reg	= bgpio_read32be;
+			bgc->write_reg	= bgpio_write32be;
+		} else {
+			bgc->read_reg	= bgpio_read32;
+			bgc->write_reg	= bgpio_write32;
+		}
+		break;
+#if BITS_PER_LONG >= 64
+	case 64:
+		if (byte_be) {
+			dev_err(dev,
+				"64 bit big endian byte order unsupported\n");
+			return -EINVAL;
+		} else {
+			bgc->read_reg	= bgpio_read64;
+			bgc->write_reg	= bgpio_write64;
+		}
 		break;
+#endif /* BITS_PER_LONG >= 64 */
 	default:
-		dev_err(dev, "Unsupported data width %u bits\n", bgc->bits);
+		dev_err(dev, "unsupported data width %u bits\n", bgc->bits);
 		return -EINVAL;
 	}
 
-	bgc->pin2mask = be ? bgpio_pin2mask_be : bgpio_pin2mask;
-
 	return 0;
 }
 
@@ -188,7 +294,7 @@ static int bgpio_setup_accessors(struct device_d *dev, struct bgpio_chip *bgc,
  *	- single input/output register resource (named "dat").
  *	- set/clear pair (named "set" and "clr").
  *	- single output register resource and single input resource ("set" and
- *	  dat").
+ *	dat").
  *
  * For the single output register, this drives a 1 by setting a bit and a zero
  * by clearing a bit.  For the set clr pair, this drives a 1 by setting a bit
@@ -206,123 +312,211 @@ static int bgpio_setup_accessors(struct device_d *dev, struct bgpio_chip *bgc,
 static int bgpio_setup_io(struct bgpio_chip *bgc,
 			  void __iomem *dat,
 			  void __iomem *set,
-			  void __iomem *clr)
+			  void __iomem *clr,
+			  unsigned long flags)
 {
-	if (!dat)
-		return -EINVAL;
+	struct gpio_ops *ops = bgc->gc.ops;
 
 	bgc->reg_dat = dat;
+	if (!bgc->reg_dat)
+		return -EINVAL;
 
 	if (set && clr) {
 		bgc->reg_set = set;
 		bgc->reg_clr = clr;
-		bgc->gc.ops->set = bgpio_set_with_clear;
+		ops->set = bgpio_set_with_clear;
 	} else if (set && !clr) {
 		bgc->reg_set = set;
-		bgc->gc.ops->set = bgpio_set_set;
-	} else
-		bgc->gc.ops->set = bgpio_set;
+		ops->set = bgpio_set_set;
+	} else if (flags & BGPIOF_NO_OUTPUT) {
+		ops->set = bgpio_set_none;
+	} else {
+		ops->set = bgpio_set;
+	}
 
-	bgc->gc.ops->get = bgpio_get;
+	if (!(flags & BGPIOF_UNREADABLE_REG_SET) && (flags & BGPIOF_READ_OUTPUT_REG_SET))
+		ops->get = bgpio_get_set;
+	else
+		ops->get = bgpio_get;
 
 	return 0;
 }
 
 static int bgpio_setup_direction(struct bgpio_chip *bgc,
 				 void __iomem *dirout,
-				 void __iomem *dirin)
+				 void __iomem *dirin,
+				 unsigned long flags)
 {
-	if (dirout && dirin)
-		return -EINVAL;
-
-	if (dirout) {
-		bgc->reg_dir = dirout;
-		bgc->gc.ops->direction_output = bgpio_dir_out;
-		bgc->gc.ops->direction_input = bgpio_dir_in;
-	} else if (dirin) {
-		bgc->reg_dir = dirin;
-		bgc->gc.ops->direction_output = bgpio_dir_out_inv;
-		bgc->gc.ops->direction_input = bgpio_dir_in_inv;
+	struct gpio_ops *ops = bgc->gc.ops;
+
+	if (dirout || dirin) {
+		bgc->reg_dir_out = dirout;
+		bgc->reg_dir_in = dirin;
+		if (flags & BGPIOF_NO_SET_ON_INPUT)
+			ops->direction_output = bgpio_dir_out_dir_first;
+		else
+			ops->direction_output = bgpio_dir_out_val_first;
+		ops->direction_input = bgpio_dir_in;
+		ops->get_direction = bgpio_get_dir;
 	} else {
-		bgc->gc.ops->direction_output = bgpio_simple_dir_out;
-		bgc->gc.ops->direction_input = bgpio_simple_dir_in;
+		if (flags & BGPIOF_NO_OUTPUT)
+			ops->direction_output = bgpio_dir_out_err;
+		else
+			ops->direction_output = bgpio_simple_dir_out;
+		ops->direction_input = bgpio_simple_dir_in;
 	}
 
 	return 0;
 }
 
+static int bgpio_request(struct gpio_chip *chip, unsigned gpio_pin)
+{
+	if (gpio_pin < chip->ngpio)
+		return 0;
+
+	return -EINVAL;
+}
+
+/**
+ * bgpio_init() - Initialize generic GPIO accessor functions
+ * @bgc: the GPIO chip to set up
+ * @dev: the parent device of the new GPIO chip (compulsory)
+ * @sz: the size (width) of the MMIO registers in bytes, typically 1, 2 or 4
+ * @dat: MMIO address for the register to READ the value of the GPIO lines, it
+ *	is expected that a 1 in the corresponding bit in this register means the
+ *	line is asserted
+ * @set: MMIO address for the register to SET the value of the GPIO lines, it is
+ *	expected that we write the line with 1 in this register to drive the GPIO line
+ *	high.
+ * @clr: MMIO address for the register to CLEAR the value of the GPIO lines, it is
+ *	expected that we write the line with 1 in this register to drive the GPIO line
+ *	low. It is allowed to leave this address as NULL, in that case the SET register
+ *	will be assumed to also clear the GPIO lines, by actively writing the line
+ *	with 0.
+ * @dirout: MMIO address for the register to set the line as OUTPUT. It is assumed
+ *	that setting a line to 1 in this register will turn that line into an
+ *	output line. Conversely, setting the line to 0 will turn that line into
+ *	an input.
+ * @dirin: MMIO address for the register to set this line as INPUT. It is assumed
+ *	that setting a line to 1 in this register will turn that line into an
+ *	input line. Conversely, setting the line to 0 will turn that line into
+ *	an output.
+ * @flags: Different flags that will affect the behaviour of the device, such as
+ *	endianness etc.
+ */
 int bgpio_init(struct bgpio_chip *bgc, struct device_d *dev,
 	       unsigned int sz, void __iomem *dat, void __iomem *set,
 	       void __iomem *clr, void __iomem *dirout, void __iomem *dirin,
 	       unsigned long flags)
 {
+	struct gpio_ops *ops = &bgc->ops;
 	int ret;
 
-	if ((sz > 4) || !is_power_of_2(sz))
+	if (!is_power_of_2(sz))
 		return -EINVAL;
 
 	bgc->bits = sz * 8;
-	bgc->gc.ngpio = bgc->bits;
+	if (bgc->bits > BITS_PER_LONG)
+		return -EINVAL;
+
 	bgc->gc.base = -1;
+	bgc->gc.ngpio = bgc->bits;
 	bgc->gc.dev = dev;
-	bgc->gc.ops = &bgc->ops;
+	bgc->gc.ops = ops;
+	ops->request = bgpio_request;
+	bgc->be_bits = !!(flags & BGPIOF_BIG_ENDIAN);
 
-	ret = bgpio_setup_io(bgc, dat, set, clr);
+	ret = bgpio_setup_io(bgc, dat, set, clr, flags);
 	if (ret)
 		return ret;
 
-	ret = bgpio_setup_accessors(dev, bgc, flags & BGPIOF_BIG_ENDIAN);
+	ret = bgpio_setup_accessors(dev, bgc, flags & BGPIOF_BIG_ENDIAN_BYTE_ORDER);
 	if (ret)
 		return ret;
 
-	ret = bgpio_setup_direction(bgc, dirout, dirin);
+	ret = bgpio_setup_direction(bgc, dirout, dirin, flags);
 	if (ret)
 		return ret;
 
 	bgc->data = bgc->read_reg(bgc->reg_dat);
-
-	if (bgc->gc.ops->set == bgpio_set_set && !(flags &
-	    BGPIOF_UNREADABLE_REG_SET))
+	if (ops->set == bgpio_set_set &&
+			!(flags & BGPIOF_UNREADABLE_REG_SET))
 		bgc->data = bgc->read_reg(bgc->reg_set);
 
-	if (bgc->reg_dir && !(flags & BGPIOF_UNREADABLE_REG_DIR))
-		bgc->dir = bgc->read_reg(bgc->reg_dir);
+	if (flags & BGPIOF_UNREADABLE_REG_DIR)
+		bgc->dir_unreadable = true;
+
+	/*
+	 * Inspect hardware to find initial direction setting.
+	 */
+	if ((bgc->reg_dir_out || bgc->reg_dir_in) &&
+	    !(flags & BGPIOF_UNREADABLE_REG_DIR)) {
+		if (bgc->reg_dir_out)
+			bgc->dir = bgc->read_reg(bgc->reg_dir_out);
+		else if (bgc->reg_dir_in)
+			bgc->dir = ~bgc->read_reg(bgc->reg_dir_in);
+		/*
+		 * If we have two direction registers, synchronise
+		 * input setting to output setting, the library
+		 * can not handle a line being input and output at
+		 * the same time.
+		 */
+		if (bgc->reg_dir_out && bgc->reg_dir_in)
+			bgc->write_reg(bgc->reg_dir_in, ~bgc->dir);
+	}
 
 	return ret;
 }
+EXPORT_SYMBOL_GPL(bgpio_init);
 
 void bgpio_remove(struct bgpio_chip *bgc)
 {
 	gpiochip_remove(&bgc->gc);
 	free(bgc);
 }
+EXPORT_SYMBOL_GPL(bgpio_remove);
 
 #ifdef CONFIG_GPIO_GENERIC_PLATFORM
 
-static void __iomem *bgpio_map(struct device_d *dev, const char *name,
-			       resource_size_t sane_sz, int *err)
+static void __iomem *bgpio_map(struct device_d *dev,
+			       const char *name,
+			       resource_size_t sane_sz)
 {
 	struct resource *r;
-	struct resource *ret;
-
-	*err = 0;
+	resource_size_t sz;
 
-	r = dev_get_resource_by_name(dev, IORESOURCE_MEM, name);
+	r = dev_request_mem_resource_by_name(dev, name);
 	if (IS_ERR(r))
 		return NULL;
 
-	if (resource_size(r) != sane_sz) {
-		*err = -EINVAL;
-		return NULL;
-	}
+	sz = resource_size(r);
+	if (sz != sane_sz)
+		return IOMEM_ERR_PTR(-EINVAL);
+
+	return IOMEM(r->start);
+}
+
+static const struct of_device_id bgpio_of_match[];
 
-	ret = request_iomem_region(dev_name(dev), r->start, r->end);
-	if (IS_ERR(ret)) {
-		*err = PTR_ERR(ret);
+static struct bgpio_pdata *bgpio_parse_dt(struct device_d *dev,
+					  unsigned long *flags)
+{
+	struct bgpio_pdata *pdata;
+
+	if (!of_match_device(bgpio_of_match, dev))
 		return NULL;
-	}
 
-	return IOMEM(ret->start);
+	pdata = xzalloc(sizeof(struct bgpio_pdata));
+
+	pdata->base = -1;
+
+	if (of_device_is_big_endian(dev->device_node))
+		*flags |= BGPIOF_BIG_ENDIAN_BYTE_ORDER;
+
+	if (of_property_read_bool(dev->device_node, "no-output"))
+		*flags |= BGPIOF_NO_OUTPUT;
+
+	return pdata;
 }
 
 static int bgpio_dev_probe(struct device_d *dev)
@@ -337,34 +531,37 @@ static int bgpio_dev_probe(struct device_d *dev)
 	unsigned long flags = 0;
 	int err;
 	struct bgpio_chip *bgc;
+	struct bgpio_pdata *pdata;
 
-	r = dev_get_resource_by_name(dev, IORESOURCE_MEM, "dat");
-	if (IS_ERR(r))
-		return PTR_ERR(r);
+	pdata = bgpio_parse_dt(dev, &flags);
+	if (IS_ERR(pdata))
+		return PTR_ERR(pdata);
+
+	r = dev_request_mem_resource_by_name(dev, "dat");
+	if (!r)
+		return -EINVAL;
 
 	sz = resource_size(r);
 
-	dat = bgpio_map(dev, "dat", sz, &err);
-	if (!dat)
-		return err ? err : -EINVAL;
+	dat = bgpio_map(dev, "dat", sz);
+	if (IS_ERR(dat))
+		return PTR_ERR(dat);
 
-	set = bgpio_map(dev, "set", sz, &err);
-	if (err)
-		return err;
+	set = bgpio_map(dev, "set", sz);
+	if (IS_ERR(set))
+		return PTR_ERR(set);
 
-	clr = bgpio_map(dev, "clr", sz, &err);
-	if (err)
-		return err;
-
-	dirout = bgpio_map(dev, "dirout", sz, &err);
-	if (err)
-		return err;
+	clr = bgpio_map(dev, "clr", sz);
+	if (IS_ERR(clr))
+		return PTR_ERR(clr);
 
-	dirin = bgpio_map(dev, "dirin", sz, &err);
-	if (err)
-		return err;
+	dirout = bgpio_map(dev, "dirout", sz);
+	if (IS_ERR(dirout))
+		return PTR_ERR(dirout);
 
-	dev_get_drvdata(dev, (const void **)&flags);
+	dirin = bgpio_map(dev, "dirin", sz);
+	if (IS_ERR(dirin))
+		return PTR_ERR(dirin);
 
 	bgc = xzalloc(sizeof(struct bgpio_chip));
 
@@ -372,6 +569,12 @@ static int bgpio_dev_probe(struct device_d *dev)
 	if (err)
 		return err;
 
+	bgc->gc.base = pdata->base;
+	bgc->gc.dev = dev;
+	bgc->gc.ops = &bgc->ops;
+	if (pdata->ngpio > 0)
+		bgc->gc.ngpio = pdata->ngpio;
+
 	dev->priv = bgc;
 
 	return gpiochip_add(&bgc->gc);
@@ -384,9 +587,15 @@ static void bgpio_dev_remove(struct device_d *dev)
 	bgpio_remove(bgc);
 }
 
-static struct of_device_id __maybe_unused bgpio_of_match[] = {
+static const struct of_device_id bgpio_of_match[] = {
 	{
 		.compatible = "wd,mbl-gpio",
+	},
+	{
+		.compatible = "brcm,bcm6345-gpio"
+	},
+	{
+		.compatible = "ni,169445-nand-gpio"
 	}, {
 		/* sentinel */
 	}
diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c
index 1ef459684d64..d48a8aa7fbb0 100644
--- a/drivers/gpio/gpio-mpc8xxx.c
+++ b/drivers/gpio/gpio-mpc8xxx.c
@@ -65,7 +65,8 @@ static int mpc8xxx_probe(struct device_d *dev)
 		ret = bgpio_init(bgc, dev, 4,
 				 mpc8xxx_gc->regs + GPIO_DAT,
 				 NULL, NULL,
-				 mpc8xxx_gc->regs + GPIO_DIR, NULL, 0);
+				 mpc8xxx_gc->regs + GPIO_DIR, NULL,
+				 BGPIOF_BIG_ENDIAN);
 		if (ret)
 			goto err;
 		dev_dbg(dev, "GPIO registers are LITTLE endian\n");
@@ -74,7 +75,8 @@ static int mpc8xxx_probe(struct device_d *dev)
 				 mpc8xxx_gc->regs + GPIO_DAT,
 				 NULL, NULL,
 				 mpc8xxx_gc->regs + GPIO_DIR, NULL,
-				 BGPIOF_BIG_ENDIAN);
+				 BGPIOF_BIG_ENDIAN
+				 | BGPIOF_BIG_ENDIAN_BYTE_ORDER);
 		if (ret)
 			goto err;
 		dev_dbg(dev, "GPIO registers are BIG endian\n");
diff --git a/include/io.h b/include/io.h
index 913002072240..79d8b56c4e3f 100644
--- a/include/io.h
+++ b/include/io.h
@@ -4,4 +4,6 @@
 
 #include <asm/io.h>
 
+#define IOMEM_ERR_PTR(err) (__force void __iomem *)ERR_PTR(err)
+
 #endif /* __IO_H */
diff --git a/include/linux/basic_mmio_gpio.h b/include/linux/basic_mmio_gpio.h
index e927194b51b3..34e2f470fb07 100644
--- a/include/linux/basic_mmio_gpio.h
+++ b/include/linux/basic_mmio_gpio.h
@@ -27,13 +27,17 @@ struct bgpio_chip {
 	struct gpio_chip gc;
 	struct gpio_ops ops;
 
-	unsigned int (*read_reg)(void __iomem *reg);
-	void (*write_reg)(void __iomem *reg, unsigned int data);
+	unsigned long (*read_reg)(void __iomem *reg);
+	void (*write_reg)(void __iomem *reg, unsigned long data);
 
 	void __iomem *reg_dat;
 	void __iomem *reg_set;
 	void __iomem *reg_clr;
-	void __iomem *reg_dir;
+	void __iomem *reg_dir_out;
+	void __iomem *reg_dir_in;
+
+	bool dir_unreadable;
+	bool be_bits;
 
 	/* Number of bits (GPIOs): <register width> * 8. */
 	int bits;
@@ -65,5 +69,9 @@ void bgpio_remove(struct bgpio_chip *bgc);
 #define BGPIOF_BIG_ENDIAN		BIT(0)
 #define BGPIOF_UNREADABLE_REG_SET	BIT(1) /* reg_set is unreadable */
 #define BGPIOF_UNREADABLE_REG_DIR	BIT(2) /* reg_dir is unreadable */
+#define BGPIOF_BIG_ENDIAN_BYTE_ORDER	BIT(3)
+#define BGPIOF_READ_OUTPUT_REG_SET	BIT(4) /* reg_set stores output value */
+#define BGPIOF_NO_OUTPUT		BIT(5) /* only input */
+#define BGPIOF_NO_SET_ON_INPUT		BIT(6)
 
 #endif /* __BASIC_MMIO_GPIO_H */
-- 
2.29.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 10/12] gpio: add SiFive GPIO controller support
  2021-04-27 20:22 [PATCH 01/12] clk: add SiFive PRCI clock controller support Ahmad Fatoum
                   ` (7 preceding siblings ...)
  2021-04-27 20:23 ` [PATCH 09/12] gpio: generic: sync with upstream Linux gpio-mmio driver Ahmad Fatoum
@ 2021-04-27 20:23 ` Ahmad Fatoum
  2021-04-27 20:23 ` [PATCH 11/12] net: macb: add SiFive support Ahmad Fatoum
  2021-04-27 20:23 ` [PATCH 12/12] RISC-V: sifive: add HiFive board support Ahmad Fatoum
  10 siblings, 0 replies; 20+ messages in thread
From: Ahmad Fatoum @ 2021-04-27 20:23 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum, rcz

The SiFive GPIO controller is a straight forward generic gpio-mmio
controller. Only difference is that the number of GPIOs is described by
the number of interrupts in the device tree. Import the Linux v5.12
driver to support it.

Tested with gpio-restart on qemu-system-riscv64 -M sifive_u.

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
 drivers/gpio/Kconfig       |  7 +++
 drivers/gpio/Makefile      |  1 +
 drivers/gpio/gpio-sifive.c | 87 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 95 insertions(+)
 create mode 100644 drivers/gpio/gpio-sifive.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 261b6e666257..a8ee9e58b84e 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -164,6 +164,13 @@ config GPIO_SX150X
 	  Say Y here to build support for the Semtec Sx150x I2C GPIO
 	  expander chip.
 
+config GPIO_SIFIVE
+	bool "SiFive GPIO support"
+	depends on OF_GPIO
+	select GPIO_GENERIC
+	help
+	  Say yes here to support the GPIO device on SiFive SoCs.
+
 config GPIO_LIBFTDI1
 	bool "libftdi1 driver"
 	depends on SANDBOX
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 77dcf58f640d..25e12105d83d 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -23,3 +23,4 @@ obj-$(CONFIG_GPIO_DESIGNWARE)	+= gpio-dw.o
 obj-$(CONFIG_GPIO_SX150X)	+= gpio-sx150x.o
 obj-$(CONFIG_GPIO_VF610)	+= gpio-vf610.o
 obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o
+obj-$(CONFIG_GPIO_SIFIVE)	+= gpio-sifive.o
diff --git a/drivers/gpio/gpio-sifive.c b/drivers/gpio/gpio-sifive.c
new file mode 100644
index 000000000000..63f2c097e446
--- /dev/null
+++ b/drivers/gpio/gpio-sifive.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 SiFive
+ */
+
+#include <linux/basic_mmio_gpio.h>
+#include <printk.h>
+#include <driver.h>
+#include <errno.h>
+
+#define SIFIVE_GPIO_INPUT_VAL	0x00
+#define SIFIVE_GPIO_INPUT_EN	0x04
+#define SIFIVE_GPIO_OUTPUT_EN	0x08
+#define SIFIVE_GPIO_OUTPUT_VAL	0x0C
+#define SIFIVE_GPIO_RISE_IE	0x18
+#define SIFIVE_GPIO_FALL_IE	0x20
+#define SIFIVE_GPIO_HIGH_IE	0x28
+#define SIFIVE_GPIO_LOW_IE	0x30
+
+#define SIFIVE_GPIO_MAX		32
+
+static int __of_irq_count(struct device_node *np)
+{
+	unsigned npins = 0;
+
+	of_get_property(np, "interrupts", &npins);
+
+	return npins / sizeof(__be32);
+}
+
+static int sifive_gpio_probe(struct device_d *dev)
+{
+	struct bgpio_chip *bgc;
+	struct resource *res;
+	void __iomem *base;
+	int ret, ngpio;
+
+	bgc = xzalloc(sizeof(*bgc));
+
+	res = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(res)) {
+		dev_err(dev, "failed to request device memory\n");
+		return PTR_ERR(res);
+	}
+	base = IOMEM(res->start);
+
+	ngpio = __of_irq_count(dev->device_node);
+	if (ngpio > SIFIVE_GPIO_MAX) {
+		dev_err(dev, "Too many GPIO interrupts (max=%d)\n",
+			SIFIVE_GPIO_MAX);
+		return -ENXIO;
+	}
+
+	ret = bgpio_init(bgc, dev, 4,
+			 base + SIFIVE_GPIO_INPUT_VAL,
+			 base + SIFIVE_GPIO_OUTPUT_VAL,
+			 NULL,
+			 base + SIFIVE_GPIO_OUTPUT_EN,
+			 base + SIFIVE_GPIO_INPUT_EN,
+			 0);
+	if (ret) {
+		dev_err(dev, "unable to init generic GPIO\n");
+		return ret;
+	}
+
+	/* Disable all GPIO interrupts */
+	writel(0, base + SIFIVE_GPIO_RISE_IE);
+	writel(0, base + SIFIVE_GPIO_FALL_IE);
+	writel(0, base + SIFIVE_GPIO_HIGH_IE);
+	writel(0, base + SIFIVE_GPIO_LOW_IE);
+
+	bgc->gc.ngpio = ngpio;
+	return gpiochip_add(&bgc->gc);
+}
+
+static const struct of_device_id sifive_gpio_match[] = {
+	{ .compatible = "sifive,gpio0" },
+	{ .compatible = "sifive,fu540-c000-gpio" },
+	{ },
+};
+
+static struct driver_d sifive_gpio_driver = {
+	.name		= "sifive_gpio",
+	.of_compatible	= sifive_gpio_match,
+	.probe		= sifive_gpio_probe,
+};
+postcore_platform_driver(sifive_gpio_driver);
-- 
2.29.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 11/12] net: macb: add SiFive support
  2021-04-27 20:22 [PATCH 01/12] clk: add SiFive PRCI clock controller support Ahmad Fatoum
                   ` (8 preceding siblings ...)
  2021-04-27 20:23 ` [PATCH 10/12] gpio: add SiFive GPIO controller support Ahmad Fatoum
@ 2021-04-27 20:23 ` Ahmad Fatoum
  2021-05-17  6:39   ` Sascha Hauer
  2021-04-27 20:23 ` [PATCH 12/12] RISC-V: sifive: add HiFive board support Ahmad Fatoum
  10 siblings, 1 reply; 20+ messages in thread
From: Ahmad Fatoum @ 2021-04-27 20:23 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum, rcz

The Ethernet controller on the SiFive SoCs needs some special TX clock
setup. Port the relevant Linux v5.12 bits to enable it.

Tested on qemu-system-riscv64 -M sifive_u with dhcp.

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
 drivers/net/macb.c | 113 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 113 insertions(+)

diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 14a0b45322bf..9c4fdbd5bc4f 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -52,6 +52,17 @@
 #define TX_RING_BYTES		(sizeof(struct macb_dma_desc) * TX_RING_SIZE)
 #define GEM_Q1_DESC_BYTES	(sizeof(struct macb_dma_desc) * GEM_Q1_DESCS)
 
+/* This structure is only used for MACB on SiFive FU540 devices */
+struct sifive_fu540_macb_mgmt {
+	void __iomem *reg;
+	unsigned long rate;
+	struct clk clk;
+};
+
+struct macb_config {
+	int (*txclk_init)(struct device_d *dev, struct clk **tx_clk);
+};
+
 struct macb_device {
 	void			__iomem *regs;
 
@@ -666,12 +677,101 @@ static void macb_init_rx_buffer_size(struct macb_device *bp, size_t size)
 		   size, bp->rx_buffer_size);
 }
 
+static struct sifive_fu540_macb_mgmt *mgmt;
+
+static unsigned long fu540_macb_tx_recalc_rate(struct clk *clk,
+					       unsigned long parent_rate)
+{
+	return mgmt->rate;
+}
+
+static long fu540_macb_tx_round_rate(struct clk *clk, 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 *clk, unsigned long rate,
+				  unsigned long parent_rate)
+{
+	rate = fu540_macb_tx_round_rate(clk, 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_txclk_init(struct device_d *dev, struct clk **tx_clk)
+{
+	struct clk *clk;
+	struct resource *res;
+	int err = 0;
+
+	mgmt = xzalloc(sizeof(*mgmt));
+
+	res = dev_request_mem_resource(dev, 1);
+	if (IS_ERR(res))
+		return PTR_ERR(res);
+
+	mgmt->reg = IOMEM(res->start);
+
+	clk = &mgmt->clk;
+
+	clk->name = "sifive-gemgxl-mgmt";
+	clk->ops = &fu540_c000_ops;
+
+	err = clk_register(&mgmt->clk);
+	if (err)
+		return err;
+
+	*tx_clk = &mgmt->clk;
+
+	err = clk_enable(*tx_clk);
+	if (err) {
+		dev_err(dev, "failed to enable tx_clk (%u)\n", err);
+		*tx_clk = NULL;
+		return err;
+	}
+
+	dev_info(dev, "Registered clk switch '%s'\n", clk->name);
+	return 0;
+}
+
 static int macb_probe(struct device_d *dev)
 {
 	struct resource *iores;
 	struct eth_device *edev;
 	struct macb_device *macb;
 	const char *pclk_name, *hclk_name;
+	const struct macb_config *config = NULL;
 	u32 ncfgr;
 
 	macb = xzalloc(sizeof(*macb));
@@ -725,6 +825,8 @@ static int macb_probe(struct device_d *dev)
 		macb->phy_addr = -1;
 		pclk_name = "pclk";
 		hclk_name = "hclk";
+
+		config = device_get_match_data(dev);
 	} else {
 		dev_err(dev, "macb: no platform_data\n");
 		return -ENODEV;
@@ -767,6 +869,12 @@ static int macb_probe(struct device_d *dev)
 	if (!IS_ERR(macb->rxclk))
 		clk_enable(macb->rxclk);
 
+	if (config) {
+		int ret = config->txclk_init(dev, &macb->txclk);
+		if (ret)
+			return ret;
+	}
+
 	macb->is_gem = read_is_gem(macb);
 
 	if (macb_is_gem(macb))
@@ -808,12 +916,17 @@ static void macb_remove(struct device_d *dev)
 	macb_halt(&macb->netdev);
 }
 
+static const struct macb_config fu540_c000_config = {
+	.txclk_init = fu540_c000_txclk_init,
+};
+
 static const struct of_device_id macb_dt_ids[] = {
 	{ .compatible = "cdns,at91sam9260-macb",},
 	{ .compatible = "atmel,sama5d2-gem",},
 	{ .compatible = "atmel,sama5d3-gem",},
 	{ .compatible = "cdns,zynq-gem",},
 	{ .compatible = "cdns,zynqmp-gem",},
+	{ .compatible = "sifive,fu540-c000-gem", .data = &fu540_c000_config },
 	{ /* sentinel */ }
 };
 
-- 
2.29.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 12/12] RISC-V: sifive: add HiFive board support
  2021-04-27 20:22 [PATCH 01/12] clk: add SiFive PRCI clock controller support Ahmad Fatoum
                   ` (9 preceding siblings ...)
  2021-04-27 20:23 ` [PATCH 11/12] net: macb: add SiFive support Ahmad Fatoum
@ 2021-04-27 20:23 ` Ahmad Fatoum
  10 siblings, 0 replies; 20+ messages in thread
From: Ahmad Fatoum @ 2021-04-27 20:23 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum, rcz

With the recently added SiFive support, we now have enough functionality
to boot a HiFive board to shell:

  qemu-system-riscv64 -M sifive_u serial_stdio \
  -kernel./images/barebox-hifive-unleashed.img

Some more drivers need to be ported for this to be useful:

  - sifive,spi0		needed for talking to SD-Card
  - clocksource		The riscv-timer seems to be 10x too fast

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
 arch/riscv/Kconfig.socs                 |  19 ++++
 arch/riscv/boards/Makefile              |   1 +
 arch/riscv/boards/hifive/Makefile       |   3 +
 arch/riscv/boards/hifive/lowlevel.c     |  25 +++++
 arch/riscv/configs/sifive_defconfig     | 128 ++++++++++++++++++++++++
 arch/riscv/dts/Makefile                 |   2 +
 arch/riscv/dts/hifive-unleashed-a00.dts |   3 +
 arch/riscv/dts/hifive-unmatched-a00.dts |   3 +
 arch/riscv/include/asm/debug_ll.h       |  14 +++
 common/Kconfig                          |   4 +
 images/Makefile.riscv                   |   5 +
 11 files changed, 207 insertions(+)
 create mode 100644 arch/riscv/boards/hifive/Makefile
 create mode 100644 arch/riscv/boards/hifive/lowlevel.c
 create mode 100644 arch/riscv/configs/sifive_defconfig
 create mode 100644 arch/riscv/dts/hifive-unleashed-a00.dts
 create mode 100644 arch/riscv/dts/hifive-unmatched-a00.dts

diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
index ea5ae0a6e9b5..c6875738d05c 100644
--- a/arch/riscv/Kconfig.socs
+++ b/arch/riscv/Kconfig.socs
@@ -21,4 +21,23 @@ config SOC_VIRT
 	  Generates an image tht can be be booted by QEMU. The image is called
 	  barebox-dt-2nd.img
 
+config SOC_SIFIVE
+	bool "SiFive SoCs"
+	select CLK_SIFIVE
+	select CLK_SIFIVE_PRCI
+	select RISCV_TIMER
+	select HAS_MACB
+	select HAS_ASM_DEBUG_LL
+	help
+	  This enables support for SiFive SoC platform hardware.
+
+if SOC_SIFIVE
+
+config BOARD_HIFIVE
+	bool "HiFive"
+	depends on ARCH_RV64I
+	select USE_COMPRESSED_DTB
+
+endif
+
 endmenu
diff --git a/arch/riscv/boards/Makefile b/arch/riscv/boards/Makefile
index 2ce9af41e03b..99f22f32b470 100644
--- a/arch/riscv/boards/Makefile
+++ b/arch/riscv/boards/Makefile
@@ -1,2 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_BOARD_ERIZO_GENERIC)	+= erizo/
+obj-$(CONFIG_BOARD_HIFIVE)		+= hifive/
diff --git a/arch/riscv/boards/hifive/Makefile b/arch/riscv/boards/hifive/Makefile
new file mode 100644
index 000000000000..3d217ffe0b93
--- /dev/null
+++ b/arch/riscv/boards/hifive/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+pbl-y += lowlevel.o
diff --git a/arch/riscv/boards/hifive/lowlevel.c b/arch/riscv/boards/hifive/lowlevel.c
new file mode 100644
index 000000000000..1de13cac1688
--- /dev/null
+++ b/arch/riscv/boards/hifive/lowlevel.c
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <common.h>
+#include <asm/barebox-riscv.h>
+#include <debug_ll.h>
+
+ENTRY_FUNCTION(start_hifive_unmatched, a0, a1, a2)
+{
+	extern char __dtb_z_hifive_unmatched_a00_start[];
+
+	putc_ll('>');
+
+	barebox_riscv_entry(0x80000000, SZ_128M,
+			    __dtb_z_hifive_unmatched_a00_start + get_runtime_offset());
+}
+
+ENTRY_FUNCTION(start_hifive_unleashed, a0, a1, a2)
+{
+	extern char __dtb_z_hifive_unleashed_a00_start[];
+
+	putc_ll('>');
+
+	barebox_riscv_entry(0x80000000, SZ_128M,
+			    __dtb_z_hifive_unleashed_a00_start + get_runtime_offset());
+}
diff --git a/arch/riscv/configs/sifive_defconfig b/arch/riscv/configs/sifive_defconfig
new file mode 100644
index 000000000000..59cfebf194df
--- /dev/null
+++ b/arch/riscv/configs/sifive_defconfig
@@ -0,0 +1,128 @@
+CONFIG_ARCH_RV64I=y
+CONFIG_SOC_SIFIVE=y
+CONFIG_BOARD_HIFIVE=y
+CONFIG_BOARD_RISCV_GENERIC_DT=y
+CONFIG_RISCV_OPTIMZED_STRING_FUNCTIONS=y
+CONFIG_STACK_SIZE=0x20000
+CONFIG_MALLOC_SIZE=0x0
+CONFIG_MALLOC_TLSF=y
+CONFIG_KALLSYMS=y
+CONFIG_RELOCATABLE=y
+CONFIG_PANIC_HANG=y
+CONFIG_HUSH_FANCY_PROMPT=y
+CONFIG_CMDLINE_EDITING=y
+CONFIG_AUTO_COMPLETE=y
+CONFIG_MENU=y
+CONFIG_IMD_TARGET=y
+CONFIG_CONSOLE_ALLOW_COLOR=y
+CONFIG_PBL_CONSOLE=y
+CONFIG_PARTITION_DISK_EFI=y
+CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y
+CONFIG_BAREBOXENV_TARGET=y
+CONFIG_BAREBOXCRC32_TARGET=y
+CONFIG_STATE=y
+CONFIG_STATE_CRYPTO=y
+CONFIG_BOOTCHOOSER=y
+CONFIG_RESET_SOURCE=y
+CONFIG_MACHINE_ID=y
+CONFIG_CMD_DMESG=y
+CONFIG_LONGHELP=y
+CONFIG_CMD_IOMEM=y
+CONFIG_CMD_IMD=y
+CONFIG_CMD_MEMINFO=y
+CONFIG_CMD_POLLER=y
+CONFIG_CMD_SLICE=y
+CONFIG_CMD_GO=y
+CONFIG_CMD_LOADY=y
+CONFIG_CMD_RESET=y
+CONFIG_CMD_BOOTCHOOSER=y
+CONFIG_CMD_EXPORT=y
+CONFIG_CMD_PRINTENV=y
+CONFIG_CMD_MAGICVAR=y
+CONFIG_CMD_MAGICVAR_HELP=y
+CONFIG_CMD_SAVEENV=y
+CONFIG_CMD_CMP=y
+CONFIG_CMD_FILETYPE=y
+CONFIG_CMD_LN=y
+CONFIG_CMD_MD5SUM=y
+CONFIG_CMD_SHA1SUM=y
+CONFIG_CMD_SHA256SUM=y
+CONFIG_CMD_MSLEEP=y
+CONFIG_CMD_SLEEP=y
+CONFIG_CMD_DHCP=y
+CONFIG_CMD_MIITOOL=y
+CONFIG_CMD_PING=y
+CONFIG_CMD_EDIT=y
+CONFIG_CMD_SPLASH=y
+CONFIG_CMD_FBTEST=y
+CONFIG_CMD_READLINE=y
+CONFIG_CMD_TIMEOUT=y
+CONFIG_CMD_MEMTEST=y
+CONFIG_CMD_MM=y
+CONFIG_CMD_CLK=y
+CONFIG_CMD_DETECT=y
+CONFIG_CMD_FLASH=y
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_I2C=y
+CONFIG_CMD_POWEROFF=y
+CONFIG_CMD_SPI=y
+CONFIG_CMD_2048=y
+CONFIG_CMD_BAREBOX_UPDATE=y
+CONFIG_CMD_OF_DIFF=y
+CONFIG_CMD_OF_NODE=y
+CONFIG_CMD_OF_PROPERTY=y
+CONFIG_CMD_OF_DISPLAY_TIMINGS=y
+CONFIG_CMD_OF_FIXUP_STATUS=y
+CONFIG_CMD_OF_OVERLAY=y
+CONFIG_CMD_OFTREE=y
+CONFIG_CMD_TIME=y
+CONFIG_CMD_DHRYSTONE=y
+CONFIG_NET=y
+CONFIG_NET_NFS=y
+CONFIG_NET_FASTBOOT=y
+CONFIG_DRIVER_SERIAL_NS16550=y
+CONFIG_VIRTIO_CONSOLE=y
+CONFIG_SERIAL_SIFIVE=y
+CONFIG_DRIVER_NET_MACB=y
+CONFIG_DRIVER_SPI_GPIO=y
+CONFIG_I2C=y
+CONFIG_I2C_GPIO=y
+CONFIG_MTD=y
+# CONFIG_MTD_OOB_DEVICE is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_M25P80=y
+CONFIG_DRIVER_CFI=y
+CONFIG_DRIVER_CFI_BANK_WIDTH_8=y
+CONFIG_DISK=y
+CONFIG_DISK_WRITE=y
+CONFIG_VIRTIO_BLK=y
+CONFIG_VIDEO=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_DRIVER_VIDEO_SIMPLEFB_CLIENT=y
+CONFIG_CLOCKSOURCE_DUMMY_RATE=60000
+CONFIG_EEPROM_AT24=y
+CONFIG_HWRNG=y
+CONFIG_HW_RANDOM_VIRTIO=y
+CONFIG_GPIO_SIFIVE=y
+# CONFIG_PINCTRL is not set
+CONFIG_SYSCON_REBOOT_MODE=y
+CONFIG_POWER_RESET_SYSCON=y
+CONFIG_POWER_RESET_SYSCON_POWEROFF=y
+CONFIG_POWER_RESET_GPIO_RESTART=y
+CONFIG_VIRTIO_MMIO=y
+CONFIG_FS_EXT4=y
+CONFIG_FS_TFTP=y
+CONFIG_FS_NFS=y
+CONFIG_FS_FAT=y
+CONFIG_FS_FAT_WRITE=y
+CONFIG_FS_FAT_LFN=y
+CONFIG_FS_UIMAGEFS=y
+CONFIG_FS_PSTORE=y
+CONFIG_FS_SQUASHFS=y
+CONFIG_ZLIB=y
+CONFIG_BZLIB=y
+CONFIG_LZ4_DECOMPRESS=y
+CONFIG_ZSTD_DECOMPRESS=y
+CONFIG_XZ_DECOMPRESS=y
+CONFIG_BASE64=y
+CONFIG_DIGEST_CRC32_GENERIC=y
diff --git a/arch/riscv/dts/Makefile b/arch/riscv/dts/Makefile
index 4041c34e0c45..17fdc9445bd0 100644
--- a/arch/riscv/dts/Makefile
+++ b/arch/riscv/dts/Makefile
@@ -5,5 +5,7 @@
 obj- += dummy.o
 
 pbl-$(CONFIG_BOARD_ERIZO_GENERIC) += erizo-generic.dtb.o
+pbl-$(CONFIG_BOARD_HIFIVE) += hifive-unmatched-a00.dtb.o \
+                              hifive-unleashed-a00.dtb.o
 
 clean-files := *.dtb *.dtb.S .*.dtc .*.pre .*.dts
diff --git a/arch/riscv/dts/hifive-unleashed-a00.dts b/arch/riscv/dts/hifive-unleashed-a00.dts
new file mode 100644
index 000000000000..65694bfd246a
--- /dev/null
+++ b/arch/riscv/dts/hifive-unleashed-a00.dts
@@ -0,0 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0 OR X11 */
+
+#include <riscv/sifive/hifive-unleashed-a00.dts>
diff --git a/arch/riscv/dts/hifive-unmatched-a00.dts b/arch/riscv/dts/hifive-unmatched-a00.dts
new file mode 100644
index 000000000000..b8793e910555
--- /dev/null
+++ b/arch/riscv/dts/hifive-unmatched-a00.dts
@@ -0,0 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0 OR X11 */
+
+#include <riscv/sifive/hifive-unmatched-a00.dts>
diff --git a/arch/riscv/include/asm/debug_ll.h b/arch/riscv/include/asm/debug_ll.h
index 755ed09786d5..6ef26280d14e 100644
--- a/arch/riscv/include/asm/debug_ll.h
+++ b/arch/riscv/include/asm/debug_ll.h
@@ -24,6 +24,20 @@
 
 #include <asm/debug_ll_ns16550.h>
 
+#elif defined CONFIG_DEBUG_SIFIVE
+
+#include <io.h>
+
+static inline void PUTC_LL(char ch)
+{
+	void __iomem *uart0 = IOMEM(0x10010000);
+
+	while (readl(uart0) & 0x80000000)
+		;
+
+	writel(ch, uart0);
+}
+
 #endif
 
 #endif /* __ASM_DEBUG_LL__ */
diff --git a/common/Kconfig b/common/Kconfig
index 6d7a1c6b0494..a883f2f69cb9 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -1347,6 +1347,10 @@ config DEBUG_ERIZO
 	bool "Erizo ns16550 port"
 	depends on SOC_ERIZO
 
+config DEBUG_SIFIVE
+	bool "SiFive serial0 port"
+	depends on SOC_SIFIVE
+
 endchoice
 
 config DEBUG_IMX_UART_PORT
diff --git a/images/Makefile.riscv b/images/Makefile.riscv
index 463c6ce4400d..c44c683431f7 100644
--- a/images/Makefile.riscv
+++ b/images/Makefile.riscv
@@ -10,3 +10,8 @@ $(obj)/%.nmon: $(obj)/%.img FORCE
 pblb-$(CONFIG_BOARD_ERIZO_GENERIC) += start_erizo_generic
 FILE_barebox-erizo-generic.img = start_erizo_generic.pblb
 image-$(CONFIG_BOARD_ERIZO_GENERIC) += barebox-erizo-generic.img barebox-erizo-generic.nmon
+
+pblb-$(CONFIG_BOARD_HIFIVE) += start_hifive_unmatched start_hifive_unleashed
+FILE_barebox-hifive-unmatched.img = start_hifive_unmatched.pblb
+FILE_barebox-hifive-unleashed.img = start_hifive_unleashed.pblb
+image-$(CONFIG_BOARD_HIFIVE) += barebox-hifive-unmatched.img barebox-hifive-unleashed.img
-- 
2.29.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 04/12] RISC-V: support multi-image for all machines
  2021-04-27 20:23 ` [PATCH 04/12] RISC-V: support multi-image for all machines Ahmad Fatoum
@ 2021-05-03 11:33   ` Sascha Hauer
  2021-05-03 11:39     ` Ahmad Fatoum
  0 siblings, 1 reply; 20+ messages in thread
From: Sascha Hauer @ 2021-05-03 11:33 UTC (permalink / raw)
  To: Ahmad Fatoum; +Cc: barebox, rcz

Hi Ahmad,

This patch doesn't apply, I think there's something wrong with it.

On Tue, Apr 27, 2021 at 10:23:01PM +0200, Ahmad Fatoum wrote:
> -config MACH_ERIZO
> -	bool "erizo family"
> -	select ARCH_RV32I
> -	select HAS_DEBUG_LL
> -	select HAS_NMON
> -	select USE_COMPRESSED_DTB
> -	select RISCV_M_MODE
> -	select RISCV_TIMER
> -
> -config MACH_VIRT
> -	bool "virt family"
> -	select BOARD_RISCV_GENERIC_DT
> -	select CLINT_TIMER
> -	help
> -	  Generates an image tht can be be booted by QEMU. The image is called
> -	  barebox-dt-2nd.img

This drops MACH_ERIZO and MACH_VIRT in favour of:

> +config SOC_ERIZO
> +	bool "Erizo SoC"
> +	select ARCH_RV32I
> +	select HAS_DEBUG_LL
> +	select HAS_NMON
> +	select USE_COMPRESSED_DTB
> +	select RISCV_M_MODE
> +	select RISCV_TIMER
> +
> +config SOC_VIRT
> +	bool "QEMU Virt Machine"
> +	select BOARD_RISCV_GENERIC_DT
> +	select CLINT_TIMER
> +	help
> +	  Generates an image tht can be be booted by QEMU. The image is called
> +	  barebox-dt-2nd.img

> @@ -19,7 +19,7 @@ LDFLAGS_pbl += $(riscv-ldflags-y)
>  cflags-y += $(riscv-cflags-y)
>  LDFLAGS_barebox += -nostdlib
>  
> -machine-$(CONFIG_MACH_ERIZO)	:= erizo
> +machine-$(CONFIG_SOC_ERIZO)	:= erizo

for CONFIG_*_ERIZO this is changed here as well, but here the file has:

machine-$(CONFIG_MACH_ERIZO)	:= erizo
machine-$(CONFIG_MACH_VIRT)	:= virt

I think CONFIG_MACH_VIRT should be replaced here as well. I could fix
the obvious, but I am not sure how this happened and if this is the only
mistake here, so not applying this. Please resend.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 04/12] RISC-V: support multi-image for all machines
  2021-05-03 11:33   ` Sascha Hauer
@ 2021-05-03 11:39     ` Ahmad Fatoum
  2021-05-03 12:00       ` Sascha Hauer
  0 siblings, 1 reply; 20+ messages in thread
From: Ahmad Fatoum @ 2021-05-03 11:39 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: barebox, rcz

Hello Sascha,

On 03.05.21 13:33, Sascha Hauer wrote:
> Hi Ahmad,
> 
> This patch doesn't apply, I think there's something wrong with it.
> 
> On Tue, Apr 27, 2021 at 10:23:01PM +0200, Ahmad Fatoum wrote:
>> -config MACH_ERIZO
>> -	bool "erizo family"
>> -	select ARCH_RV32I
>> -	select HAS_DEBUG_LL
>> -	select HAS_NMON
>> -	select USE_COMPRESSED_DTB
>> -	select RISCV_M_MODE
>> -	select RISCV_TIMER
>> -
>> -config MACH_VIRT
>> -	bool "virt family"
>> -	select BOARD_RISCV_GENERIC_DT
>> -	select CLINT_TIMER
>> -	help
>> -	  Generates an image tht can be be booted by QEMU. The image is called
>> -	  barebox-dt-2nd.img
> 
> This drops MACH_ERIZO and MACH_VIRT in favour of:
> 
>> +config SOC_ERIZO
>> +	bool "Erizo SoC"
>> +	select ARCH_RV32I
>> +	select HAS_DEBUG_LL
>> +	select HAS_NMON
>> +	select USE_COMPRESSED_DTB
>> +	select RISCV_M_MODE
>> +	select RISCV_TIMER
>> +
>> +config SOC_VIRT
>> +	bool "QEMU Virt Machine"
>> +	select BOARD_RISCV_GENERIC_DT
>> +	select CLINT_TIMER
>> +	help
>> +	  Generates an image tht can be be booted by QEMU. The image is called
>> +	  barebox-dt-2nd.img
> 
>> @@ -19,7 +19,7 @@ LDFLAGS_pbl += $(riscv-ldflags-y)
>>  cflags-y += $(riscv-cflags-y)
>>  LDFLAGS_barebox += -nostdlib
>>  
>> -machine-$(CONFIG_MACH_ERIZO)	:= erizo
>> +machine-$(CONFIG_SOC_ERIZO)	:= erizo
> 
> for CONFIG_*_ERIZO this is changed here as well, but here the file has:
> 
> machine-$(CONFIG_MACH_ERIZO)	:= erizo
> machine-$(CONFIG_MACH_VIRT)	:= virt
> 
> I think CONFIG_MACH_VIRT should be replaced here as well. I could fix
> the obvious, but I am not sure how this happened and if this is the only
> mistake here, so not applying this. Please resend.

Sorry, I should have noted that this applied on top of the earlier RISC-V
patches:

https://lore.barebox.org/barebox/20210410110638.2106658-1-ahmad@a3f.at/

> 
> Sascha
> 

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 04/12] RISC-V: support multi-image for all machines
  2021-05-03 11:39     ` Ahmad Fatoum
@ 2021-05-03 12:00       ` Sascha Hauer
  0 siblings, 0 replies; 20+ messages in thread
From: Sascha Hauer @ 2021-05-03 12:00 UTC (permalink / raw)
  To: Ahmad Fatoum; +Cc: barebox, rcz

On Mon, May 03, 2021 at 01:39:59PM +0200, Ahmad Fatoum wrote:
> Hello Sascha,
> 
> On 03.05.21 13:33, Sascha Hauer wrote:
> > Hi Ahmad,
> > 
> > This patch doesn't apply, I think there's something wrong with it.
> > 
> > On Tue, Apr 27, 2021 at 10:23:01PM +0200, Ahmad Fatoum wrote:
> >> -config MACH_ERIZO
> >> -	bool "erizo family"
> >> -	select ARCH_RV32I
> >> -	select HAS_DEBUG_LL
> >> -	select HAS_NMON
> >> -	select USE_COMPRESSED_DTB
> >> -	select RISCV_M_MODE
> >> -	select RISCV_TIMER
> >> -
> >> -config MACH_VIRT
> >> -	bool "virt family"
> >> -	select BOARD_RISCV_GENERIC_DT
> >> -	select CLINT_TIMER
> >> -	help
> >> -	  Generates an image tht can be be booted by QEMU. The image is called
> >> -	  barebox-dt-2nd.img
> > 
> > This drops MACH_ERIZO and MACH_VIRT in favour of:
> > 
> >> +config SOC_ERIZO
> >> +	bool "Erizo SoC"
> >> +	select ARCH_RV32I
> >> +	select HAS_DEBUG_LL
> >> +	select HAS_NMON
> >> +	select USE_COMPRESSED_DTB
> >> +	select RISCV_M_MODE
> >> +	select RISCV_TIMER
> >> +
> >> +config SOC_VIRT
> >> +	bool "QEMU Virt Machine"
> >> +	select BOARD_RISCV_GENERIC_DT
> >> +	select CLINT_TIMER
> >> +	help
> >> +	  Generates an image tht can be be booted by QEMU. The image is called
> >> +	  barebox-dt-2nd.img
> > 
> >> @@ -19,7 +19,7 @@ LDFLAGS_pbl += $(riscv-ldflags-y)
> >>  cflags-y += $(riscv-cflags-y)
> >>  LDFLAGS_barebox += -nostdlib
> >>  
> >> -machine-$(CONFIG_MACH_ERIZO)	:= erizo
> >> +machine-$(CONFIG_SOC_ERIZO)	:= erizo
> > 
> > for CONFIG_*_ERIZO this is changed here as well, but here the file has:
> > 
> > machine-$(CONFIG_MACH_ERIZO)	:= erizo
> > machine-$(CONFIG_MACH_VIRT)	:= virt
> > 
> > I think CONFIG_MACH_VIRT should be replaced here as well. I could fix
> > the obvious, but I am not sure how this happened and if this is the only
> > mistake here, so not applying this. Please resend.
> 
> Sorry, I should have noted that this applied on top of the earlier RISC-V
> patches:
> 
> https://lore.barebox.org/barebox/20210410110638.2106658-1-ahmad@a3f.at/

Ok, applied that one first.

Sascha


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 06/12] RISC-V: erizo: drop mach-erizo directory
  2021-04-27 20:23 ` [PATCH 06/12] RISC-V: erizo: drop mach-erizo directory Ahmad Fatoum
@ 2021-05-05 10:18   ` Antony Pavlov
  2021-05-05 10:21     ` Ahmad Fatoum
  0 siblings, 1 reply; 20+ messages in thread
From: Antony Pavlov @ 2021-05-05 10:18 UTC (permalink / raw)
  To: Ahmad Fatoum; +Cc: barebox, rcz

On Tue, 27 Apr 2021 22:23:03 +0200
Ahmad Fatoum <a.fatoum@pengutronix.de> wrote:

Hi Ahmad!

Could you please rebase this patchseries on top of pengutronix next branch
and push it to github?

My latest LiteX SoC support patchseries introduces mach-litex/include/mach/debug_ll.h.

> With the recent changes, we can now delete mach-erizo. Do so.
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
> ---
>  arch/riscv/Kconfig.socs                        |  2 +-
>  arch/riscv/Makefile                            | 13 -------------
>  .../include/mach => include/asm}/debug_ll.h    | 18 +++++++-----------
>  arch/riscv/mach-erizo/Makefile                 |  3 ---
>  common/Kconfig                                 |  5 +++++
>  5 files changed, 13 insertions(+), 28 deletions(-)
>  rename arch/riscv/{mach-erizo/include/mach => include/asm}/debug_ll.h (57%)
>  delete mode 100644 arch/riscv/mach-erizo/Makefile
> 
> diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
> index 093bca33806c..ea5ae0a6e9b5 100644
> --- a/arch/riscv/Kconfig.socs
> +++ b/arch/riscv/Kconfig.socs
> @@ -3,7 +3,7 @@ menu "SoC selection"
>  config SOC_ERIZO
>  	bool "Erizo SoC"
>  	depends on ARCH_RV32I
> -	select HAS_DEBUG_LL
> +	select HAS_ASM_DEBUG_LL
>  	select HAS_NMON
>  	select USE_COMPRESSED_DTB
>  	select RISCV_M_MODE
> diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
> index 09a94d69b220..0b1278936d91 100644
> --- a/arch/riscv/Makefile
> +++ b/arch/riscv/Makefile
> @@ -19,8 +19,6 @@ LDFLAGS_pbl += $(riscv-ldflags-y)
>  cflags-y += $(riscv-cflags-y)
>  LDFLAGS_barebox += -nostdlib
>  
> -machine-$(CONFIG_SOC_ERIZO)	:= erizo
> -
>  LDFLAGS_barebox += $(riscv-ldflags-y)
>  
>  ifndef CONFIG_MODULES
> @@ -31,21 +29,10 @@ endif
>  
>  KBUILD_BINARY := barebox.bin
>  
> -machdirs := $(patsubst %,arch/riscv/mach-%/,$(machine-y))
> -
> -KBUILD_CPPFLAGS += $(patsubst %,-I$(srctree)/%include,$(machdirs))
> -
>  archprepare: maketools
>  
>  PHONY += maketools
>  
> -ifneq ($(machine-y),)
> -MACH  := arch/riscv/mach-$(machine-y)/
> -else
> -MACH  :=
> -endif
> -
> -common-y += $(MACH)
>  common-y += arch/riscv/boards/
>  common-y += arch/riscv/cpu/
>  common-y += arch/riscv/lib/
> diff --git a/arch/riscv/mach-erizo/include/mach/debug_ll.h b/arch/riscv/include/asm/debug_ll.h
> similarity index 57%
> rename from arch/riscv/mach-erizo/include/mach/debug_ll.h
> rename to arch/riscv/include/asm/debug_ll.h
> index a20acfcdfb79..755ed09786d5 100644
> --- a/arch/riscv/mach-erizo/include/mach/debug_ll.h
> +++ b/arch/riscv/include/asm/debug_ll.h
> @@ -1,18 +1,10 @@
>  /* SPDX-License-Identifier: GPL-2.0-only */
>  /*
>   * Copyright (C) 2017 Antony Pavlov <antonynpavlov@gmail.com>
> - *
> - * This file is part of barebox.
> - *
> - * 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.
> - *
>   */
>  
> -#ifndef __MACH_ERIZO_DEBUG_LL__
> -#define __MACH_ERIZO_DEBUG_LL__
> +#ifndef __ASM_DEBUG_LL__
> +#define __ASM_DEBUG_LL__
>  
>  /** @file
>   *  This File contains declaration for early output support
> @@ -20,6 +12,8 @@
>  
>  #include <linux/kconfig.h>
>  
> +#ifdef CONFIG_DEBUG_ERIZO
> +
>  #define DEBUG_LL_UART_ADDR	0x90000000
>  #define DEBUG_LL_UART_SHIFT	2
>  #define DEBUG_LL_UART_IOSIZE32
> @@ -30,4 +24,6 @@
>  
>  #include <asm/debug_ll_ns16550.h>
>  
> -#endif /* __MACH_ERIZO_DEBUG_LL__ */
> +#endif
> +
> +#endif /* __ASM_DEBUG_LL__ */
> diff --git a/arch/riscv/mach-erizo/Makefile b/arch/riscv/mach-erizo/Makefile
> deleted file mode 100644
> index d9c51e74c379..000000000000
> --- a/arch/riscv/mach-erizo/Makefile
> +++ /dev/null
> @@ -1,3 +0,0 @@
> -# just to build a built-in.o. Otherwise compilation fails when no o-files is
> -# created.
> -obj- += dummy.o
> diff --git a/common/Kconfig b/common/Kconfig
> index b10fb45b722d..6d7a1c6b0494 100644
> --- a/common/Kconfig
> +++ b/common/Kconfig
> @@ -1342,6 +1342,11 @@ config DEBUG_RPI3_MINI_UART
>  	help
>  	  Say Y here if you want low-level debugging support on
>  	  RaspberryPi 3 board mini UART.
> +
> +config DEBUG_ERIZO
> +	bool "Erizo ns16550 port"
> +	depends on SOC_ERIZO
> +
>  endchoice
>  
>  config DEBUG_IMX_UART_PORT
> -- 
> 2.29.2
> 


-- 
Best regards,
  Antony Pavlov

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 06/12] RISC-V: erizo: drop mach-erizo directory
  2021-05-05 10:18   ` Antony Pavlov
@ 2021-05-05 10:21     ` Ahmad Fatoum
  2021-05-07 11:27       ` Antony Pavlov
  0 siblings, 1 reply; 20+ messages in thread
From: Ahmad Fatoum @ 2021-05-05 10:21 UTC (permalink / raw)
  To: Antony Pavlov; +Cc: barebox, rcz

Hello Antony,

On 05.05.21 12:18, Antony Pavlov wrote:
> On Tue, 27 Apr 2021 22:23:03 +0200
> Ahmad Fatoum <a.fatoum@pengutronix.de> wrote:
> 
> Hi Ahmad!
> 
> Could you please rebase this patchseries on top of pengutronix next branch
> and push it to github?
> 
> My latest LiteX SoC support patchseries introduces mach-litex/include/mach/debug_ll.h.

I just commented that on your series :D
next Branch already contains this series.

By the way, there's now lore.barebox.org, which allows you
to download patch series as mbox via b4 (or a web browser).

Cheers,
Ahmad

> 
>> With the recent changes, we can now delete mach-erizo. Do so.
>>
>> Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
>> ---
>>  arch/riscv/Kconfig.socs                        |  2 +-
>>  arch/riscv/Makefile                            | 13 -------------
>>  .../include/mach => include/asm}/debug_ll.h    | 18 +++++++-----------
>>  arch/riscv/mach-erizo/Makefile                 |  3 ---
>>  common/Kconfig                                 |  5 +++++
>>  5 files changed, 13 insertions(+), 28 deletions(-)
>>  rename arch/riscv/{mach-erizo/include/mach => include/asm}/debug_ll.h (57%)
>>  delete mode 100644 arch/riscv/mach-erizo/Makefile
>>
>> diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
>> index 093bca33806c..ea5ae0a6e9b5 100644
>> --- a/arch/riscv/Kconfig.socs
>> +++ b/arch/riscv/Kconfig.socs
>> @@ -3,7 +3,7 @@ menu "SoC selection"
>>  config SOC_ERIZO
>>  	bool "Erizo SoC"
>>  	depends on ARCH_RV32I
>> -	select HAS_DEBUG_LL
>> +	select HAS_ASM_DEBUG_LL
>>  	select HAS_NMON
>>  	select USE_COMPRESSED_DTB
>>  	select RISCV_M_MODE
>> diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
>> index 09a94d69b220..0b1278936d91 100644
>> --- a/arch/riscv/Makefile
>> +++ b/arch/riscv/Makefile
>> @@ -19,8 +19,6 @@ LDFLAGS_pbl += $(riscv-ldflags-y)
>>  cflags-y += $(riscv-cflags-y)
>>  LDFLAGS_barebox += -nostdlib
>>  
>> -machine-$(CONFIG_SOC_ERIZO)	:= erizo
>> -
>>  LDFLAGS_barebox += $(riscv-ldflags-y)
>>  
>>  ifndef CONFIG_MODULES
>> @@ -31,21 +29,10 @@ endif
>>  
>>  KBUILD_BINARY := barebox.bin
>>  
>> -machdirs := $(patsubst %,arch/riscv/mach-%/,$(machine-y))
>> -
>> -KBUILD_CPPFLAGS += $(patsubst %,-I$(srctree)/%include,$(machdirs))
>> -
>>  archprepare: maketools
>>  
>>  PHONY += maketools
>>  
>> -ifneq ($(machine-y),)
>> -MACH  := arch/riscv/mach-$(machine-y)/
>> -else
>> -MACH  :=
>> -endif
>> -
>> -common-y += $(MACH)
>>  common-y += arch/riscv/boards/
>>  common-y += arch/riscv/cpu/
>>  common-y += arch/riscv/lib/
>> diff --git a/arch/riscv/mach-erizo/include/mach/debug_ll.h b/arch/riscv/include/asm/debug_ll.h
>> similarity index 57%
>> rename from arch/riscv/mach-erizo/include/mach/debug_ll.h
>> rename to arch/riscv/include/asm/debug_ll.h
>> index a20acfcdfb79..755ed09786d5 100644
>> --- a/arch/riscv/mach-erizo/include/mach/debug_ll.h
>> +++ b/arch/riscv/include/asm/debug_ll.h
>> @@ -1,18 +1,10 @@
>>  /* SPDX-License-Identifier: GPL-2.0-only */
>>  /*
>>   * Copyright (C) 2017 Antony Pavlov <antonynpavlov@gmail.com>
>> - *
>> - * This file is part of barebox.
>> - *
>> - * 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.
>> - *
>>   */
>>  
>> -#ifndef __MACH_ERIZO_DEBUG_LL__
>> -#define __MACH_ERIZO_DEBUG_LL__
>> +#ifndef __ASM_DEBUG_LL__
>> +#define __ASM_DEBUG_LL__
>>  
>>  /** @file
>>   *  This File contains declaration for early output support
>> @@ -20,6 +12,8 @@
>>  
>>  #include <linux/kconfig.h>
>>  
>> +#ifdef CONFIG_DEBUG_ERIZO
>> +
>>  #define DEBUG_LL_UART_ADDR	0x90000000
>>  #define DEBUG_LL_UART_SHIFT	2
>>  #define DEBUG_LL_UART_IOSIZE32
>> @@ -30,4 +24,6 @@
>>  
>>  #include <asm/debug_ll_ns16550.h>
>>  
>> -#endif /* __MACH_ERIZO_DEBUG_LL__ */
>> +#endif
>> +
>> +#endif /* __ASM_DEBUG_LL__ */
>> diff --git a/arch/riscv/mach-erizo/Makefile b/arch/riscv/mach-erizo/Makefile
>> deleted file mode 100644
>> index d9c51e74c379..000000000000
>> --- a/arch/riscv/mach-erizo/Makefile
>> +++ /dev/null
>> @@ -1,3 +0,0 @@
>> -# just to build a built-in.o. Otherwise compilation fails when no o-files is
>> -# created.
>> -obj- += dummy.o
>> diff --git a/common/Kconfig b/common/Kconfig
>> index b10fb45b722d..6d7a1c6b0494 100644
>> --- a/common/Kconfig
>> +++ b/common/Kconfig
>> @@ -1342,6 +1342,11 @@ config DEBUG_RPI3_MINI_UART
>>  	help
>>  	  Say Y here if you want low-level debugging support on
>>  	  RaspberryPi 3 board mini UART.
>> +
>> +config DEBUG_ERIZO
>> +	bool "Erizo ns16550 port"
>> +	depends on SOC_ERIZO
>> +
>>  endchoice
>>  
>>  config DEBUG_IMX_UART_PORT
>> -- 
>> 2.29.2
>>
> 
> 

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 09/12] gpio: generic: sync with upstream Linux gpio-mmio driver
  2021-04-27 20:23 ` [PATCH 09/12] gpio: generic: sync with upstream Linux gpio-mmio driver Ahmad Fatoum
@ 2021-05-06 23:45   ` Antony Pavlov
  0 siblings, 0 replies; 20+ messages in thread
From: Antony Pavlov @ 2021-05-06 23:45 UTC (permalink / raw)
  To: Ahmad Fatoum; +Cc: barebox, rcz, Steffen Trumtrar

On Tue, 27 Apr 2021 22:23:06 +0200
Ahmad Fatoum <a.fatoum@pengutronix.de> wrote:

Hi Ahmad!

> --- a/drivers/gpio/gpio-generic.c
> +++ b/drivers/gpio/gpio-generic.c
...
> @@ -337,34 +531,37 @@ static int bgpio_dev_probe(struct device_d *dev)
>  	unsigned long flags = 0;
>  	int err;
>  	struct bgpio_chip *bgc;
> +	struct bgpio_pdata *pdata;
>  
> -	r = dev_get_resource_by_name(dev, IORESOURCE_MEM, "dat");
> -	if (IS_ERR(r))
> -		return PTR_ERR(r);
> +	pdata = bgpio_parse_dt(dev, &flags);
> +	if (IS_ERR(pdata))
> +		return PTR_ERR(pdata);
> +

This patch breaks RISC-V erizo gpio, here is error message:

basic-mmio-gpio 91000000.gpio@91000000.of: probe failed: error 22


The problem is here:

> +	r = dev_request_mem_resource_by_name(dev, "dat");
> +	if (!r)
> +		return -EINVAL;
>  
>  	sz = resource_size(r);
>  
> -	dat = bgpio_map(dev, "dat", sz, &err);
> -	if (!dat)
> -		return err ? err : -EINVAL;
> +	dat = bgpio_map(dev, "dat", sz);

the dev_request_mem_resource_by_name() function invokes request_iomem_region() (success),
but bgpio_map() invokes dev_request_mem_resource_by_name() for the same dev and name again.
This time dev_request_mem_resource_by_name() fails.



-- 
Best regards,
  Antony Pavlov

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 06/12] RISC-V: erizo: drop mach-erizo directory
  2021-05-05 10:21     ` Ahmad Fatoum
@ 2021-05-07 11:27       ` Antony Pavlov
  0 siblings, 0 replies; 20+ messages in thread
From: Antony Pavlov @ 2021-05-07 11:27 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: barebox, Ahmad Fatoum

On Wed, 5 May 2021 12:21:25 +0200
Ahmad Fatoum <a.fatoum@pengutronix.de> wrote:

Hi Sascha!

> Hello Antony,
> 
> On 05.05.21 12:18, Antony Pavlov wrote:
> > On Tue, 27 Apr 2021 22:23:03 +0200
> > Ahmad Fatoum <a.fatoum@pengutronix.de> wrote:
> > 
> > Hi Ahmad!
> > 
> > Could you please rebase this patchseries on top of pengutronix next branch
> > and push it to github?
> > 
> > My latest LiteX SoC support patchseries introduces mach-litex/include/mach/debug_ll.h.
> 
> I just commented that on your series :D
> next Branch already contains this series.
> 
> By the way, there's now lore.barebox.org, which allows you
> to download patch series as mbox via b4 (or a web browser).

Can we add lore.barebox.org link to the main page of https://www.barebox.org/ ?

I suppose we can add RISC-V to list of computer architectures supported by barebox
at https://www.barebox.org/.

> Cheers,
> Ahmad
> 
> > 
> >> With the recent changes, we can now delete mach-erizo. Do so.
> >>
> >> Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
> >> ---
> >>  arch/riscv/Kconfig.socs                        |  2 +-
> >>  arch/riscv/Makefile                            | 13 -------------
> >>  .../include/mach => include/asm}/debug_ll.h    | 18 +++++++-----------
> >>  arch/riscv/mach-erizo/Makefile                 |  3 ---
> >>  common/Kconfig                                 |  5 +++++
> >>  5 files changed, 13 insertions(+), 28 deletions(-)
> >>  rename arch/riscv/{mach-erizo/include/mach => include/asm}/debug_ll.h (57%)
> >>  delete mode 100644 arch/riscv/mach-erizo/Makefile
> >>
> >> diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
> >> index 093bca33806c..ea5ae0a6e9b5 100644
> >> --- a/arch/riscv/Kconfig.socs
> >> +++ b/arch/riscv/Kconfig.socs
> >> @@ -3,7 +3,7 @@ menu "SoC selection"
> >>  config SOC_ERIZO
> >>  	bool "Erizo SoC"
> >>  	depends on ARCH_RV32I
> >> -	select HAS_DEBUG_LL
> >> +	select HAS_ASM_DEBUG_LL
> >>  	select HAS_NMON
> >>  	select USE_COMPRESSED_DTB
> >>  	select RISCV_M_MODE
> >> diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
> >> index 09a94d69b220..0b1278936d91 100644
> >> --- a/arch/riscv/Makefile
> >> +++ b/arch/riscv/Makefile
> >> @@ -19,8 +19,6 @@ LDFLAGS_pbl += $(riscv-ldflags-y)
> >>  cflags-y += $(riscv-cflags-y)
> >>  LDFLAGS_barebox += -nostdlib
> >>  
> >> -machine-$(CONFIG_SOC_ERIZO)	:= erizo
> >> -
> >>  LDFLAGS_barebox += $(riscv-ldflags-y)
> >>  
> >>  ifndef CONFIG_MODULES
> >> @@ -31,21 +29,10 @@ endif
> >>  
> >>  KBUILD_BINARY := barebox.bin
> >>  
> >> -machdirs := $(patsubst %,arch/riscv/mach-%/,$(machine-y))
> >> -
> >> -KBUILD_CPPFLAGS += $(patsubst %,-I$(srctree)/%include,$(machdirs))
> >> -
> >>  archprepare: maketools
> >>  
> >>  PHONY += maketools
> >>  
> >> -ifneq ($(machine-y),)
> >> -MACH  := arch/riscv/mach-$(machine-y)/
> >> -else
> >> -MACH  :=
> >> -endif
> >> -
> >> -common-y += $(MACH)
> >>  common-y += arch/riscv/boards/
> >>  common-y += arch/riscv/cpu/
> >>  common-y += arch/riscv/lib/
> >> diff --git a/arch/riscv/mach-erizo/include/mach/debug_ll.h b/arch/riscv/include/asm/debug_ll.h
> >> similarity index 57%
> >> rename from arch/riscv/mach-erizo/include/mach/debug_ll.h
> >> rename to arch/riscv/include/asm/debug_ll.h
> >> index a20acfcdfb79..755ed09786d5 100644
> >> --- a/arch/riscv/mach-erizo/include/mach/debug_ll.h
> >> +++ b/arch/riscv/include/asm/debug_ll.h
> >> @@ -1,18 +1,10 @@
> >>  /* SPDX-License-Identifier: GPL-2.0-only */
> >>  /*
> >>   * Copyright (C) 2017 Antony Pavlov <antonynpavlov@gmail.com>
> >> - *
> >> - * This file is part of barebox.
> >> - *
> >> - * 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.
> >> - *
> >>   */
> >>  
> >> -#ifndef __MACH_ERIZO_DEBUG_LL__
> >> -#define __MACH_ERIZO_DEBUG_LL__
> >> +#ifndef __ASM_DEBUG_LL__
> >> +#define __ASM_DEBUG_LL__
> >>  
> >>  /** @file
> >>   *  This File contains declaration for early output support
> >> @@ -20,6 +12,8 @@
> >>  
> >>  #include <linux/kconfig.h>
> >>  
> >> +#ifdef CONFIG_DEBUG_ERIZO
> >> +
> >>  #define DEBUG_LL_UART_ADDR	0x90000000
> >>  #define DEBUG_LL_UART_SHIFT	2
> >>  #define DEBUG_LL_UART_IOSIZE32
> >> @@ -30,4 +24,6 @@
> >>  
> >>  #include <asm/debug_ll_ns16550.h>
> >>  
> >> -#endif /* __MACH_ERIZO_DEBUG_LL__ */
> >> +#endif
> >> +
> >> +#endif /* __ASM_DEBUG_LL__ */
> >> diff --git a/arch/riscv/mach-erizo/Makefile b/arch/riscv/mach-erizo/Makefile
> >> deleted file mode 100644
> >> index d9c51e74c379..000000000000
> >> --- a/arch/riscv/mach-erizo/Makefile
> >> +++ /dev/null
> >> @@ -1,3 +0,0 @@
> >> -# just to build a built-in.o. Otherwise compilation fails when no o-files is
> >> -# created.
> >> -obj- += dummy.o
> >> diff --git a/common/Kconfig b/common/Kconfig
> >> index b10fb45b722d..6d7a1c6b0494 100644
> >> --- a/common/Kconfig
> >> +++ b/common/Kconfig
> >> @@ -1342,6 +1342,11 @@ config DEBUG_RPI3_MINI_UART
> >>  	help
> >>  	  Say Y here if you want low-level debugging support on
> >>  	  RaspberryPi 3 board mini UART.
> >> +
> >> +config DEBUG_ERIZO
> >> +	bool "Erizo ns16550 port"
> >> +	depends on SOC_ERIZO
> >> +
> >>  endchoice
> >>  
> >>  config DEBUG_IMX_UART_PORT
> >> -- 
> >> 2.29.2
> >>
> > 
> > 
> 
> -- 
> Pengutronix e.K.                           |                             |
> Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
> 31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


-- 
Best regards,
  Antony Pavlov

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 11/12] net: macb: add SiFive support
  2021-04-27 20:23 ` [PATCH 11/12] net: macb: add SiFive support Ahmad Fatoum
@ 2021-05-17  6:39   ` Sascha Hauer
  0 siblings, 0 replies; 20+ messages in thread
From: Sascha Hauer @ 2021-05-17  6:39 UTC (permalink / raw)
  To: Ahmad Fatoum; +Cc: barebox, rcz

On Tue, Apr 27, 2021 at 10:23:08PM +0200, Ahmad Fatoum wrote:
> The Ethernet controller on the SiFive SoCs needs some special TX clock
> setup. Port the relevant Linux v5.12 bits to enable it.
> 
> Tested on qemu-system-riscv64 -M sifive_u with dhcp.
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
> ---
>  drivers/net/macb.c | 113 +++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 113 insertions(+)
> 
> diff --git a/drivers/net/macb.c b/drivers/net/macb.c
> index 14a0b45322bf..9c4fdbd5bc4f 100644
> --- a/drivers/net/macb.c
> +++ b/drivers/net/macb.c
> @@ -52,6 +52,17 @@
>  #define TX_RING_BYTES		(sizeof(struct macb_dma_desc) * TX_RING_SIZE)
>  #define GEM_Q1_DESC_BYTES	(sizeof(struct macb_dma_desc) * GEM_Q1_DESCS)
>  
> +/* This structure is only used for MACB on SiFive FU540 devices */
> +struct sifive_fu540_macb_mgmt {
> +	void __iomem *reg;
> +	unsigned long rate;
> +	struct clk clk;
> +};
> +
> +struct macb_config {
> +	int (*txclk_init)(struct device_d *dev, struct clk **tx_clk);
> +};
> +
>  struct macb_device {
>  	void			__iomem *regs;
>  
> @@ -666,12 +677,101 @@ static void macb_init_rx_buffer_size(struct macb_device *bp, size_t size)
>  		   size, bp->rx_buffer_size);
>  }
>  
> +static struct sifive_fu540_macb_mgmt *mgmt;
> +
> +static unsigned long fu540_macb_tx_recalc_rate(struct clk *clk,
> +					       unsigned long parent_rate)
> +{
> +	return mgmt->rate;
> +}

Unfortunately I had to drop this one. The macb driver is used by some of
the old at91 configs which have their own clk implementation. Among
other things there is no recalc_rate hook.

Can we place the clk code inside a #ifdef CONFIG_COMMON_CLK?

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2021-05-17  6:41 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-27 20:22 [PATCH 01/12] clk: add SiFive PRCI clock controller support Ahmad Fatoum
2021-04-27 20:22 ` [PATCH 02/12] serial: implement SiFive UART support Ahmad Fatoum
2021-04-27 20:23 ` [PATCH 03/12] debug_ll: support <asm/debug_ll.h> to get rid of mach directories Ahmad Fatoum
2021-04-27 20:23 ` [PATCH 04/12] RISC-V: support multi-image for all machines Ahmad Fatoum
2021-05-03 11:33   ` Sascha Hauer
2021-05-03 11:39     ` Ahmad Fatoum
2021-05-03 12:00       ` Sascha Hauer
2021-04-27 20:23 ` [PATCH 05/12] RISC-V: erizo: restrict to RV32I Ahmad Fatoum
2021-04-27 20:23 ` [PATCH 06/12] RISC-V: erizo: drop mach-erizo directory Ahmad Fatoum
2021-05-05 10:18   ` Antony Pavlov
2021-05-05 10:21     ` Ahmad Fatoum
2021-05-07 11:27       ` Antony Pavlov
2021-04-27 20:23 ` [PATCH 07/12] RISC-V: add SBI based cpuinfo Ahmad Fatoum
2021-04-27 20:23 ` [PATCH 08/12] gpio: gpio-generic-platform: remove unused non-DT support Ahmad Fatoum
2021-04-27 20:23 ` [PATCH 09/12] gpio: generic: sync with upstream Linux gpio-mmio driver Ahmad Fatoum
2021-05-06 23:45   ` Antony Pavlov
2021-04-27 20:23 ` [PATCH 10/12] gpio: add SiFive GPIO controller support Ahmad Fatoum
2021-04-27 20:23 ` [PATCH 11/12] net: macb: add SiFive support Ahmad Fatoum
2021-05-17  6:39   ` Sascha Hauer
2021-04-27 20:23 ` [PATCH 12/12] RISC-V: sifive: add HiFive board support Ahmad Fatoum

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox