Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 5 Aug 2019 17:43:45 +0000 (UTC)
From:      Emmanuel Vadot <manu@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org
Subject:   svn commit: r350600 - in stable/12/sys: arm/mv arm64/conf conf dev/fdt dev/iicbus/twsi dev/sdhci
Message-ID:  <201908051743.x75HhjS9098115@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: manu
Date: Mon Aug  5 17:43:44 2019
New Revision: 350600
URL: https://svnweb.freebsd.org/changeset/base/350600

Log:
  MFC r342008, r342010-r342020
  
  r342008:
  fdt: Add support for simple-mfd bus
  
  Quoting the binding Documentation :
  
  "These devices comprise a nexus for heterogeneous hardware blocks containing
  more than one non-unique yet varying hardware functionality."
  
  Reviewed by:	loos
  Sponsored by:	Rubicon Communications, LLC ("Netgate")
  Differential Revision:	https://reviews.freebsd.org/D17751
  
  r342010:
  arm64: Add new SoC type MARVELL_8K
  
  Sponsored by:	Rubicon Communications, LLC ("Netgate")
  
  r342011:
  arm64: mvebu_pinctrl: Add driver for Marvell Pinmux Controller
  
  Add a driver compatible with Marvell mvebu-pinctrl and add ap806-pinctrl
  support.
  
  Sponsored by:	Rubicon Communications, LCC ("Netgate")
  
  r342012:
  arm64: marvell: Add driver for Marvell Ap806 System Controller
  
  The first two clocks are for the clusters and their frequencies can be
  found reading a register. Then a fixed 1200Mhz clock is present and two
  fixed clocks, 'mss' which is 1200 / 6 and 'sdio' which is 1200 / 3.
  
  Sponsored by:	Rubicon Communications, LLC ("Netgate")
  
  r342013:
  arm64: mv_gpio: Add Marvell 8K support
  
  While here put the interrupts setup in it's own function
  
  Sponsored by:	Rubicon Communications, LCC ("Netgate")
  
  r342014:
  arm64: marvell: Add cp110 clock controller support
  
  The cp110 clock controller controls the clocks and gate of the CP110
  hardware block.
  
  Every clock/gate are implemented except the NAND clock.
  
  Sponsored by:	Rubicon Communications, LLC ("Netgate")
  
  r342015:
  twsi: Clean up marvell part and add support for Marvell 7k/8k
  
  Sponsored by:	Rubicon Communications, LLC ("Netgate")
  
  r342016:
  arm64: Add mv_cp110_icu and mv_cp110_gicp
  
  icu is a interrupt concentrator in the CP110 block and gicp
  is a gic extension to allow interrupts in the CP block to be turned
  into GIC SPI interrupts
  
  Sponsored by:	Rubicon Communications, LLC ("Netgate")
  
  r342017:
  sdhci_xenon: Add Marvell 8k compatible string
  
  Sponsored by:	Rubicon Communications, LLC ("Netgate")
  
  r342018:
  mv_gpio: Since it's also an interrupt controller, attach sooner
  
  Sponsored by:	Rubicon Communications, LLC ("Netgate")
  
  r342019:
  arm64: mv_cp110_icu: Fix build
  
  r342020:
  mv_thermal: Add thermal driver for AP806 and CP110 thermal sensor
  
  Sponsored by:	Rubicon Communications, LLC ("Netgate")

Added:
  stable/12/sys/arm/mv/mv_ap806_clock.c
     - copied unchanged from r342020, head/sys/arm/mv/mv_ap806_clock.c
  stable/12/sys/arm/mv/mv_ap806_gicp.c
     - copied unchanged from r342020, head/sys/arm/mv/mv_ap806_gicp.c
  stable/12/sys/arm/mv/mv_cp110_clock.c
     - copied unchanged from r342020, head/sys/arm/mv/mv_cp110_clock.c
  stable/12/sys/arm/mv/mv_cp110_clock.h
     - copied unchanged from r342020, head/sys/arm/mv/mv_cp110_clock.h
  stable/12/sys/arm/mv/mv_cp110_icu.c
     - copied unchanged from r342020, head/sys/arm/mv/mv_cp110_icu.c
  stable/12/sys/arm/mv/mv_thermal.c
     - copied unchanged from r342020, head/sys/arm/mv/mv_thermal.c
  stable/12/sys/arm/mv/mvebu_pinctrl.c
     - copied unchanged from r342020, head/sys/arm/mv/mvebu_pinctrl.c
  stable/12/sys/dev/fdt/simple_mfd.c
     - copied unchanged from r342008, head/sys/dev/fdt/simple_mfd.c
