From owner-dev-commits-src-main@freebsd.org Mon Dec 28 13:19:09 2020 Return-Path: Delivered-To: dev-commits-src-main@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 939DB4B4B9D; Mon, 28 Dec 2020 13:19:09 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4D4J6P3nc6z3Qfk; Mon, 28 Dec 2020 13:19:09 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 74CD31A196; Mon, 28 Dec 2020 13:19:09 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 0BSDJ99t035636; Mon, 28 Dec 2020 13:19:09 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 0BSDJ9rT035635; Mon, 28 Dec 2020 13:19:09 GMT (envelope-from git) Date: Mon, 28 Dec 2020 13:19:09 GMT Message-Id: <202012281319.0BSDJ9rT035635@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Michal Meloun Subject: git: e90347891960 - main - ARM64: Port FreeBSD to Nvidia Jetson TX1 and Nano. MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: mmel X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: e903478919602c90fdc202a8628b89eb7c3bc104 Auto-Submitted: auto-generated X-BeenThere: dev-commits-src-main@freebsd.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: "Commit messages for the main branch of the src repository." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 28 Dec 2020 13:19:09 -0000 The branch main has been updated by mmel: URL: https://cgit.FreeBSD.org/src/commit/?id=e903478919602c90fdc202a8628b89eb7c3bc104 commit e903478919602c90fdc202a8628b89eb7c3bc104 Author: Michal Meloun AuthorDate: 2018-01-04 12:18:24 +0000 Commit: Michal Meloun 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 + * + * 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 +__FBSDID("$FreeBSD$"); + +/* + * MAX77620 PMIC driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#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 + * + * 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 + +#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 + * + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#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 ***