git: e90347891960 - main - ARM64: Port FreeBSD to Nvidia Jetson TX1 and Nano.

Michal Meloun mmel at FreeBSD.org
Mon Dec 28 13:19:09 UTC 2020


The branch main has been updated by mmel:

URL: https://cgit.FreeBSD.org/src/commit/?id=e903478919602c90fdc202a8628b89eb7c3bc104

commit e903478919602c90fdc202a8628b89eb7c3bc104
Author:     Michal Meloun <mmel at FreeBSD.org>
AuthorDate: 2018-01-04 12:18:24 +0000
Commit:     Michal Meloun <mmel at FreeBSD.org>
CommitDate: 2020-12-28 13:12:41 +0000

    ARM64: Port FreeBSD to Nvidia Jetson TX1 and Nano.
    
    Add support for the Tergra210 SoC and its companion PMIC MAX77620.
---
 sys/arm64/nvidia/tegra210/max77620.c            |  511 ++++++
 sys/arm64/nvidia/tegra210/max77620.h            |  262 +++
 sys/arm64/nvidia/tegra210/max77620_gpio.c       |  715 +++++++++
 sys/arm64/nvidia/tegra210/max77620_regulators.c |  888 ++++++++++
 sys/arm64/nvidia/tegra210/max77620_rtc.c        |  413 +++++
 sys/arm64/nvidia/tegra210/tegra210_car.c        |  601 +++++++
 sys/arm64/nvidia/tegra210/tegra210_car.h        |  528 ++++++
 sys/arm64/nvidia/tegra210/tegra210_clk_per.c    |  951 +++++++++++
 sys/arm64/nvidia/tegra210/tegra210_clk_pll.c    | 1494 +++++++++++++++++
 sys/arm64/nvidia/tegra210/tegra210_clk_super.c  |  231 +++
 sys/arm64/nvidia/tegra210/tegra210_coretemp.c   |  272 ++++
 sys/arm64/nvidia/tegra210/tegra210_cpufreq.c    |  502 ++++++
 sys/arm64/nvidia/tegra210/tegra210_pinmux.c     |  758 +++++++++
 sys/arm64/nvidia/tegra210/tegra210_pmc.c        |  628 ++++++++
 sys/arm64/nvidia/tegra210/tegra210_xusbpadctl.c | 1963 +++++++++++++++++++++++
 sys/conf/files.arm64                            |   48 +
 sys/conf/options.arm64                          |    1 +
 sys/gnu/dts/arm64/nvidia/Makefile               |    7 +
 18 files changed, 10773 insertions(+)