Modified:
  stable/12/sys/arm/mv/gpio.c
  stable/12/sys/arm64/conf/GENERIC
  stable/12/sys/conf/files
  stable/12/sys/conf/files.arm64
  stable/12/sys/conf/options.arm64
  stable/12/sys/dev/fdt/simplebus.c
  stable/12/sys/dev/fdt/simplebus.h
  stable/12/sys/dev/iicbus/twsi/mv_twsi.c
  stable/12/sys/dev/iicbus/twsi/twsi.h
  stable/12/sys/dev/sdhci/sdhci_xenon.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/arm/mv/gpio.c
==============================================================================
--- stable/12/sys/arm/mv/gpio.c	Mon Aug  5 17:36:00 2019	(r350599)
+++ stable/12/sys/arm/mv/gpio.c	Mon Aug  5 17:43:44 2019	(r350600)
@@ -60,6 +60,10 @@ __FBSDID("$FreeBSD$");
 
 #include "gpio_if.h"
 
+#ifdef __aarch64__
+#include "opt_soc.h"
+#endif
+
 #define GPIO_MAX_INTR_COUNT	8
 #define GPIO_PINS_PER_REG	32
 #define GPIO_GENERIC_CAP	(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT |		\
@@ -74,6 +78,7 @@ __FBSDID("$FreeBSD$");
 #define DEBOUNCE_CHECK_TICKS	((hz / 1000) * DEBOUNCE_CHECK_MS)
 
 struct mv_gpio_softc {
+	device_t		dev;
 	device_t		sc_busdev;
 	struct resource	*	mem_res;
 	int			mem_rid;
@@ -83,6 +88,7 @@ struct mv_gpio_softc {
 	void			*ih_cookie[GPIO_MAX_INTR_COUNT];
 	bus_space_tag_t		bst;
 	bus_space_handle_t	bsh;
+	uint32_t		offset;
 	struct mtx		mutex;
 	uint8_t			pin_num;	/* number of GPIO pins */
 	uint8_t			irq_num;	/* number of real IRQs occupied by GPIO controller */
@@ -187,11 +193,15 @@ static driver_t mv_gpio_driver = {
 
 static devclass_t mv_gpio_devclass;
 
-DRIVER_MODULE(mv_gpio, simplebus, mv_gpio_driver, mv_gpio_devclass, 0, 0);
+EARLY_DRIVER_MODULE(mv_gpio, simplebus, mv_gpio_driver, mv_gpio_devclass, 0, 0,
+    BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST);
 
-struct ofw_compat_data gpio_controllers[] = {
-	{ "mrvl,gpio", (uintptr_t)true },
-	{ "marvell,orion-gpio", (uintptr_t)true },
+struct ofw_compat_data compat_data[] = {
+	{ "mrvl,gpio", 1 },
+	{ "marvell,orion-gpio", 1 },
+#ifdef SOC_MARVELL_8K
+	{ "marvell,armada-8k-gpio", 1 },
+#endif
 	{ NULL, 0 }
 };
 
@@ -201,7 +211,7 @@ mv_gpio_probe(device_t dev)
 	if (!ofw_bus_status_okay(dev))
 		return (ENXIO);
 
-	if (ofw_bus_search_compatible(dev, gpio_controllers)->ocd_data == 0)
+	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
 		return (ENXIO);
 
 	device_set_desc(dev, "Marvell Integrated GPIO Controller");
@@ -209,61 +219,75 @@ mv_gpio_probe(device_t dev)
 }
 
 static int
-mv_gpio_attach(device_t dev)
+mv_gpio_setup_interrupts(struct mv_gpio_softc *sc, phandle_t node)
 {
-	int i, size;
-	struct mv_gpio_softc *sc;
-	pcell_t pincnt = 0;
-	pcell_t irq_cells = 0;
 	phandle_t iparent;
+	pcell_t irq_cells;
+	int i, size;
 
-	sc = (struct mv_gpio_softc *)device_get_softc(dev);
-	if (sc == NULL)
-		return (ENXIO);
-
-	if (OF_getencprop(ofw_bus_get_node(dev), "pin-count", &pincnt,
-	    sizeof(pcell_t)) >= 0 ||
-	    OF_getencprop(ofw_bus_get_node(dev), "ngpios", &pincnt,
-	    sizeof(pcell_t)) >= 0) {
-		sc->pin_num = MIN(pincnt, MV_GPIO_MAX_NPINS);
-		if (bootverbose)
-			device_printf(dev, "%d pins available\n", sc->pin_num);
-	} else {
-		device_printf(dev, "ERROR: no pin-count or ngpios entry found!\n");
-		return (ENXIO);
-	}
-
-	/* Assign generic capabilities to every gpio pin */
-	for(i = 0; i < sc->pin_num; i++)
-		sc->gpio_setup[i].gp_caps = GPIO_GENERIC_CAP;
-
 	/* Find root interrupt controller */
-	iparent = ofw_bus_find_iparent(ofw_bus_get_node(dev));
+	iparent = ofw_bus_find_iparent(node);
 	if (iparent == 0) {
-		device_printf(dev, "No interrupt-parrent found. "
+		device_printf(sc->dev, "No interrupt-parrent found. "
 				"Error in DTB\n");
 		return (ENXIO);
 	} else {
 		/* While at parent - store interrupt cells prop */
 		if (OF_searchencprop(OF_node_from_xref(iparent),
 		    "#interrupt-cells", &irq_cells, sizeof(irq_cells)) == -1) {
-			device_printf(dev, "DTB: Missing #interrupt-cells "
+			device_printf(sc->dev, "DTB: Missing #interrupt-cells "
 			    "property in interrupt parent node\n");
 			return (ENXIO);
 		}
 	}
 
-	size = OF_getproplen(ofw_bus_get_node(dev), "interrupts");
+	size = OF_getproplen(node, "interrupts");
 	if (size != -1) {
 		size = size / sizeof(pcell_t);
 		size = size / irq_cells;
 		sc->irq_num = size;
-		device_printf(dev, "%d IRQs available\n", sc->irq_num);
+		device_printf(sc->dev, "%d IRQs available\n", sc->irq_num);
 	} else {
-		device_printf(dev, "ERROR: no interrupts entry found!\n");
+		device_printf(sc->dev, "ERROR: no interrupts entry found!\n");
 		return (ENXIO);
 	}
 
+	for (i = 0; i < sc->irq_num; i++) {
+		sc->irq_rid[i] = i;
+		sc->irq_res[i] = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ,
+			&sc->irq_rid[i], RF_ACTIVE);
+		if (!sc->irq_res[i]) {
+			mtx_destroy(&sc->mutex);
+			device_printf(sc->dev,
+			    "could not allocate gpio%d interrupt\n", i+1);
+			return (ENXIO);
+		}
+	}
+
+	device_printf(sc->dev, "Disable interrupts (offset = %x + EDGE(0x18)\n", sc->offset);
+	/* Disable all interrupts */
+	bus_space_write_4(sc->bst, sc->bsh, sc->offset + GPIO_INT_EDGE_MASK, 0);
+	device_printf(sc->dev, "Disable interrupts (offset = %x + LEV(0x1C))\n", sc->offset);
+	bus_space_write_4(sc->bst, sc->bsh, sc->offset + GPIO_INT_LEV_MASK, 0);
+
+	for (i = 0; i < sc->irq_num; i++) {
+		device_printf(sc->dev, "Setup intr %d\n", i);
+		if (bus_setup_intr(sc->dev, sc->irq_res[i],
+		    INTR_TYPE_MISC,
+		    (driver_filter_t *)mv_gpio_intr, NULL,
+		    sc, &sc->ih_cookie[i]) != 0) {
+			mtx_destroy(&sc->mutex);
+			bus_release_resource(sc->dev, SYS_RES_IRQ,
+				sc->irq_rid[i], sc->irq_res[i]);
+			device_printf(sc->dev, "could not set up intr %d\n", i);
+			return (ENXIO);
+		}
+	}
+
+	/* Clear interrupt status. */
+	device_printf(sc->dev, "Clear int status (offset = %x)\n", sc->offset);
+	bus_space_write_4(sc->bst, sc->bsh, sc->offset + GPIO_INT_CAUSE, 0);
+
 	sc->debounce_callouts = (struct callout **)malloc(sc->pin_num *
 	    sizeof(struct callout *), M_DEVBUF, M_WAITOK | M_ZERO);
 	if (sc->debounce_callouts == NULL)
@@ -274,11 +298,46 @@ mv_gpio_attach(device_t dev)
 	if (sc->debounce_counters == NULL)
 		return (ENOMEM);
 
+	return (0);
+}
+
+static int
+mv_gpio_attach(device_t dev)
+{
+	int i, rv;
+	struct mv_gpio_softc *sc;
+	phandle_t node;
+	pcell_t pincnt = 0;
+
+	sc = (struct mv_gpio_softc *)device_get_softc(dev);
+	if (sc == NULL)
+		return (ENXIO);
+
+	node = ofw_bus_get_node(dev);
+	sc->dev = dev;
+
+	if (OF_getencprop(node, "pin-count", &pincnt, sizeof(pcell_t)) >= 0 ||
+	    OF_getencprop(node, "ngpios", &pincnt, sizeof(pcell_t)) >= 0) {
+		sc->pin_num = MIN(pincnt, MV_GPIO_MAX_NPINS);
+		if (bootverbose)
+			device_printf(dev, "%d pins available\n", sc->pin_num);
+	} else {
+		device_printf(dev, "ERROR: no pin-count or ngpios entry found!\n");
+		return (ENXIO);
+	}
+
+	if (OF_getencprop(node, "offset", &sc->offset, sizeof(sc->offset)) == -1)
+		sc->offset = 0;
+
+	/* Assign generic capabilities to every gpio pin */
+	for(i = 0; i < sc->pin_num; i++)
+		sc->gpio_setup[i].gp_caps = GPIO_GENERIC_CAP;
+
 	mtx_init(&sc->mutex, device_get_nameunit(dev), NULL, MTX_SPIN);
 
 	sc->mem_rid = 0;
 	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid,
-		 RF_ACTIVE);
+		 RF_ACTIVE | RF_SHAREABLE );
 
 	if (!sc->mem_res) {
 		mtx_destroy(&sc->mutex);
@@ -289,38 +348,10 @@ mv_gpio_attach(device_t dev)
 	sc->bst = rman_get_bustag(sc->mem_res);
 	sc->bsh = rman_get_bushandle(sc->mem_res);
 
-	for (i = 0; i < sc->irq_num; i++) {
-		sc->irq_rid[i] = i;
-		sc->irq_res[i] = bus_alloc_resource_any(dev, SYS_RES_IRQ,
-			&sc->irq_rid[i], RF_ACTIVE);
-		if (!sc->irq_res[i]) {
-			mtx_destroy(&sc->mutex);
-			device_printf(dev,
-			    "could not allocate gpio%d interrupt\n", i+1);
-			return (ENXIO);
-		}
-	}
+	rv = mv_gpio_setup_interrupts(sc, node);
+	if (rv != 0)
+		return (rv);
 
-	/* Disable all interrupts */
-	bus_space_write_4(sc->bst, sc->bsh, GPIO_INT_EDGE_MASK, 0);
-	bus_space_write_4(sc->bst, sc->bsh, GPIO_INT_LEV_MASK, 0);
-
-	for (i = 0; i < sc->irq_num; i++) {
-		if (bus_setup_intr(dev, sc->irq_res[i],
-		    INTR_TYPE_MISC,
-		    (driver_filter_t *)mv_gpio_intr, NULL,
-		    sc, &sc->ih_cookie[i]) != 0) {
-			mtx_destroy(&sc->mutex);
-			bus_release_resource(dev, SYS_RES_IRQ,
-				sc->irq_rid[i], sc->irq_res[i]);
-			device_printf(dev, "could not set up intr %d\n", i);
-			return (ENXIO);
-		}
-	}
-
-	/* Clear interrupt status. */
-	bus_space_write_4(sc->bst, sc->bsh, GPIO_INT_CAUSE, 0);
-
 	sc->sc_busdev = gpiobus_attach_bus(dev);
 	if (sc->sc_busdev == NULL) {
 		mtx_destroy(&sc->mutex);
@@ -540,6 +571,8 @@ mv_gpio_configure(device_t dev, uint32_t pin, uint32_t
 		return (EINVAL);
 
 	if (mask & MV_GPIO_IN_DEBOUNCE) {
+		if (sc->irq_num == 0)
+			return (EINVAL);
 		error = mv_gpio_debounce_prepare(dev, pin);
 		if (error != 0)
 			return (error);
@@ -845,7 +878,7 @@ mv_gpio_reg_read(device_t dev, uint32_t reg)
 	struct mv_gpio_softc *sc;
 	sc = (struct mv_gpio_softc *)device_get_softc(dev);
 
-	return (bus_space_read_4(sc->bst, sc->bsh, reg));
+	return (bus_space_read_4(sc->bst, sc->bsh, sc->offset + reg));
 }
 
 static void
@@ -854,7 +887,7 @@ mv_gpio_reg_write(device_t dev, uint32_t reg, uint32_t
 	struct mv_gpio_softc *sc;
 	sc = (struct mv_gpio_softc *)device_get_softc(dev);
 
-	bus_space_write_4(sc->bst, sc->bsh, reg, val);
+	bus_space_write_4(sc->bst, sc->bsh, sc->offset + reg, val);
 }
 
 static void

Copied: stable/12/sys/arm/mv/mv_ap806_clock.c (from r342020, head/sys/arm/mv/mv_ap806_clock.c)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ stable/12/sys/arm/mv/mv_ap806_clock.c	Mon Aug  5 17:43:44 2019	(r350600, copy of r342020, head/sys/arm/mv/mv_ap806_clock.c)
@@ -0,0 +1,210 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2018 Rubicon Communications, LLC (Netgate)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+
+#include <dev/fdt/simplebus.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/extres/clk/clk_fixed.h>
+
+static struct clk_fixed_def ap806_clk_cluster_0 = {
+	.clkdef.id = 0,
+	.clkdef.name = "ap806-cpu-cluster-0",
+	.freq = 0,
+};
+
+static struct clk_fixed_def ap806_clk_cluster_1 = {
+	.clkdef.id = 1,
+	.clkdef.name = "ap806-cpu-cluster-1",
+	.freq = 0,
+};
+
+static struct clk_fixed_def ap806_clk_fixed = {
+	.clkdef.id = 2,
+	.clkdef.name = "ap806-fixed",
+	.freq = 1200000000,
+};
+
+/* Thoses are the only exported clocks AFAICT */
+
+static const char *mss_parents[] = {"ap806-fixed"};
+static struct clk_fixed_def ap806_clk_mss = {
+	.clkdef.id = 3,
+	.clkdef.name = "ap806-mss",
+	.clkdef.parent_names = mss_parents,
+	.clkdef.parent_cnt = 1,
+	.mult = 1,
+	.div = 6,
+};
+
+static const char *sdio_parents[] = {"ap806-fixed"};
+static struct clk_fixed_def ap806_clk_sdio = {
+	.clkdef.id = 4,
+	.clkdef.name = "ap806-sdio",
+	.clkdef.parent_names = sdio_parents,
+	.clkdef.parent_cnt = 1,
+	.mult = 1,
+	.div = 3,
+};
+
+struct mv_ap806_clock_softc {
+	struct simplebus_softc	simplebus_sc;
+	device_t		dev;
+	struct resource		*res;
+};
+
+static struct resource_spec mv_ap806_clock_res_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE | RF_SHAREABLE },
+	{ -1, 0 }
+};
+
+static struct ofw_compat_data compat_data[] = {
+	{"marvell,ap806-clock", 1},
+	{NULL,             0}
+};
+
+#define	RD4(sc, reg)		bus_read_4((sc)->res, (reg))
+#define	WR4(sc, reg, val)	bus_write_4((sc)->res, (reg), (val))
+
+static int
+mv_ap806_clock_probe(device_t dev)
+{
+
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+		return (ENXIO);
+
+	device_set_desc(dev, "Marvell AP806 Clock Controller");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+mv_ap806_clock_attach(device_t dev)
+{
+	struct mv_ap806_clock_softc *sc;
+	struct clkdom *clkdom;
+	uint64_t clock_freq;
+	uint32_t reg;
+
+	sc = device_get_softc(dev);
+	sc->dev = dev;
+
+	if (bus_alloc_resources(dev, mv_ap806_clock_res_spec, &sc->res) != 0) {
+		device_printf(dev, "cannot allocate resources for device\n");
+		return (ENXIO);
+	}
+
+	/* 
+	 * We might miss some combinations
+	 * Those are the only possible ones on the mcbin
+	 */
+	reg = RD4(sc, 0x400);
+	switch (reg & 0x1f) {
+	case 0x0:
+	case 0x1:
+		clock_freq = 2000000000;
+		break;
+	case 0x6:
+		clock_freq = 1800000000;
+		break;
+	case 0xd:
+		clock_freq = 1600000000;
+		break;
+	case 0x14:
+		clock_freq = 1333000000;
+		break;
+	default:
+		device_printf(dev, "Cannot guess clock freq with reg %x\n", reg & 0x1f);
+		return (ENXIO);
+		break;
+	};
+
+	ap806_clk_cluster_0.freq = clock_freq;
+	ap806_clk_cluster_1.freq = clock_freq;
+	clkdom = clkdom_create(dev);
+
+	clknode_fixed_register(clkdom, &ap806_clk_cluster_0);
+	clknode_fixed_register(clkdom, &ap806_clk_cluster_1);
+	clknode_fixed_register(clkdom, &ap806_clk_fixed);
+	clknode_fixed_register(clkdom, &ap806_clk_mss);
+	clknode_fixed_register(clkdom, &ap806_clk_sdio);
+
+	clkdom_finit(clkdom);
+
+	if (bootverbose)
+		clkdom_dump(clkdom);
+	return (0);
+}
+
+static int
+mv_ap806_clock_detach(device_t dev)
+{
+
+	return (EBUSY);
+}
+
+static device_method_t mv_ap806_clock_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		mv_ap806_clock_probe),
+	DEVMETHOD(device_attach,	mv_ap806_clock_attach),
+	DEVMETHOD(device_detach,	mv_ap806_clock_detach),
+
+	DEVMETHOD_END
+};
+
+static devclass_t mv_ap806_clock_devclass;
+
+static driver_t mv_ap806_clock_driver = {
+	"mv_ap806_clock",
+	mv_ap806_clock_methods,
+	sizeof(struct mv_ap806_clock_softc),
+};
+
+EARLY_DRIVER_MODULE(mv_ap806_clock, simplebus, mv_ap806_clock_driver,
+    mv_ap806_clock_devclass, 0, 0, BUS_PASS_RESOURCE + BUS_PASS_ORDER_LATE);

Copied: stable/12/sys/arm/mv/mv_ap806_gicp.c (from r342020, head/sys/arm/mv/mv_ap806_gicp.c)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ stable/12/sys/arm/mv/mv_ap806_gicp.c	Mon Aug  5 17:43:44 2019	(r350600, copy of r342020, head/sys/arm/mv/mv_ap806_gicp.c)
@@ -0,0 +1,289 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2018 Rubicon Communications, LLC (Netgate)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+
+#include <dev/fdt/simplebus.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "pic_if.h"
+
+#define	MV_AP806_GICP_MAX_NIRQS	207
+
+struct mv_ap806_gicp_softc {
+	device_t		dev;
+	device_t		parent;
+	struct resource		*res;
+
+	ssize_t			spi_ranges_cnt;
+	uint32_t		*spi_ranges;
+};
+
+static struct ofw_compat_data compat_data[] = {
+	{"marvell,ap806-gicp", 1},
+	{NULL,             0}
+};
+
+#define	RD4(sc, reg)		bus_read_4((sc)->res, (reg))
+#define	WR4(sc, reg, val)	bus_write_4((sc)->res, (reg), (val))
+
+static int
+mv_ap806_gicp_probe(device_t dev)
+{
+
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+		return (ENXIO);
+
+	device_set_desc(dev, "Marvell GICP");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+mv_ap806_gicp_attach(device_t dev)
+{
+	struct mv_ap806_gicp_softc *sc;
+	phandle_t node, xref, intr_parent;
+
+	sc = device_get_softc(dev);
+	sc->dev = dev;
+	node = ofw_bus_get_node(dev);
+
+	/* Look for our parent */
+	if ((intr_parent = ofw_bus_find_iparent(node)) == 0) {
+		device_printf(dev, "Cannot find our parent interrupt controller\n");
+		return (ENXIO);
+	}
+	if ((sc->parent = OF_device_from_xref(intr_parent)) == NULL) {
+		device_printf(dev, "cannot find parent interrupt controller device\n");
+		return (ENXIO);
+	}
+
+	sc->spi_ranges_cnt = OF_getencprop_alloc(node, "marvell,spi-ranges",
+	    (void **)&sc->spi_ranges);
+
+	xref = OF_xref_from_node(node);
+	if (intr_pic_register(dev, xref) == NULL) {
+		device_printf(dev, "Cannot register GICP\n");
+		return (ENXIO);
+	}
+
+	OF_device_register_xref(xref, dev);
+
+	return (0);
+}
+
+static int
+mv_ap806_gicp_detach(device_t dev)
+{
+
+	return (EBUSY);
+}
+
+static int
+mv_ap806_gicp_activate_intr(device_t dev, struct intr_irqsrc *isrc,
+    struct resource *res, struct intr_map_data *data)
+{
+	struct mv_ap806_gicp_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	return (PIC_ACTIVATE_INTR(sc->parent, isrc, res, data));
+}
+
+static void
+mv_ap806_gicp_enable_intr(device_t dev, struct intr_irqsrc *isrc)
+{
+	struct mv_ap806_gicp_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	PIC_ENABLE_INTR(sc->parent, isrc);
+}
+
+static void
+mv_ap806_gicp_disable_intr(device_t dev, struct intr_irqsrc *isrc)
+{
+	struct mv_ap806_gicp_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	PIC_DISABLE_INTR(sc->parent, isrc);
+}
+
+static int
+mv_ap806_gicp_map_intr(device_t dev, struct intr_map_data *data,
+    struct intr_irqsrc **isrcp)
+{
+	struct mv_ap806_gicp_softc *sc;
+	struct intr_map_data_fdt *daf;
+	uint32_t group, irq_num, irq_type;
+	int i;
+
+	sc = device_get_softc(dev);
+
+	if (data->type != INTR_MAP_DATA_FDT)
+		return (ENOTSUP);
+
+	daf = (struct intr_map_data_fdt *)data;
+	if (daf->ncells != 3 || daf->cells[0] >= MV_AP806_GICP_MAX_NIRQS)
+		return (EINVAL);
+
+	group = daf->cells[0];
+	irq_num = daf->cells[1];
+	irq_type = daf->cells[2];
+
+	/* Map the interrupt number to spi number */
+	for (i = 0; i < sc->spi_ranges_cnt / 2; i += 2) {
+		if (irq_num < sc->spi_ranges[i + 1]) {
+			irq_num += sc->spi_ranges[i];
+			break;
+		}
+
+		irq_num -= sc->spi_ranges[i];
+	}
+
+	daf->cells[1] = irq_num - 32;
+
+	return (PIC_MAP_INTR(sc->parent, data, isrcp));
+}
+
+static int
+mv_ap806_gicp_deactivate_intr(device_t dev, struct intr_irqsrc *isrc,
+    struct resource *res, struct intr_map_data *data)
+{
+	struct mv_ap806_gicp_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	return (PIC_DEACTIVATE_INTR(sc->parent, isrc, res, data));
+}
+
+static int
+mv_ap806_gicp_setup_intr(device_t dev, struct intr_irqsrc *isrc,
+    struct resource *res, struct intr_map_data *data)
+{
+	struct mv_ap806_gicp_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	return (PIC_SETUP_INTR(sc->parent, isrc, res, data));
+}
+
+static int
+mv_ap806_gicp_teardown_intr(device_t dev, struct intr_irqsrc *isrc,
+    struct resource *res, struct intr_map_data *data)
+{
+	struct mv_ap806_gicp_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	return (PIC_TEARDOWN_INTR(sc->parent, isrc, res, data));
+}
+
+static void
+mv_ap806_gicp_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
+{
+	struct mv_ap806_gicp_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	PIC_PRE_ITHREAD(sc->parent, isrc);
+}
+
+static void
+mv_ap806_gicp_post_ithread(device_t dev, struct intr_irqsrc *isrc)
+{
+	struct mv_ap806_gicp_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	PIC_POST_ITHREAD(sc->parent, isrc);
+}
+
+static void
+mv_ap806_gicp_post_filter(device_t dev, struct intr_irqsrc *isrc)
+{
+	struct mv_ap806_gicp_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	PIC_POST_FILTER(sc->parent, isrc);
+}
+
+static device_method_t mv_ap806_gicp_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		mv_ap806_gicp_probe),
+	DEVMETHOD(device_attach,	mv_ap806_gicp_attach),
+	DEVMETHOD(device_detach,	mv_ap806_gicp_detach),
+
+	/* Interrupt controller interface */
+	DEVMETHOD(pic_activate_intr,	mv_ap806_gicp_activate_intr),
+	DEVMETHOD(pic_disable_intr,	mv_ap806_gicp_disable_intr),
+	DEVMETHOD(pic_enable_intr,	mv_ap806_gicp_enable_intr),
+	DEVMETHOD(pic_map_intr,		mv_ap806_gicp_map_intr),
+	DEVMETHOD(pic_deactivate_intr,	mv_ap806_gicp_deactivate_intr),
+	DEVMETHOD(pic_setup_intr,	mv_ap806_gicp_setup_intr),
+	DEVMETHOD(pic_teardown_intr,	mv_ap806_gicp_teardown_intr),
+	DEVMETHOD(pic_post_filter,	mv_ap806_gicp_post_filter),
+	DEVMETHOD(pic_post_ithread,	mv_ap806_gicp_post_ithread),
+	DEVMETHOD(pic_pre_ithread,	mv_ap806_gicp_pre_ithread),
+
+	DEVMETHOD_END
+};
+
+static devclass_t mv_ap806_gicp_devclass;
+
+static driver_t mv_ap806_gicp_driver = {
+	"mv_ap806_gicp",
+	mv_ap806_gicp_methods,
+	sizeof(struct mv_ap806_gicp_softc),
+};
+
+EARLY_DRIVER_MODULE(mv_ap806_gicp, simplebus, mv_ap806_gicp_driver,
+    mv_ap806_gicp_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);

Copied: stable/12/sys/arm/mv/mv_cp110_clock.c (from r342020, head/sys/arm/mv/mv_cp110_clock.c)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ stable/12/sys/arm/mv/mv_cp110_clock.c	Mon Aug  5 17:43:44 2019	(r350600, copy of r342020, head/sys/arm/mv/mv_cp110_clock.c)
@@ -0,0 +1,375 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2018 Rubicon Communications, LLC (Netgate)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+
+#include <dev/fdt/simplebus.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/extres/clk/clk_fixed.h>
+#include <dev/extres/clk/clk_gate.h>
+
+#include <arm/mv/mv_cp110_clock.h>
+
+#include "clkdev_if.h"
+
+/* Clocks */
+static struct clk_fixed_def cp110_clk_pll_0 = {
+	.clkdef.id = CP110_PLL_0,
+	.freq = 1000000000,
+};
+
+static const char *clk_parents_0[] = {"cp110-pll0-0"};
+static const char *clk_parents_1[] = {"cp110-pll0-1"};
+
+static struct clk_fixed_def cp110_clk_ppv2_core = {
+	.clkdef.id = CP110_PPV2_CORE,
+	.clkdef.parent_cnt = 1,
+	.mult = 1,
+	.div = 3,
+};
+
+static struct clk_fixed_def cp110_clk_x2core = {
+	.clkdef.id = CP110_X2CORE,
+	.clkdef.parent_cnt = 1,
+	.mult = 1,
+	.div = 2,
+};
+
+static const char *core_parents_0[] = {"cp110-x2core-0"};
+static const char *core_parents_1[] = {"cp110-x2core-1"};
+
+static struct clk_fixed_def cp110_clk_core = {
+	.clkdef.id = CP110_CORE,
+	.clkdef.parent_cnt = 1,
+	.mult = 1,
+	.div = 2,
+};
+
+static struct clk_fixed_def cp110_clk_sdio = {
+	.clkdef.id = CP110_SDIO,
+	.clkdef.parent_cnt = 1,
+	.mult = 2,
+	.div = 5,
+};
+
+/* Gates */
+
+static struct cp110_gate cp110_gates[] = {
+	CCU_GATE(CP110_GATE_AUDIO, "cp110-gate-audio", 0)
+	CCU_GATE(CP110_GATE_COMM_UNIT, "cp110-gate-comm_unit", 1)
+	/* CCU_GATE(CP110_GATE_NAND, "cp110-gate-nand", 2) */
+	CCU_GATE(CP110_GATE_PPV2, "cp110-gate-ppv2", 3)
+	CCU_GATE(CP110_GATE_SDIO, "cp110-gate-sdio", 4)
+	CCU_GATE(CP110_GATE_MG, "cp110-gate-mg", 5)
+	CCU_GATE(CP110_GATE_MG_CORE, "cp110-gate-mg_core", 6)
+	CCU_GATE(CP110_GATE_XOR1, "cp110-gate-xor1", 7)
+	CCU_GATE(CP110_GATE_XOR0, "cp110-gate-xor0", 8)
+	CCU_GATE(CP110_GATE_GOP_DP, "cp110-gate-gop_dp", 9)
+	CCU_GATE(CP110_GATE_PCIE_X1_0, "cp110-gate-pcie_x10", 11)
+	CCU_GATE(CP110_GATE_PCIE_X1_1, "cp110-gate-pcie_x11", 12)
+	CCU_GATE(CP110_GATE_PCIE_X4, "cp110-gate-pcie_x4", 13)
+	CCU_GATE(CP110_GATE_PCIE_XOR, "cp110-gate-pcie_xor", 14)
+	CCU_GATE(CP110_GATE_SATA, "cp110-gate-sata", 15)
+	CCU_GATE(CP110_GATE_SATA_USB, "cp110-gate-sata_usb", 16)
+	CCU_GATE(CP110_GATE_MAIN, "cp110-gate-main", 17)
+	CCU_GATE(CP110_GATE_SDMMC_GOP, "cp110-gate-sdmmc_gop", 18)
+	CCU_GATE(CP110_GATE_SLOW_IO, "cp110-gate-slow_io", 21)
+	CCU_GATE(CP110_GATE_USB3H0, "cp110-gate-usb3h0", 22)
+	CCU_GATE(CP110_GATE_USB3H1, "cp110-gate-usb3h1", 23)
+	CCU_GATE(CP110_GATE_USB3DEV, "cp110-gate-usb3dev", 24)
+	CCU_GATE(CP110_GATE_EIP150, "cp110-gate-eip150", 25)
+	CCU_GATE(CP110_GATE_EIP197, "cp110-gate-eip197", 26)
+};
+
+struct mv_cp110_clock_softc {
+	struct simplebus_softc	simplebus_sc;
+	device_t		dev;
+	struct resource		*res;
+	struct mtx		mtx;
+};
+
+static struct resource_spec mv_cp110_clock_res_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE | RF_SHAREABLE },
+	{ -1, 0 }
+};
+
+static struct ofw_compat_data compat_data[] = {
+	{"marvell,cp110-clock", 1},
+	{NULL,             0}
+};
+
+#define	RD4(sc, reg)		bus_read_4((sc)->res, (reg))
+#define	WR4(sc, reg, val)	bus_write_4((sc)->res, (reg), (val))
+
+static char *
+mv_cp110_clock_name(device_t dev, const char *name)
+{
+	char *clkname = NULL;
+	int unit;
+
+	unit = device_get_unit(dev);
+	if (asprintf(&clkname, M_DEVBUF, "%s-%d", name, unit) <= 0)
+		panic("Cannot generate unique clock name for %s\n", name);
+	return (clkname);
+}
+
+static int
+mv_cp110_clock_probe(device_t dev)
+{
+
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+		return (ENXIO);
+
+	device_set_desc(dev, "Marvell CP110 Clock Controller");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+cp110_ofw_map(struct clkdom *clkdom, uint32_t ncells,
+    phandle_t *cells, struct clknode **clk)
+{
+	int id = 0;
+
+	if (ncells != 2)
+		return (ENXIO);
+
+	id = cells[1];
+	if (cells[0] == 1)
+		id += CP110_MAX_CLOCK;
+
+	*clk = clknode_find_by_id(clkdom, id);
+
+	return (0);
+}
+
+static int
+mv_cp110_clock_attach(device_t dev)
+{
+	struct mv_cp110_clock_softc *sc;
+	struct clkdom *clkdom;
+	struct clk_gate_def def;
+	char *pll0_name;
+	int unit, i;
+
+	sc = device_get_softc(dev);
+	sc->dev = dev;
+
+	if (bus_alloc_resources(dev, mv_cp110_clock_res_spec, &sc->res) != 0) {
+		device_printf(dev, "cannot allocate resources for device\n");
+		return (ENXIO);
+	}
+
+	unit = device_get_unit(dev);
+	if (unit > 1) {

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201908051743.x75HhjS9098115>