svn commit: r350600 - in stable/12/sys: arm/mv arm64/conf conf dev/fdt dev/iicbus/twsi dev/sdhci
Emmanuel Vadot
manu at FreeBSD.org
Mon Aug 5 17:43:46 UTC 2019
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 ***
More information about the svn-src-stable-12
mailing list