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-main
mailing list