diff --git a/sys/arm64/nvidia/tegra210/max77620.c b/sys/arm64/nvidia/tegra210/max77620.c
new file mode 100644
index 000000000000..d46417ce0e28
--- /dev/null
+++ b/sys/arm64/nvidia/tegra210/max77620.c
@@ -0,0 +1,511 @@
+/*-
+ * Copyright (c) 2019 Michal Meloun <mmel at FreeBSD.org>
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * MAX77620 PMIC driver
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/gpio.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+#include <sys/sx.h>
+
+#include <machine/bus.h>
+
+#include <dev/extres/regulator/regulator.h>
+#include <dev/fdt/fdt_pinctrl.h>
+#include <dev/gpio/gpiobusvar.h>
+#include <dev/iicbus/iiconf.h>
+#include <dev/iicbus/iicbus.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <gnu/dts/include/dt-bindings/mfd/max77620.h>
+
+#include "clock_if.h"
+#include "regdev_if.h"
+
+#include "max77620.h"
+
+static struct ofw_compat_data compat_data[] = {
+	{"maxim,max77620",	1},
+	{NULL,			0},
+};
+
+#define	LOCK(_sc)		sx_xlock(&(_sc)->lock)
+#define	UNLOCK(_sc)		sx_xunlock(&(_sc)->lock)
+#define	LOCK_INIT(_sc)		sx_init(&(_sc)->lock, "max77620")
+#define	LOCK_DESTROY(_sc)	sx_destroy(&(_sc)->lock);
+#define	ASSERT_LOCKED(_sc)	sx_assert(&(_sc)->lock, SA_XLOCKED);
+#define	ASSERT_UNLOCKED(_sc)	sx_assert(&(_sc)->lock, SA_UNLOCKED);
+
+#define	MAX77620_DEVICE_ID	0x0C
+
+/*
+ * Raw register access function.
+ */
+int
+max77620_read(struct max77620_softc *sc, uint8_t reg, uint8_t *val)
+{
+	uint8_t addr;
+	int rv;
+	struct iic_msg msgs[2] = {
+		{0, IIC_M_WR, 1, &addr},
+		{0, IIC_M_RD, 1, val},
+	};
+
+	msgs[0].slave = sc->bus_addr;
+	msgs[1].slave = sc->bus_addr;
+	addr = reg;
+
+	rv = iicbus_transfer(sc->dev, msgs, 2);
+	if (rv != 0) {
+		device_printf(sc->dev,
+		    "Error when reading reg 0x%02X, rv: %d\n", reg,  rv);
+		return (EIO);
+	}
+
+	return (0);
+}
+
+int max77620_read_buf(struct max77620_softc *sc, uint8_t reg, uint8_t *buf,
+    size_t size)
+{
+	uint8_t addr;
+	int rv;
+	struct iic_msg msgs[2] = {
+		{0, IIC_M_WR, 1, &addr},
+		{0, IIC_M_RD, size, buf},
+	};
+
+	msgs[0].slave = sc->bus_addr;
+	msgs[1].slave = sc->bus_addr;
+	addr = reg;
+
+	rv = iicbus_transfer(sc->dev, msgs, 2);
+	if (rv != 0) {
+		device_printf(sc->dev,
+		    "Error when reading reg 0x%02X, rv: %d\n", reg,  rv);
+		return (EIO);
+	}
+
+	return (0);
+}
+
+int
+max77620_write(struct max77620_softc *sc, uint8_t reg, uint8_t val)
+{
+	uint8_t data[2];
+	int rv;
+
+	struct iic_msg msgs[1] = {
+		{0, IIC_M_WR, 2, data},
+	};
+
+	msgs[0].slave = sc->bus_addr;
+	data[0] = reg;
+	data[1] = val;
+
+	rv = iicbus_transfer(sc->dev, msgs, 1);
+	if (rv != 0) {
+		device_printf(sc->dev,
+		    "Error when writing reg 0x%02X, rv: %d\n", reg, rv);
+		return (EIO);
+	}
+	return (0);
+}
+
+int
+max77620_write_buf(struct max77620_softc *sc, uint8_t reg, uint8_t *buf,
+    size_t size)
+{
+	uint8_t data[1];
+	int rv;
+	struct iic_msg msgs[2] = {
+		{0, IIC_M_WR, 1, data},
+		{0, IIC_M_WR | IIC_M_NOSTART, size, buf},
+	};
+
+	msgs[0].slave = sc->bus_addr;
+	msgs[1].slave = sc->bus_addr;
+	data[0] = reg;
+
+	rv = iicbus_transfer(sc->dev, msgs, 2);
+	if (rv != 0) {
+		device_printf(sc->dev,
+		    "Error when writing reg 0x%02X, rv: %d\n", reg, rv);
+		return (EIO);
+	}
+	return (0);
+}
+
+int
+max77620_modify(struct max77620_softc *sc, uint8_t reg, uint8_t clear,
+    uint8_t set)
+{
+	uint8_t val;
+	int rv;
+
+	rv = max77620_read(sc, reg, &val);
+	if (rv != 0)
+		return (rv);
+
+	val &= ~clear;
+	val |= set;
+
+	rv = max77620_write(sc, reg, val);
+	if (rv != 0)
+		return (rv);
+
+	return (0);
+}
+
+static int
+max77620_parse_fps(struct max77620_softc *sc, int id, phandle_t node)
+{
+	int val;
+
+	if (OF_getencprop(node, "maxim,shutdown-fps-time-period-us", &val,
+	    sizeof(val)) >= 0) {
+		val = min(val, MAX77620_FPS_PERIOD_MAX_US);
+		val = max(val, MAX77620_FPS_PERIOD_MIN_US);
+		sc->shutdown_fps[id] = val;
+	}
+	if (OF_getencprop(node, "maxim,suspend-fps-time-period-us", &val,
+	    sizeof(val)) >= 0) {
+		val = min(val, MAX77620_FPS_PERIOD_MAX_US);
+		val = max(val, MAX77620_FPS_PERIOD_MIN_US);
+		sc->suspend_fps[id] = val;
+	}
+	if (OF_getencprop(node, "maxim,fps-event-source", &val,
+	    sizeof(val)) >= 0) {
+		if (val > 2) {
+			device_printf(sc->dev, "Invalid 'fps-event-source' "
+			    "value: %d\n", val);
+			return (EINVAL);
+		}
+		sc->event_source[id] = val;
+	}
+	return (0);
+}
+
+static int
+max77620_parse_fdt(struct max77620_softc *sc, phandle_t node)
+{
+	 phandle_t fpsnode;
+	 char fps_name[6];
+	 int i, rv;
+
+	for (i = 0; i < MAX77620_FPS_COUNT; i++) {
+		sc->shutdown_fps[i] = -1;
+		sc->suspend_fps[i] = -1;
+		sc->event_source[i] = -1;
+	}
+
+	fpsnode = ofw_bus_find_child(node, "fps");
+	if (fpsnode > 0) {
+		for (i = 0; i < MAX77620_FPS_COUNT; i++) {
+			sprintf(fps_name, "fps%d", i);
+			node = ofw_bus_find_child(node, fps_name);
+			if (node <= 0)
+				continue;
+			rv = max77620_parse_fps(sc, i, node);
+			if (rv != 0)
+				return (rv);
+		}
+	}
+	return (0);
+}
+
+static int
+max77620_get_version(struct max77620_softc *sc)
+{
+	uint8_t buf[6];
+	int i;
+	int rv;
+
+	/* Verify ID string (5 bytes ). */
+	for (i = 0; i <= 6; i++) {
+		rv = RD1(sc, MAX77620_REG_CID0 + i , buf + i);
+		if (rv != 0) {
+			device_printf(sc->dev, "Cannot read chip ID: %d\n", rv);
+			return (ENXIO);
+		}
+	}
+	if (bootverbose) {
+		device_printf(sc->dev,
+		    " ID: [0x%02X, 0x%02X, 0x%02X, 0x%02X]\n",
+		    buf[0], buf[1], buf[2], buf[3]);
+	}
+	device_printf(sc->dev, " MAX77620 version - OTP: 0x%02X, ES: 0x%02X\n",
+	    buf[4], buf[5]);
+
+	return (0);
+}
+
+static uint8_t
+max77620_encode_fps_period(struct max77620_softc *sc, int val)
+{
+	uint8_t i;
+	int period;
+
+	period = MAX77620_FPS_PERIOD_MIN_US;
+	for (i = 0; i < 7; i++) {
+		if (period >= val)
+			return (i);
+		period *= 2;
+	}
+	return (i);
+}
+
+static int
+max77620_init(struct max77620_softc *sc)
+{
+	uint8_t mask, val, tmp;;
+	int i, rv;
+
+	mask = 0;
+	val = 0;
+	for (i = 0; i < MAX77620_FPS_COUNT; i++) {
+		if (sc->shutdown_fps[i] != -1) {
+			mask |= MAX77620_FPS_TIME_PERIOD_MASK;
+			tmp  = max77620_encode_fps_period(sc,
+			    sc->shutdown_fps[i]);
+			val |= (tmp << MAX77620_FPS_TIME_PERIOD_SHIFT) &
+			    MAX77620_FPS_TIME_PERIOD_MASK;
+		}
+
+		if (sc->event_source[i] != -1) {
+			mask |= MAX77620_FPS_EN_SRC_MASK;
+			tmp = sc->event_source[i];
+			val |= (tmp << MAX77620_FPS_EN_SRC_SHIFT) &
+			    MAX77620_FPS_EN_SRC_MASK;
+			if (sc->event_source[i] == 2) {
+				mask |= MAX77620_FPS_ENFPS_SW_MASK;
+				val |= MAX77620_FPS_ENFPS_SW;
+			}
+
+		}
+		rv = RM1(sc, MAX77620_REG_FPS_CFG0 + i, mask, val);
+		if (rv != 0) {
+			device_printf(sc->dev, "I/O error: %d\n", rv);
+			return (ENXIO);
+		}
+	}
+
+	/* Global mask interrupts */
+	rv = RM1(sc, MAX77620_REG_INTENLBT, 0x81, 0x81);
+	rv = RM1(sc, MAX77620_REG_IRQTOPM, 0x81, 0x81);
+	if (rv != 0)
+		return (ENXIO);
+	return (0);
+}
+#ifdef notyet
+static void
+max77620_intr(void *arg)
+{
+	struct max77620_softc *sc;
+	uint8_t intenlbt, intlbt, irqtop, irqtopm, irqsd, irqmasksd;
+	uint8_t irq_lvl2_l0_7, irq_lvl2_l8, irq_lvl2_gpio, irq_msk_l0_7, irq_msk_l8;
+	uint8_t onoffirq, onoffirqm;
+
+	sc = (struct max77620_softc *)arg;
+	/* XXX Finish temperature alarms. */
+	RD1(sc, MAX77620_REG_INTENLBT, &intenlbt);
+	RD1(sc, MAX77620_REG_INTLBT, &intlbt);
+
+	RD1(sc, MAX77620_REG_IRQTOP, &irqtop);
+	RD1(sc, MAX77620_REG_IRQTOPM, &irqtopm);
+	RD1(sc, MAX77620_REG_IRQSD, &irqsd);
+	RD1(sc, MAX77620_REG_IRQMASKSD, &irqmasksd);
+	RD1(sc, MAX77620_REG_IRQ_LVL2_L0_7, &irq_lvl2_l0_7);
+	RD1(sc, MAX77620_REG_IRQ_MSK_L0_7, &irq_msk_l0_7);
+	RD1(sc, MAX77620_REG_IRQ_LVL2_L8, &irq_lvl2_l8);
+	RD1(sc, MAX77620_REG_IRQ_MSK_L8, &irq_msk_l8);
+	RD1(sc, MAX77620_REG_IRQ_LVL2_GPIO, &irq_lvl2_gpio);
+	RD1(sc, MAX77620_REG_ONOFFIRQ, &onoffirq);
+	RD1(sc, MAX77620_REG_ONOFFIRQM, &onoffirqm);
+	printf("%s: intlbt: 0x%02X, intenlbt: 0x%02X\n", __func__, intlbt, intenlbt);
+	printf("%s: irqtop: 0x%02X, irqtopm: 0x%02X\n", __func__, irqtop, irqtopm);
+	printf("%s: irqsd: 0x%02X, irqmasksd: 0x%02X\n", __func__, irqsd, irqmasksd);
+	printf("%s: onoffirq: 0x%02X, onoffirqm: 0x%02X\n", __func__, onoffirq, onoffirqm);
+	printf("%s: irq_lvl2_l0_7: 0x%02X, irq_msk_l0_7: 0x%02X\n", __func__, irq_lvl2_l0_7, irq_msk_l0_7);
+	printf("%s: irq_lvl2_l8: 0x%02X, irq_msk_l8: 0x%02X\n", __func__, irq_lvl2_l8, irq_msk_l8);
+	printf("%s: irq_lvl2_gpio: 0x%02X\n", __func__, irq_lvl2_gpio);
+}
+#endif
+
+static int
+max77620_probe(device_t dev)
+{
+
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
+		return (ENXIO);
+
+	device_set_desc(dev, "MAX77620 PMIC");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+max77620_attach(device_t dev)
+{
+	struct max77620_softc *sc;
+	const char *dname;
+	int dunit, rv, rid;
+	phandle_t node;
+
+	sc = device_get_softc(dev);
+	sc->dev = dev;
+	sc->bus_addr = iicbus_get_addr(dev);
+	node = ofw_bus_get_node(sc->dev);
+	dname = device_get_name(dev);
+	dunit = device_get_unit(dev);
+	rv = 0;
+	LOCK_INIT(sc);
+
+#ifdef notyet /* Interrupt parent is not implemented */
+	rid = 0;
+	sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+	    RF_ACTIVE);
+	if (sc->irq_res == NULL) {
+		device_printf(dev, "Cannot allocate interrupt.\n");
+		rv = ENXIO;
+		goto fail;
+	}
+#endif
+	rv = max77620_parse_fdt(sc, node);
+	if (rv != 0)
+		goto fail;
+
+	rv = max77620_get_version(sc);
+	if (rv != 0)
+		goto fail;
+
+	rv = max77620_init(sc);
+	if (rv != 0)
+		goto fail;
+	rv = max77620_regulator_attach(sc, node);
+	if (rv != 0)
+		goto fail;
+	rv = max77620_gpio_attach(sc, node);
+	if (rv != 0)
+		goto fail;
+
+	rv = max77620_rtc_create(sc, node);
+	if (rv != 0)
+		goto fail;
+
+	fdt_pinctrl_register(dev, NULL);
+	fdt_pinctrl_configure_by_name(dev, "default");
+
+	/* Setup interrupt. */
+#ifdef notyet
+	rv = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
+	    NULL, max77620_intr, sc, &sc->irq_h);
+	if (rv) {
+		device_printf(dev, "Cannot setup interrupt.\n");
+		goto fail;
+	}
+#endif
+	return (bus_generic_attach(dev));
+
+fail:
+	if (sc->irq_h != NULL)
+		bus_teardown_intr(dev, sc->irq_res, sc->irq_h);
+	if (sc->irq_res != NULL)
+		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
+	LOCK_DESTROY(sc);
+	return (rv);
+}
+
+static int
+max77620_detach(device_t dev)
+{
+	struct max77620_softc *sc;
+
+	sc = device_get_softc(dev);
+	if (sc->irq_h != NULL)
+		bus_teardown_intr(dev, sc->irq_res, sc->irq_h);
+	if (sc->irq_res != NULL)
+		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
+	LOCK_DESTROY(sc);
+
+	return (bus_generic_detach(dev));
+}
+
+static phandle_t
+max77620_gpio_get_node(device_t bus, device_t dev)
+{
+
+	/* We only have one child, the GPIO bus, which needs our own node. */
+	return (ofw_bus_get_node(bus));
+}
+
+static device_method_t max77620_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		max77620_probe),
+	DEVMETHOD(device_attach,	max77620_attach),
+	DEVMETHOD(device_detach,	max77620_detach),
+
+	/* Regdev interface */
+	DEVMETHOD(regdev_map,		max77620_regulator_map),
+
+	/* GPIO protocol interface */
+	DEVMETHOD(gpio_get_bus,		max77620_gpio_get_bus),
+	DEVMETHOD(gpio_pin_max,		max77620_gpio_pin_max),
+	DEVMETHOD(gpio_pin_getname,	max77620_gpio_pin_getname),
+	DEVMETHOD(gpio_pin_getflags,	max77620_gpio_pin_getflags),
+	DEVMETHOD(gpio_pin_getcaps,	max77620_gpio_pin_getcaps),
+	DEVMETHOD(gpio_pin_setflags,	max77620_gpio_pin_setflags),
+	DEVMETHOD(gpio_pin_get,		max77620_gpio_pin_get),
+	DEVMETHOD(gpio_pin_set,		max77620_gpio_pin_set),
+	DEVMETHOD(gpio_pin_toggle,	max77620_gpio_pin_toggle),
+	DEVMETHOD(gpio_map_gpios,	max77620_gpio_map_gpios),
+
+	/* fdt_pinctrl interface */
+	DEVMETHOD(fdt_pinctrl_configure, max77620_pinmux_configure),
+
+	/* ofw_bus interface */
+	DEVMETHOD(ofw_bus_get_node,	max77620_gpio_get_node),
+
+	DEVMETHOD_END
+};
+
+static devclass_t max77620_devclass;
+static DEFINE_CLASS_0(gpio, max77620_driver, max77620_methods,
+    sizeof(struct max77620_softc));
+EARLY_DRIVER_MODULE(max77620, iicbus, max77620_driver, max77620_devclass,
+    NULL, NULL, 74);
diff --git a/sys/arm64/nvidia/tegra210/max77620.h b/sys/arm64/nvidia/tegra210/max77620.h
new file mode 100644
index 000000000000..32d486add2b8
--- /dev/null
+++ b/sys/arm64/nvidia/tegra210/max77620.h
@@ -0,0 +1,262 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright 2020 Michal Meloun <mmel at FreeBSD.org>
+ *
+ * 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$
+ */
+
+#ifndef _MAX77620_H_
+
+#include <sys/clock.h>
+
+#define	MAX77620_REG_CNFGGLBL1		0x00
+#define	MAX77620_REG_CNFGGLBL2		0x01
+#define	MAX77620_REG_CNFGGLBL3		0x02
+#define	MAX77620_REG_CNFG1_32K		0x03
+#define	MAX77620_REG_CNFGBBC		0x04
+#define	MAX77620_REG_IRQTOP		0x05
+#define	MAX77620_REG_INTLBT		0x06
+#define	MAX77620_REG_IRQSD		0x07
+#define	MAX77620_REG_IRQ_LVL2_L0_7	0x08
+#define	MAX77620_REG_IRQ_LVL2_L8	0x09
+#define	MAX77620_REG_IRQ_LVL2_GPIO	0x0A
+#define	MAX77620_REG_ONOFFIRQ		0x0B
+#define	MAX77620_REG_NVERC		0x0C
+#define	MAX77620_REG_IRQTOPM		0x0D
+#define	MAX77620_REG_INTENLBT		0x0E
+#define	MAX77620_REG_IRQMASKSD		0x0F
+#define	MAX77620_REG_IRQ_MSK_L0_7	0x10
+#define	MAX77620_REG_IRQ_MSK_L8		0x11
+#define	MAX77620_REG_ONOFFIRQM		0x12
+#define	MAX77620_REG_STATLBT		0x13
+#define	MAX77620_REG_STATSD		0x14
+#define	MAX77620_REG_ONOFFSTAT		0x15
+#define	MAX77620_REG_SD0		0x16
+#define	 MAX77620_SD0_VSEL_MASK			0x3F
+
+#define	MAX77620_REG_SD1		0x17
+#define	 MAX77620_SD1_VSEL_MASK			0x7F
+
+#define	MAX77620_REG_SD2		0x18
+#define	MAX77620_REG_SD3		0x19
+#define	MAX77620_REG_SD4		0x1A
+#define	 MAX77620_SDX_VSEL_MASK			0xFF
+
+#define	MAX77620_REG_DVSSD0		0x1B
+#define	MAX77620_REG_DVSSD1		0x1C
+#define	MAX77620_REG_CFG_SD0		0x1D
+#define	MAX77620_REG_CFG_SD1		0x1E
+#define	MAX77620_REG_CFG_SD2		0x1F
+#define	MAX77620_REG_CFG_SD3		0x20
+#define	MAX77620_REG_CFG_SD4		0x21
+#define	 MAX77620_SD_SR_MASK			0xC0
+#define	 MAX77620_SD_SR_SHIFT			6
+#define	 MAX77620_SD_POWER_MODE_MASK		0x30
+#define	 MAX77620_SD_POWER_MODE_SHIFT		4
+#define	 MAX77620_SD_FPWM_MASK			0x04
+#define	 MAX77620_SD_FPWM_SHIFT			2
+#define	 MAX77620_SD_FSRADE_MASK		0x01
+#define	 MAX77620_SD_FSRADE_SHIFT		0
+
+#define	MAX77620_REG_CFG2_SD		0x22
+#define	MAX77620_REG_CFG_LDO0		0x23
+#define	MAX77620_REG_CFG2_LDO0		0x24
+#define	MAX77620_REG_CFG_LDO1		0x25
+#define	MAX77620_REG_CFG2_LDO1		0x26
+#define	MAX77620_REG_CFG_LDO2		0x27
+#define	MAX77620_REG_CFG2_LDO2		0x28
+#define	MAX77620_REG_CFG_LDO3		0x29
+#define	MAX77620_REG_CFG2_LDO3		0x2A
+#define	MAX77620_REG_CFG_LDO4		0x2B
+#define	MAX77620_REG_CFG2_LDO4		0x2C
+#define	MAX77620_REG_CFG_LDO5		0x2D
+#define	MAX77620_REG_CFG2_LDO5		0x2E
+#define	MAX77620_REG_CFG_LDO6		0x2F
+#define	MAX77620_REG_CFG2_LDO6		0x30
+#define	MAX77620_REG_CFG_LDO7		0x31
+#define	MAX77620_REG_CFG2_LDO7		0x32
+#define	MAX77620_REG_CFG_LDO8		0x33
+#define	 MAX77620_LDO_POWER_MODE_MASK		0xC0
+#define	 MAX77620_LDO_POWER_MODE_SHIFT		6
+#define	 MAX77620_LDO_VSEL_MASK			0x3F
+
+#define	MAX77620_REG_CFG2_LDO8		0x34
+#define	 MAX77620_LDO_SLEW_RATE_MASK		0x1
+#define	 MAX77620_LDO_SLEW_RATE_SHIFT		0x0
+
+#define	MAX77620_REG_CFG3_LDO		0x35
+
+#define	MAX77620_REG_GPIO0		0x36
+#define	MAX77620_REG_GPIO1		0x37
+#define	MAX77620_REG_GPIO2		0x38
+#define	MAX77620_REG_GPIO3		0x39
+#define	MAX77620_REG_GPIO4		0x3A
+#define	MAX77620_REG_GPIO5		0x3B
+#define	MAX77620_REG_GPIO6		0x3C
+#define	MAX77620_REG_GPIO7		0x3D
+#define	 MAX77620_REG_GPIO_INT_GET(x)		(((x) >> 5) & 0x3)
+#define	 MAX77620_REG_GPIO_INT(x)		(((x) & 0x3) << 5)
+#define	  MAX77620_REG_GPIO_INT_NONE			0
+#define	  MAX77620_REG_GPIO_INT_FALLING			1
+#define	  MAX77620_REG_GPIO_INT_RISING			2
+#define	  MAX77620_REG_GPIO_INT_BOTH			3
+#define	 MAX77620_REG_GPIO_OUTPUT_VAL_GET(x)	(((x) >> 3) & 0x1)
+#define	 MAX77620_REG_GPIO_OUTPUT_VAL(x)	(((x) & 0x1) << 3)
+#define	 MAX77620_REG_GPIO_INPUT_VAL_GET(x)	(((x) << 2) & 0x1)
+#define	 MAX77620_REG_GPIO_INPUT_VAL		(1 << 2)
+#define	 MAX77620_REG_GPIO_DRV_GET(x)		(((x) >> 0) & 0x1)
+#define	 MAX77620_REG_GPIO_DRV(x)		(((x) & 0x1) << 0)
+#define	  MAX77620_REG_GPIO_DRV_PUSHPULL		1
+#define	  MAX77620_REG_GPIO_DRV_OPENDRAIN		0
+
+#define	MAX77620_REG_PUE_GPIO		0x3E
+#define	MAX77620_REG_PDE_GPIO		0x3F
+#define	MAX77620_REG_AME_GPIO		0x40
+#define	MAX77620_REG_ONOFFCNFG1		0x41
+#define	MAX77620_REG_ONOFFCNFG2		0x42
+
+#define	MAX77620_REG_FPS_CFG0		0x43
+#define	MAX77620_REG_FPS_CFG1		0x44
+#define	MAX77620_REG_FPS_CFG2		0x45
+#define	 MAX77620_FPS_TIME_PERIOD_MASK		0x38
+#define	 MAX77620_FPS_TIME_PERIOD_SHIFT		3
+#define	 MAX77620_FPS_EN_SRC_MASK		0x06
+#define	 MAX77620_FPS_EN_SRC_SHIFT		1
+#define	 MAX77620_FPS_ENFPS_SW_MASK		0x01
+#define	 MAX77620_FPS_ENFPS_SW			0x01
+
+#define	MAX77620_REG_FPS_LDO0		0x46
+#define	MAX77620_REG_FPS_LDO1		0x47
+#define	MAX77620_REG_FPS_LDO2		0x48
+#define	MAX77620_REG_FPS_LDO3		0x49
+#define	MAX77620_REG_FPS_LDO4		0x4A
+#define	MAX77620_REG_FPS_LDO5		0x4B
+#define	MAX77620_REG_FPS_LDO6		0x4C
+#define	MAX77620_REG_FPS_LDO7		0x4D
+#define	MAX77620_REG_FPS_LDO8		0x4E
+#define	MAX77620_REG_FPS_SD0		0x4F
+#define	MAX77620_REG_FPS_SD1		0x50
+#define	MAX77620_REG_FPS_SD2		0x51
+#define	MAX77620_REG_FPS_SD3		0x52
+#define	MAX77620_REG_FPS_SD4		0x53
+#define	MAX77620_REG_FPS_GPIO1		0x54
+#define	MAX77620_REG_FPS_GPIO2		0x55
+#define	MAX77620_REG_FPS_GPIO3		0x56
+#define	MAX77620_REG_FPS_RSO		0x57
+#define	 MAX77620_FPS_SRC_MASK			0xC0
+#define	 MAX77620_FPS_SRC_SHIFT			6
+#define	 MAX77620_FPS_PU_PERIOD_MASK		0x38
+#define	 MAX77620_FPS_PU_PERIOD_SHIFT		3
+#define	 MAX77620_FPS_PD_PERIOD_MASK		0x07
+#define	 MAX77620_FPS_PD_PERIOD_SHIFT		0
+
+#define	MAX77620_REG_CID0		0x58
+#define	MAX77620_REG_CID1		0x59
+#define	MAX77620_REG_CID2		0x5A
+#define	MAX77620_REG_CID3		0x5B
+#define	MAX77620_REG_CID4		0x5C
+#define	MAX77620_REG_CID5		0x5D
+#define	MAX77620_REG_DVSSD4		0x5E
+#define	MAX20024_REG_MAX_ADD		0x70
+
+/* MIsc FPS definitions. */
+#define	MAX77620_FPS_COUNT			3
+#define	MAX77620_FPS_PERIOD_MIN_US		40
+#define	MAX77620_FPS_PERIOD_MAX_US		2560
+
+/* Power modes */
+#define	MAX77620_POWER_MODE_NORMAL		3
+#define	MAX77620_POWER_MODE_LPM			2
+#define	MAX77620_POWER_MODE_GLPM		1
+#define	MAX77620_POWER_MODE_DISABLE		0
+
+
+struct max77620_reg_sc;
+struct max77620_gpio_pin;
+
+struct max77620_softc {
+	device_t			dev;
+	struct sx			lock;
+	int				bus_addr;
+	struct resource			*irq_res;
+	void				*irq_h;
+
+	int 				shutdown_fps[MAX77620_FPS_COUNT];
+	int 				suspend_fps[MAX77620_FPS_COUNT];
+	int 				event_source[MAX77620_FPS_COUNT];
+
+	/* Regulators. */
+	struct max77620_reg_sc		**regs;
+	int				nregs;
+
+	/* GPIO */
+	device_t			gpio_busdev;
+	struct max77620_gpio_pin 	**gpio_pins;
+	int				gpio_npins;
+	struct sx			gpio_lock;
+	uint8_t				gpio_reg_pue;	/* pull-up enables */
+	uint8_t				gpio_reg_pde;	/* pull-down enables */
+	uint8_t				gpio_reg_ame;	/* alternate fnc */
+
+
+};
+
+#define	RD1(sc, reg, val)	max77620_read(sc, reg, val)
+#define	WR1(sc, reg, val)	max77620_write(sc, reg, val)
+#define	RM1(sc, reg, clr, set)	max77620_modify(sc, reg, clr, set)
+
+int max77620_read(struct max77620_softc *sc, uint8_t reg, uint8_t *val);
+int max77620_write(struct max77620_softc *sc, uint8_t reg, uint8_t val);
+int max77620_modify(struct max77620_softc *sc, uint8_t reg, uint8_t clear,
+    uint8_t set);
+int max77620_read_buf(struct max77620_softc *sc, uint8_t reg, uint8_t *buf,
+    size_t size);
+int max77620_write_buf(struct max77620_softc *sc, uint8_t reg, uint8_t *buf,
+    size_t size);
+
+/* Regulators */
+int max77620_regulator_attach(struct max77620_softc *sc, phandle_t node);
+int max77620_regulator_map(device_t dev, phandle_t xref, int ncells,
+    pcell_t *cells, intptr_t *num);
+
+/* RTC */
+int max77620_rtc_create(struct max77620_softc *sc, phandle_t node);
+
+/* GPIO */
+device_t max77620_gpio_get_bus(device_t dev);
+int max77620_gpio_pin_max(device_t dev, int *maxpin);
+int max77620_gpio_pin_getname(device_t dev, uint32_t pin, char *name);
+int max77620_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags);
+int max77620_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps);
+int max77620_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags);
+int max77620_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value);
+int max77620_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val);
+int max77620_gpio_pin_toggle(device_t dev, uint32_t pin);
+int max77620_gpio_map_gpios(device_t dev, phandle_t pdev, phandle_t gparent,
+    int gcells, pcell_t *gpios, uint32_t *pin, uint32_t *flags);
+int max77620_gpio_attach(struct max77620_softc *sc, phandle_t node);
+int max77620_pinmux_configure(device_t dev, phandle_t cfgxref);
+
+#endif /* _MAX77620_H_ */
diff --git a/sys/arm64/nvidia/tegra210/max77620_gpio.c b/sys/arm64/nvidia/tegra210/max77620_gpio.c
new file mode 100644
index 000000000000..2e9156801d97
--- /dev/null
+++ b/sys/arm64/nvidia/tegra210/max77620_gpio.c
@@ -0,0 +1,715 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright 2020 Michal Meloun <mmel at FreeBSD.org>
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/gpio.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/sx.h>
+
+#include <machine/bus.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/gpio/gpiobusvar.h>
+
+#include "max77620.h"
+
+MALLOC_DEFINE(M_MAX77620_GPIO, "MAX77620 gpio", "MAX77620 GPIO");
+
+#define	NGPIO		8
+
+#define	GPIO_LOCK(_sc)	sx_slock(&(_sc)->gpio_lock)
+#define	GPIO_UNLOCK(_sc)	sx_unlock(&(_sc)->gpio_lock)
+#define	GPIO_ASSERT(_sc)	sx_assert(&(_sc)->gpio_lock, SA_LOCKED)
+
+enum prop_id {
+	CFG_BIAS_PULL_UP,
+	CFG_BIAS_PULL_DOWN,
+	CFG_OPEN_DRAIN,
+	CFG_PUSH_PULL,
+
+	CFG_ACTIVE_FPS_SRC,
+	CFG_ACTIVE_PWRUP_SLOT,
+	CFG_ACTIVE_PWRDOWN_SLOT,
+	CFG_SUSPEND_FPS_SRC,
+	CFG_SUSPEND_PWRUP_SLOT,
+	CFG_SUSPEND_PWRDOWN_SLOT,
+
+	PROP_ID_MAX_ID
+};
+
+static const struct {
+	const char	*name;
+	enum prop_id  	id;
+} max77620_prop_names[] = {
+	{"bias-pull-up",			CFG_BIAS_PULL_UP},
+	{"bias-pull-down",			CFG_BIAS_PULL_DOWN},
+	{"drive-open-drain",			CFG_OPEN_DRAIN},
+	{"drive-push-pull",			CFG_PUSH_PULL},
+	{"maxim,active-fps-source",		CFG_ACTIVE_FPS_SRC},
+	{"maxim,active-fps-power-up-slot",	CFG_ACTIVE_PWRUP_SLOT},
+	{"maxim,active-fps-power-down-slot",	CFG_ACTIVE_PWRDOWN_SLOT},
+	{"maxim,suspend-fps-source",		CFG_SUSPEND_FPS_SRC},
+	{"maxim,suspend-fps-power-up-slot",	CFG_SUSPEND_PWRUP_SLOT},
+	{"maxim,suspend-fps-power-down-slot",	CFG_SUSPEND_PWRDOWN_SLOT},
+};
+
+/* Configuration for one pin group. */
+struct max77620_pincfg {
+	bool	alt_func;
+	int	params[PROP_ID_MAX_ID];
+};
+
+static char *altfnc_table[] = {
+	"lpm-control-in",
+	"fps-out",
+	"32k-out1",
+	"sd0-dvs-in",
+	"sd1-dvs-in",
+	"reference-out",
+};
+
+struct max77620_gpio_pin {
+	int		pin_caps;
+	char		pin_name[GPIOMAXNAME];
+	uint8_t		reg;
+
+	/* Runtime data  */
+	bool		alt_func;	/* GPIO or alternate function */
+};
+
+/* --------------------------------------------------------------------------
+ *
+ *  Pinmux functions.
+ */
+static int
+max77620_pinmux_get_function(struct max77620_softc *sc, char *name,
+    struct max77620_pincfg *cfg)
+{
+	int i;
+
+	if (strcmp("gpio", name) == 0) {
+		cfg->alt_func = false;
+		return (0);
+	}
+	for (i = 0; i < nitems(altfnc_table); i++) {
+		if (strcmp(altfnc_table[i], name) == 0) {
+			cfg->alt_func = true;
+			return (0);
+		}
+	}
+	return (-1);
+}
+
+static int
+max77620_pinmux_set_fps(struct max77620_softc *sc, int pin_num,
+    struct max77620_gpio_pin *pin)
+{
+#if 0
+	struct max77620_fps_config *fps_config = &mpci->fps_config[pin];
+	int addr, ret;
+	int param_val;
+	int mask, shift;
+
+	if ((pin < 1) || (pin > 3))
+		return (0);
+
+	switch (param) {
+	case MAX77620_ACTIVE_FPS_SOURCE:
+	case MAX77620_SUSPEND_FPS_SOURCE:
+		mask = MAX77620_FPS_SRC_MASK;
+		shift = MAX77620_FPS_SRC_SHIFT;
+		param_val = fps_config->active_fps_src;
+		if (param == MAX77620_SUSPEND_FPS_SOURCE)
+			param_val = fps_config->suspend_fps_src;
+		break;
+
+	case MAX77620_ACTIVE_FPS_POWER_ON_SLOTS:
+	case MAX77620_SUSPEND_FPS_POWER_ON_SLOTS:
+		mask = MAX77620_FPS_PU_PERIOD_MASK;
+		shift = MAX77620_FPS_PU_PERIOD_SHIFT;
+		param_val = fps_config->active_power_up_slots;
+		if (param == MAX77620_SUSPEND_FPS_POWER_ON_SLOTS)
+			param_val = fps_config->suspend_power_up_slots;
*** 9957 LINES SKIPPED ***


More information about the dev-commits-src-all mailing list