aboutsummaryrefslogtreecommitdiffstats
path: root/roms/u-boot/drivers/gpio
diff options
context:
space:
mode:
authorAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
committerAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
commitaf1a266670d040d2f4083ff309d732d648afba2a (patch)
tree2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/u-boot/drivers/gpio
parente02cda008591317b1625707ff8e115a4841aa889 (diff)
Add submodule dependency filesHEADmaster
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/u-boot/drivers/gpio')
-rw-r--r--roms/u-boot/drivers/gpio/74x164_gpio.c193
-rw-r--r--roms/u-boot/drivers/gpio/Kconfig498
-rw-r--r--roms/u-boot/drivers/gpio/Makefile71
-rw-r--r--roms/u-boot/drivers/gpio/adi_gpio2.c425
-rw-r--r--roms/u-boot/drivers/gpio/altera_pio.c123
-rw-r--r--roms/u-boot/drivers/gpio/at91_gpio.c638
-rw-r--r--roms/u-boot/drivers/gpio/atmel_pio4.c367
-rw-r--r--roms/u-boot/drivers/gpio/axp_gpio.c179
-rw-r--r--roms/u-boot/drivers/gpio/bcm2835_gpio.c142
-rw-r--r--roms/u-boot/drivers/gpio/bcm6345_gpio.c119
-rw-r--r--roms/u-boot/drivers/gpio/cortina_gpio.c113
-rw-r--r--roms/u-boot/drivers/gpio/da8xx_gpio.c569
-rw-r--r--roms/u-boot/drivers/gpio/da8xx_gpio.h41
-rw-r--r--roms/u-boot/drivers/gpio/db8500_gpio.c221
-rw-r--r--roms/u-boot/drivers/gpio/dwapb_gpio.c241
-rw-r--r--roms/u-boot/drivers/gpio/gpio-rcar.c194
-rw-r--r--roms/u-boot/drivers/gpio/gpio-rza1.c136
-rw-r--r--roms/u-boot/drivers/gpio/gpio-uclass.c1459
-rw-r--r--roms/u-boot/drivers/gpio/gpio-uniphier.c171
-rw-r--r--roms/u-boot/drivers/gpio/hi6220_gpio.c95
-rw-r--r--roms/u-boot/drivers/gpio/hsdk-creg-gpio.c169
-rw-r--r--roms/u-boot/drivers/gpio/imx_rgpio2p.c227
-rw-r--r--roms/u-boot/drivers/gpio/intel_broadwell_gpio.c190
-rw-r--r--roms/u-boot/drivers/gpio/intel_gpio.c221
-rw-r--r--roms/u-boot/drivers/gpio/intel_ich6_gpio.c242
-rw-r--r--roms/u-boot/drivers/gpio/iproc_gpio.c290
-rw-r--r--roms/u-boot/drivers/gpio/kona_gpio.c141
-rw-r--r--roms/u-boot/drivers/gpio/kw_gpio.c149
-rw-r--r--roms/u-boot/drivers/gpio/lpc32xx_gpio.c321
-rw-r--r--roms/u-boot/drivers/gpio/mpc83xx_gpio.c183
-rw-r--r--roms/u-boot/drivers/gpio/mpc83xx_spisel_boot.c149
-rw-r--r--roms/u-boot/drivers/gpio/mpc8xxx_gpio.c273
-rw-r--r--roms/u-boot/drivers/gpio/mscc_sgpio.c279
-rw-r--r--roms/u-boot/drivers/gpio/msm_gpio.c134
-rw-r--r--roms/u-boot/drivers/gpio/mt7620_gpio.c146
-rw-r--r--roms/u-boot/drivers/gpio/mt7621_gpio.c183
-rw-r--r--roms/u-boot/drivers/gpio/mvebu_gpio.c121
-rw-r--r--roms/u-boot/drivers/gpio/mvgpio.c97
-rw-r--r--roms/u-boot/drivers/gpio/mvgpio.h53
-rw-r--r--roms/u-boot/drivers/gpio/mvmfp.c55
-rw-r--r--roms/u-boot/drivers/gpio/mxc_gpio.c399
-rw-r--r--roms/u-boot/drivers/gpio/mxs_gpio.c311
-rw-r--r--roms/u-boot/drivers/gpio/nx_gpio.c251
-rw-r--r--roms/u-boot/drivers/gpio/octeon_gpio.c242
-rw-r--r--roms/u-boot/drivers/gpio/omap_gpio.c381
-rw-r--r--roms/u-boot/drivers/gpio/pca953x.c295
-rw-r--r--roms/u-boot/drivers/gpio/pca953x_gpio.c390
-rw-r--r--roms/u-boot/drivers/gpio/pca9698.c127
-rw-r--r--roms/u-boot/drivers/gpio/pcf8575_gpio.c182
-rw-r--r--roms/u-boot/drivers/gpio/pic32_gpio.c166
-rw-r--r--roms/u-boot/drivers/gpio/pm8916_gpio.c301
-rw-r--r--roms/u-boot/drivers/gpio/rk_gpio.c182
-rw-r--r--roms/u-boot/drivers/gpio/s5p_gpio.c372
-rw-r--r--roms/u-boot/drivers/gpio/sandbox.c581
-rw-r--r--roms/u-boot/drivers/gpio/sh_pfc.c639
-rw-r--r--roms/u-boot/drivers/gpio/sifive-gpio.c178
-rw-r--r--roms/u-boot/drivers/gpio/spear_gpio.c89
-rw-r--r--roms/u-boot/drivers/gpio/stm32_gpio.c349
-rw-r--r--roms/u-boot/drivers/gpio/sunxi_gpio.c378
-rw-r--r--roms/u-boot/drivers/gpio/tca642x.c356
-rw-r--r--roms/u-boot/drivers/gpio/tegra186_gpio.c283
-rw-r--r--roms/u-boot/drivers/gpio/tegra186_gpio_priv.h61
-rw-r--r--roms/u-boot/drivers/gpio/tegra_gpio.c382
-rw-r--r--roms/u-boot/drivers/gpio/vybrid_gpio.c138
-rw-r--r--roms/u-boot/drivers/gpio/xilinx_gpio.c308
-rw-r--r--roms/u-boot/drivers/gpio/zynq_gpio.c411
66 files changed, 17370 insertions, 0 deletions
diff --git a/roms/u-boot/drivers/gpio/74x164_gpio.c b/roms/u-boot/drivers/gpio/74x164_gpio.c
new file mode 100644
index 000000000..7a7cfe861
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/74x164_gpio.c
@@ -0,0 +1,193 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Take drivers/gpio/gpio-74x164.c as reference.
+ *
+ * 74Hx164 - Generic serial-in/parallel-out 8-bits shift register GPIO driver
+ *
+ * Copyright (C) 2016 Peng Fan <van.freenix@gmail.com>
+ *
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <malloc.h>
+#include <asm/global_data.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <spi.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * struct gen_74x164_chip - Data for 74Hx164
+ *
+ * @oe: OE pin
+ * @nregs: number of registers
+ * @buffer: buffer for chained chips
+ */
+#define GEN_74X164_NUMBER_GPIOS 8
+
+struct gen_74x164_priv {
+ struct gpio_desc oe;
+ u32 nregs;
+ /*
+ * Since the nregs are chained, every byte sent will make
+ * the previous byte shift to the next register in the
+ * chain. Thus, the first byte sent will end up in the last
+ * register at the end of the transfer. So, to have a logical
+ * numbering, store the bytes in reverse order.
+ */
+ u8 *buffer;
+};
+
+static int gen_74x164_write_conf(struct udevice *dev)
+{
+ struct gen_74x164_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = dm_spi_claim_bus(dev);
+ if (ret)
+ return ret;
+
+ ret = dm_spi_xfer(dev, priv->nregs * 8, priv->buffer, NULL,
+ SPI_XFER_BEGIN | SPI_XFER_END);
+
+ dm_spi_release_bus(dev);
+
+ return ret;
+}
+
+static int gen_74x164_get_value(struct udevice *dev, unsigned offset)
+{
+ struct gen_74x164_priv *priv = dev_get_priv(dev);
+ uint bank = priv->nregs - 1 - offset / 8;
+ uint pin = offset % 8;
+
+ return (priv->buffer[bank] >> pin) & 0x1;
+}
+
+static int gen_74x164_set_value(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct gen_74x164_priv *priv = dev_get_priv(dev);
+ uint bank = priv->nregs - 1 - offset / 8;
+ uint pin = offset % 8;
+ int ret;
+
+ if (value)
+ priv->buffer[bank] |= 1 << pin;
+ else
+ priv->buffer[bank] &= ~(1 << pin);
+
+ ret = gen_74x164_write_conf(dev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int gen_74x164_direction_input(struct udevice *dev, unsigned offset)
+{
+ return -ENOSYS;
+}
+
+static int gen_74x164_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ return gen_74x164_set_value(dev, offset, value);
+}
+
+static int gen_74x164_get_function(struct udevice *dev, unsigned offset)
+{
+ return GPIOF_OUTPUT;
+}
+
+static int gen_74x164_xlate(struct udevice *dev, struct gpio_desc *desc,
+ struct ofnode_phandle_args *args)
+{
+ desc->offset = args->args[0];
+ desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
+
+ return 0;
+}
+
+static const struct dm_gpio_ops gen_74x164_ops = {
+ .direction_input = gen_74x164_direction_input,
+ .direction_output = gen_74x164_direction_output,
+ .get_value = gen_74x164_get_value,
+ .set_value = gen_74x164_set_value,
+ .get_function = gen_74x164_get_function,
+ .xlate = gen_74x164_xlate,
+};
+
+static int gen_74x164_probe(struct udevice *dev)
+{
+ struct gen_74x164_priv *priv = dev_get_priv(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ char *str, name[32];
+ int ret;
+ const void *fdt = gd->fdt_blob;
+ int node = dev_of_offset(dev);
+
+ snprintf(name, sizeof(name), "%s_", dev->name);
+ str = strdup(name);
+ if (!str)
+ return -ENOMEM;
+
+ /*
+ * See Linux kernel:
+ * Documentation/devicetree/bindings/gpio/gpio-74x164.txt
+ */
+ priv->nregs = fdtdec_get_int(fdt, node, "registers-number", 1);
+ priv->buffer = calloc(priv->nregs, sizeof(u8));
+ if (!priv->buffer) {
+ ret = -ENOMEM;
+ goto free_str;
+ }
+
+ ret = fdtdec_get_byte_array(fdt, node, "registers-default",
+ priv->buffer, priv->nregs);
+ if (ret)
+ dev_dbg(dev, "No registers-default property\n");
+
+ ret = gpio_request_by_name(dev, "oe-gpios", 0, &priv->oe,
+ GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+ if (ret) {
+ dev_dbg(dev, "No oe-pins property\n");
+ }
+
+ uc_priv->bank_name = str;
+ uc_priv->gpio_count = priv->nregs * 8;
+
+ ret = gen_74x164_write_conf(dev);
+ if (ret)
+ goto free_buf;
+
+ dev_dbg(dev, "%s is ready\n", dev->name);
+
+ return 0;
+
+free_buf:
+ free(priv->buffer);
+free_str:
+ free(str);
+ return ret;
+}
+
+static const struct udevice_id gen_74x164_ids[] = {
+ { .compatible = "fairchild,74hc595" },
+ { }
+};
+
+U_BOOT_DRIVER(74x164) = {
+ .name = "74x164",
+ .id = UCLASS_GPIO,
+ .ops = &gen_74x164_ops,
+ .probe = gen_74x164_probe,
+ .priv_auto = sizeof(struct gen_74x164_priv),
+ .of_match = gen_74x164_ids,
+};
diff --git a/roms/u-boot/drivers/gpio/Kconfig b/roms/u-boot/drivers/gpio/Kconfig
new file mode 100644
index 000000000..d24884739
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/Kconfig
@@ -0,0 +1,498 @@
+#
+# GPIO infrastructure and drivers
+#
+
+menu "GPIO Support"
+
+config DM_GPIO
+ bool "Enable Driver Model for GPIO drivers"
+ depends on DM
+ help
+ Enable driver model for GPIO access. The standard GPIO
+ interface (gpio_get_value(), etc.) is then implemented by
+ the GPIO uclass. Drivers provide methods to query the
+ particular GPIOs that they provide. The uclass interface
+ is defined in include/asm-generic/gpio.h.
+
+config SPL_DM_GPIO
+ bool "Enable Driver Model for GPIO drivers in SPL"
+ depends on DM_GPIO && SPL_DM && SPL_GPIO_SUPPORT
+ default y
+ help
+ Enable driver model for GPIO access in SPL. The standard GPIO
+ interface (gpio_get_value(), etc.) is then implemented by
+ the GPIO uclass. Drivers provide methods to query the
+ particular GPIOs that they provide. The uclass interface
+ is defined in include/asm-generic/gpio.h.
+
+config TPL_DM_GPIO
+ bool "Enable Driver Model for GPIO drivers in TPL"
+ depends on DM_GPIO && TPL_DM && TPL_GPIO_SUPPORT
+ default y
+ help
+ Enable driver model for GPIO access in TPL. The standard GPIO
+ interface (gpio_get_value(), etc.) is then implemented by
+ the GPIO uclass. Drivers provide methods to query the
+ particular GPIOs that they provide. The uclass interface
+ is defined in include/asm-generic/gpio.h.
+
+config GPIO_HOG
+ bool "Enable GPIO hog support"
+ depends on DM_GPIO
+ default n
+ help
+ Enable gpio hog support
+ The GPIO chip may contain GPIO hog definitions. GPIO hogging
+ is a mechanism providing automatic GPIO request and config-
+ uration as part of the gpio-controller's driver probe function.
+
+config DM_GPIO_LOOKUP_LABEL
+ bool "Enable searching for gpio labelnames"
+ depends on DM_GPIO
+ help
+ This option enables searching for gpio names in
+ the defined gpio labels, if the search for the
+ gpio bank name failed. This makes sense if you use
+ different gpios on different hardware versions
+ for the same functionality in board code.
+
+config SPL_DM_GPIO_LOOKUP_LABEL
+ bool "Enable searching for gpio labelnames"
+ depends on DM_GPIO && SPL_DM && SPL_GPIO_SUPPORT
+ help
+ This option enables searching for gpio names in
+ the defined gpio labels, if the search for the
+ gpio bank name failed. This makes sense if you use
+ different gpios on different hardware versions
+ for the same functionality in board code.
+
+config ALTERA_PIO
+ bool "Altera PIO driver"
+ depends on DM_GPIO
+ help
+ Select this to enable PIO for Altera devices. Please find
+ details on the "Embedded Peripherals IP User Guide" of Altera.
+
+config BCM6345_GPIO
+ bool "BCM6345 GPIO driver"
+ depends on DM_GPIO && (ARCH_BMIPS || ARCH_BCM68360 || \
+ ARCH_BCM6858 || ARCH_BCM63158)
+ help
+ This driver supports the GPIO banks on BCM6345 SoCs.
+
+config CORTINA_GPIO
+ bool "Cortina-Access GPIO driver"
+ depends on DM_GPIO && CORTINA_PLATFORM
+ help
+ Enable support for the GPIO controller in Cortina CAxxxx SoCs.
+ This driver supports all CPU ISA variants supported by Cortina
+ Access CAxxxx SoCs.
+
+config DWAPB_GPIO
+ bool "DWAPB GPIO driver"
+ depends on DM && DM_GPIO
+ default n
+ help
+ Support for the Designware APB GPIO driver.
+
+config AT91_GPIO
+ bool "AT91 PIO GPIO driver"
+ default n
+ help
+ Say yes here to select AT91 PIO GPIO driver. AT91 PIO
+ controller manages up to 32 fully programmable input/output
+ lines. Each I/O line may be dedicated as a general-purpose
+ I/O or be assigned to a function of an embedded peripheral.
+ The assignment to a function of an embedded peripheral is
+ the responsibility of AT91 Pinctrl driver. This driver is
+ responsible for the general-purpose I/O.
+
+config ATMEL_PIO4
+ bool "ATMEL PIO4 driver"
+ depends on DM_GPIO
+ default n
+ help
+ Say yes here to support the Atmel PIO4 driver.
+ The PIO4 is new version of Atmel PIO controller, which manages
+ up to 128 fully programmable input/output lines. Each I/O line
+ may be dedicated as a general purpose I/O or be assigned to
+ a function of an embedded peripheral.
+
+config DA8XX_GPIO
+ bool "DA8xx GPIO Driver"
+ help
+ This driver supports the DA8xx GPIO controller
+
+config INTEL_BROADWELL_GPIO
+ bool "Intel Broadwell GPIO driver"
+ depends on DM
+ help
+ This driver supports Broadwell U devices which have an expanded
+ GPIO feature set. The difference is large enough to merit a separate
+ driver from the common Intel ICH6 driver. It supports a total of
+ 95 GPIOs which can be configured from the device tree.
+
+config INTEL_GPIO
+ bool "Intel generic GPIO driver"
+ depends on DM_GPIO
+ help
+ Say yes here to select Intel generic GPIO driver. This controller
+ supports recent chips (e.g. Apollo Lake). It permits basic GPIO
+ control including setting pins to input/output. It makes use of its
+ parent pinctrl driver to actually effect changes.
+
+config INTEL_ICH6_GPIO
+ bool "Intel ICH6 compatible legacy GPIO driver"
+ depends on DM_GPIO
+ help
+ Say yes here to select Intel ICH6 compatible legacy GPIO driver.
+
+config IMX_RGPIO2P
+ bool "i.MX7ULP RGPIO2P driver"
+ depends on DM
+ default n
+ help
+ This driver supports i.MX7ULP Rapid GPIO2P controller.
+
+config IPROC_GPIO
+ bool "Broadcom iProc GPIO driver(without pinconf)"
+ default n
+ help
+ The Broadcom iProc based SoCs- Cygnus, NS2, NS3, NSP and Stingray,
+ use the same GPIO Controller IP hence this driver could be used
+ for all.
+
+ The Broadcom iProc based SoCs have multiple GPIO controllers and only
+ the always-ON GPIO controller (CRMU/AON) is supported by this driver.
+
+config HSDK_CREG_GPIO
+ bool "HSDK CREG GPIO griver"
+ depends on DM_GPIO
+ default n
+ help
+ This driver supports CREG GPIOs on Synopsys HSDK SOC.
+
+config LPC32XX_GPIO
+ bool "LPC32XX GPIO driver"
+ depends on DM
+ default n
+ help
+ Support for the LPC32XX GPIO driver.
+
+config MSCC_SGPIO
+ bool "Microsemi Serial GPIO driver"
+ depends on DM_GPIO && SOC_VCOREIII
+ help
+ Support for the VCoreIII SoC serial GPIO device. By using a
+ serial interface, the SIO controller significantly extends
+ the number of available GPIOs with a minimum number of
+ additional pins on the device. The primary purpose of the
+ SIO controller is to connect control signals from SFP
+ modules and to act as an LED controller.
+
+config MSM_GPIO
+ bool "Qualcomm GPIO driver"
+ depends on DM_GPIO
+ default n
+ help
+ Support GPIO controllers on Qualcomm Snapdragon family of SoCs.
+ This controller have single bank (default name "soc"), every
+ gpio has it's own set of registers.
+ Only simple GPIO operations are supported (get/set, change of
+ direction and checking pin function).
+ Supported devices:
+ - APQ8016
+ - MSM8916
+
+config MXC_GPIO
+ bool "Freescale/NXP MXC GPIO driver"
+ help
+ Support GPIO controllers on various i.MX platforms
+
+config MXS_GPIO
+ bool "Freescale/NXP MXS GPIO driver"
+ help
+ Support GPIO controllers on i.MX23 and i.MX28 platforms
+
+config OMAP_GPIO
+ bool "TI OMAP GPIO driver"
+ depends on ARCH_OMAP2PLUS
+ default y
+ help
+ Support GPIO controllers on the TI OMAP3/4/5 and related (such as
+ AM335x/AM43xx/AM57xx/DRA7xx/etc) families of SoCs.
+
+config CMD_PCA953X
+ bool "Enable the pca953x command"
+ help
+ Deprecated: This should be converted to driver model.
+
+ This command provides access to a pca953x GPIO device using the
+ legacy GPIO interface. Several subcommands are provided which mirror
+ the standard 'gpio' command. It should use that instead.
+
+config PM8916_GPIO
+ bool "Qualcomm PM8916 PMIC GPIO/keypad driver"
+ depends on DM_GPIO && PMIC_PM8916
+ help
+ Support for GPIO pins and power/reset buttons found on
+ Qualcomm PM8916 PMIC.
+ Default name for GPIO bank is "pm8916".
+ Power and reset buttons are placed in "pm8916_key" bank and
+ have gpio numbers 0 and 1 respectively.
+
+config PCF8575_GPIO
+ bool "PCF8575 I2C GPIO Expander driver"
+ depends on DM_GPIO && DM_I2C
+ help
+ Support for PCF8575 I2C 16-bit GPIO expander. Most of these
+ chips are from NXP and TI.
+
+config RCAR_GPIO
+ bool "Renesas RCar GPIO driver"
+ depends on DM_GPIO && ARCH_RMOBILE
+ help
+ This driver supports the GPIO banks on Renesas RCar SoCs.
+
+config RZA1_GPIO
+ bool "Renesas RZ/A1 GPIO driver"
+ depends on DM_GPIO && RZA1
+ help
+ This driver supports the GPIO banks on Renesas RZ/A1 R7S72100 SoCs.
+
+config ROCKCHIP_GPIO
+ bool "Rockchip GPIO driver"
+ depends on DM_GPIO
+ help
+ Support GPIO access on Rockchip SoCs. The GPIOs are arranged into
+ a number of banks (different for each SoC type) each with 32 GPIOs.
+ The GPIOs for a device are defined in the device tree with one node
+ for each bank.
+
+config SANDBOX_GPIO
+ bool "Enable sandbox GPIO driver"
+ depends on SANDBOX && DM && DM_GPIO
+ help
+ This driver supports some simulated GPIOs which can be adjusted
+ using 'back door' functions like sandbox_gpio_set_value(). Then the
+ GPIOs can be inspected through the normal get_get_value()
+ interface. The purpose of this is to allow GPIOs to be used as
+ normal in sandbox, perhaps with test code actually driving the
+ behaviour of those GPIOs.
+
+config SANDBOX_GPIO_COUNT
+ int "Number of sandbox GPIOs"
+ depends on SANDBOX_GPIO
+ default 128
+ help
+ The sandbox driver can support any number of GPIOs. Generally these
+ are specified using the device tree. But you can also have a number
+ of 'anonymous' GPIOs that do not belong to any device or bank.
+ Select a suitable value depending on your needs.
+
+config SUNXI_GPIO
+ bool "Allwinner GPIO driver"
+ depends on ARCH_SUNXI
+ help
+ Support the GPIO device in Allwinner SoCs.
+
+config XILINX_GPIO
+ bool "Xilinx GPIO driver"
+ depends on DM_GPIO
+ help
+ This config enable the Xilinx GPIO driver for Microblaze.
+
+config CMD_TCA642X
+ bool "tca642x - Command to access tca642x state"
+ help
+ DEPRECATED - This needs conversion to driver model
+
+ This provides a way to looking at the pin state of this device.
+ This mirrors the 'gpio' command and that should be used in preference
+ to custom code.
+
+config TEGRA_GPIO
+ bool "Tegra20..210 GPIO driver"
+ depends on DM_GPIO
+ help
+ Support for the GPIO controller contained in NVIDIA Tegra20 through
+ Tegra210.
+
+config TEGRA186_GPIO
+ bool "Tegra186 GPIO driver"
+ depends on DM_GPIO
+ help
+ Support for the GPIO controller contained in NVIDIA Tegra186. This
+ covers both the "main" and "AON" controller instances, even though
+ they have slightly different register layout.
+
+config GPIO_UNIPHIER
+ bool "UniPhier GPIO"
+ depends on ARCH_UNIPHIER
+ help
+ Say yes here to support UniPhier GPIOs.
+
+config VYBRID_GPIO
+ bool "Vybrid GPIO driver"
+ depends on DM
+ default n
+ help
+ Say yes here to support Vybrid vf610 GPIOs.
+
+config PIC32_GPIO
+ bool "Microchip PIC32 GPIO driver"
+ depends on DM_GPIO && MACH_PIC32
+ default y
+ help
+ Say yes here to support Microchip PIC32 GPIOs.
+
+config OCTEON_GPIO
+ bool "Octeon II/III/TX/TX2 GPIO driver"
+ depends on DM_GPIO && DM_PCI && (ARCH_OCTEON || ARCH_OCTEONTX || ARCH_OCTEONTX2)
+ default y
+ help
+ Add support for the Marvell Octeon GPIO driver. This is used with
+ various Octeon parts such as Octeon II/III and OcteonTX/TX2.
+ Octeon II/III has 32 GPIOs (count defined via DT) and OcteonTX/TX2
+ has 64 GPIOs (count defined via internal register).
+
+config STM32_GPIO
+ bool "ST STM32 GPIO driver"
+ depends on DM_GPIO && (ARCH_STM32 || ARCH_STM32MP)
+ default y
+ help
+ Device model driver support for STM32 GPIO controller. It should be
+ usable on many stm32 families like stm32f4/f7/h7 and stm32mp1.
+ Tested on STM32F7.
+
+config SIFIVE_GPIO
+ bool "SiFive GPIO driver"
+ depends on DM_GPIO
+ help
+ Device model driver for GPIO controller present in SiFive FU540 SoC. This
+ driver enables GPIO interface on HiFive Unleashed A00 board.
+
+config MVEBU_GPIO
+ bool "Marvell MVEBU GPIO driver"
+ depends on DM_GPIO && (ARCH_MVEBU || ARCH_KIRKWOOD)
+ default y
+ help
+ Say yes here to support Marvell MVEBU (Armada XP/38x) GPIOs.
+
+config ZYNQ_GPIO
+ bool "Zynq GPIO driver"
+ depends on DM_GPIO
+ default y if ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_VERSAL
+ help
+ Supports GPIO access on Zynq SoC.
+
+config DM_74X164
+ bool "74x164 serial-in/parallel-out 8-bits shift register"
+ depends on DM_GPIO
+ help
+ Driver for 74x164 compatible serial-in/parallel-out 8-outputs
+ shift registers, such as 74lv165, 74hc595.
+ This driver can be used to provide access to more gpio outputs.
+
+config DM_PCA953X
+ bool "PCA95[357]x, PCA9698, TCA64xx, and MAX7310 I/O ports"
+ depends on DM_GPIO
+ help
+ Say yes here to provide access to several register-oriented
+ SMBus I/O expanders, made mostly by NXP or TI. Compatible
+ models include:
+
+ 4 bits: pca9536, pca9537
+
+ 8 bits: max7310, max7315, pca6107, pca9534, pca9538, pca9554,
+ pca9556, pca9557, pca9574, tca6408, xra1202
+
+ 16 bits: max7312, max7313, pca9535, pca9539, pca9555, pca9575,
+ tca6416
+
+ 24 bits: tca6424
+
+ 40 bits: pca9505, pca9698
+
+ Now, max 24 bits chips and PCA953X compatible chips are
+ supported
+
+config SPL_DM_PCA953X
+ bool "PCA95[357]x, PCA9698, TCA64xx, and MAX7310 I/O ports in SPL"
+ depends on DM_GPIO
+ help
+ Say yes here to provide access to several register-oriented
+ SMBus I/O expanders, made mostly by NXP or TI. Compatible
+ models include:
+
+ 4 bits: pca9536, pca9537
+
+ 8 bits: max7310, max7315, pca6107, pca9534, pca9538, pca9554,
+ pca9556, pca9557, pca9574, tca6408, xra1202
+
+ 16 bits: max7312, max7313, pca9535, pca9539, pca9555, pca9575,
+ tca6416
+
+ 24 bits: tca6424
+
+ 40 bits: pca9505, pca9698
+
+ Now, max 24 bits chips and PCA953X compatible chips are
+ supported
+
+config MPC8XXX_GPIO
+ bool "Freescale MPC8XXX GPIO driver"
+ depends on DM_GPIO
+ help
+ This driver supports the built-in GPIO controller of MPC8XXX CPUs.
+ Each GPIO bank is identified by its own entry in the device tree,
+ i.e.
+
+ gpio-controller@fc00 {
+ #gpio-cells = <2>;
+ compatible = "fsl,pq3-gpio";
+ reg = <0xfc00 0x100>
+ }
+
+ By default, each bank is assumed to have 32 GPIOs, but the ngpios
+ setting is honored, so the number of GPIOs for each bank is
+ configurable to match the actual GPIO count of the SoC (e.g. the
+ 32/32/23 banks of the P1022 SoC).
+
+ Aside from the standard functions of input/output mode, and output
+ value setting, the open-drain feature, which can configure individual
+ GPIOs to work as open-drain outputs, is supported.
+
+config MPC83XX_SPISEL_BOOT
+ bool "Freescale MPC83XX SPISEL_BOOT driver"
+ depends on DM_GPIO && ARCH_MPC830X
+ help
+ GPIO driver to set/clear dedicated SPISEL_BOOT output on MPC83XX.
+
+ This pin is typically used as spi chip select to a spi nor flash.
+
+config MT7620_GPIO
+ bool "MediaTek MT7620 GPIO driver"
+ depends on DM_GPIO && SOC_MT7620
+ default y
+ help
+ Device model driver for GPIO controller present in MediaTek MT7620
+ and earlier SoCs.
+
+config MT7621_GPIO
+ bool "MediaTek MT7621 GPIO driver"
+ depends on DM_GPIO && SOC_MT7628
+ default y
+ help
+ Say yes here to support MediaTek MT7621 compatible GPIOs.
+
+config NX_GPIO
+ bool "Nexell GPIO driver"
+ depends on DM_GPIO
+ help
+ Support GPIO access on Nexell SoCs. The GPIOs are arranged into
+ a number of banks (different for each SoC type) each with 32 GPIOs.
+ The GPIOs for a device are defined in the device tree with one node
+ for each bank.
+
+endmenu
diff --git a/roms/u-boot/drivers/gpio/Makefile b/roms/u-boot/drivers/gpio/Makefile
new file mode 100644
index 000000000..8541ba0b0
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/Makefile
@@ -0,0 +1,71 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright 2000-2008
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+
+ifndef CONFIG_SPL_BUILD
+obj-$(CONFIG_DWAPB_GPIO) += dwapb_gpio.o
+obj-$(CONFIG_AXP_GPIO) += axp_gpio.o
+obj-$(CONFIG_DM_74X164) += 74x164_gpio.o
+endif
+obj-$(CONFIG_$(SPL_TPL_)DM_GPIO) += gpio-uclass.o
+
+obj-$(CONFIG_$(SPL_)DM_PCA953X) += pca953x_gpio.o
+
+obj-$(CONFIG_AT91_GPIO) += at91_gpio.o
+obj-$(CONFIG_ATMEL_PIO4) += atmel_pio4.o
+obj-$(CONFIG_BCM6345_GPIO) += bcm6345_gpio.o
+obj-$(CONFIG_CORTINA_GPIO) += cortina_gpio.o
+obj-$(CONFIG_INTEL_GPIO) += intel_gpio.o
+obj-$(CONFIG_INTEL_ICH6_GPIO) += intel_ich6_gpio.o
+obj-$(CONFIG_INTEL_BROADWELL_GPIO) += intel_broadwell_gpio.o
+obj-$(CONFIG_IPROC_GPIO) += iproc_gpio.o
+obj-$(CONFIG_KIRKWOOD_GPIO) += kw_gpio.o
+obj-$(CONFIG_KONA_GPIO) += kona_gpio.o
+obj-$(CONFIG_MARVELL_GPIO) += mvgpio.o
+obj-$(CONFIG_MARVELL_MFP) += mvmfp.o
+obj-$(CONFIG_MXC_GPIO) += mxc_gpio.o
+obj-$(CONFIG_MXS_GPIO) += mxs_gpio.o
+obj-$(CONFIG_PCA953X) += pca953x.o
+obj-$(CONFIG_PCA9698) += pca9698.o
+obj-$(CONFIG_ROCKCHIP_GPIO) += rk_gpio.o
+obj-$(CONFIG_RCAR_GPIO) += gpio-rcar.o
+obj-$(CONFIG_RZA1_GPIO) += gpio-rza1.o
+obj-$(CONFIG_S5P) += s5p_gpio.o
+obj-$(CONFIG_SANDBOX_GPIO) += sandbox.o
+obj-$(CONFIG_SPEAR_GPIO) += spear_gpio.o
+obj-$(CONFIG_TEGRA_GPIO) += tegra_gpio.o
+obj-$(CONFIG_TEGRA186_GPIO) += tegra186_gpio.o
+obj-$(CONFIG_DA8XX_GPIO) += da8xx_gpio.o
+obj-$(CONFIG_DM644X_GPIO) += da8xx_gpio.o
+obj-$(CONFIG_ALTERA_PIO) += altera_pio.o
+obj-$(CONFIG_MPC83XX_GPIO) += mpc83xx_gpio.o
+obj-$(CONFIG_MPC8XXX_GPIO) += mpc8xxx_gpio.o
+obj-$(CONFIG_MPC83XX_SPISEL_BOOT) += mpc83xx_spisel_boot.o
+obj-$(CONFIG_SH_GPIO_PFC) += sh_pfc.o
+obj-$(CONFIG_OMAP_GPIO) += omap_gpio.o
+obj-$(CONFIG_DB8500_GPIO) += db8500_gpio.o
+obj-$(CONFIG_BCM2835_GPIO) += bcm2835_gpio.o
+obj-$(CONFIG_XILINX_GPIO) += xilinx_gpio.o
+obj-$(CONFIG_ADI_GPIO2) += adi_gpio2.o
+obj-$(CONFIG_TCA642X) += tca642x.o
+obj-$(CONFIG_SUNXI_GPIO) += sunxi_gpio.o
+obj-$(CONFIG_LPC32XX_GPIO) += lpc32xx_gpio.o
+obj-$(CONFIG_STM32_GPIO) += stm32_gpio.o
+obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o
+obj-$(CONFIG_ZYNQ_GPIO) += zynq_gpio.o
+obj-$(CONFIG_VYBRID_GPIO) += vybrid_gpio.o
+obj-$(CONFIG_HIKEY_GPIO) += hi6220_gpio.o
+obj-$(CONFIG_HSDK_CREG_GPIO) += hsdk-creg-gpio.o
+obj-$(CONFIG_IMX_RGPIO2P) += imx_rgpio2p.o
+obj-$(CONFIG_PIC32_GPIO) += pic32_gpio.o
+obj-$(CONFIG_OCTEON_GPIO) += octeon_gpio.o
+obj-$(CONFIG_MVEBU_GPIO) += mvebu_gpio.o
+obj-$(CONFIG_MSM_GPIO) += msm_gpio.o
+obj-$(CONFIG_$(SPL_)PCF8575_GPIO) += pcf8575_gpio.o
+obj-$(CONFIG_PM8916_GPIO) += pm8916_gpio.o
+obj-$(CONFIG_MT7620_GPIO) += mt7620_gpio.o
+obj-$(CONFIG_MT7621_GPIO) += mt7621_gpio.o
+obj-$(CONFIG_MSCC_SGPIO) += mscc_sgpio.o
+obj-$(CONFIG_NX_GPIO) += nx_gpio.o
+obj-$(CONFIG_SIFIVE_GPIO) += sifive-gpio.o
diff --git a/roms/u-boot/drivers/gpio/adi_gpio2.c b/roms/u-boot/drivers/gpio/adi_gpio2.c
new file mode 100644
index 000000000..d0849c85c
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/adi_gpio2.c
@@ -0,0 +1,425 @@
+/*
+ * ADI GPIO2 Abstraction Layer
+ * Support BF54x, BF60x and future processors.
+ *
+ * Copyright 2008-2013 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <linux/bug.h>
+#include <linux/errno.h>
+#include <asm/gpio.h>
+
+#define RESOURCE_LABEL_SIZE 16
+
+static struct str_ident {
+ char name[RESOURCE_LABEL_SIZE];
+} str_ident[MAX_RESOURCES];
+
+static void gpio_error(unsigned gpio)
+{
+ printf("adi_gpio2: GPIO %d wasn't requested!\n", gpio);
+}
+
+static void set_label(unsigned short ident, const char *label)
+{
+ if (label) {
+ strncpy(str_ident[ident].name, label,
+ RESOURCE_LABEL_SIZE);
+ str_ident[ident].name[RESOURCE_LABEL_SIZE - 1] = 0;
+ }
+}
+
+static char *get_label(unsigned short ident)
+{
+ return *str_ident[ident].name ? str_ident[ident].name : "UNKNOWN";
+}
+
+static int cmp_label(unsigned short ident, const char *label)
+{
+ if (label == NULL)
+ printf("adi_gpio2: please provide none-null label\n");
+
+ if (label)
+ return strcmp(str_ident[ident].name, label);
+ else
+ return -EINVAL;
+}
+
+#define map_entry(m, i) reserved_##m##_map[gpio_bank(i)]
+#define is_reserved(m, i, e) (map_entry(m, i) & gpio_bit(i))
+#define reserve(m, i) (map_entry(m, i) |= gpio_bit(i))
+#define unreserve(m, i) (map_entry(m, i) &= ~gpio_bit(i))
+#define DECLARE_RESERVED_MAP(m, c) unsigned short reserved_##m##_map[c]
+
+static DECLARE_RESERVED_MAP(gpio, GPIO_BANK_NUM);
+static DECLARE_RESERVED_MAP(peri, gpio_bank(MAX_RESOURCES));
+
+inline int check_gpio(unsigned gpio)
+{
+#if defined(CONFIG_BF54x)
+ if (gpio == GPIO_PB15 || gpio == GPIO_PC14 || gpio == GPIO_PC15 ||
+ gpio == GPIO_PH14 || gpio == GPIO_PH15 ||
+ gpio == GPIO_PJ14 || gpio == GPIO_PJ15)
+ return -EINVAL;
+#endif
+ if (gpio >= MAX_GPIOS)
+ return -EINVAL;
+ return 0;
+}
+
+static void port_setup(unsigned gpio, unsigned short usage)
+{
+#if defined(CONFIG_BF54x)
+ if (usage == GPIO_USAGE)
+ gpio_array[gpio_bank(gpio)]->port_fer &= ~gpio_bit(gpio);
+ else
+ gpio_array[gpio_bank(gpio)]->port_fer |= gpio_bit(gpio);
+#else
+ if (usage == GPIO_USAGE)
+ gpio_array[gpio_bank(gpio)]->port_fer_clear = gpio_bit(gpio);
+ else
+ gpio_array[gpio_bank(gpio)]->port_fer_set = gpio_bit(gpio);
+#endif
+}
+
+inline void portmux_setup(unsigned short per)
+{
+ u32 pmux;
+ u16 ident = P_IDENT(per);
+ u16 function = P_FUNCT2MUX(per);
+
+ pmux = gpio_array[gpio_bank(ident)]->port_mux;
+
+ pmux &= ~(0x3 << (2 * gpio_sub_n(ident)));
+ pmux |= (function & 0x3) << (2 * gpio_sub_n(ident));
+
+ gpio_array[gpio_bank(ident)]->port_mux = pmux;
+}
+
+inline u16 get_portmux(unsigned short per)
+{
+ u32 pmux;
+ u16 ident = P_IDENT(per);
+
+ pmux = gpio_array[gpio_bank(ident)]->port_mux;
+
+ return pmux >> (2 * gpio_sub_n(ident)) & 0x3;
+}
+
+unsigned short get_gpio_dir(unsigned gpio)
+{
+ return 0x01 &
+ (gpio_array[gpio_bank(gpio)]->dir_clear >> gpio_sub_n(gpio));
+}
+
+/***********************************************************
+*
+* FUNCTIONS: Peripheral Resource Allocation
+* and PortMux Setup
+*
+* INPUTS/OUTPUTS:
+* per Peripheral Identifier
+* label String
+*
+* DESCRIPTION: Peripheral Resource Allocation and Setup API
+**************************************************************/
+
+int peripheral_request(unsigned short per, const char *label)
+{
+ unsigned short ident = P_IDENT(per);
+
+ /*
+ * Don't cares are pins with only one dedicated function
+ */
+
+ if (per & P_DONTCARE)
+ return 0;
+
+ if (!(per & P_DEFINED))
+ return -EINVAL;
+
+ BUG_ON(ident >= MAX_RESOURCES);
+
+ /* If a pin can be muxed as either GPIO or peripheral, make
+ * sure it is not already a GPIO pin when we request it.
+ */
+ if (unlikely(!check_gpio(ident) && is_reserved(gpio, ident, 1))) {
+ printf("%s: Peripheral %d is already reserved as GPIO by %s!\n",
+ __func__, ident, get_label(ident));
+ return -EBUSY;
+ }
+
+ if (unlikely(is_reserved(peri, ident, 1))) {
+ /*
+ * Pin functions like AMC address strobes my
+ * be requested and used by several drivers
+ */
+
+ if (!((per & P_MAYSHARE) &&
+ get_portmux(per) == P_FUNCT2MUX(per))) {
+ /*
+ * Allow that the identical pin function can
+ * be requested from the same driver twice
+ */
+
+ if (cmp_label(ident, label) == 0)
+ goto anyway;
+
+ printf("%s: Peripheral %d function %d is already "
+ "reserved by %s!\n", __func__, ident,
+ P_FUNCT2MUX(per), get_label(ident));
+ return -EBUSY;
+ }
+ }
+
+ anyway:
+ reserve(peri, ident);
+
+ portmux_setup(per);
+ port_setup(ident, PERIPHERAL_USAGE);
+
+ set_label(ident, label);
+
+ return 0;
+}
+
+int peripheral_request_list(const unsigned short per[], const char *label)
+{
+ u16 cnt;
+ int ret;
+
+ for (cnt = 0; per[cnt] != 0; cnt++) {
+ ret = peripheral_request(per[cnt], label);
+
+ if (ret < 0) {
+ for (; cnt > 0; cnt--)
+ peripheral_free(per[cnt - 1]);
+
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+void peripheral_free(unsigned short per)
+{
+ unsigned short ident = P_IDENT(per);
+
+ if (per & P_DONTCARE)
+ return;
+
+ if (!(per & P_DEFINED))
+ return;
+
+ if (unlikely(!is_reserved(peri, ident, 0)))
+ return;
+
+ if (!(per & P_MAYSHARE))
+ port_setup(ident, GPIO_USAGE);
+
+ unreserve(peri, ident);
+
+ set_label(ident, "free");
+}
+
+void peripheral_free_list(const unsigned short per[])
+{
+ u16 cnt;
+ for (cnt = 0; per[cnt] != 0; cnt++)
+ peripheral_free(per[cnt]);
+}
+
+/***********************************************************
+*
+* FUNCTIONS: GPIO Driver
+*
+* INPUTS/OUTPUTS:
+* gpio PIO Number between 0 and MAX_GPIOS
+* label String
+*
+* DESCRIPTION: GPIO Driver API
+**************************************************************/
+
+int gpio_request(unsigned gpio, const char *label)
+{
+ if (check_gpio(gpio) < 0)
+ return -EINVAL;
+
+ /*
+ * Allow that the identical GPIO can
+ * be requested from the same driver twice
+ * Do nothing and return -
+ */
+
+ if (cmp_label(gpio, label) == 0)
+ return 0;
+
+ if (unlikely(is_reserved(gpio, gpio, 1))) {
+ printf("adi_gpio2: GPIO %d is already reserved by %s!\n",
+ gpio, get_label(gpio));
+ return -EBUSY;
+ }
+ if (unlikely(is_reserved(peri, gpio, 1))) {
+ printf("adi_gpio2: GPIO %d is already reserved as Peripheral "
+ "by %s!\n", gpio, get_label(gpio));
+ return -EBUSY;
+ }
+
+ reserve(gpio, gpio);
+ set_label(gpio, label);
+
+ port_setup(gpio, GPIO_USAGE);
+
+ return 0;
+}
+
+int gpio_free(unsigned gpio)
+{
+ if (check_gpio(gpio) < 0)
+ return -1;
+
+ if (unlikely(!is_reserved(gpio, gpio, 0))) {
+ gpio_error(gpio);
+ return -1;
+ }
+
+ unreserve(gpio, gpio);
+
+ set_label(gpio, "free");
+
+ return 0;
+}
+
+#ifdef ADI_SPECIAL_GPIO_BANKS
+static DECLARE_RESERVED_MAP(special_gpio, gpio_bank(MAX_RESOURCES));
+
+int special_gpio_request(unsigned gpio, const char *label)
+{
+ /*
+ * Allow that the identical GPIO can
+ * be requested from the same driver twice
+ * Do nothing and return -
+ */
+
+ if (cmp_label(gpio, label) == 0)
+ return 0;
+
+ if (unlikely(is_reserved(special_gpio, gpio, 1))) {
+ printf("adi_gpio2: GPIO %d is already reserved by %s!\n",
+ gpio, get_label(gpio));
+ return -EBUSY;
+ }
+ if (unlikely(is_reserved(peri, gpio, 1))) {
+ printf("adi_gpio2: GPIO %d is already reserved as Peripheral "
+ "by %s!\n", gpio, get_label(gpio));
+
+ return -EBUSY;
+ }
+
+ reserve(special_gpio, gpio);
+ reserve(peri, gpio);
+
+ set_label(gpio, label);
+ port_setup(gpio, GPIO_USAGE);
+
+ return 0;
+}
+
+void special_gpio_free(unsigned gpio)
+{
+ if (unlikely(!is_reserved(special_gpio, gpio, 0))) {
+ gpio_error(gpio);
+ return;
+ }
+
+ unreserve(special_gpio, gpio);
+ unreserve(peri, gpio);
+ set_label(gpio, "free");
+}
+#endif
+
+static inline void __gpio_direction_input(unsigned gpio)
+{
+ gpio_array[gpio_bank(gpio)]->dir_clear = gpio_bit(gpio);
+#if defined(CONFIG_BF54x)
+ gpio_array[gpio_bank(gpio)]->inen |= gpio_bit(gpio);
+#else
+ gpio_array[gpio_bank(gpio)]->inen_set = gpio_bit(gpio);
+#endif
+}
+
+int gpio_direction_input(unsigned gpio)
+{
+ unsigned long flags;
+
+ if (!is_reserved(gpio, gpio, 0)) {
+ gpio_error(gpio);
+ return -EINVAL;
+ }
+
+ local_irq_save(flags);
+ __gpio_direction_input(gpio);
+ local_irq_restore(flags);
+
+ return 0;
+}
+
+int gpio_set_value(unsigned gpio, int arg)
+{
+ if (arg)
+ gpio_array[gpio_bank(gpio)]->data_set = gpio_bit(gpio);
+ else
+ gpio_array[gpio_bank(gpio)]->data_clear = gpio_bit(gpio);
+
+ return 0;
+}
+
+int gpio_direction_output(unsigned gpio, int value)
+{
+ unsigned long flags;
+
+ if (!is_reserved(gpio, gpio, 0)) {
+ gpio_error(gpio);
+ return -EINVAL;
+ }
+
+ local_irq_save(flags);
+
+#if defined(CONFIG_BF54x)
+ gpio_array[gpio_bank(gpio)]->inen &= ~gpio_bit(gpio);
+#else
+ gpio_array[gpio_bank(gpio)]->inen_clear = gpio_bit(gpio);
+#endif
+ gpio_set_value(gpio, value);
+ gpio_array[gpio_bank(gpio)]->dir_set = gpio_bit(gpio);
+
+ local_irq_restore(flags);
+
+ return 0;
+}
+
+int gpio_get_value(unsigned gpio)
+{
+ return 1 & (gpio_array[gpio_bank(gpio)]->data >> gpio_sub_n(gpio));
+}
+
+void gpio_labels(void)
+{
+ int c, gpio;
+
+ for (c = 0; c < MAX_RESOURCES; c++) {
+ gpio = is_reserved(gpio, c, 1);
+ if (!check_gpio(c) && gpio)
+ printf("GPIO_%d:\t%s\tGPIO %s\n", c, get_label(c),
+ get_gpio_dir(c) ? "OUTPUT" : "INPUT");
+ else if (is_reserved(peri, c, 1))
+ printf("GPIO_%d:\t%s\tPeripheral\n", c, get_label(c));
+ else
+ continue;
+ }
+}
diff --git a/roms/u-boot/drivers/gpio/altera_pio.c b/roms/u-boot/drivers/gpio/altera_pio.c
new file mode 100644
index 000000000..edc5a8093
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/altera_pio.c
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015 Thomas Chou <thomas@wytron.com.tw>
+ * Copyright (C) 2011 Missing Link Electronics
+ * Joachim Foerster <joachim@missinglinkelectronics.com>
+ */
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <malloc.h>
+#include <fdtdec.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct altera_pio_regs {
+ u32 data; /* Data register */
+ u32 direction; /* Direction register */
+};
+
+struct altera_pio_plat {
+ struct altera_pio_regs *regs;
+ int gpio_count;
+ const char *bank_name;
+};
+
+static int altera_pio_direction_input(struct udevice *dev, unsigned pin)
+{
+ struct altera_pio_plat *plat = dev_get_plat(dev);
+ struct altera_pio_regs *const regs = plat->regs;
+
+ clrbits_le32(&regs->direction, 1 << pin);
+
+ return 0;
+}
+
+static int altera_pio_direction_output(struct udevice *dev, unsigned pin,
+ int val)
+{
+ struct altera_pio_plat *plat = dev_get_plat(dev);
+ struct altera_pio_regs *const regs = plat->regs;
+
+ if (val)
+ setbits_le32(&regs->data, 1 << pin);
+ else
+ clrbits_le32(&regs->data, 1 << pin);
+ /* change the data first, then the direction. to avoid glitch */
+ setbits_le32(&regs->direction, 1 << pin);
+
+ return 0;
+}
+
+static int altera_pio_get_value(struct udevice *dev, unsigned pin)
+{
+ struct altera_pio_plat *plat = dev_get_plat(dev);
+ struct altera_pio_regs *const regs = plat->regs;
+
+ return !!(readl(&regs->data) & (1 << pin));
+}
+
+
+static int altera_pio_set_value(struct udevice *dev, unsigned pin, int val)
+{
+ struct altera_pio_plat *plat = dev_get_plat(dev);
+ struct altera_pio_regs *const regs = plat->regs;
+
+ if (val)
+ setbits_le32(&regs->data, 1 << pin);
+ else
+ clrbits_le32(&regs->data, 1 << pin);
+
+ return 0;
+}
+
+static int altera_pio_probe(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct altera_pio_plat *plat = dev_get_plat(dev);
+
+ uc_priv->gpio_count = plat->gpio_count;
+ uc_priv->bank_name = plat->bank_name;
+
+ return 0;
+}
+
+static int altera_pio_of_to_plat(struct udevice *dev)
+{
+ struct altera_pio_plat *plat = dev_get_plat(dev);
+
+ plat->regs = map_physmem(dev_read_addr(dev),
+ sizeof(struct altera_pio_regs),
+ MAP_NOCACHE);
+ plat->gpio_count = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
+ "altr,gpio-bank-width", 32);
+ plat->bank_name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
+ "gpio-bank-name", NULL);
+
+ return 0;
+}
+
+static const struct dm_gpio_ops altera_pio_ops = {
+ .direction_input = altera_pio_direction_input,
+ .direction_output = altera_pio_direction_output,
+ .get_value = altera_pio_get_value,
+ .set_value = altera_pio_set_value,
+};
+
+static const struct udevice_id altera_pio_ids[] = {
+ { .compatible = "altr,pio-1.0" },
+ { }
+};
+
+U_BOOT_DRIVER(altera_pio) = {
+ .name = "altera_pio",
+ .id = UCLASS_GPIO,
+ .of_match = altera_pio_ids,
+ .ops = &altera_pio_ops,
+ .of_to_plat = altera_pio_of_to_plat,
+ .plat_auto = sizeof(struct altera_pio_plat),
+ .probe = altera_pio_probe,
+};
diff --git a/roms/u-boot/drivers/gpio/at91_gpio.c b/roms/u-boot/drivers/gpio/at91_gpio.c
new file mode 100644
index 000000000..1409db5dc
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/at91_gpio.c
@@ -0,0 +1,638 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2013 Bo Shen <voice.shen@atmel.com>
+ *
+ * Copyright (C) 2009 Jens Scharsig (js_at_ng@scharsoft.de)
+ *
+ * Copyright (C) 2005 HP Labs
+ */
+
+#include <config.h>
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <linux/sizes.h>
+#include <asm/gpio.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/at91_pio.h>
+
+#define GPIO_PER_BANK 32
+
+static struct at91_port *at91_pio_get_port(unsigned port)
+{
+ switch (port) {
+ case AT91_PIO_PORTA:
+ return (struct at91_port *)ATMEL_BASE_PIOA;
+ case AT91_PIO_PORTB:
+ return (struct at91_port *)ATMEL_BASE_PIOB;
+ case AT91_PIO_PORTC:
+ return (struct at91_port *)ATMEL_BASE_PIOC;
+#if (ATMEL_PIO_PORTS > 3)
+ case AT91_PIO_PORTD:
+ return (struct at91_port *)ATMEL_BASE_PIOD;
+#if (ATMEL_PIO_PORTS > 4)
+ case AT91_PIO_PORTE:
+ return (struct at91_port *)ATMEL_BASE_PIOE;
+#endif
+#endif
+ default:
+ printf("Error: at91_gpio: Fail to get PIO base!\n");
+ return NULL;
+ }
+}
+
+static void at91_set_port_pullup(struct at91_port *at91_port, unsigned offset,
+ int use_pullup)
+{
+ u32 mask;
+
+ mask = 1 << offset;
+ if (use_pullup)
+ writel(mask, &at91_port->puer);
+ else
+ writel(mask, &at91_port->pudr);
+ writel(mask, &at91_port->per);
+}
+
+int at91_set_pio_pullup(unsigned port, unsigned pin, int use_pullup)
+{
+ struct at91_port *at91_port = at91_pio_get_port(port);
+
+ if (at91_port && (pin < GPIO_PER_BANK))
+ at91_set_port_pullup(at91_port, pin, use_pullup);
+
+ return 0;
+}
+
+/*
+ * mux the pin to the "GPIO" peripheral role.
+ */
+int at91_set_pio_periph(unsigned port, unsigned pin, int use_pullup)
+{
+ struct at91_port *at91_port = at91_pio_get_port(port);
+ u32 mask;
+
+ if (at91_port && (pin < GPIO_PER_BANK)) {
+ mask = 1 << pin;
+ writel(mask, &at91_port->idr);
+ at91_set_pio_pullup(port, pin, use_pullup);
+ writel(mask, &at91_port->per);
+ }
+
+ return 0;
+}
+
+/*
+ * mux the pin to the "A" internal peripheral role.
+ */
+int at91_set_a_periph(unsigned port, unsigned pin, int use_pullup)
+{
+ struct at91_port *at91_port = at91_pio_get_port(port);
+ u32 mask;
+
+ if (at91_port && (pin < GPIO_PER_BANK)) {
+ mask = 1 << pin;
+ writel(mask, &at91_port->idr);
+ at91_set_pio_pullup(port, pin, use_pullup);
+ writel(mask, &at91_port->mux.pio2.asr);
+ writel(mask, &at91_port->pdr);
+ }
+
+ return 0;
+}
+
+/*
+ * mux the pin to the "B" internal peripheral role.
+ */
+int at91_set_b_periph(unsigned port, unsigned pin, int use_pullup)
+{
+ struct at91_port *at91_port = at91_pio_get_port(port);
+ u32 mask;
+
+ if (at91_port && (pin < GPIO_PER_BANK)) {
+ mask = 1 << pin;
+ writel(mask, &at91_port->idr);
+ at91_set_pio_pullup(port, pin, use_pullup);
+ writel(mask, &at91_port->mux.pio2.bsr);
+ writel(mask, &at91_port->pdr);
+ }
+
+ return 0;
+}
+
+/*
+ * mux the pin to the "A" internal peripheral role.
+ */
+int at91_pio3_set_a_periph(unsigned port, unsigned pin, int use_pullup)
+{
+ struct at91_port *at91_port = at91_pio_get_port(port);
+ u32 mask;
+
+ if (at91_port && (pin < GPIO_PER_BANK)) {
+ mask = 1 << pin;
+ writel(mask, &at91_port->idr);
+ at91_set_pio_pullup(port, pin, use_pullup);
+ writel(readl(&at91_port->mux.pio3.abcdsr1) & ~mask,
+ &at91_port->mux.pio3.abcdsr1);
+ writel(readl(&at91_port->mux.pio3.abcdsr2) & ~mask,
+ &at91_port->mux.pio3.abcdsr2);
+
+ writel(mask, &at91_port->pdr);
+ }
+
+ return 0;
+}
+
+/*
+ * mux the pin to the "B" internal peripheral role.
+ */
+int at91_pio3_set_b_periph(unsigned port, unsigned pin, int use_pullup)
+{
+ struct at91_port *at91_port = at91_pio_get_port(port);
+ u32 mask;
+
+ if (at91_port && (pin < GPIO_PER_BANK)) {
+ mask = 1 << pin;
+ writel(mask, &at91_port->idr);
+ at91_set_pio_pullup(port, pin, use_pullup);
+ writel(readl(&at91_port->mux.pio3.abcdsr1) | mask,
+ &at91_port->mux.pio3.abcdsr1);
+ writel(readl(&at91_port->mux.pio3.abcdsr2) & ~mask,
+ &at91_port->mux.pio3.abcdsr2);
+
+ writel(mask, &at91_port->pdr);
+ }
+
+ return 0;
+}
+/*
+ * mux the pin to the "C" internal peripheral role.
+ */
+int at91_pio3_set_c_periph(unsigned port, unsigned pin, int use_pullup)
+{
+ struct at91_port *at91_port = at91_pio_get_port(port);
+ u32 mask;
+
+ if (at91_port && (pin < GPIO_PER_BANK)) {
+ mask = 1 << pin;
+ writel(mask, &at91_port->idr);
+ at91_set_pio_pullup(port, pin, use_pullup);
+ writel(readl(&at91_port->mux.pio3.abcdsr1) & ~mask,
+ &at91_port->mux.pio3.abcdsr1);
+ writel(readl(&at91_port->mux.pio3.abcdsr2) | mask,
+ &at91_port->mux.pio3.abcdsr2);
+ writel(mask, &at91_port->pdr);
+ }
+
+ return 0;
+}
+
+/*
+ * mux the pin to the "D" internal peripheral role.
+ */
+int at91_pio3_set_d_periph(unsigned port, unsigned pin, int use_pullup)
+{
+ struct at91_port *at91_port = at91_pio_get_port(port);
+ u32 mask;
+
+ if (at91_port && (pin < GPIO_PER_BANK)) {
+ mask = 1 << pin;
+ writel(mask, &at91_port->idr);
+ at91_set_pio_pullup(port, pin, use_pullup);
+ writel(readl(&at91_port->mux.pio3.abcdsr1) | mask,
+ &at91_port->mux.pio3.abcdsr1);
+ writel(readl(&at91_port->mux.pio3.abcdsr2) | mask,
+ &at91_port->mux.pio3.abcdsr2);
+ writel(mask, &at91_port->pdr);
+ }
+
+ return 0;
+}
+
+#if CONFIG_IS_ENABLED(DM_GPIO)
+static bool at91_get_port_output(struct at91_port *at91_port, int offset)
+{
+ u32 mask, val;
+
+ mask = 1 << offset;
+ val = readl(&at91_port->osr);
+ return val & mask;
+}
+#endif
+
+static void at91_set_port_input(struct at91_port *at91_port, int offset,
+ int use_pullup)
+{
+ u32 mask;
+
+ mask = 1 << offset;
+ writel(mask, &at91_port->idr);
+ at91_set_port_pullup(at91_port, offset, use_pullup);
+ writel(mask, &at91_port->odr);
+ writel(mask, &at91_port->per);
+}
+
+/*
+ * mux the pin to the gpio controller (instead of "A" or "B" peripheral), and
+ * configure it for an input.
+ */
+int at91_set_pio_input(unsigned port, u32 pin, int use_pullup)
+{
+ struct at91_port *at91_port = at91_pio_get_port(port);
+
+ if (at91_port && (pin < GPIO_PER_BANK))
+ at91_set_port_input(at91_port, pin, use_pullup);
+
+ return 0;
+}
+
+static void at91_set_port_output(struct at91_port *at91_port, int offset,
+ int value)
+{
+ u32 mask;
+
+ mask = 1 << offset;
+ writel(mask, &at91_port->idr);
+ writel(mask, &at91_port->pudr);
+ if (value)
+ writel(mask, &at91_port->sodr);
+ else
+ writel(mask, &at91_port->codr);
+ writel(mask, &at91_port->oer);
+ writel(mask, &at91_port->per);
+}
+
+/*
+ * mux the pin to the gpio controller (instead of "A" or "B" peripheral),
+ * and configure it for an output.
+ */
+int at91_set_pio_output(unsigned port, u32 pin, int value)
+{
+ struct at91_port *at91_port = at91_pio_get_port(port);
+
+ if (at91_port && (pin < GPIO_PER_BANK))
+ at91_set_port_output(at91_port, pin, value);
+
+ return 0;
+}
+
+/*
+ * enable/disable the glitch filter. mostly used with IRQ handling.
+ */
+int at91_set_pio_deglitch(unsigned port, unsigned pin, int is_on)
+{
+ struct at91_port *at91_port = at91_pio_get_port(port);
+ u32 mask;
+
+ if (at91_port && (pin < GPIO_PER_BANK)) {
+ mask = 1 << pin;
+ if (is_on)
+ writel(mask, &at91_port->ifer);
+ else
+ writel(mask, &at91_port->ifdr);
+ }
+
+ return 0;
+}
+
+/*
+ * enable/disable the glitch filter. mostly used with IRQ handling.
+ */
+int at91_pio3_set_pio_deglitch(unsigned port, unsigned pin, int is_on)
+{
+ struct at91_port *at91_port = at91_pio_get_port(port);
+ u32 mask;
+
+ if (at91_port && (pin < GPIO_PER_BANK)) {
+ mask = 1 << pin;
+ if (is_on) {
+ writel(mask, &at91_port->mux.pio3.ifscdr);
+ writel(mask, &at91_port->ifer);
+ } else {
+ writel(mask, &at91_port->ifdr);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * enable/disable the debounce filter.
+ */
+int at91_pio3_set_pio_debounce(unsigned port, unsigned pin, int is_on, int div)
+{
+ struct at91_port *at91_port = at91_pio_get_port(port);
+ u32 mask;
+
+ if (at91_port && (pin < GPIO_PER_BANK)) {
+ mask = 1 << pin;
+ if (is_on) {
+ writel(mask, &at91_port->mux.pio3.ifscer);
+ writel(div & PIO_SCDR_DIV, &at91_port->mux.pio3.scdr);
+ writel(mask, &at91_port->ifer);
+ } else {
+ writel(mask, &at91_port->ifdr);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * enable/disable the pull-down.
+ * If pull-up already enabled while calling the function, we disable it.
+ */
+int at91_pio3_set_pio_pulldown(unsigned port, unsigned pin, int is_on)
+{
+ struct at91_port *at91_port = at91_pio_get_port(port);
+ u32 mask;
+
+ if (at91_port && (pin < GPIO_PER_BANK)) {
+ mask = 1 << pin;
+ if (is_on) {
+ at91_set_pio_pullup(port, pin, 0);
+ writel(mask, &at91_port->mux.pio3.ppder);
+ } else
+ writel(mask, &at91_port->mux.pio3.ppddr);
+ }
+
+ return 0;
+}
+
+int at91_pio3_set_pio_pullup(unsigned port, unsigned pin, int use_pullup)
+{
+ struct at91_port *at91_port = at91_pio_get_port(port);
+
+ if (use_pullup)
+ at91_pio3_set_pio_pulldown(port, pin, 0);
+
+ if (at91_port && (pin < GPIO_PER_BANK))
+ at91_set_port_pullup(at91_port, pin, use_pullup);
+
+ return 0;
+}
+
+/*
+ * disable Schmitt trigger
+ */
+int at91_pio3_set_pio_disable_schmitt_trig(unsigned port, unsigned pin)
+{
+ struct at91_port *at91_port = at91_pio_get_port(port);
+ u32 mask;
+
+ if (at91_port && (pin < GPIO_PER_BANK)) {
+ mask = 1 << pin;
+ writel(readl(&at91_port->schmitt) | mask,
+ &at91_port->schmitt);
+ }
+
+ return 0;
+}
+
+/*
+ * enable/disable the multi-driver. This is only valid for output and
+ * allows the output pin to run as an open collector output.
+ */
+int at91_set_pio_multi_drive(unsigned port, unsigned pin, int is_on)
+{
+ struct at91_port *at91_port = at91_pio_get_port(port);
+ u32 mask;
+
+ if (at91_port && (pin < GPIO_PER_BANK)) {
+ mask = 1 << pin;
+ if (is_on)
+ writel(mask, &at91_port->mder);
+ else
+ writel(mask, &at91_port->mddr);
+ }
+
+ return 0;
+}
+
+static void at91_set_port_value(struct at91_port *at91_port, int offset,
+ int value)
+{
+ u32 mask;
+
+ mask = 1 << offset;
+ if (value)
+ writel(mask, &at91_port->sodr);
+ else
+ writel(mask, &at91_port->codr);
+}
+
+/*
+ * assuming the pin is muxed as a gpio output, set its value.
+ */
+int at91_set_pio_value(unsigned port, unsigned pin, int value)
+{
+ struct at91_port *at91_port = at91_pio_get_port(port);
+
+ if (at91_port && (pin < GPIO_PER_BANK))
+ at91_set_port_value(at91_port, pin, value);
+
+ return 0;
+}
+
+static int at91_get_port_value(struct at91_port *at91_port, int offset)
+{
+ u32 pdsr = 0, mask;
+
+ mask = 1 << offset;
+ pdsr = readl(&at91_port->pdsr) & mask;
+
+ return pdsr != 0;
+}
+/*
+ * read the pin's value (works even if it's not muxed as a gpio).
+ */
+int at91_get_pio_value(unsigned port, unsigned pin)
+{
+ struct at91_port *at91_port = at91_pio_get_port(port);
+
+ if (at91_port && (pin < GPIO_PER_BANK))
+ return at91_get_port_value(at91_port, pin);
+
+ return 0;
+}
+
+#if !CONFIG_IS_ENABLED(DM_GPIO)
+/* Common GPIO API */
+
+int gpio_request(unsigned gpio, const char *label)
+{
+ return 0;
+}
+
+int gpio_free(unsigned gpio)
+{
+ return 0;
+}
+
+int gpio_direction_input(unsigned gpio)
+{
+ at91_set_pio_input(at91_gpio_to_port(gpio),
+ at91_gpio_to_pin(gpio), 0);
+ return 0;
+}
+
+int gpio_direction_output(unsigned gpio, int value)
+{
+ at91_set_pio_output(at91_gpio_to_port(gpio),
+ at91_gpio_to_pin(gpio), value);
+ return 0;
+}
+
+int gpio_get_value(unsigned gpio)
+{
+ return at91_get_pio_value(at91_gpio_to_port(gpio),
+ at91_gpio_to_pin(gpio));
+}
+
+int gpio_set_value(unsigned gpio, int value)
+{
+ at91_set_pio_value(at91_gpio_to_port(gpio),
+ at91_gpio_to_pin(gpio), value);
+
+ return 0;
+}
+#endif
+
+#if CONFIG_IS_ENABLED(DM_GPIO)
+
+struct at91_port_priv {
+ struct at91_port *regs;
+};
+
+/* set GPIO pin 'gpio' as an input */
+static int at91_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+ struct at91_port_priv *port = dev_get_priv(dev);
+
+ at91_set_port_input(port->regs, offset, 0);
+
+ return 0;
+}
+
+/* set GPIO pin 'gpio' as an output, with polarity 'value' */
+static int at91_gpio_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct at91_port_priv *port = dev_get_priv(dev);
+
+ at91_set_port_output(port->regs, offset, value);
+
+ return 0;
+}
+
+/* read GPIO IN value of pin 'gpio' */
+static int at91_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+ struct at91_port_priv *port = dev_get_priv(dev);
+
+ return at91_get_port_value(port->regs, offset);
+}
+
+/* write GPIO OUT value to pin 'gpio' */
+static int at91_gpio_set_value(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct at91_port_priv *port = dev_get_priv(dev);
+
+ at91_set_port_value(port->regs, offset, value);
+
+ return 0;
+}
+
+static int at91_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+ struct at91_port_priv *port = dev_get_priv(dev);
+
+ /* GPIOF_FUNC is not implemented yet */
+ if (at91_get_port_output(port->regs, offset))
+ return GPIOF_OUTPUT;
+ else
+ return GPIOF_INPUT;
+}
+
+static const char *at91_get_bank_name(uint32_t base_addr)
+{
+ switch (base_addr) {
+ case ATMEL_BASE_PIOA:
+ return "PIOA";
+ case ATMEL_BASE_PIOB:
+ return "PIOB";
+ case ATMEL_BASE_PIOC:
+ return "PIOC";
+#if (ATMEL_PIO_PORTS > 3)
+ case ATMEL_BASE_PIOD:
+ return "PIOD";
+#if (ATMEL_PIO_PORTS > 4)
+ case ATMEL_BASE_PIOE:
+ return "PIOE";
+#endif
+#endif
+ }
+
+ return "undefined";
+}
+
+static const struct dm_gpio_ops gpio_at91_ops = {
+ .direction_input = at91_gpio_direction_input,
+ .direction_output = at91_gpio_direction_output,
+ .get_value = at91_gpio_get_value,
+ .set_value = at91_gpio_set_value,
+ .get_function = at91_gpio_get_function,
+};
+
+static int at91_gpio_probe(struct udevice *dev)
+{
+ struct at91_port_priv *port = dev_get_priv(dev);
+ struct at91_port_plat *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct clk clk;
+ int ret;
+
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(&clk);
+ if (ret)
+ return ret;
+
+ clk_free(&clk);
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+ plat->base_addr = dev_read_addr(dev);
+#endif
+ plat->bank_name = at91_get_bank_name(plat->base_addr);
+ port->regs = (struct at91_port *)plat->base_addr;
+
+ uc_priv->bank_name = plat->bank_name;
+ uc_priv->gpio_count = GPIO_PER_BANK;
+
+ return 0;
+}
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+static const struct udevice_id at91_gpio_ids[] = {
+ { .compatible = "atmel,at91rm9200-gpio" },
+ { }
+};
+#endif
+
+U_BOOT_DRIVER(atmel_at91rm9200_gpio) = {
+ .name = "atmel_at91rm9200_gpio",
+ .id = UCLASS_GPIO,
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+ .of_match = at91_gpio_ids,
+ .plat_auto = sizeof(struct at91_port_plat),
+#endif
+ .ops = &gpio_at91_ops,
+ .probe = at91_gpio_probe,
+ .priv_auto = sizeof(struct at91_port_priv),
+};
+#endif
diff --git a/roms/u-boot/drivers/gpio/atmel_pio4.c b/roms/u-boot/drivers/gpio/atmel_pio4.c
new file mode 100644
index 000000000..bea609db9
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/atmel_pio4.c
@@ -0,0 +1,367 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Atmel PIO4 device driver
+ *
+ * Copyright (C) 2015 Atmel Corporation
+ * Wenyou.Yang <wenyou.yang@atmel.com>
+ */
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <malloc.h>
+#include <asm/arch/hardware.h>
+#include <asm/global_data.h>
+#include <asm/gpio.h>
+#include <linux/bitops.h>
+#include <mach/gpio.h>
+#include <mach/atmel_pio4.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct atmel_pio4_port *atmel_pio4_port_base(u32 port)
+{
+ struct atmel_pio4_port *base = NULL;
+
+ switch (port) {
+ case AT91_PIO_PORTA:
+ base = (struct atmel_pio4_port *)ATMEL_BASE_PIOA;
+ break;
+ case AT91_PIO_PORTB:
+ base = (struct atmel_pio4_port *)ATMEL_BASE_PIOB;
+ break;
+ case AT91_PIO_PORTC:
+ base = (struct atmel_pio4_port *)ATMEL_BASE_PIOC;
+ break;
+ case AT91_PIO_PORTD:
+ base = (struct atmel_pio4_port *)ATMEL_BASE_PIOD;
+ break;
+ default:
+ printf("Error: Atmel PIO4: Failed to get PIO base of port#%d!\n",
+ port);
+ break;
+ }
+
+ return base;
+}
+
+static int atmel_pio4_config_io_func(u32 port, u32 pin,
+ u32 func, u32 config)
+{
+ struct atmel_pio4_port *port_base;
+ u32 reg, mask;
+
+ if (pin >= ATMEL_PIO_NPINS_PER_BANK)
+ return -EINVAL;
+
+ port_base = atmel_pio4_port_base(port);
+ if (!port_base)
+ return -EINVAL;
+
+ mask = 1 << pin;
+ reg = func;
+ reg |= config;
+
+ writel(mask, &port_base->mskr);
+ writel(reg, &port_base->cfgr);
+
+ return 0;
+}
+
+int atmel_pio4_set_gpio(u32 port, u32 pin, u32 config)
+{
+ return atmel_pio4_config_io_func(port, pin,
+ ATMEL_PIO_CFGR_FUNC_GPIO,
+ config);
+}
+
+int atmel_pio4_set_a_periph(u32 port, u32 pin, u32 config)
+{
+ return atmel_pio4_config_io_func(port, pin,
+ ATMEL_PIO_CFGR_FUNC_PERIPH_A,
+ config);
+}
+
+int atmel_pio4_set_b_periph(u32 port, u32 pin, u32 config)
+{
+ return atmel_pio4_config_io_func(port, pin,
+ ATMEL_PIO_CFGR_FUNC_PERIPH_B,
+ config);
+}
+
+int atmel_pio4_set_c_periph(u32 port, u32 pin, u32 config)
+{
+ return atmel_pio4_config_io_func(port, pin,
+ ATMEL_PIO_CFGR_FUNC_PERIPH_C,
+ config);
+}
+
+int atmel_pio4_set_d_periph(u32 port, u32 pin, u32 config)
+{
+ return atmel_pio4_config_io_func(port, pin,
+ ATMEL_PIO_CFGR_FUNC_PERIPH_D,
+ config);
+}
+
+int atmel_pio4_set_e_periph(u32 port, u32 pin, u32 config)
+{
+ return atmel_pio4_config_io_func(port, pin,
+ ATMEL_PIO_CFGR_FUNC_PERIPH_E,
+ config);
+}
+
+int atmel_pio4_set_f_periph(u32 port, u32 pin, u32 config)
+{
+ return atmel_pio4_config_io_func(port, pin,
+ ATMEL_PIO_CFGR_FUNC_PERIPH_F,
+ config);
+}
+
+int atmel_pio4_set_g_periph(u32 port, u32 pin, u32 config)
+{
+ return atmel_pio4_config_io_func(port, pin,
+ ATMEL_PIO_CFGR_FUNC_PERIPH_G,
+ config);
+}
+
+int atmel_pio4_set_pio_output(u32 port, u32 pin, u32 value)
+{
+ struct atmel_pio4_port *port_base;
+ u32 reg, mask;
+
+ if (pin >= ATMEL_PIO_NPINS_PER_BANK)
+ return -EINVAL;
+
+ port_base = atmel_pio4_port_base(port);
+ if (!port_base)
+ return -EINVAL;
+
+ mask = 0x01 << pin;
+ reg = ATMEL_PIO_CFGR_FUNC_GPIO | ATMEL_PIO_DIR_MASK;
+
+ writel(mask, &port_base->mskr);
+ writel(reg, &port_base->cfgr);
+
+ if (value)
+ writel(mask, &port_base->sodr);
+ else
+ writel(mask, &port_base->codr);
+
+ return 0;
+}
+
+int atmel_pio4_get_pio_input(u32 port, u32 pin)
+{
+ struct atmel_pio4_port *port_base;
+ u32 reg, mask;
+
+ if (pin >= ATMEL_PIO_NPINS_PER_BANK)
+ return -EINVAL;
+
+ port_base = atmel_pio4_port_base(port);
+ if (!port_base)
+ return -EINVAL;
+
+ mask = 0x01 << pin;
+ reg = ATMEL_PIO_CFGR_FUNC_GPIO;
+
+ writel(mask, &port_base->mskr);
+ writel(reg, &port_base->cfgr);
+
+ return (readl(&port_base->pdsr) & mask) ? 1 : 0;
+}
+
+#if CONFIG_IS_ENABLED(DM_GPIO)
+
+/**
+ * struct atmel_pioctrl_data - Atmel PIO controller (pinmux + gpio) data struct
+ * @nbanks: number of PIO banks
+ * @last_bank_count: number of lines in the last bank (can be less than
+ * the rest of the banks).
+ */
+struct atmel_pioctrl_data {
+ u32 nbanks;
+ u32 last_bank_count;
+};
+
+struct atmel_pio4_plat {
+ struct atmel_pio4_port *reg_base;
+};
+
+static struct atmel_pio4_port *atmel_pio4_bank_base(struct udevice *dev,
+ u32 bank)
+{
+ struct atmel_pio4_plat *plat = dev_get_plat(dev);
+ struct atmel_pio4_port *port_base =
+ (struct atmel_pio4_port *)((u32)plat->reg_base +
+ ATMEL_PIO_BANK_OFFSET * bank);
+
+ return port_base;
+}
+
+static int atmel_pio4_direction_input(struct udevice *dev, unsigned offset)
+{
+ u32 bank = ATMEL_PIO_BANK(offset);
+ u32 line = ATMEL_PIO_LINE(offset);
+ struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank);
+ u32 mask = BIT(line);
+
+ writel(mask, &port_base->mskr);
+
+ clrbits_le32(&port_base->cfgr,
+ ATMEL_PIO_CFGR_FUNC_MASK | ATMEL_PIO_DIR_MASK);
+
+ return 0;
+}
+
+static int atmel_pio4_direction_output(struct udevice *dev,
+ unsigned offset, int value)
+{
+ u32 bank = ATMEL_PIO_BANK(offset);
+ u32 line = ATMEL_PIO_LINE(offset);
+ struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank);
+ u32 mask = BIT(line);
+
+ writel(mask, &port_base->mskr);
+
+ clrsetbits_le32(&port_base->cfgr,
+ ATMEL_PIO_CFGR_FUNC_MASK, ATMEL_PIO_DIR_MASK);
+
+ if (value)
+ writel(mask, &port_base->sodr);
+ else
+ writel(mask, &port_base->codr);
+
+ return 0;
+}
+
+static int atmel_pio4_get_value(struct udevice *dev, unsigned offset)
+{
+ u32 bank = ATMEL_PIO_BANK(offset);
+ u32 line = ATMEL_PIO_LINE(offset);
+ struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank);
+ u32 mask = BIT(line);
+
+ return (readl(&port_base->pdsr) & mask) ? 1 : 0;
+}
+
+static int atmel_pio4_set_value(struct udevice *dev,
+ unsigned offset, int value)
+{
+ u32 bank = ATMEL_PIO_BANK(offset);
+ u32 line = ATMEL_PIO_LINE(offset);
+ struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank);
+ u32 mask = BIT(line);
+
+ if (value)
+ writel(mask, &port_base->sodr);
+ else
+ writel(mask, &port_base->codr);
+
+ return 0;
+}
+
+static int atmel_pio4_get_function(struct udevice *dev, unsigned offset)
+{
+ u32 bank = ATMEL_PIO_BANK(offset);
+ u32 line = ATMEL_PIO_LINE(offset);
+ struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank);
+ u32 mask = BIT(line);
+
+ writel(mask, &port_base->mskr);
+
+ return (readl(&port_base->cfgr) &
+ ATMEL_PIO_DIR_MASK) ? GPIOF_OUTPUT : GPIOF_INPUT;
+}
+
+static const struct dm_gpio_ops atmel_pio4_ops = {
+ .direction_input = atmel_pio4_direction_input,
+ .direction_output = atmel_pio4_direction_output,
+ .get_value = atmel_pio4_get_value,
+ .set_value = atmel_pio4_set_value,
+ .get_function = atmel_pio4_get_function,
+};
+
+static int atmel_pio4_bind(struct udevice *dev)
+{
+ return dm_scan_fdt_dev(dev);
+}
+
+static int atmel_pio4_probe(struct udevice *dev)
+{
+ struct atmel_pio4_plat *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct atmel_pioctrl_data *pioctrl_data;
+ struct clk clk;
+ fdt_addr_t addr_base;
+ u32 nbanks;
+ int ret;
+
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(&clk);
+ if (ret)
+ return ret;
+
+ clk_free(&clk);
+
+ addr_base = dev_read_addr(dev);
+ if (addr_base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ plat->reg_base = (struct atmel_pio4_port *)addr_base;
+
+ pioctrl_data = (struct atmel_pioctrl_data *)dev_get_driver_data(dev);
+ nbanks = pioctrl_data->nbanks;
+
+ uc_priv->bank_name = fdt_get_name(gd->fdt_blob, dev_of_offset(dev),
+ NULL);
+ uc_priv->gpio_count = nbanks * ATMEL_PIO_NPINS_PER_BANK;
+
+ /* if last bank has limited number of pins, adjust accordingly */
+ if (pioctrl_data->last_bank_count != ATMEL_PIO_NPINS_PER_BANK) {
+ uc_priv->gpio_count -= ATMEL_PIO_NPINS_PER_BANK;
+ uc_priv->gpio_count += pioctrl_data->last_bank_count;
+ }
+
+ return 0;
+}
+
+/*
+ * The number of banks can be different from a SoC to another one.
+ * We can have up to 16 banks.
+ */
+static const struct atmel_pioctrl_data atmel_sama5d2_pioctrl_data = {
+ .nbanks = 4,
+ .last_bank_count = ATMEL_PIO_NPINS_PER_BANK,
+};
+
+static const struct atmel_pioctrl_data microchip_sama7g5_pioctrl_data = {
+ .nbanks = 5,
+ .last_bank_count = 8, /* 5th bank has only 8 lines on sama7g5 */
+};
+
+static const struct udevice_id atmel_pio4_ids[] = {
+ {
+ .compatible = "atmel,sama5d2-gpio",
+ .data = (ulong)&atmel_sama5d2_pioctrl_data,
+ }, {
+ .compatible = "microchip,sama7g5-gpio",
+ .data = (ulong)&microchip_sama7g5_pioctrl_data,
+ },
+ {}
+};
+
+U_BOOT_DRIVER(gpio_atmel_pio4) = {
+ .name = "gpio_atmel_pio4",
+ .id = UCLASS_GPIO,
+ .ops = &atmel_pio4_ops,
+ .probe = atmel_pio4_probe,
+ .bind = atmel_pio4_bind,
+ .of_match = atmel_pio4_ids,
+ .plat_auto = sizeof(struct atmel_pio4_plat),
+};
+
+#endif
diff --git a/roms/u-boot/drivers/gpio/axp_gpio.c b/roms/u-boot/drivers/gpio/axp_gpio.c
new file mode 100644
index 000000000..73058cf40
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/axp_gpio.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2015 Hans de Goede <hdegoede@redhat.com>
+ *
+ * X-Powers AXP Power Management ICs gpio driver
+ */
+
+#include <common.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/pmic_bus.h>
+#include <asm/gpio.h>
+#include <axp_pmic.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+#include <errno.h>
+
+static int axp_gpio_set_value(struct udevice *dev, unsigned pin, int val);
+
+static u8 axp_get_gpio_ctrl_reg(unsigned pin)
+{
+ switch (pin) {
+ case 0: return AXP_GPIO0_CTRL;
+ case 1: return AXP_GPIO1_CTRL;
+#ifdef AXP_GPIO2_CTRL
+ case 2: return AXP_GPIO2_CTRL;
+#endif
+#ifdef AXP_GPIO3_CTRL
+ case 3: return AXP_GPIO3_CTRL;
+#endif
+ }
+ return 0;
+}
+
+static int axp_gpio_direction_input(struct udevice *dev, unsigned pin)
+{
+ u8 reg;
+
+ switch (pin) {
+#ifndef CONFIG_AXP152_POWER /* NA on axp152 */
+ case SUNXI_GPIO_AXP0_VBUS_DETECT:
+ return 0;
+#endif
+ default:
+ reg = axp_get_gpio_ctrl_reg(pin);
+ if (reg == 0)
+ return -EINVAL;
+
+ return pmic_bus_write(reg, AXP_GPIO_CTRL_INPUT);
+ }
+}
+
+static int axp_gpio_direction_output(struct udevice *dev, unsigned pin,
+ int val)
+{
+ __maybe_unused int ret;
+ u8 reg;
+
+ switch (pin) {
+#ifdef AXP_MISC_CTRL_N_VBUSEN_FUNC
+ /* Only available on later PMICs */
+ case SUNXI_GPIO_AXP0_VBUS_ENABLE:
+ ret = pmic_bus_clrbits(AXP_MISC_CTRL,
+ AXP_MISC_CTRL_N_VBUSEN_FUNC);
+ if (ret)
+ return ret;
+
+ return axp_gpio_set_value(dev, pin, val);
+#endif
+ default:
+ reg = axp_get_gpio_ctrl_reg(pin);
+ if (reg == 0)
+ return -EINVAL;
+
+ return pmic_bus_write(reg, val ? AXP_GPIO_CTRL_OUTPUT_HIGH :
+ AXP_GPIO_CTRL_OUTPUT_LOW);
+ }
+}
+
+static int axp_gpio_get_value(struct udevice *dev, unsigned pin)
+{
+ u8 reg, val, mask;
+ int ret;
+
+ switch (pin) {
+#ifndef CONFIG_AXP152_POWER /* NA on axp152 */
+ case SUNXI_GPIO_AXP0_VBUS_DETECT:
+ ret = pmic_bus_read(AXP_POWER_STATUS, &val);
+ mask = AXP_POWER_STATUS_VBUS_PRESENT;
+ break;
+#endif
+#ifdef AXP_MISC_CTRL_N_VBUSEN_FUNC
+ /* Only available on later PMICs */
+ case SUNXI_GPIO_AXP0_VBUS_ENABLE:
+ ret = pmic_bus_read(AXP_VBUS_IPSOUT, &val);
+ mask = AXP_VBUS_IPSOUT_DRIVEBUS;
+ break;
+#endif
+ default:
+ reg = axp_get_gpio_ctrl_reg(pin);
+ if (reg == 0)
+ return -EINVAL;
+
+ ret = pmic_bus_read(AXP_GPIO_STATE, &val);
+ mask = 1 << (pin + AXP_GPIO_STATE_OFFSET);
+ }
+ if (ret)
+ return ret;
+
+ return (val & mask) ? 1 : 0;
+}
+
+static int axp_gpio_set_value(struct udevice *dev, unsigned pin, int val)
+{
+ u8 reg;
+
+ switch (pin) {
+#ifdef AXP_MISC_CTRL_N_VBUSEN_FUNC
+ /* Only available on later PMICs */
+ case SUNXI_GPIO_AXP0_VBUS_ENABLE:
+ if (val)
+ return pmic_bus_setbits(AXP_VBUS_IPSOUT,
+ AXP_VBUS_IPSOUT_DRIVEBUS);
+ else
+ return pmic_bus_clrbits(AXP_VBUS_IPSOUT,
+ AXP_VBUS_IPSOUT_DRIVEBUS);
+#endif
+ default:
+ reg = axp_get_gpio_ctrl_reg(pin);
+ if (reg == 0)
+ return -EINVAL;
+
+ return pmic_bus_write(reg, val ? AXP_GPIO_CTRL_OUTPUT_HIGH :
+ AXP_GPIO_CTRL_OUTPUT_LOW);
+ }
+}
+
+static const struct dm_gpio_ops gpio_axp_ops = {
+ .direction_input = axp_gpio_direction_input,
+ .direction_output = axp_gpio_direction_output,
+ .get_value = axp_gpio_get_value,
+ .set_value = axp_gpio_set_value,
+};
+
+static int gpio_axp_probe(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ /* Tell the uclass how many GPIOs we have */
+ uc_priv->bank_name = strdup(SUNXI_GPIO_AXP0_PREFIX);
+ uc_priv->gpio_count = SUNXI_GPIO_AXP0_GPIO_COUNT;
+
+ return 0;
+}
+
+U_BOOT_DRIVER(gpio_axp) = {
+ .name = "gpio_axp",
+ .id = UCLASS_GPIO,
+ .ops = &gpio_axp_ops,
+ .probe = gpio_axp_probe,
+};
+
+int axp_gpio_init(void)
+{
+ struct udevice *dev;
+ int ret;
+
+ ret = pmic_bus_init();
+ if (ret)
+ return ret;
+
+ /* There is no devicetree support for the axp yet, so bind directly */
+ ret = device_bind_driver(dm_root(), "gpio_axp", "AXP-gpio", &dev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
diff --git a/roms/u-boot/drivers/gpio/bcm2835_gpio.c b/roms/u-boot/drivers/gpio/bcm2835_gpio.c
new file mode 100644
index 000000000..704a6fa71
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/bcm2835_gpio.c
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2012 Vikram Narayananan
+ * <vikram186@gmail.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/pinctrl.h>
+#include <errno.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <fdtdec.h>
+
+struct bcm2835_gpios {
+ struct bcm2835_gpio_regs *reg;
+ struct udevice *pinctrl;
+};
+
+static int bcm2835_gpio_direction_input(struct udevice *dev, unsigned gpio)
+{
+ struct bcm2835_gpios *gpios = dev_get_priv(dev);
+ unsigned val;
+
+ val = readl(&gpios->reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]);
+ val &= ~(BCM2835_GPIO_FSEL_MASK << BCM2835_GPIO_FSEL_SHIFT(gpio));
+ val |= (BCM2835_GPIO_INPUT << BCM2835_GPIO_FSEL_SHIFT(gpio));
+ writel(val, &gpios->reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]);
+
+ return 0;
+}
+
+static int bcm2835_gpio_direction_output(struct udevice *dev, unsigned int gpio,
+ int value)
+{
+ struct bcm2835_gpios *gpios = dev_get_priv(dev);
+ unsigned val;
+
+ gpio_set_value(gpio, value);
+
+ val = readl(&gpios->reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]);
+ val &= ~(BCM2835_GPIO_FSEL_MASK << BCM2835_GPIO_FSEL_SHIFT(gpio));
+ val |= (BCM2835_GPIO_OUTPUT << BCM2835_GPIO_FSEL_SHIFT(gpio));
+ writel(val, &gpios->reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]);
+
+ return 0;
+}
+
+static int bcm2835_get_value(const struct bcm2835_gpios *gpios, unsigned gpio)
+{
+ unsigned val;
+
+ val = readl(&gpios->reg->gplev[BCM2835_GPIO_COMMON_BANK(gpio)]);
+
+ return (val >> BCM2835_GPIO_COMMON_SHIFT(gpio)) & 0x1;
+}
+
+static int bcm2835_gpio_get_value(struct udevice *dev, unsigned gpio)
+{
+ const struct bcm2835_gpios *gpios = dev_get_priv(dev);
+
+ return bcm2835_get_value(gpios, gpio);
+}
+
+static int bcm2835_gpio_set_value(struct udevice *dev, unsigned gpio,
+ int value)
+{
+ struct bcm2835_gpios *gpios = dev_get_priv(dev);
+ u32 *output_reg = value ? gpios->reg->gpset : gpios->reg->gpclr;
+
+ writel(1 << BCM2835_GPIO_COMMON_SHIFT(gpio),
+ &output_reg[BCM2835_GPIO_COMMON_BANK(gpio)]);
+
+ return 0;
+}
+
+static int bcm2835_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+ struct bcm2835_gpios *priv = dev_get_priv(dev);
+ int funcid;
+
+ funcid = pinctrl_get_gpio_mux(priv->pinctrl, 0, offset);
+
+ switch (funcid) {
+ case BCM2835_GPIO_OUTPUT:
+ return GPIOF_OUTPUT;
+ case BCM2835_GPIO_INPUT:
+ return GPIOF_INPUT;
+ default:
+ return GPIOF_FUNC;
+ }
+}
+
+static const struct dm_gpio_ops gpio_bcm2835_ops = {
+ .direction_input = bcm2835_gpio_direction_input,
+ .direction_output = bcm2835_gpio_direction_output,
+ .get_value = bcm2835_gpio_get_value,
+ .set_value = bcm2835_gpio_set_value,
+ .get_function = bcm2835_gpio_get_function,
+};
+
+static int bcm2835_gpio_probe(struct udevice *dev)
+{
+ struct bcm2835_gpios *gpios = dev_get_priv(dev);
+ struct bcm2835_gpio_plat *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ uc_priv->bank_name = "GPIO";
+ uc_priv->gpio_count = BCM2835_GPIO_COUNT;
+ gpios->reg = (struct bcm2835_gpio_regs *)plat->base;
+
+ /* We know we're spawned by the pinctrl driver */
+ gpios->pinctrl = dev->parent;
+
+ return 0;
+}
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+static int bcm2835_gpio_of_to_plat(struct udevice *dev)
+{
+ struct bcm2835_gpio_plat *plat = dev_get_plat(dev);
+ fdt_addr_t addr;
+
+ addr = dev_read_addr(dev);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ plat->base = addr;
+ return 0;
+}
+#endif
+
+U_BOOT_DRIVER(gpio_bcm2835) = {
+ .name = "gpio_bcm2835",
+ .id = UCLASS_GPIO,
+ .of_to_plat = of_match_ptr(bcm2835_gpio_of_to_plat),
+ .plat_auto = sizeof(struct bcm2835_gpio_plat),
+ .ops = &gpio_bcm2835_ops,
+ .probe = bcm2835_gpio_probe,
+ .flags = DM_FLAG_PRE_RELOC,
+ .priv_auto = sizeof(struct bcm2835_gpios),
+};
diff --git a/roms/u-boot/drivers/gpio/bcm6345_gpio.c b/roms/u-boot/drivers/gpio/bcm6345_gpio.c
new file mode 100644
index 000000000..e031f71a7
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/bcm6345_gpio.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/arch/mips/bcm63xx/gpio.c:
+ * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
+ * Copyright (C) 2008-2011 Florian Fainelli <florian@openwrt.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+
+struct bcm6345_gpio_priv {
+ void __iomem *reg_dirout;
+ void __iomem *reg_data;
+};
+
+static int bcm6345_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+ struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
+
+ return !!(readl(priv->reg_data) & BIT(offset));
+}
+
+static int bcm6345_gpio_set_value(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
+
+ if (value)
+ setbits_32(priv->reg_data, BIT(offset));
+ else
+ clrbits_32(priv->reg_data, BIT(offset));
+
+ return 0;
+}
+
+static int bcm6345_gpio_set_direction(void __iomem *dirout, unsigned offset,
+ bool input)
+{
+ if (input)
+ clrbits_32(dirout, BIT(offset));
+ else
+ setbits_32(dirout, BIT(offset));
+
+ return 0;
+}
+
+static int bcm6345_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+ struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
+
+ return bcm6345_gpio_set_direction(priv->reg_dirout, offset, 1);
+}
+
+static int bcm6345_gpio_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
+
+ bcm6345_gpio_set_value(dev, offset, value);
+
+ return bcm6345_gpio_set_direction(priv->reg_dirout, offset, 0);
+}
+
+static int bcm6345_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+ struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
+
+ if (readl(priv->reg_dirout) & BIT(offset))
+ return GPIOF_OUTPUT;
+ else
+ return GPIOF_INPUT;
+}
+
+static const struct dm_gpio_ops bcm6345_gpio_ops = {
+ .direction_input = bcm6345_gpio_direction_input,
+ .direction_output = bcm6345_gpio_direction_output,
+ .get_value = bcm6345_gpio_get_value,
+ .set_value = bcm6345_gpio_set_value,
+ .get_function = bcm6345_gpio_get_function,
+};
+
+static int bcm6345_gpio_probe(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
+
+ priv->reg_dirout = dev_remap_addr_index(dev, 0);
+ if (!priv->reg_dirout)
+ return -EINVAL;
+
+ priv->reg_data = dev_remap_addr_index(dev, 1);
+ if (!priv->reg_data)
+ return -EINVAL;
+
+ uc_priv->gpio_count = dev_read_u32_default(dev, "ngpios", 32);
+ uc_priv->bank_name = dev->name;
+
+ return 0;
+}
+
+static const struct udevice_id bcm6345_gpio_ids[] = {
+ { .compatible = "brcm,bcm6345-gpio" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(bcm6345_gpio) = {
+ .name = "bcm6345-gpio",
+ .id = UCLASS_GPIO,
+ .of_match = bcm6345_gpio_ids,
+ .ops = &bcm6345_gpio_ops,
+ .priv_auto = sizeof(struct bcm6345_gpio_priv),
+ .probe = bcm6345_gpio_probe,
+};
diff --git a/roms/u-boot/drivers/gpio/cortina_gpio.c b/roms/u-boot/drivers/gpio/cortina_gpio.c
new file mode 100644
index 000000000..72ef523be
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/cortina_gpio.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Cortina-Access
+ *
+ * GPIO Driver for Cortina Access CAxxxx Line of SoCs
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <linux/bitops.h>
+#include <linux/compat.h>
+#include <linux/compiler.h>
+
+/* GPIO Register Map */
+#define CORTINA_GPIO_CFG 0x00
+#define CORTINA_GPIO_OUT 0x04
+#define CORTINA_GPIO_IN 0x08
+#define CORTINA_GPIO_LVL 0x0C
+#define CORTINA_GPIO_EDGE 0x10
+#define CORTINA_GPIO_BOTHEDGE 0x14
+#define CORTINA_GPIO_IE 0x18
+#define CORTINA_GPIO_INT 0x1C
+#define CORTINA_GPIO_STAT 0x20
+
+struct cortina_gpio_bank {
+ void __iomem *base;
+};
+
+#ifdef CONFIG_DM_GPIO
+static int ca_gpio_direction_input(struct udevice *dev, unsigned int offset)
+{
+ struct cortina_gpio_bank *priv = dev_get_priv(dev);
+
+ setbits_32(priv->base, BIT(offset));
+ return 0;
+}
+
+static int
+ca_gpio_direction_output(struct udevice *dev, unsigned int offset, int value)
+{
+ struct cortina_gpio_bank *priv = dev_get_priv(dev);
+
+ clrbits_32(priv->base, BIT(offset));
+ return 0;
+}
+
+static int ca_gpio_get_value(struct udevice *dev, unsigned int offset)
+{
+ struct cortina_gpio_bank *priv = dev_get_priv(dev);
+
+ return readl(priv->base + CORTINA_GPIO_IN) & BIT(offset);
+}
+
+static int ca_gpio_set_value(struct udevice *dev, unsigned int offset,
+ int value)
+{
+ struct cortina_gpio_bank *priv = dev_get_priv(dev);
+
+ setbits_32(priv->base + CORTINA_GPIO_OUT, BIT(offset));
+ return 0;
+}
+
+static int ca_gpio_get_function(struct udevice *dev, unsigned int offset)
+{
+ struct cortina_gpio_bank *priv = dev_get_priv(dev);
+
+ if (readl(priv->base) & BIT(offset))
+ return GPIOF_INPUT;
+ else
+ return GPIOF_OUTPUT;
+}
+
+static const struct dm_gpio_ops gpio_cortina_ops = {
+ .direction_input = ca_gpio_direction_input,
+ .direction_output = ca_gpio_direction_output,
+ .get_value = ca_gpio_get_value,
+ .set_value = ca_gpio_set_value,
+ .get_function = ca_gpio_get_function,
+};
+
+static int ca_gpio_probe(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct cortina_gpio_bank *priv = dev_get_priv(dev);
+
+ priv->base = dev_remap_addr_index(dev, 0);
+ if (!priv->base)
+ return -EINVAL;
+
+ uc_priv->gpio_count = dev_read_u32_default(dev, "ngpios", 32);
+ uc_priv->bank_name = dev->name;
+
+ debug("Done Cortina GPIO init\n");
+ return 0;
+}
+
+static const struct udevice_id ca_gpio_ids[] = {
+ {.compatible = "cortina,ca-gpio"},
+ {}
+};
+
+U_BOOT_DRIVER(cortina_gpio) = {
+ .name = "cortina-gpio",
+ .id = UCLASS_GPIO,
+ .ops = &gpio_cortina_ops,
+ .probe = ca_gpio_probe,
+ .priv_auto = sizeof(struct cortina_gpio_bank),
+ .of_match = ca_gpio_ids,
+};
+#endif /* CONFIG_DM_GPIO */
diff --git a/roms/u-boot/drivers/gpio/da8xx_gpio.c b/roms/u-boot/drivers/gpio/da8xx_gpio.c
new file mode 100644
index 000000000..d106e9846
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/da8xx_gpio.c
@@ -0,0 +1,569 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * GPIO driver for TI DaVinci DA8xx SOCs.
+ *
+ * (C) Copyright 2011 Guralp Systems Ltd.
+ * Laurence Withers <lwithers@guralp.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <asm/global_data.h>
+#include <asm/gpio.h>
+#include <dt-bindings/gpio/gpio.h>
+
+#include "da8xx_gpio.h"
+
+#if !CONFIG_IS_ENABLED(DM_GPIO)
+#include <asm/arch/hardware.h>
+#include <asm/arch/davinci_misc.h>
+
+static struct gpio_registry {
+ int is_registered;
+ char name[GPIO_NAME_SIZE];
+} gpio_registry[MAX_NUM_GPIOS];
+
+#if defined(CONFIG_SOC_DA8XX)
+#define pinmux(x) (&davinci_syscfg_regs->pinmux[x])
+
+#if defined(CONFIG_SOC_DA8XX) && !defined(CONFIG_SOC_DA850)
+static const struct pinmux_config gpio_pinmux[] = {
+ { pinmux(13), 8, 6 }, /* GP0[0] */
+ { pinmux(13), 8, 7 },
+ { pinmux(14), 8, 0 },
+ { pinmux(14), 8, 1 },
+ { pinmux(14), 8, 2 },
+ { pinmux(14), 8, 3 },
+ { pinmux(14), 8, 4 },
+ { pinmux(14), 8, 5 },
+ { pinmux(14), 8, 6 },
+ { pinmux(14), 8, 7 },
+ { pinmux(15), 8, 0 },
+ { pinmux(15), 8, 1 },
+ { pinmux(15), 8, 2 },
+ { pinmux(15), 8, 3 },
+ { pinmux(15), 8, 4 },
+ { pinmux(15), 8, 5 },
+ { pinmux(15), 8, 6 }, /* GP1[0] */
+ { pinmux(15), 8, 7 },
+ { pinmux(16), 8, 0 },
+ { pinmux(16), 8, 1 },
+ { pinmux(16), 8, 2 },
+ { pinmux(16), 8, 3 },
+ { pinmux(16), 8, 4 },
+ { pinmux(16), 8, 5 },
+ { pinmux(16), 8, 6 },
+ { pinmux(16), 8, 7 },
+ { pinmux(17), 8, 0 },
+ { pinmux(17), 8, 1 },
+ { pinmux(17), 8, 2 },
+ { pinmux(17), 8, 3 },
+ { pinmux(17), 8, 4 },
+ { pinmux(17), 8, 5 },
+ { pinmux(17), 8, 6 }, /* GP2[0] */
+ { pinmux(17), 8, 7 },
+ { pinmux(18), 8, 0 },
+ { pinmux(18), 8, 1 },
+ { pinmux(18), 8, 2 },
+ { pinmux(18), 8, 3 },
+ { pinmux(18), 8, 4 },
+ { pinmux(18), 8, 5 },
+ { pinmux(18), 8, 6 },
+ { pinmux(18), 8, 7 },
+ { pinmux(19), 8, 0 },
+ { pinmux(9), 8, 2 },
+ { pinmux(9), 8, 3 },
+ { pinmux(9), 8, 4 },
+ { pinmux(9), 8, 5 },
+ { pinmux(9), 8, 6 },
+ { pinmux(10), 8, 1 }, /* GP3[0] */
+ { pinmux(10), 8, 2 },
+ { pinmux(10), 8, 3 },
+ { pinmux(10), 8, 4 },
+ { pinmux(10), 8, 5 },
+ { pinmux(10), 8, 6 },
+ { pinmux(10), 8, 7 },
+ { pinmux(11), 8, 0 },
+ { pinmux(11), 8, 1 },
+ { pinmux(11), 8, 2 },
+ { pinmux(11), 8, 3 },
+ { pinmux(11), 8, 4 },
+ { pinmux(9), 8, 7 },
+ { pinmux(2), 8, 6 },
+ { pinmux(11), 8, 5 },
+ { pinmux(11), 8, 6 },
+ { pinmux(12), 8, 4 }, /* GP4[0] */
+ { pinmux(12), 8, 5 },
+ { pinmux(12), 8, 6 },
+ { pinmux(12), 8, 7 },
+ { pinmux(13), 8, 0 },
+ { pinmux(13), 8, 1 },
+ { pinmux(13), 8, 2 },
+ { pinmux(13), 8, 3 },
+ { pinmux(13), 8, 4 },
+ { pinmux(13), 8, 5 },
+ { pinmux(11), 8, 7 },
+ { pinmux(12), 8, 0 },
+ { pinmux(12), 8, 1 },
+ { pinmux(12), 8, 2 },
+ { pinmux(12), 8, 3 },
+ { pinmux(9), 8, 1 },
+ { pinmux(7), 8, 3 }, /* GP5[0] */
+ { pinmux(7), 8, 4 },
+ { pinmux(7), 8, 5 },
+ { pinmux(7), 8, 6 },
+ { pinmux(7), 8, 7 },
+ { pinmux(8), 8, 0 },
+ { pinmux(8), 8, 1 },
+ { pinmux(8), 8, 2 },
+ { pinmux(8), 8, 3 },
+ { pinmux(8), 8, 4 },
+ { pinmux(8), 8, 5 },
+ { pinmux(8), 8, 6 },
+ { pinmux(8), 8, 7 },
+ { pinmux(9), 8, 0 },
+ { pinmux(7), 8, 1 },
+ { pinmux(7), 8, 2 },
+ { pinmux(5), 8, 1 }, /* GP6[0] */
+ { pinmux(5), 8, 2 },
+ { pinmux(5), 8, 3 },
+ { pinmux(5), 8, 4 },
+ { pinmux(5), 8, 5 },
+ { pinmux(5), 8, 6 },
+ { pinmux(5), 8, 7 },
+ { pinmux(6), 8, 0 },
+ { pinmux(6), 8, 1 },
+ { pinmux(6), 8, 2 },
+ { pinmux(6), 8, 3 },
+ { pinmux(6), 8, 4 },
+ { pinmux(6), 8, 5 },
+ { pinmux(6), 8, 6 },
+ { pinmux(6), 8, 7 },
+ { pinmux(7), 8, 0 },
+ { pinmux(1), 8, 0 }, /* GP7[0] */
+ { pinmux(1), 8, 1 },
+ { pinmux(1), 8, 2 },
+ { pinmux(1), 8, 3 },
+ { pinmux(1), 8, 4 },
+ { pinmux(1), 8, 5 },
+ { pinmux(1), 8, 6 },
+ { pinmux(1), 8, 7 },
+ { pinmux(2), 8, 0 },
+ { pinmux(2), 8, 1 },
+ { pinmux(2), 8, 2 },
+ { pinmux(2), 8, 3 },
+ { pinmux(2), 8, 4 },
+ { pinmux(2), 8, 5 },
+ { pinmux(0), 1, 0 },
+ { pinmux(0), 1, 1 },
+};
+#else /* CONFIG_SOC_DA8XX && CONFIG_SOC_DA850 */
+static const struct pinmux_config gpio_pinmux[] = {
+ { pinmux(1), 8, 7 }, /* GP0[0] */
+ { pinmux(1), 8, 6 },
+ { pinmux(1), 8, 5 },
+ { pinmux(1), 8, 4 },
+ { pinmux(1), 8, 3 },
+ { pinmux(1), 8, 2 },
+ { pinmux(1), 8, 1 },
+ { pinmux(1), 8, 0 },
+ { pinmux(0), 8, 7 },
+ { pinmux(0), 8, 6 },
+ { pinmux(0), 8, 5 },
+ { pinmux(0), 8, 4 },
+ { pinmux(0), 8, 3 },
+ { pinmux(0), 8, 2 },
+ { pinmux(0), 8, 1 },
+ { pinmux(0), 8, 0 },
+ { pinmux(4), 8, 7 }, /* GP1[0] */
+ { pinmux(4), 8, 6 },
+ { pinmux(4), 8, 5 },
+ { pinmux(4), 8, 4 },
+ { pinmux(4), 8, 3 },
+ { pinmux(4), 8, 2 },
+ { pinmux(4), 4, 1 },
+ { pinmux(4), 4, 0 },
+ { pinmux(3), 4, 0 },
+ { pinmux(2), 4, 6 },
+ { pinmux(2), 4, 5 },
+ { pinmux(2), 4, 4 },
+ { pinmux(2), 4, 3 },
+ { pinmux(2), 4, 2 },
+ { pinmux(2), 4, 1 },
+ { pinmux(2), 8, 0 },
+ { pinmux(6), 8, 7 }, /* GP2[0] */
+ { pinmux(6), 8, 6 },
+ { pinmux(6), 8, 5 },
+ { pinmux(6), 8, 4 },
+ { pinmux(6), 8, 3 },
+ { pinmux(6), 8, 2 },
+ { pinmux(6), 8, 1 },
+ { pinmux(6), 8, 0 },
+ { pinmux(5), 8, 7 },
+ { pinmux(5), 8, 6 },
+ { pinmux(5), 8, 5 },
+ { pinmux(5), 8, 4 },
+ { pinmux(5), 8, 3 },
+ { pinmux(5), 8, 2 },
+ { pinmux(5), 8, 1 },
+ { pinmux(5), 8, 0 },
+ { pinmux(8), 8, 7 }, /* GP3[0] */
+ { pinmux(8), 8, 6 },
+ { pinmux(8), 8, 5 },
+ { pinmux(8), 8, 4 },
+ { pinmux(8), 8, 3 },
+ { pinmux(8), 8, 2 },
+ { pinmux(8), 8, 1 },
+ { pinmux(8), 8, 0 },
+ { pinmux(7), 8, 7 },
+ { pinmux(7), 8, 6 },
+ { pinmux(7), 8, 5 },
+ { pinmux(7), 8, 4 },
+ { pinmux(7), 8, 3 },
+ { pinmux(7), 8, 2 },
+ { pinmux(7), 8, 1 },
+ { pinmux(7), 8, 0 },
+ { pinmux(10), 8, 7 }, /* GP4[0] */
+ { pinmux(10), 8, 6 },
+ { pinmux(10), 8, 5 },
+ { pinmux(10), 8, 4 },
+ { pinmux(10), 8, 3 },
+ { pinmux(10), 8, 2 },
+ { pinmux(10), 8, 1 },
+ { pinmux(10), 8, 0 },
+ { pinmux(9), 8, 7 },
+ { pinmux(9), 8, 6 },
+ { pinmux(9), 8, 5 },
+ { pinmux(9), 8, 4 },
+ { pinmux(9), 8, 3 },
+ { pinmux(9), 8, 2 },
+ { pinmux(9), 8, 1 },
+ { pinmux(9), 8, 0 },
+ { pinmux(12), 8, 7 }, /* GP5[0] */
+ { pinmux(12), 8, 6 },
+ { pinmux(12), 8, 5 },
+ { pinmux(12), 8, 4 },
+ { pinmux(12), 8, 3 },
+ { pinmux(12), 8, 2 },
+ { pinmux(12), 8, 1 },
+ { pinmux(12), 8, 0 },
+ { pinmux(11), 8, 7 },
+ { pinmux(11), 8, 6 },
+ { pinmux(11), 8, 5 },
+ { pinmux(11), 8, 4 },
+ { pinmux(11), 8, 3 },
+ { pinmux(11), 8, 2 },
+ { pinmux(11), 8, 1 },
+ { pinmux(11), 8, 0 },
+ { pinmux(19), 8, 6 }, /* GP6[0] */
+ { pinmux(19), 8, 5 },
+ { pinmux(19), 8, 4 },
+ { pinmux(19), 8, 3 },
+ { pinmux(19), 8, 2 },
+ { pinmux(16), 8, 1 },
+ { pinmux(14), 8, 1 },
+ { pinmux(14), 8, 0 },
+ { pinmux(13), 8, 7 },
+ { pinmux(13), 8, 6 },
+ { pinmux(13), 8, 5 },
+ { pinmux(13), 8, 4 },
+ { pinmux(13), 8, 3 },
+ { pinmux(13), 8, 2 },
+ { pinmux(13), 8, 1 },
+ { pinmux(13), 8, 0 },
+ { pinmux(18), 8, 1 }, /* GP7[0] */
+ { pinmux(18), 8, 0 },
+ { pinmux(17), 8, 7 },
+ { pinmux(17), 8, 6 },
+ { pinmux(17), 8, 5 },
+ { pinmux(17), 8, 4 },
+ { pinmux(17), 8, 3 },
+ { pinmux(17), 8, 2 },
+ { pinmux(17), 8, 1 },
+ { pinmux(17), 8, 0 },
+ { pinmux(16), 8, 7 },
+ { pinmux(16), 8, 6 },
+ { pinmux(16), 8, 5 },
+ { pinmux(16), 8, 4 },
+ { pinmux(16), 8, 3 },
+ { pinmux(16), 8, 2 },
+ { pinmux(19), 8, 0 }, /* GP8[0] */
+ { pinmux(3), 4, 7 },
+ { pinmux(3), 4, 6 },
+ { pinmux(3), 4, 5 },
+ { pinmux(3), 4, 4 },
+ { pinmux(3), 4, 3 },
+ { pinmux(3), 4, 2 },
+ { pinmux(2), 4, 7 },
+ { pinmux(19), 8, 1 },
+ { pinmux(19), 8, 0 },
+ { pinmux(18), 8, 7 },
+ { pinmux(18), 8, 6 },
+ { pinmux(18), 8, 5 },
+ { pinmux(18), 8, 4 },
+ { pinmux(18), 8, 3 },
+ { pinmux(18), 8, 2 },
+};
+#endif /* CONFIG_SOC_DA8XX && !CONFIG_SOC_DA850 */
+#else /* !CONFIG_SOC_DA8XX */
+#define davinci_configure_pin_mux(a, b)
+#endif /* CONFIG_SOC_DA8XX */
+
+int gpio_request(unsigned int gpio, const char *label)
+{
+ if (gpio >= MAX_NUM_GPIOS)
+ return -1;
+
+ if (gpio_registry[gpio].is_registered)
+ return -1;
+
+ gpio_registry[gpio].is_registered = 1;
+ strncpy(gpio_registry[gpio].name, label, GPIO_NAME_SIZE);
+ gpio_registry[gpio].name[GPIO_NAME_SIZE - 1] = 0;
+
+ davinci_configure_pin_mux(&gpio_pinmux[gpio], 1);
+
+ return 0;
+}
+
+int gpio_free(unsigned int gpio)
+{
+ if (gpio >= MAX_NUM_GPIOS)
+ return -1;
+
+ if (!gpio_registry[gpio].is_registered)
+ return -1;
+
+ gpio_registry[gpio].is_registered = 0;
+ gpio_registry[gpio].name[0] = '\0';
+ /* Do not configure as input or change pin mux here */
+ return 0;
+}
+#endif
+
+static int _gpio_direction_input(struct davinci_gpio *bank, unsigned int gpio)
+{
+ setbits_le32(&bank->dir, 1U << GPIO_BIT(gpio));
+ return 0;
+}
+
+static int _gpio_get_value(struct davinci_gpio *bank, unsigned int gpio)
+{
+ unsigned int ip;
+ ip = in_le32(&bank->in_data) & (1U << GPIO_BIT(gpio));
+ return ip ? 1 : 0;
+}
+
+static int _gpio_set_value(struct davinci_gpio *bank, unsigned int gpio, int value)
+{
+ if (value)
+ bank->set_data = 1U << GPIO_BIT(gpio);
+ else
+ bank->clr_data = 1U << GPIO_BIT(gpio);
+
+ return 0;
+}
+
+static int _gpio_get_dir(struct davinci_gpio *bank, unsigned int gpio)
+{
+ return in_le32(&bank->dir) & (1U << GPIO_BIT(gpio));
+}
+
+static int _gpio_direction_output(struct davinci_gpio *bank, unsigned int gpio,
+ int value)
+{
+ clrbits_le32(&bank->dir, 1U << GPIO_BIT(gpio));
+ _gpio_set_value(bank, gpio, value);
+ return 0;
+}
+
+#if !CONFIG_IS_ENABLED(DM_GPIO)
+
+void gpio_info(void)
+{
+ unsigned int gpio, dir, val;
+ struct davinci_gpio *bank;
+
+ for (gpio = 0; gpio < MAX_NUM_GPIOS; ++gpio) {
+ bank = GPIO_BANK(gpio);
+ dir = _gpio_get_dir(bank, gpio);
+ val = gpio_get_value(gpio);
+
+ printf("% 4d: %s: %d [%c] %s\n",
+ gpio, dir ? " in" : "out", val,
+ gpio_registry[gpio].is_registered ? 'x' : ' ',
+ gpio_registry[gpio].name);
+ }
+}
+
+int gpio_direction_input(unsigned int gpio)
+{
+ struct davinci_gpio *bank;
+
+ bank = GPIO_BANK(gpio);
+ return _gpio_direction_input(bank, gpio);
+}
+
+int gpio_direction_output(unsigned int gpio, int value)
+{
+ struct davinci_gpio *bank;
+
+ bank = GPIO_BANK(gpio);
+ return _gpio_direction_output(bank, gpio, value);
+}
+
+int gpio_get_value(unsigned int gpio)
+{
+ struct davinci_gpio *bank;
+
+ bank = GPIO_BANK(gpio);
+ return _gpio_get_value(bank, gpio);
+}
+
+int gpio_set_value(unsigned int gpio, int value)
+{
+ struct davinci_gpio *bank;
+
+ bank = GPIO_BANK(gpio);
+ return _gpio_set_value(bank, gpio, value);
+}
+
+#else /* DM_GPIO */
+
+static struct davinci_gpio *davinci_get_gpio_bank(struct udevice *dev, unsigned int offset)
+{
+ struct davinci_gpio_bank *bank = dev_get_priv(dev);
+ unsigned long addr;
+
+ /*
+ * The device tree is not broken into banks but the infrastructure is
+ * expecting it this way, so we'll first include the 0x10 offset, then
+ * calculate the bank manually based on the offset.
+ * Casting 'addr' as Unsigned long is needed to make the math work.
+ */
+ addr = ((unsigned long)(struct davinci_gpio *)bank->base) +
+ 0x10 + (0x28 * (offset >> 5));
+ return (struct davinci_gpio *)addr;
+}
+
+static int davinci_gpio_direction_input(struct udevice *dev, unsigned int offset)
+{
+ struct davinci_gpio *base = davinci_get_gpio_bank(dev, offset);
+
+ /*
+ * Fetch the address based on GPIO, but only pass the masked low 32-bits
+ */
+ _gpio_direction_input(base, (offset & 0x1f));
+ return 0;
+}
+
+static int davinci_gpio_direction_output(struct udevice *dev, unsigned int offset,
+ int value)
+{
+ struct davinci_gpio *base = davinci_get_gpio_bank(dev, offset);
+
+ _gpio_direction_output(base, (offset & 0x1f), value);
+ return 0;
+}
+
+static int davinci_gpio_get_value(struct udevice *dev, unsigned int offset)
+{
+ struct davinci_gpio *base = davinci_get_gpio_bank(dev, offset);
+
+ return _gpio_get_value(base, (offset & 0x1f));
+}
+
+static int davinci_gpio_set_value(struct udevice *dev, unsigned int offset,
+ int value)
+{
+ struct davinci_gpio *base = davinci_get_gpio_bank(dev, offset);
+
+ _gpio_set_value(base, (offset & 0x1f), value);
+
+ return 0;
+}
+
+static int davinci_gpio_get_function(struct udevice *dev, unsigned int offset)
+{
+ unsigned int dir;
+ struct davinci_gpio *base = davinci_get_gpio_bank(dev, offset);
+
+ dir = _gpio_get_dir(base, offset);
+
+ if (dir)
+ return GPIOF_INPUT;
+
+ return GPIOF_OUTPUT;
+}
+
+static int davinci_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
+ struct ofnode_phandle_args *args)
+{
+ desc->offset = args->args[0];
+
+ if (args->args[1] & GPIO_ACTIVE_LOW)
+ desc->flags = GPIOD_ACTIVE_LOW;
+ else
+ desc->flags = 0;
+ return 0;
+}
+
+static const struct dm_gpio_ops gpio_davinci_ops = {
+ .direction_input = davinci_gpio_direction_input,
+ .direction_output = davinci_gpio_direction_output,
+ .get_value = davinci_gpio_get_value,
+ .set_value = davinci_gpio_set_value,
+ .get_function = davinci_gpio_get_function,
+ .xlate = davinci_gpio_xlate,
+};
+
+static int davinci_gpio_probe(struct udevice *dev)
+{
+ struct davinci_gpio_bank *bank = dev_get_priv(dev);
+ struct davinci_gpio_plat *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ const void *fdt = gd->fdt_blob;
+ int node = dev_of_offset(dev);
+
+ uc_priv->bank_name = plat->port_name;
+ uc_priv->gpio_count = fdtdec_get_int(fdt, node, "ti,ngpio", -1);
+ bank->base = (struct davinci_gpio *)plat->base;
+ return 0;
+}
+
+static const struct udevice_id davinci_gpio_ids[] = {
+ { .compatible = "ti,dm6441-gpio" },
+ { .compatible = "ti,k2g-gpio" },
+ { .compatible = "ti,keystone-gpio" },
+ { }
+};
+
+static int davinci_gpio_of_to_plat(struct udevice *dev)
+{
+ struct davinci_gpio_plat *plat = dev_get_plat(dev);
+ fdt_addr_t addr;
+
+ addr = dev_read_addr(dev);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ plat->base = addr;
+ return 0;
+}
+
+U_BOOT_DRIVER(ti_dm6441_gpio) = {
+ .name = "ti_dm6441_gpio",
+ .id = UCLASS_GPIO,
+ .ops = &gpio_davinci_ops,
+ .of_to_plat = of_match_ptr(davinci_gpio_of_to_plat),
+ .of_match = davinci_gpio_ids,
+ .bind = dm_scan_fdt_dev,
+ .plat_auto = sizeof(struct davinci_gpio_plat),
+ .probe = davinci_gpio_probe,
+ .priv_auto = sizeof(struct davinci_gpio_bank),
+};
+
+#endif
diff --git a/roms/u-boot/drivers/gpio/da8xx_gpio.h b/roms/u-boot/drivers/gpio/da8xx_gpio.h
new file mode 100644
index 000000000..ca59d6a90
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/da8xx_gpio.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef _GPIO_DA8XX_DEFS_H_
+#define _GPIO_DA8XX_DEFS_H_
+
+struct davinci_gpio {
+ unsigned int dir;
+ unsigned int out_data;
+ unsigned int set_data;
+ unsigned int clr_data;
+ unsigned int in_data;
+ unsigned int set_rising;
+ unsigned int clr_rising;
+ unsigned int set_falling;
+ unsigned int clr_falling;
+ unsigned int intstat;
+};
+
+struct davinci_gpio_bank {
+ int num_gpio;
+ unsigned int irq_num;
+ unsigned int irq_mask;
+ unsigned long *in_use;
+ struct davinci_gpio *base;
+};
+
+#define GPIO_NAME_SIZE 20
+#define MAX_NUM_GPIOS 144
+#define GPIO_BIT(gp) ((gp) & 0x1F)
+
+#if CONFIG_IS_ENABLED(DM_GPIO)
+
+/* Information about a GPIO bank */
+struct davinci_gpio_plat {
+ int bank_index;
+ ulong base; /* address of registers in physical memory */
+ const char *port_name;
+};
+#endif
+
+#endif
diff --git a/roms/u-boot/drivers/gpio/db8500_gpio.c b/roms/u-boot/drivers/gpio/db8500_gpio.c
new file mode 100644
index 000000000..eefb56d83
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/db8500_gpio.c
@@ -0,0 +1,221 @@
+/*
+ * Code ported from Nomadik GPIO driver in ST-Ericsson Linux kernel code.
+ * The purpose is that GPIO config found in kernel should work by simply
+ * copy-paste it to U-Boot.
+ *
+ * Original Linux authors:
+ * Copyright (C) 2008,2009 STMicroelectronics
+ * Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it>
+ * Rewritten based on work by Prafulla WADASKAR <prafulla.wadaskar@st.com>
+ *
+ * Ported to U-Boot by:
+ * Copyright (C) 2010 Joakim Axelsson <joakim.axelsson AT stericsson.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+#include <asm/arch/db8500_gpio.h>
+#include <asm/arch/db8500_pincfg.h>
+#include <linux/compiler.h>
+
+#define IO_ADDR(x) (void *) (x)
+
+/*
+ * The GPIO module in the db8500 Systems-on-Chip is an
+ * AMBA device, managing 32 pins and alternate functions. The logic block
+ * is currently only used in the db8500.
+ */
+
+#define GPIO_TOTAL_PINS 268
+#define GPIO_PINS_PER_BLOCK 32
+#define GPIO_BLOCKS_COUNT (GPIO_TOTAL_PINS/GPIO_PINS_PER_BLOCK + 1)
+#define GPIO_BLOCK(pin) (((pin + GPIO_PINS_PER_BLOCK) >> 5) - 1)
+#define GPIO_PIN_WITHIN_BLOCK(pin) ((pin)%(GPIO_PINS_PER_BLOCK))
+
+/* Register in the logic block */
+#define DB8500_GPIO_DAT 0x00
+#define DB8500_GPIO_DATS 0x04
+#define DB8500_GPIO_DATC 0x08
+#define DB8500_GPIO_PDIS 0x0c
+#define DB8500_GPIO_DIR 0x10
+#define DB8500_GPIO_DIRS 0x14
+#define DB8500_GPIO_DIRC 0x18
+#define DB8500_GPIO_SLPC 0x1c
+#define DB8500_GPIO_AFSLA 0x20
+#define DB8500_GPIO_AFSLB 0x24
+
+#define DB8500_GPIO_RIMSC 0x40
+#define DB8500_GPIO_FIMSC 0x44
+#define DB8500_GPIO_IS 0x48
+#define DB8500_GPIO_IC 0x4c
+#define DB8500_GPIO_RWIMSC 0x50
+#define DB8500_GPIO_FWIMSC 0x54
+#define DB8500_GPIO_WKS 0x58
+
+static void __iomem *get_gpio_addr(unsigned gpio)
+{
+ /* Our list of GPIO chips */
+ static void __iomem *gpio_addrs[GPIO_BLOCKS_COUNT] = {
+ IO_ADDR(CFG_GPIO_0_BASE),
+ IO_ADDR(CFG_GPIO_1_BASE),
+ IO_ADDR(CFG_GPIO_2_BASE),
+ IO_ADDR(CFG_GPIO_3_BASE),
+ IO_ADDR(CFG_GPIO_4_BASE),
+ IO_ADDR(CFG_GPIO_5_BASE),
+ IO_ADDR(CFG_GPIO_6_BASE),
+ IO_ADDR(CFG_GPIO_7_BASE),
+ IO_ADDR(CFG_GPIO_8_BASE)
+ };
+
+ return gpio_addrs[GPIO_BLOCK(gpio)];
+}
+
+static unsigned get_gpio_offset(unsigned gpio)
+{
+ return GPIO_PIN_WITHIN_BLOCK(gpio);
+}
+
+/* Can only be called from config_pin. Don't configure alt-mode directly */
+static void gpio_set_mode(unsigned gpio, enum db8500_gpio_alt mode)
+{
+ void __iomem *addr = get_gpio_addr(gpio);
+ unsigned offset = get_gpio_offset(gpio);
+ u32 bit = 1 << offset;
+ u32 afunc, bfunc;
+
+ afunc = readl(addr + DB8500_GPIO_AFSLA) & ~bit;
+ bfunc = readl(addr + DB8500_GPIO_AFSLB) & ~bit;
+ if (mode & DB8500_GPIO_ALT_A)
+ afunc |= bit;
+ if (mode & DB8500_GPIO_ALT_B)
+ bfunc |= bit;
+ writel(afunc, addr + DB8500_GPIO_AFSLA);
+ writel(bfunc, addr + DB8500_GPIO_AFSLB);
+}
+
+/**
+ * db8500_gpio_set_pull() - enable/disable pull up/down on a gpio
+ * @gpio: pin number
+ * @pull: one of DB8500_GPIO_PULL_DOWN, DB8500_GPIO_PULL_UP,
+ * and DB8500_GPIO_PULL_NONE
+ *
+ * Enables/disables pull up/down on a specified pin. This only takes effect if
+ * the pin is configured as an input (either explicitly or by the alternate
+ * function).
+ *
+ * NOTE: If enabling the pull up/down, the caller must ensure that the GPIO is
+ * configured as an input. Otherwise, due to the way the controller registers
+ * work, this function will change the value output on the pin.
+ */
+void db8500_gpio_set_pull(unsigned gpio, enum db8500_gpio_pull pull)
+{
+ void __iomem *addr = get_gpio_addr(gpio);
+ unsigned offset = get_gpio_offset(gpio);
+ u32 bit = 1 << offset;
+ u32 pdis;
+
+ pdis = readl(addr + DB8500_GPIO_PDIS);
+ if (pull == DB8500_GPIO_PULL_NONE)
+ pdis |= bit;
+ else
+ pdis &= ~bit;
+ writel(pdis, addr + DB8500_GPIO_PDIS);
+
+ if (pull == DB8500_GPIO_PULL_UP)
+ writel(bit, addr + DB8500_GPIO_DATS);
+ else if (pull == DB8500_GPIO_PULL_DOWN)
+ writel(bit, addr + DB8500_GPIO_DATC);
+}
+
+void db8500_gpio_make_input(unsigned gpio)
+{
+ void __iomem *addr = get_gpio_addr(gpio);
+ unsigned offset = get_gpio_offset(gpio);
+
+ writel(1 << offset, addr + DB8500_GPIO_DIRC);
+}
+
+int db8500_gpio_get_input(unsigned gpio)
+{
+ void __iomem *addr = get_gpio_addr(gpio);
+ unsigned offset = get_gpio_offset(gpio);
+ u32 bit = 1 << offset;
+
+ printf("db8500_gpio_get_input gpio=%u addr=%p offset=%u bit=%#x\n",
+ gpio, addr, offset, bit);
+
+ return (readl(addr + DB8500_GPIO_DAT) & bit) != 0;
+}
+
+void db8500_gpio_make_output(unsigned gpio, int val)
+{
+ void __iomem *addr = get_gpio_addr(gpio);
+ unsigned offset = get_gpio_offset(gpio);
+
+ writel(1 << offset, addr + DB8500_GPIO_DIRS);
+ db8500_gpio_set_output(gpio, val);
+}
+
+void db8500_gpio_set_output(unsigned gpio, int val)
+{
+ void __iomem *addr = get_gpio_addr(gpio);
+ unsigned offset = get_gpio_offset(gpio);
+
+ if (val)
+ writel(1 << offset, addr + DB8500_GPIO_DATS);
+ else
+ writel(1 << offset, addr + DB8500_GPIO_DATC);
+}
+
+/**
+ * config_pin - configure a pin's mux attributes
+ * @cfg: pin configuration
+ *
+ * Configures a pin's mode (alternate function or GPIO), its pull up status,
+ * and its sleep mode based on the specified configuration. The @cfg is
+ * usually one of the SoC specific macros defined in mach/<soc>-pins.h. These
+ * are constructed using, and can be further enhanced with, the macros in
+ * plat/pincfg.h.
+ *
+ * If a pin's mode is set to GPIO, it is configured as an input to avoid
+ * side-effects. The gpio can be manipulated later using standard GPIO API
+ * calls.
+ */
+static void config_pin(unsigned long cfg)
+{
+ int pin = PIN_NUM(cfg);
+ int pull = PIN_PULL(cfg);
+ int af = PIN_ALT(cfg);
+ int output = PIN_DIR(cfg);
+ int val = PIN_VAL(cfg);
+
+ if (output)
+ db8500_gpio_make_output(pin, val);
+ else {
+ db8500_gpio_make_input(pin);
+ db8500_gpio_set_pull(pin, pull);
+ }
+
+ gpio_set_mode(pin, af);
+}
+
+/**
+ * db8500_config_pins - configure several pins at once
+ * @cfgs: array of pin configurations
+ * @num: number of elments in the array
+ *
+ * Configures several pins using config_pin(). Refer to that function for
+ * further information.
+ */
+void db8500_gpio_config_pins(unsigned long *cfgs, size_t num)
+{
+ size_t i;
+
+ for (i = 0; i < num; i++)
+ config_pin(cfgs[i]);
+}
diff --git a/roms/u-boot/drivers/gpio/dwapb_gpio.c b/roms/u-boot/drivers/gpio/dwapb_gpio.c
new file mode 100644
index 000000000..e6e919444
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/dwapb_gpio.c
@@ -0,0 +1,241 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2015 Marek Vasut <marex@denx.de>
+ *
+ * DesignWare APB GPIO driver
+ */
+
+#include <common.h>
+#include <log.h>
+#include <malloc.h>
+#include <asm/arch/gpio.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+#include <errno.h>
+#include <reset.h>
+#include <linux/bitops.h>
+
+#define GPIO_SWPORT_DR(p) (0x00 + (p) * 0xc)
+#define GPIO_SWPORT_DDR(p) (0x04 + (p) * 0xc)
+#define GPIO_INTEN 0x30
+#define GPIO_INTMASK 0x34
+#define GPIO_INTTYPE_LEVEL 0x38
+#define GPIO_INT_POLARITY 0x3c
+#define GPIO_INTSTATUS 0x40
+#define GPIO_PORTA_DEBOUNCE 0x48
+#define GPIO_PORTA_EOI 0x4c
+#define GPIO_EXT_PORT(p) (0x50 + (p) * 4)
+
+struct gpio_dwapb_priv {
+ struct reset_ctl_bulk resets;
+};
+
+struct gpio_dwapb_plat {
+ const char *name;
+ int bank;
+ int pins;
+ void __iomem *base;
+};
+
+static int dwapb_gpio_direction_input(struct udevice *dev, unsigned pin)
+{
+ struct gpio_dwapb_plat *plat = dev_get_plat(dev);
+
+ clrbits_le32(plat->base + GPIO_SWPORT_DDR(plat->bank), 1 << pin);
+ return 0;
+}
+
+static int dwapb_gpio_direction_output(struct udevice *dev, unsigned pin,
+ int val)
+{
+ struct gpio_dwapb_plat *plat = dev_get_plat(dev);
+
+ setbits_le32(plat->base + GPIO_SWPORT_DDR(plat->bank), 1 << pin);
+
+ if (val)
+ setbits_le32(plat->base + GPIO_SWPORT_DR(plat->bank), 1 << pin);
+ else
+ clrbits_le32(plat->base + GPIO_SWPORT_DR(plat->bank), 1 << pin);
+
+ return 0;
+}
+
+static int dwapb_gpio_set_value(struct udevice *dev, unsigned pin, int val)
+{
+ struct gpio_dwapb_plat *plat = dev_get_plat(dev);
+
+ if (val)
+ setbits_le32(plat->base + GPIO_SWPORT_DR(plat->bank), 1 << pin);
+ else
+ clrbits_le32(plat->base + GPIO_SWPORT_DR(plat->bank), 1 << pin);
+
+ return 0;
+}
+
+static int dwapb_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+ struct gpio_dwapb_plat *plat = dev_get_plat(dev);
+ u32 gpio;
+
+ gpio = readl(plat->base + GPIO_SWPORT_DDR(plat->bank));
+
+ if (gpio & BIT(offset))
+ return GPIOF_OUTPUT;
+ else
+ return GPIOF_INPUT;
+}
+
+static int dwapb_gpio_get_value(struct udevice *dev, unsigned pin)
+{
+ struct gpio_dwapb_plat *plat = dev_get_plat(dev);
+ u32 value;
+
+ if (dwapb_gpio_get_function(dev, pin) == GPIOF_OUTPUT)
+ value = readl(plat->base + GPIO_SWPORT_DR(plat->bank));
+ else
+ value = readl(plat->base + GPIO_EXT_PORT(plat->bank));
+ return !!(value & BIT(pin));
+}
+
+static const struct dm_gpio_ops gpio_dwapb_ops = {
+ .direction_input = dwapb_gpio_direction_input,
+ .direction_output = dwapb_gpio_direction_output,
+ .get_value = dwapb_gpio_get_value,
+ .set_value = dwapb_gpio_set_value,
+ .get_function = dwapb_gpio_get_function,
+};
+
+static int gpio_dwapb_reset(struct udevice *dev)
+{
+ int ret;
+ struct gpio_dwapb_priv *priv = dev_get_priv(dev);
+
+ ret = reset_get_bulk(dev, &priv->resets);
+ if (ret) {
+ /* Return 0 if error due to !CONFIG_DM_RESET and reset
+ * DT property is not present.
+ */
+ if (ret == -ENOENT || ret == -ENOTSUPP)
+ return 0;
+
+ dev_warn(dev, "Can't get reset: %d\n", ret);
+ return ret;
+ }
+
+ ret = reset_deassert_bulk(&priv->resets);
+ if (ret) {
+ reset_release_bulk(&priv->resets);
+ dev_err(dev, "Failed to reset: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int gpio_dwapb_probe(struct udevice *dev)
+{
+ struct gpio_dev_priv *priv = dev_get_uclass_priv(dev);
+ struct gpio_dwapb_plat *plat = dev_get_plat(dev);
+
+ if (!plat) {
+ /* Reset on parent device only */
+ return gpio_dwapb_reset(dev);
+ }
+
+ priv->gpio_count = plat->pins;
+ priv->bank_name = plat->name;
+
+ return 0;
+}
+
+static int gpio_dwapb_bind(struct udevice *dev)
+{
+ struct gpio_dwapb_plat *plat = dev_get_plat(dev);
+ struct udevice *subdev;
+ fdt_addr_t base;
+ int ret, bank = 0;
+ ofnode node;
+
+ /* If this is a child device, there is nothing to do here */
+ if (plat)
+ return 0;
+
+ base = dev_read_addr(dev);
+ if (base == FDT_ADDR_T_NONE) {
+ debug("Can't get the GPIO register base address\n");
+ return -ENXIO;
+ }
+
+ for (node = dev_read_first_subnode(dev); ofnode_valid(node);
+ node = dev_read_next_subnode(node)) {
+ if (!ofnode_read_bool(node, "gpio-controller"))
+ continue;
+
+ plat = devm_kcalloc(dev, 1, sizeof(*plat), GFP_KERNEL);
+ if (!plat)
+ return -ENOMEM;
+
+ plat->base = (void *)base;
+ plat->bank = bank;
+ plat->pins = ofnode_read_u32_default(node, "snps,nr-gpios", 0);
+
+ if (ofnode_read_string_index(node, "bank-name", 0,
+ &plat->name)) {
+ /*
+ * Fall back to node name. This means accessing pins
+ * via bank name won't work.
+ */
+ char name[32];
+
+ snprintf(name, sizeof(name), "%s_",
+ ofnode_get_name(node));
+ plat->name = strdup(name);
+ if (!plat->name) {
+ kfree(plat);
+ return -ENOMEM;
+ }
+ }
+
+ ret = device_bind(dev, dev->driver, plat->name, plat, node,
+ &subdev);
+ if (ret)
+ return ret;
+
+ bank++;
+ }
+
+ return 0;
+}
+
+static int gpio_dwapb_remove(struct udevice *dev)
+{
+ struct gpio_dwapb_plat *plat = dev_get_plat(dev);
+ struct gpio_dwapb_priv *priv = dev_get_priv(dev);
+
+ if (!plat && priv)
+ return reset_release_bulk(&priv->resets);
+
+ return 0;
+}
+
+static const struct udevice_id gpio_dwapb_ids[] = {
+ { .compatible = "snps,dw-apb-gpio" },
+ { }
+};
+
+U_BOOT_DRIVER(gpio_dwapb) = {
+ .name = "gpio-dwapb",
+ .id = UCLASS_GPIO,
+ .of_match = gpio_dwapb_ids,
+ .ops = &gpio_dwapb_ops,
+ .bind = gpio_dwapb_bind,
+ .probe = gpio_dwapb_probe,
+ .remove = gpio_dwapb_remove,
+ .priv_auto = sizeof(struct gpio_dwapb_priv),
+};
diff --git a/roms/u-boot/drivers/gpio/gpio-rcar.c b/roms/u-boot/drivers/gpio/gpio-rcar.c
new file mode 100644
index 000000000..5f1ec39a9
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/gpio-rcar.c
@@ -0,0 +1,194 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017 Marek Vasut <marek.vasut@gmail.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <malloc.h>
+#include <asm/global_data.h>
+#include <dm/device_compat.h>
+#include <dm/pinctrl.h>
+#include <errno.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+#include "../pinctrl/renesas/sh_pfc.h"
+
+#define GPIO_IOINTSEL 0x00 /* General IO/Interrupt Switching Register */
+#define GPIO_INOUTSEL 0x04 /* General Input/Output Switching Register */
+#define GPIO_OUTDT 0x08 /* General Output Register */
+#define GPIO_INDT 0x0c /* General Input Register */
+#define GPIO_INTDT 0x10 /* Interrupt Display Register */
+#define GPIO_INTCLR 0x14 /* Interrupt Clear Register */
+#define GPIO_INTMSK 0x18 /* Interrupt Mask Register */
+#define GPIO_MSKCLR 0x1c /* Interrupt Mask Clear Register */
+#define GPIO_POSNEG 0x20 /* Positive/Negative Logic Select Register */
+#define GPIO_EDGLEVEL 0x24 /* Edge/level Select Register */
+#define GPIO_FILONOFF 0x28 /* Chattering Prevention On/Off Register */
+#define GPIO_BOTHEDGE 0x4c /* One Edge/Both Edge Select Register */
+
+#define RCAR_MAX_GPIO_PER_BANK 32
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct rcar_gpio_priv {
+ void __iomem *regs;
+ int pfc_offset;
+};
+
+static int rcar_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+ struct rcar_gpio_priv *priv = dev_get_priv(dev);
+ const u32 bit = BIT(offset);
+
+ /*
+ * Testing on r8a7790 shows that INDT does not show correct pin state
+ * when configured as output, so use OUTDT in case of output pins.
+ */
+ if (readl(priv->regs + GPIO_INOUTSEL) & bit)
+ return !!(readl(priv->regs + GPIO_OUTDT) & bit);
+ else
+ return !!(readl(priv->regs + GPIO_INDT) & bit);
+}
+
+static int rcar_gpio_set_value(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct rcar_gpio_priv *priv = dev_get_priv(dev);
+
+ if (value)
+ setbits_le32(priv->regs + GPIO_OUTDT, BIT(offset));
+ else
+ clrbits_le32(priv->regs + GPIO_OUTDT, BIT(offset));
+
+ return 0;
+}
+
+static void rcar_gpio_set_direction(struct udevice *dev, unsigned offset,
+ bool output)
+{
+ struct rcar_gpio_priv *priv = dev_get_priv(dev);
+ void __iomem *regs = priv->regs;
+
+ /*
+ * follow steps in the GPIO documentation for
+ * "Setting General Output Mode" and
+ * "Setting General Input Mode"
+ */
+
+ /* Configure postive logic in POSNEG */
+ clrbits_le32(regs + GPIO_POSNEG, BIT(offset));
+
+ /* Select "General Input/Output Mode" in IOINTSEL */
+ clrbits_le32(regs + GPIO_IOINTSEL, BIT(offset));
+
+ /* Select Input Mode or Output Mode in INOUTSEL */
+ if (output)
+ setbits_le32(regs + GPIO_INOUTSEL, BIT(offset));
+ else
+ clrbits_le32(regs + GPIO_INOUTSEL, BIT(offset));
+}
+
+static int rcar_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+ rcar_gpio_set_direction(dev, offset, false);
+
+ return 0;
+}
+
+static int rcar_gpio_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ /* write GPIO value to output before selecting output mode of pin */
+ rcar_gpio_set_value(dev, offset, value);
+ rcar_gpio_set_direction(dev, offset, true);
+
+ return 0;
+}
+
+static int rcar_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+ struct rcar_gpio_priv *priv = dev_get_priv(dev);
+
+ if (readl(priv->regs + GPIO_INOUTSEL) & BIT(offset))
+ return GPIOF_OUTPUT;
+ else
+ return GPIOF_INPUT;
+}
+
+static int rcar_gpio_request(struct udevice *dev, unsigned offset,
+ const char *label)
+{
+ return pinctrl_gpio_request(dev, offset);
+}
+
+static int rcar_gpio_free(struct udevice *dev, unsigned offset)
+{
+ return pinctrl_gpio_free(dev, offset);
+}
+
+static const struct dm_gpio_ops rcar_gpio_ops = {
+ .request = rcar_gpio_request,
+ .rfree = rcar_gpio_free,
+ .direction_input = rcar_gpio_direction_input,
+ .direction_output = rcar_gpio_direction_output,
+ .get_value = rcar_gpio_get_value,
+ .set_value = rcar_gpio_set_value,
+ .get_function = rcar_gpio_get_function,
+};
+
+static int rcar_gpio_probe(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct rcar_gpio_priv *priv = dev_get_priv(dev);
+ struct fdtdec_phandle_args args;
+ struct clk clk;
+ int node = dev_of_offset(dev);
+ int ret;
+
+ priv->regs = dev_read_addr_ptr(dev);
+ uc_priv->bank_name = dev->name;
+
+ ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, node, "gpio-ranges",
+ NULL, 3, 0, &args);
+ priv->pfc_offset = ret == 0 ? args.args[1] : -1;
+ uc_priv->gpio_count = ret == 0 ? args.args[2] : RCAR_MAX_GPIO_PER_BANK;
+
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret < 0) {
+ dev_err(dev, "Failed to get GPIO bank clock\n");
+ return ret;
+ }
+
+ ret = clk_enable(&clk);
+ clk_free(&clk);
+ if (ret) {
+ dev_err(dev, "Failed to enable GPIO bank clock\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct udevice_id rcar_gpio_ids[] = {
+ { .compatible = "renesas,gpio-r8a7795" },
+ { .compatible = "renesas,gpio-r8a7796" },
+ { .compatible = "renesas,gpio-r8a77965" },
+ { .compatible = "renesas,gpio-r8a77970" },
+ { .compatible = "renesas,gpio-r8a77990" },
+ { .compatible = "renesas,gpio-r8a77995" },
+ { .compatible = "renesas,rcar-gen2-gpio" },
+ { .compatible = "renesas,rcar-gen3-gpio" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(rcar_gpio) = {
+ .name = "rcar-gpio",
+ .id = UCLASS_GPIO,
+ .of_match = rcar_gpio_ids,
+ .ops = &rcar_gpio_ops,
+ .priv_auto = sizeof(struct rcar_gpio_priv),
+ .probe = rcar_gpio_probe,
+};
diff --git a/roms/u-boot/drivers/gpio/gpio-rza1.c b/roms/u-boot/drivers/gpio/gpio-rza1.c
new file mode 100644
index 000000000..f14be871e
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/gpio-rza1.c
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Marek Vasut <marek.vasut@gmail.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/global_data.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+
+#define P(bank) (0x0000 + (bank) * 4)
+#define PSR(bank) (0x0100 + (bank) * 4)
+#define PPR(bank) (0x0200 + (bank) * 4)
+#define PM(bank) (0x0300 + (bank) * 4)
+#define PMC(bank) (0x0400 + (bank) * 4)
+#define PFC(bank) (0x0500 + (bank) * 4)
+#define PFCE(bank) (0x0600 + (bank) * 4)
+#define PNOT(bank) (0x0700 + (bank) * 4)
+#define PMSR(bank) (0x0800 + (bank) * 4)
+#define PMCSR(bank) (0x0900 + (bank) * 4)
+#define PFCAE(bank) (0x0A00 + (bank) * 4)
+#define PIBC(bank) (0x4000 + (bank) * 4)
+#define PBDC(bank) (0x4100 + (bank) * 4)
+#define PIPC(bank) (0x4200 + (bank) * 4)
+
+#define RZA1_MAX_GPIO_PER_BANK 16
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct r7s72100_gpio_priv {
+ void __iomem *regs;
+ int bank;
+};
+
+static int r7s72100_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+ struct r7s72100_gpio_priv *priv = dev_get_priv(dev);
+
+ return !!(readw(priv->regs + PPR(priv->bank)) & BIT(offset));
+}
+
+static int r7s72100_gpio_set_value(struct udevice *dev, unsigned line,
+ int value)
+{
+ struct r7s72100_gpio_priv *priv = dev_get_priv(dev);
+
+ writel(BIT(line + 16) | (value ? BIT(line) : 0),
+ priv->regs + PSR(priv->bank));
+
+ return 0;
+}
+
+static void r7s72100_gpio_set_direction(struct udevice *dev, unsigned line,
+ bool output)
+{
+ struct r7s72100_gpio_priv *priv = dev_get_priv(dev);
+
+ writel(BIT(line + 16), priv->regs + PMCSR(priv->bank));
+ writel(BIT(line + 16) | (output ? 0 : BIT(line)),
+ priv->regs + PMSR(priv->bank));
+
+ clrsetbits_le16(priv->regs + PIBC(priv->bank), BIT(line),
+ output ? 0 : BIT(line));
+}
+
+static int r7s72100_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+ r7s72100_gpio_set_direction(dev, offset, false);
+ return 0;
+}
+
+static int r7s72100_gpio_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ /* write GPIO value to output before selecting output mode of pin */
+ r7s72100_gpio_set_value(dev, offset, value);
+ r7s72100_gpio_set_direction(dev, offset, true);
+
+ return 0;
+}
+
+static int r7s72100_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+ struct r7s72100_gpio_priv *priv = dev_get_priv(dev);
+
+ if (readw(priv->regs + PM(priv->bank)) & BIT(offset))
+ return GPIOF_INPUT;
+ else
+ return GPIOF_OUTPUT;
+}
+
+static const struct dm_gpio_ops r7s72100_gpio_ops = {
+ .direction_input = r7s72100_gpio_direction_input,
+ .direction_output = r7s72100_gpio_direction_output,
+ .get_value = r7s72100_gpio_get_value,
+ .set_value = r7s72100_gpio_set_value,
+ .get_function = r7s72100_gpio_get_function,
+};
+
+static int r7s72100_gpio_probe(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct r7s72100_gpio_priv *priv = dev_get_priv(dev);
+ struct fdtdec_phandle_args args;
+ int node = dev_of_offset(dev);
+ int ret;
+
+ fdt_addr_t addr_base;
+
+ uc_priv->bank_name = dev->name;
+ dev = dev_get_parent(dev);
+ addr_base = dev_read_addr(dev);
+ if (addr_base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ priv->regs = (void __iomem *)addr_base;
+
+ ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, node, "gpio-ranges",
+ NULL, 3, 0, &args);
+ priv->bank = ret == 0 ? (args.args[1] / RZA1_MAX_GPIO_PER_BANK) : -1;
+ uc_priv->gpio_count = ret == 0 ? args.args[2] : RZA1_MAX_GPIO_PER_BANK;
+
+ return 0;
+}
+
+U_BOOT_DRIVER(r7s72100_gpio) = {
+ .name = "r7s72100-gpio",
+ .id = UCLASS_GPIO,
+ .ops = &r7s72100_gpio_ops,
+ .priv_auto = sizeof(struct r7s72100_gpio_priv),
+ .probe = r7s72100_gpio_probe,
+};
diff --git a/roms/u-boot/drivers/gpio/gpio-uclass.c b/roms/u-boot/drivers/gpio/gpio-uclass.c
new file mode 100644
index 000000000..131099cc1
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/gpio-uclass.c
@@ -0,0 +1,1459 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2013 Google, Inc
+ */
+
+#define LOG_CATEGORY UCLASS_GPIO
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <dm/devres.h>
+#include <dm/device_compat.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/uclass-internal.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <malloc.h>
+#include <acpi/acpi_device.h>
+#include <asm/global_data.h>
+#include <asm/gpio.h>
+#include <dm/device_compat.h>
+#include <linux/bug.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * gpio_desc_init() - Initialize the GPIO descriptor
+ *
+ * @desc: GPIO descriptor to initialize
+ * @dev: GPIO device
+ * @offset: Offset of device GPIO
+ */
+static void gpio_desc_init(struct gpio_desc *desc,
+ struct udevice *dev,
+ uint offset)
+{
+ desc->dev = dev;
+ desc->offset = offset;
+ desc->flags = 0;
+}
+
+/**
+ * gpio_to_device() - Convert global GPIO number to device, number
+ *
+ * Convert the GPIO number to an entry in the list of GPIOs
+ * or GPIO blocks registered with the GPIO controller. Returns
+ * entry on success, NULL on error.
+ *
+ * @gpio: The numeric representation of the GPIO
+ * @desc: Returns description (desc->flags will always be 0)
+ * @return 0 if found, -ENOENT if not found
+ */
+static int gpio_to_device(unsigned int gpio, struct gpio_desc *desc)
+{
+ struct gpio_dev_priv *uc_priv;
+ struct udevice *dev;
+ int ret;
+
+ for (ret = uclass_first_device(UCLASS_GPIO, &dev);
+ dev;
+ ret = uclass_next_device(&dev)) {
+ uc_priv = dev_get_uclass_priv(dev);
+ if (gpio >= uc_priv->gpio_base &&
+ gpio < uc_priv->gpio_base + uc_priv->gpio_count) {
+ gpio_desc_init(desc, dev, gpio - uc_priv->gpio_base);
+ return 0;
+ }
+ }
+
+ /* No such GPIO */
+ return ret ? ret : -ENOENT;
+}
+
+#if CONFIG_IS_ENABLED(DM_GPIO_LOOKUP_LABEL)
+/**
+ * dm_gpio_lookup_label() - look for name in gpio device
+ *
+ * search in uc_priv, if there is a gpio with labelname same
+ * as name.
+ *
+ * @name: name which is searched
+ * @uc_priv: gpio_dev_priv pointer.
+ * @offset: gpio offset within the device
+ * @return: 0 if found, -ENOENT if not.
+ */
+static int dm_gpio_lookup_label(const char *name,
+ struct gpio_dev_priv *uc_priv, ulong *offset)
+{
+ int len;
+ int i;
+
+ *offset = -1;
+ len = strlen(name);
+ for (i = 0; i < uc_priv->gpio_count; i++) {
+ if (!uc_priv->name[i])
+ continue;
+ if (!strncmp(name, uc_priv->name[i], len)) {
+ *offset = i;
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+#else
+static int
+dm_gpio_lookup_label(const char *name, struct gpio_dev_priv *uc_priv,
+ ulong *offset)
+{
+ return -ENOENT;
+}
+#endif
+
+int dm_gpio_lookup_name(const char *name, struct gpio_desc *desc)
+{
+ struct gpio_dev_priv *uc_priv = NULL;
+ struct udevice *dev;
+ ulong offset;
+ int numeric;
+ int ret;
+
+ numeric = isdigit(*name) ? simple_strtoul(name, NULL, 10) : -1;
+ for (ret = uclass_first_device(UCLASS_GPIO, &dev);
+ dev;
+ ret = uclass_next_device(&dev)) {
+ int len;
+
+ uc_priv = dev_get_uclass_priv(dev);
+ if (numeric != -1) {
+ offset = numeric - uc_priv->gpio_base;
+ /* Allow GPIOs to be numbered from 0 */
+ if (offset < uc_priv->gpio_count)
+ break;
+ }
+
+ len = uc_priv->bank_name ? strlen(uc_priv->bank_name) : 0;
+
+ if (!strncasecmp(name, uc_priv->bank_name, len)) {
+ if (!strict_strtoul(name + len, 10, &offset))
+ break;
+ }
+
+ /*
+ * if we did not found a gpio through its bank
+ * name, we search for a valid gpio label.
+ */
+ if (!dm_gpio_lookup_label(name, uc_priv, &offset))
+ break;
+ }
+
+ if (!dev)
+ return ret ? ret : -EINVAL;
+
+ gpio_desc_init(desc, dev, offset);
+
+ return 0;
+}
+
+int gpio_lookup_name(const char *name, struct udevice **devp,
+ unsigned int *offsetp, unsigned int *gpiop)
+{
+ struct gpio_desc desc;
+ int ret;
+
+ if (devp)
+ *devp = NULL;
+ ret = dm_gpio_lookup_name(name, &desc);
+ if (ret)
+ return ret;
+
+ if (devp)
+ *devp = desc.dev;
+ if (offsetp)
+ *offsetp = desc.offset;
+ if (gpiop) {
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(desc.dev);
+
+ *gpiop = uc_priv->gpio_base + desc.offset;
+ }
+
+ return 0;
+}
+
+int gpio_xlate_offs_flags(struct udevice *dev, struct gpio_desc *desc,
+ struct ofnode_phandle_args *args)
+{
+ if (args->args_count < 1)
+ return -EINVAL;
+
+ desc->offset = args->args[0];
+
+ if (args->args_count < 2)
+ return 0;
+
+ desc->flags = 0;
+ if (args->args[1] & GPIO_ACTIVE_LOW)
+ desc->flags |= GPIOD_ACTIVE_LOW;
+
+ /*
+ * need to test 2 bits for gpio output binding:
+ * OPEN_DRAIN (0x6) = SINGLE_ENDED (0x2) | LINE_OPEN_DRAIN (0x4)
+ * OPEN_SOURCE (0x2) = SINGLE_ENDED (0x2) | LINE_OPEN_SOURCE (0x0)
+ */
+ if (args->args[1] & GPIO_SINGLE_ENDED) {
+ if (args->args[1] & GPIO_LINE_OPEN_DRAIN)
+ desc->flags |= GPIOD_OPEN_DRAIN;
+ else
+ desc->flags |= GPIOD_OPEN_SOURCE;
+ }
+
+ if (args->args[1] & GPIO_PULL_UP)
+ desc->flags |= GPIOD_PULL_UP;
+
+ if (args->args[1] & GPIO_PULL_DOWN)
+ desc->flags |= GPIOD_PULL_DOWN;
+
+ return 0;
+}
+
+static int gpio_find_and_xlate(struct gpio_desc *desc,
+ struct ofnode_phandle_args *args)
+{
+ const struct dm_gpio_ops *ops = gpio_get_ops(desc->dev);
+
+ if (ops->xlate)
+ return ops->xlate(desc->dev, desc, args);
+ else
+ return gpio_xlate_offs_flags(desc->dev, desc, args);
+}
+
+#if defined(CONFIG_GPIO_HOG)
+
+struct gpio_hog_priv {
+ struct gpio_desc gpiod;
+};
+
+struct gpio_hog_data {
+ int gpiod_flags;
+ int value;
+ u32 val[2];
+};
+
+static int gpio_hog_of_to_plat(struct udevice *dev)
+{
+ struct gpio_hog_data *plat = dev_get_plat(dev);
+ const char *nodename;
+ int ret;
+
+ plat->value = 0;
+ if (dev_read_bool(dev, "input")) {
+ plat->gpiod_flags = GPIOD_IS_IN;
+ } else if (dev_read_bool(dev, "output-high")) {
+ plat->value = 1;
+ plat->gpiod_flags = GPIOD_IS_OUT;
+ } else if (dev_read_bool(dev, "output-low")) {
+ plat->gpiod_flags = GPIOD_IS_OUT;
+ } else {
+ printf("%s: missing gpio-hog state.\n", __func__);
+ return -EINVAL;
+ }
+ ret = dev_read_u32_array(dev, "gpios", plat->val, 2);
+ if (ret) {
+ printf("%s: wrong gpios property, 2 values needed %d\n",
+ __func__, ret);
+ return ret;
+ }
+ nodename = dev_read_string(dev, "line-name");
+ if (nodename)
+ device_set_name(dev, nodename);
+
+ return 0;
+}
+
+static int gpio_hog_probe(struct udevice *dev)
+{
+ struct gpio_hog_data *plat = dev_get_plat(dev);
+ struct gpio_hog_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = gpio_dev_request_index(dev->parent, dev->name, "gpio-hog",
+ plat->val[0], plat->gpiod_flags,
+ plat->val[1], &priv->gpiod);
+ if (ret < 0) {
+ debug("%s: node %s could not get gpio.\n", __func__,
+ dev->name);
+ return ret;
+ }
+
+ if (plat->gpiod_flags == GPIOD_IS_OUT) {
+ ret = dm_gpio_set_value(&priv->gpiod, plat->value);
+ if (ret < 0) {
+ debug("%s: node %s could not set gpio.\n", __func__,
+ dev->name);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int gpio_hog_probe_all(void)
+{
+ struct udevice *dev;
+ int ret;
+ int retval = 0;
+
+ for (uclass_first_device(UCLASS_NOP, &dev);
+ dev;
+ uclass_find_next_device(&dev)) {
+ if (dev->driver == DM_DRIVER_GET(gpio_hog)) {
+ ret = device_probe(dev);
+ if (ret) {
+ printf("Failed to probe device %s err: %d\n",
+ dev->name, ret);
+ retval = ret;
+ }
+ }
+ }
+
+ return retval;
+}
+
+int gpio_hog_lookup_name(const char *name, struct gpio_desc **desc)
+{
+ struct udevice *dev;
+
+ *desc = NULL;
+ gpio_hog_probe_all();
+ if (!uclass_get_device_by_name(UCLASS_NOP, name, &dev)) {
+ struct gpio_hog_priv *priv = dev_get_priv(dev);
+
+ *desc = &priv->gpiod;
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+U_BOOT_DRIVER(gpio_hog) = {
+ .name = "gpio_hog",
+ .id = UCLASS_NOP,
+ .of_to_plat = gpio_hog_of_to_plat,
+ .probe = gpio_hog_probe,
+ .priv_auto = sizeof(struct gpio_hog_priv),
+ .plat_auto = sizeof(struct gpio_hog_data),
+};
+#else
+int gpio_hog_lookup_name(const char *name, struct gpio_desc **desc)
+{
+ return 0;
+}
+#endif
+
+int dm_gpio_request(struct gpio_desc *desc, const char *label)
+{
+ const struct dm_gpio_ops *ops = gpio_get_ops(desc->dev);
+ struct udevice *dev = desc->dev;
+ struct gpio_dev_priv *uc_priv;
+ char *str;
+ int ret;
+
+ uc_priv = dev_get_uclass_priv(dev);
+ if (uc_priv->name[desc->offset])
+ return -EBUSY;
+ str = strdup(label);
+ if (!str)
+ return -ENOMEM;
+ if (ops->request) {
+ ret = ops->request(dev, desc->offset, label);
+ if (ret) {
+ free(str);
+ return ret;
+ }
+ }
+ uc_priv->name[desc->offset] = str;
+
+ return 0;
+}
+
+static int dm_gpio_requestf(struct gpio_desc *desc, const char *fmt, ...)
+{
+#if !defined(CONFIG_SPL_BUILD) || !CONFIG_IS_ENABLED(USE_TINY_PRINTF)
+ va_list args;
+ char buf[40];
+
+ va_start(args, fmt);
+ vscnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+ return dm_gpio_request(desc, buf);
+#else
+ return dm_gpio_request(desc, fmt);
+#endif
+}
+
+/**
+ * gpio_request() - [COMPAT] Request GPIO
+ * gpio: GPIO number
+ * label: Name for the requested GPIO
+ *
+ * The label is copied and allocated so the caller does not need to keep
+ * the pointer around.
+ *
+ * This function implements the API that's compatible with current
+ * GPIO API used in U-Boot. The request is forwarded to particular
+ * GPIO driver. Returns 0 on success, negative value on error.
+ */
+int gpio_request(unsigned gpio, const char *label)
+{
+ struct gpio_desc desc;
+ int ret;
+
+ ret = gpio_to_device(gpio, &desc);
+ if (ret)
+ return ret;
+
+ return dm_gpio_request(&desc, label);
+}
+
+/**
+ * gpio_requestf() - [COMPAT] Request GPIO
+ * @gpio: GPIO number
+ * @fmt: Format string for the requested GPIO
+ * @...: Arguments for the printf() format string
+ *
+ * This function implements the API that's compatible with current
+ * GPIO API used in U-Boot. The request is forwarded to particular
+ * GPIO driver. Returns 0 on success, negative value on error.
+ */
+int gpio_requestf(unsigned gpio, const char *fmt, ...)
+{
+#if !defined(CONFIG_SPL_BUILD) || !CONFIG_IS_ENABLED(USE_TINY_PRINTF)
+ va_list args;
+ char buf[40];
+
+ va_start(args, fmt);
+ vscnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+ return gpio_request(gpio, buf);
+#else
+ return gpio_request(gpio, fmt);
+#endif
+}
+
+int _dm_gpio_free(struct udevice *dev, uint offset)
+{
+ const struct dm_gpio_ops *ops = gpio_get_ops(dev);
+ struct gpio_dev_priv *uc_priv;
+ int ret;
+
+ uc_priv = dev_get_uclass_priv(dev);
+ if (!uc_priv->name[offset])
+ return -ENXIO;
+ if (ops->rfree) {
+ ret = ops->rfree(dev, offset);
+ if (ret)
+ return ret;
+ }
+
+ free(uc_priv->name[offset]);
+ uc_priv->name[offset] = NULL;
+
+ return 0;
+}
+
+/**
+ * gpio_free() - [COMPAT] Relinquish GPIO
+ * gpio: GPIO number
+ *
+ * This function implements the API that's compatible with current
+ * GPIO API used in U-Boot. The request is forwarded to particular
+ * GPIO driver. Returns 0 on success, negative value on error.
+ */
+int gpio_free(unsigned gpio)
+{
+ struct gpio_desc desc;
+ int ret;
+
+ ret = gpio_to_device(gpio, &desc);
+ if (ret)
+ return ret;
+
+ return _dm_gpio_free(desc.dev, desc.offset);
+}
+
+static int check_reserved(const struct gpio_desc *desc, const char *func)
+{
+ struct gpio_dev_priv *uc_priv;
+
+ if (!dm_gpio_is_valid(desc))
+ return -ENOENT;
+
+ uc_priv = dev_get_uclass_priv(desc->dev);
+ if (!uc_priv->name[desc->offset]) {
+ printf("%s: %s: error: gpio %s%d not reserved\n",
+ desc->dev->name, func,
+ uc_priv->bank_name ? uc_priv->bank_name : "",
+ desc->offset);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+/**
+ * gpio_direction_input() - [COMPAT] Set GPIO direction to input
+ * gpio: GPIO number
+ *
+ * This function implements the API that's compatible with current
+ * GPIO API used in U-Boot. The request is forwarded to particular
+ * GPIO driver. Returns 0 on success, negative value on error.
+ */
+int gpio_direction_input(unsigned gpio)
+{
+ struct gpio_desc desc;
+ int ret;
+
+ ret = gpio_to_device(gpio, &desc);
+ if (ret)
+ return ret;
+
+ return dm_gpio_clrset_flags(&desc, GPIOD_MASK_DIR, GPIOD_IS_IN);
+}
+
+/**
+ * gpio_direction_output() - [COMPAT] Set GPIO direction to output and set value
+ * gpio: GPIO number
+ * value: Logical value to be set on the GPIO pin
+ *
+ * This function implements the API that's compatible with current
+ * GPIO API used in U-Boot. The request is forwarded to particular
+ * GPIO driver. Returns 0 on success, negative value on error.
+ */
+int gpio_direction_output(unsigned gpio, int value)
+{
+ struct gpio_desc desc;
+ ulong flags;
+ int ret;
+
+ ret = gpio_to_device(gpio, &desc);
+ if (ret)
+ return ret;
+
+ flags = GPIOD_IS_OUT;
+ if (value)
+ flags |= GPIOD_IS_OUT_ACTIVE;
+ return dm_gpio_clrset_flags(&desc, GPIOD_MASK_DIR, flags);
+}
+
+static int _gpio_get_value(const struct gpio_desc *desc)
+{
+ const struct dm_gpio_ops *ops = gpio_get_ops(desc->dev);
+ int value;
+
+ value = ops->get_value(desc->dev, desc->offset);
+
+ return desc->flags & GPIOD_ACTIVE_LOW ? !value : value;
+}
+
+int dm_gpio_get_value(const struct gpio_desc *desc)
+{
+ int ret;
+
+ ret = check_reserved(desc, "get_value");
+ if (ret)
+ return ret;
+
+ return _gpio_get_value(desc);
+}
+
+int dm_gpio_set_value(const struct gpio_desc *desc, int value)
+{
+ const struct dm_gpio_ops *ops;
+ int ret;
+
+ ret = check_reserved(desc, "set_value");
+ if (ret)
+ return ret;
+
+ if (desc->flags & GPIOD_ACTIVE_LOW)
+ value = !value;
+
+ /* GPIOD_ are directly managed by driver in set_flags */
+ ops = gpio_get_ops(desc->dev);
+ if (ops->set_flags) {
+ ulong flags = desc->flags;
+
+ if (value)
+ flags |= GPIOD_IS_OUT_ACTIVE;
+ else
+ flags &= ~GPIOD_IS_OUT_ACTIVE;
+ return ops->set_flags(desc->dev, desc->offset, flags);
+ }
+
+ /*
+ * Emulate open drain by not actively driving the line high or
+ * Emulate open source by not actively driving the line low
+ */
+ if ((desc->flags & GPIOD_OPEN_DRAIN && value) ||
+ (desc->flags & GPIOD_OPEN_SOURCE && !value))
+ return ops->direction_input(desc->dev, desc->offset);
+ else if (desc->flags & GPIOD_OPEN_DRAIN ||
+ desc->flags & GPIOD_OPEN_SOURCE)
+ return ops->direction_output(desc->dev, desc->offset, value);
+
+ ret = ops->set_value(desc->dev, desc->offset, value);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+/* check dir flags invalid configuration */
+static int check_dir_flags(ulong flags)
+{
+ if ((flags & GPIOD_IS_OUT) && (flags & GPIOD_IS_IN)) {
+ log_debug("%s: flags 0x%lx has GPIOD_IS_OUT and GPIOD_IS_IN\n",
+ __func__, flags);
+ return -EINVAL;
+ }
+
+ if ((flags & GPIOD_PULL_UP) && (flags & GPIOD_PULL_DOWN)) {
+ log_debug("%s: flags 0x%lx has GPIOD_PULL_UP and GPIOD_PULL_DOWN\n",
+ __func__, flags);
+ return -EINVAL;
+ }
+
+ if ((flags & GPIOD_OPEN_DRAIN) && (flags & GPIOD_OPEN_SOURCE)) {
+ log_debug("%s: flags 0x%lx has GPIOD_OPEN_DRAIN and GPIOD_OPEN_SOURCE\n",
+ __func__, flags);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * _dm_gpio_set_flags() - Send flags to the driver
+ *
+ * This uses the best available method to send the given flags to the driver.
+ * Note that if flags & GPIOD_ACTIVE_LOW, the driver sees the opposite value
+ * of GPIOD_IS_OUT_ACTIVE.
+ *
+ * @desc: GPIO description
+ * @flags: flags value to set
+ * @return 0 if OK, -ve on error
+ */
+static int _dm_gpio_set_flags(struct gpio_desc *desc, ulong flags)
+{
+ struct udevice *dev = desc->dev;
+ const struct dm_gpio_ops *ops = gpio_get_ops(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ int ret = 0;
+
+ ret = check_dir_flags(flags);
+ if (ret) {
+ dev_dbg(dev,
+ "%s error: set_dir_flags for gpio %s%d has invalid dir flags 0x%lx\n",
+ desc->dev->name,
+ uc_priv->bank_name ? uc_priv->bank_name : "",
+ desc->offset, flags);
+
+ return ret;
+ }
+
+ /* If active low, invert the output state */
+ if ((flags & (GPIOD_IS_OUT | GPIOD_ACTIVE_LOW)) ==
+ (GPIOD_IS_OUT | GPIOD_ACTIVE_LOW))
+ flags ^= GPIOD_IS_OUT_ACTIVE;
+
+ /* GPIOD_ are directly managed by driver in set_flags */
+ if (ops->set_flags) {
+ ret = ops->set_flags(dev, desc->offset, flags);
+ } else {
+ if (flags & GPIOD_IS_OUT) {
+ bool value = flags & GPIOD_IS_OUT_ACTIVE;
+
+ ret = ops->direction_output(dev, desc->offset, value);
+ } else if (flags & GPIOD_IS_IN) {
+ ret = ops->direction_input(dev, desc->offset);
+ }
+ }
+
+ return ret;
+}
+
+int dm_gpio_clrset_flags(struct gpio_desc *desc, ulong clr, ulong set)
+{
+ ulong flags;
+ int ret;
+
+ ret = check_reserved(desc, "set_dir_flags");
+ if (ret)
+ return ret;
+
+ flags = (desc->flags & ~clr) | set;
+
+ ret = _dm_gpio_set_flags(desc, flags);
+ if (ret)
+ return ret;
+
+ /* save the flags also in descriptor */
+ desc->flags = flags;
+
+ return 0;
+}
+
+int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags)
+{
+ /* combine the requested flags (for IN/OUT) and the descriptor flags */
+ return dm_gpio_clrset_flags(desc, GPIOD_MASK_DIR, flags);
+}
+
+int dm_gpios_clrset_flags(struct gpio_desc *desc, int count, ulong clr,
+ ulong set)
+{
+ int ret;
+ int i;
+
+ for (i = 0; i < count; i++) {
+ ret = dm_gpio_clrset_flags(&desc[i], clr, set);
+ if (ret)
+ return log_ret(ret);
+ }
+
+ return 0;
+}
+
+int dm_gpio_get_flags(struct gpio_desc *desc, ulong *flagsp)
+{
+ struct udevice *dev = desc->dev;
+ int ret, value;
+ const struct dm_gpio_ops *ops = gpio_get_ops(dev);
+ ulong flags;
+
+ ret = check_reserved(desc, "get_flags");
+ if (ret)
+ return ret;
+
+ /* GPIOD_ are directly provided by driver except GPIOD_ACTIVE_LOW */
+ if (ops->get_flags) {
+ ret = ops->get_flags(dev, desc->offset, &flags);
+ if (ret)
+ return ret;
+
+ /* GPIOD_ACTIVE_LOW is saved in desc->flags */
+ value = flags & GPIOD_IS_OUT_ACTIVE ? 1 : 0;
+ if (desc->flags & GPIOD_ACTIVE_LOW)
+ value = !value;
+ flags &= ~(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT_ACTIVE);
+ flags |= (desc->flags & GPIOD_ACTIVE_LOW);
+ if (value)
+ flags |= GPIOD_IS_OUT_ACTIVE;
+ } else {
+ flags = desc->flags;
+ /* only GPIOD_IS_OUT_ACTIVE is provided by uclass */
+ flags &= ~GPIOD_IS_OUT_ACTIVE;
+ if ((desc->flags & GPIOD_IS_OUT) && _gpio_get_value(desc))
+ flags |= GPIOD_IS_OUT_ACTIVE;
+ }
+ *flagsp = flags;
+
+ return 0;
+}
+
+/**
+ * gpio_get_value() - [COMPAT] Sample GPIO pin and return it's value
+ * gpio: GPIO number
+ *
+ * This function implements the API that's compatible with current
+ * GPIO API used in U-Boot. The request is forwarded to particular
+ * GPIO driver. Returns the value of the GPIO pin, or negative value
+ * on error.
+ */
+int gpio_get_value(unsigned gpio)
+{
+ int ret;
+
+ struct gpio_desc desc;
+
+ ret = gpio_to_device(gpio, &desc);
+ if (ret)
+ return ret;
+ return dm_gpio_get_value(&desc);
+}
+
+/**
+ * gpio_set_value() - [COMPAT] Configure logical value on GPIO pin
+ * gpio: GPIO number
+ * value: Logical value to be set on the GPIO pin.
+ *
+ * This function implements the API that's compatible with current
+ * GPIO API used in U-Boot. The request is forwarded to particular
+ * GPIO driver. Returns 0 on success, negative value on error.
+ */
+int gpio_set_value(unsigned gpio, int value)
+{
+ struct gpio_desc desc;
+ int ret;
+
+ ret = gpio_to_device(gpio, &desc);
+ if (ret)
+ return ret;
+ return dm_gpio_set_value(&desc, value);
+}
+
+const char *gpio_get_bank_info(struct udevice *dev, int *bit_count)
+{
+ struct gpio_dev_priv *priv;
+
+ /* Must be called on an active device */
+ priv = dev_get_uclass_priv(dev);
+ assert(priv);
+
+ *bit_count = priv->gpio_count;
+ return priv->bank_name;
+}
+
+static const char * const gpio_function[GPIOF_COUNT] = {
+ "input",
+ "output",
+ "unused",
+ "unknown",
+ "func",
+};
+
+static int get_function(struct udevice *dev, int offset, bool skip_unused,
+ const char **namep)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ const struct dm_gpio_ops *ops = gpio_get_ops(dev);
+
+ BUILD_BUG_ON(GPIOF_COUNT != ARRAY_SIZE(gpio_function));
+ if (!device_active(dev))
+ return -ENODEV;
+ if (offset < 0 || offset >= uc_priv->gpio_count)
+ return -EINVAL;
+ if (namep)
+ *namep = uc_priv->name[offset];
+ if (skip_unused && !uc_priv->name[offset])
+ return GPIOF_UNUSED;
+ if (ops->get_function) {
+ int ret;
+
+ ret = ops->get_function(dev, offset);
+ if (ret < 0)
+ return ret;
+ if (ret >= ARRAY_SIZE(gpio_function))
+ return -ENODATA;
+ return ret;
+ }
+
+ return GPIOF_UNKNOWN;
+}
+
+int gpio_get_function(struct udevice *dev, int offset, const char **namep)
+{
+ return get_function(dev, offset, true, namep);
+}
+
+int gpio_get_raw_function(struct udevice *dev, int offset, const char **namep)
+{
+ return get_function(dev, offset, false, namep);
+}
+
+int gpio_get_status(struct udevice *dev, int offset, char *buf, int buffsize)
+{
+ const struct dm_gpio_ops *ops = gpio_get_ops(dev);
+ struct gpio_dev_priv *priv;
+ char *str = buf;
+ int func;
+ int ret;
+ int len;
+
+ BUILD_BUG_ON(GPIOF_COUNT != ARRAY_SIZE(gpio_function));
+
+ *buf = 0;
+ priv = dev_get_uclass_priv(dev);
+ ret = gpio_get_raw_function(dev, offset, NULL);
+ if (ret < 0)
+ return ret;
+ func = ret;
+ len = snprintf(str, buffsize, "%s%d: %s",
+ priv->bank_name ? priv->bank_name : "",
+ offset, gpio_function[func]);
+ if (func == GPIOF_INPUT || func == GPIOF_OUTPUT ||
+ func == GPIOF_UNUSED) {
+ const char *label;
+ bool used;
+
+ ret = ops->get_value(dev, offset);
+ if (ret < 0)
+ return ret;
+ used = gpio_get_function(dev, offset, &label) != GPIOF_UNUSED;
+ snprintf(str + len, buffsize - len, ": %d [%c]%s%s",
+ ret,
+ used ? 'x' : ' ',
+ used ? " " : "",
+ label ? label : "");
+ }
+
+ return 0;
+}
+
+#if CONFIG_IS_ENABLED(ACPIGEN)
+int gpio_get_acpi(const struct gpio_desc *desc, struct acpi_gpio *gpio)
+{
+ const struct dm_gpio_ops *ops;
+
+ memset(gpio, '\0', sizeof(*gpio));
+ if (!dm_gpio_is_valid(desc)) {
+ /* Indicate that the GPIO is not valid */
+ gpio->pin_count = 0;
+ gpio->pins[0] = 0;
+ return -EINVAL;
+ }
+
+ ops = gpio_get_ops(desc->dev);
+ if (!ops->get_acpi)
+ return -ENOSYS;
+
+ return ops->get_acpi(desc, gpio);
+}
+#endif
+
+int gpio_claim_vector(const int *gpio_num_array, const char *fmt)
+{
+ int i, ret;
+ int gpio;
+
+ for (i = 0; i < 32; i++) {
+ gpio = gpio_num_array[i];
+ if (gpio == -1)
+ break;
+ ret = gpio_requestf(gpio, fmt, i);
+ if (ret)
+ goto err;
+ ret = gpio_direction_input(gpio);
+ if (ret) {
+ gpio_free(gpio);
+ goto err;
+ }
+ }
+
+ return 0;
+err:
+ for (i--; i >= 0; i--)
+ gpio_free(gpio_num_array[i]);
+
+ return ret;
+}
+
+/*
+ * get a number comprised of multiple GPIO values. gpio_num_array points to
+ * the array of gpio pin numbers to scan, terminated by -1.
+ */
+int gpio_get_values_as_int(const int *gpio_list)
+{
+ int gpio;
+ unsigned bitmask = 1;
+ unsigned vector = 0;
+ int ret;
+
+ while (bitmask &&
+ ((gpio = *gpio_list++) != -1)) {
+ ret = gpio_get_value(gpio);
+ if (ret < 0)
+ return ret;
+ else if (ret)
+ vector |= bitmask;
+ bitmask <<= 1;
+ }
+
+ return vector;
+}
+
+int dm_gpio_get_values_as_int(const struct gpio_desc *desc_list, int count)
+{
+ unsigned bitmask = 1;
+ unsigned vector = 0;
+ int ret, i;
+
+ for (i = 0; i < count; i++) {
+ ret = dm_gpio_get_value(&desc_list[i]);
+ if (ret < 0)
+ return ret;
+ else if (ret)
+ vector |= bitmask;
+ bitmask <<= 1;
+ }
+
+ return vector;
+}
+
+int dm_gpio_get_values_as_int_base3(struct gpio_desc *desc_list,
+ int count)
+{
+ static const char tristate[] = "01z";
+ enum {
+ PULLUP,
+ PULLDOWN,
+
+ NUM_OPTIONS,
+ };
+ int vals[NUM_OPTIONS];
+ uint mask;
+ uint vector = 0;
+ int ret, i;
+
+ /*
+ * Limit to 19 digits which should be plenty. This avoids overflow of a
+ * 32-bit int
+ */
+ assert(count < 20);
+
+ for (i = 0; i < NUM_OPTIONS; i++) {
+ uint flags = GPIOD_IS_IN;
+
+ flags |= (i == PULLDOWN) ? GPIOD_PULL_DOWN : GPIOD_PULL_UP;
+ ret = dm_gpios_clrset_flags(desc_list, count, GPIOD_MASK_PULL,
+ flags);
+ if (ret)
+ return log_msg_ret("pu", ret);
+
+ /* Give the lines time to settle */
+ udelay(10);
+
+ ret = dm_gpio_get_values_as_int(desc_list, count);
+ if (ret < 0)
+ return log_msg_ret("get1", ret);
+ vals[i] = ret;
+ }
+
+ log_debug("values: %x %x, count = %d\n", vals[0], vals[1], count);
+ for (i = count - 1, mask = 1 << i; i >= 0; i--, mask >>= 1) {
+ uint pd = vals[PULLDOWN] & mask ? 1 : 0;
+ uint pu = vals[PULLUP] & mask ? 1 : 0;
+ uint digit;
+
+ /*
+ * Get value with internal pulldown active. If this is 1 then
+ * there is a stronger external pullup, which we call 1. If not
+ * then call it 0.
+ *
+ * If the values differ then the pin is floating so we call
+ * this a 2.
+ */
+ if (pu == pd)
+ digit = pd;
+ else
+ digit = 2;
+ log_debug("%c ", tristate[digit]);
+ vector = 3 * vector + digit;
+ }
+ log_debug("vector=%d\n", vector);
+
+ return vector;
+}
+
+/**
+ * gpio_request_tail: common work for requesting a gpio.
+ *
+ * ret: return value from previous work in function which calls
+ * this function.
+ * This seems bogus (why calling this function instead not
+ * calling it and end caller function instead?).
+ * Because on error in caller function we want to set some
+ * default values in gpio desc and have a common error
+ * debug message, which provides this function.
+ * nodename: Name of node for which gpio gets requested
+ * used for gpio label name.
+ * args: pointer to output arguments structure
+ * list_name: Name of GPIO list
+ * used for gpio label name.
+ * index: gpio index in gpio list
+ * used for gpio label name.
+ * desc: pointer to gpio descriptor, filled from this
+ * function.
+ * flags: gpio flags to use.
+ * add_index: should index added to gpio label name
+ * gpio_dev: pointer to gpio device from which the gpio
+ * will be requested. If NULL try to get the
+ * gpio device with uclass_get_device_by_ofnode()
+ *
+ * return: In error case this function sets default values in
+ * gpio descriptor, also emmits a debug message.
+ * On success it returns 0 else the error code from
+ * function calls, or the error code passed through
+ * ret to this function.
+ *
+ */
+static int gpio_request_tail(int ret, const char *nodename,
+ struct ofnode_phandle_args *args,
+ const char *list_name, int index,
+ struct gpio_desc *desc, int flags,
+ bool add_index, struct udevice *gpio_dev)
+{
+ gpio_desc_init(desc, gpio_dev, 0);
+ if (ret)
+ goto err;
+
+ if (!desc->dev) {
+ ret = uclass_get_device_by_ofnode(UCLASS_GPIO, args->node,
+ &desc->dev);
+ if (ret) {
+ debug("%s: uclass_get_device_by_ofnode failed\n",
+ __func__);
+ goto err;
+ }
+ }
+ ret = gpio_find_and_xlate(desc, args);
+ if (ret) {
+ debug("%s: gpio_find_and_xlate failed\n", __func__);
+ goto err;
+ }
+ ret = dm_gpio_requestf(desc, add_index ? "%s.%s%d" : "%s.%s",
+ nodename, list_name, index);
+ if (ret) {
+ debug("%s: dm_gpio_requestf failed\n", __func__);
+ goto err;
+ }
+
+ /* Keep any direction flags provided by the devicetree */
+ ret = dm_gpio_set_dir_flags(desc,
+ flags | (desc->flags & GPIOD_MASK_DIR));
+ if (ret) {
+ debug("%s: dm_gpio_set_dir failed\n", __func__);
+ goto err;
+ }
+
+ return 0;
+err:
+ debug("%s: Node '%s', property '%s', failed to request GPIO index %d: %d\n",
+ __func__, nodename, list_name, index, ret);
+ return ret;
+}
+
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+static int _gpio_request_by_name_nodev(ofnode node, const char *list_name,
+ int index, struct gpio_desc *desc,
+ int flags, bool add_index)
+{
+ struct ofnode_phandle_args args;
+ int ret;
+
+ ret = ofnode_parse_phandle_with_args(node, list_name, "#gpio-cells", 0,
+ index, &args);
+
+ return gpio_request_tail(ret, ofnode_get_name(node), &args, list_name,
+ index, desc, flags, add_index, NULL);
+}
+
+int gpio_request_by_name_nodev(ofnode node, const char *list_name, int index,
+ struct gpio_desc *desc, int flags)
+{
+ return _gpio_request_by_name_nodev(node, list_name, index, desc, flags,
+ index > 0);
+}
+
+int gpio_request_by_name(struct udevice *dev, const char *list_name, int index,
+ struct gpio_desc *desc, int flags)
+{
+ struct ofnode_phandle_args args;
+ ofnode node;
+ int ret;
+
+ ret = dev_read_phandle_with_args(dev, list_name, "#gpio-cells", 0,
+ index, &args);
+ node = dev_ofnode(dev);
+ return gpio_request_tail(ret, ofnode_get_name(node), &args, list_name,
+ index, desc, flags, index > 0, NULL);
+}
+
+int gpio_request_list_by_name_nodev(ofnode node, const char *list_name,
+ struct gpio_desc *desc, int max_count,
+ int flags)
+{
+ int count;
+ int ret;
+
+ for (count = 0; count < max_count; count++) {
+ ret = _gpio_request_by_name_nodev(node, list_name, count,
+ &desc[count], flags, true);
+ if (ret == -ENOENT)
+ break;
+ else if (ret)
+ goto err;
+ }
+
+ /* We ran out of GPIOs in the list */
+ return count;
+
+err:
+ gpio_free_list_nodev(desc, count - 1);
+
+ return ret;
+}
+
+int gpio_request_list_by_name(struct udevice *dev, const char *list_name,
+ struct gpio_desc *desc, int max_count,
+ int flags)
+{
+ /*
+ * This isn't ideal since we don't use dev->name in the debug()
+ * calls in gpio_request_by_name(), but we can do this until
+ * gpio_request_list_by_name_nodev() can be dropped.
+ */
+ return gpio_request_list_by_name_nodev(dev_ofnode(dev), list_name, desc,
+ max_count, flags);
+}
+
+int gpio_get_list_count(struct udevice *dev, const char *list_name)
+{
+ int ret;
+
+ ret = dev_count_phandle_with_args(dev, list_name, "#gpio-cells",
+ -ENOENT);
+ if (ret < 0) {
+ debug("%s: Node '%s', property '%s', GPIO count failed: %d\n",
+ __func__, dev->name, list_name, ret);
+ }
+
+ return ret;
+}
+#endif /* OF_PLATDATA */
+
+int dm_gpio_free(struct udevice *dev, struct gpio_desc *desc)
+{
+ /* For now, we don't do any checking of dev */
+ return _dm_gpio_free(desc->dev, desc->offset);
+}
+
+int gpio_free_list(struct udevice *dev, struct gpio_desc *desc, int count)
+{
+ int i;
+
+ /* For now, we don't do any checking of dev */
+ for (i = 0; i < count; i++)
+ dm_gpio_free(dev, &desc[i]);
+
+ return 0;
+}
+
+int gpio_free_list_nodev(struct gpio_desc *desc, int count)
+{
+ return gpio_free_list(NULL, desc, count);
+}
+
+/* We need to renumber the GPIOs when any driver is probed/removed */
+static int gpio_renumber(struct udevice *removed_dev)
+{
+ struct gpio_dev_priv *uc_priv;
+ struct udevice *dev;
+ struct uclass *uc;
+ unsigned base;
+ int ret;
+
+ ret = uclass_get(UCLASS_GPIO, &uc);
+ if (ret)
+ return ret;
+
+ /* Ensure that we have a base for each bank */
+ base = 0;
+ uclass_foreach_dev(dev, uc) {
+ if (device_active(dev) && dev != removed_dev) {
+ uc_priv = dev_get_uclass_priv(dev);
+ uc_priv->gpio_base = base;
+ base += uc_priv->gpio_count;
+ }
+ }
+
+ return 0;
+}
+
+int gpio_get_number(const struct gpio_desc *desc)
+{
+ struct udevice *dev = desc->dev;
+ struct gpio_dev_priv *uc_priv;
+
+ if (!dev)
+ return -1;
+ uc_priv = dev_get_uclass_priv(dev);
+
+ return uc_priv->gpio_base + desc->offset;
+}
+
+static int gpio_post_probe(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ uc_priv->name = calloc(uc_priv->gpio_count, sizeof(char *));
+ if (!uc_priv->name)
+ return -ENOMEM;
+
+ return gpio_renumber(NULL);
+}
+
+static int gpio_pre_remove(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ int i;
+
+ for (i = 0; i < uc_priv->gpio_count; i++) {
+ if (uc_priv->name[i])
+ free(uc_priv->name[i]);
+ }
+ free(uc_priv->name);
+
+ return gpio_renumber(dev);
+}
+
+int gpio_dev_request_index(struct udevice *dev, const char *nodename,
+ char *list_name, int index, int flags,
+ int dtflags, struct gpio_desc *desc)
+{
+ struct ofnode_phandle_args args;
+
+ args.node = ofnode_null();
+ args.args_count = 2;
+ args.args[0] = index;
+ args.args[1] = dtflags;
+
+ return gpio_request_tail(0, nodename, &args, list_name, index, desc,
+ flags, 0, dev);
+}
+
+static void devm_gpiod_release(struct udevice *dev, void *res)
+{
+ dm_gpio_free(dev, res);
+}
+
+static int devm_gpiod_match(struct udevice *dev, void *res, void *data)
+{
+ return res == data;
+}
+
+struct gpio_desc *devm_gpiod_get_index(struct udevice *dev, const char *id,
+ unsigned int index, int flags)
+{
+ int rc;
+ struct gpio_desc *desc;
+ char *propname;
+ static const char suffix[] = "-gpios";
+
+ propname = malloc(strlen(id) + sizeof(suffix));
+ if (!propname) {
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ strcpy(propname, id);
+ strcat(propname, suffix);
+
+ desc = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc),
+ __GFP_ZERO);
+ if (unlikely(!desc)) {
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ rc = gpio_request_by_name(dev, propname, index, desc, flags);
+
+end:
+ if (propname)
+ free(propname);
+
+ if (rc)
+ return ERR_PTR(rc);
+
+ devres_add(dev, desc);
+
+ return desc;
+}
+
+struct gpio_desc *devm_gpiod_get_index_optional(struct udevice *dev,
+ const char *id,
+ unsigned int index,
+ int flags)
+{
+ struct gpio_desc *desc = devm_gpiod_get_index(dev, id, index, flags);
+
+ if (IS_ERR(desc))
+ return NULL;
+
+ return desc;
+}
+
+void devm_gpiod_put(struct udevice *dev, struct gpio_desc *desc)
+{
+ int rc;
+
+ rc = devres_release(dev, devm_gpiod_release, devm_gpiod_match, desc);
+ WARN_ON(rc);
+}
+
+static int gpio_post_bind(struct udevice *dev)
+{
+ struct udevice *child;
+ ofnode node;
+
+#if defined(CONFIG_NEEDS_MANUAL_RELOC)
+ struct dm_gpio_ops *ops = (struct dm_gpio_ops *)device_get_ops(dev);
+ static int reloc_done;
+
+ if (!reloc_done) {
+ if (ops->request)
+ ops->request += gd->reloc_off;
+ if (ops->rfree)
+ ops->rfree += gd->reloc_off;
+ if (ops->direction_input)
+ ops->direction_input += gd->reloc_off;
+ if (ops->direction_output)
+ ops->direction_output += gd->reloc_off;
+ if (ops->get_value)
+ ops->get_value += gd->reloc_off;
+ if (ops->set_value)
+ ops->set_value += gd->reloc_off;
+ if (ops->get_function)
+ ops->get_function += gd->reloc_off;
+ if (ops->xlate)
+ ops->xlate += gd->reloc_off;
+ if (ops->set_flags)
+ ops->set_flags += gd->reloc_off;
+ if (ops->get_flags)
+ ops->get_flags += gd->reloc_off;
+
+ reloc_done++;
+ }
+#endif
+
+ if (IS_ENABLED(CONFIG_GPIO_HOG)) {
+ dev_for_each_subnode(node, dev) {
+ if (ofnode_read_bool(node, "gpio-hog")) {
+ const char *name = ofnode_get_name(node);
+ int ret;
+
+ ret = device_bind_driver_to_node(dev,
+ "gpio_hog",
+ name, node,
+ &child);
+ if (ret)
+ return ret;
+ }
+ }
+ }
+ return 0;
+}
+
+UCLASS_DRIVER(gpio) = {
+ .id = UCLASS_GPIO,
+ .name = "gpio",
+ .flags = DM_UC_FLAG_SEQ_ALIAS,
+ .post_probe = gpio_post_probe,
+ .post_bind = gpio_post_bind,
+ .pre_remove = gpio_pre_remove,
+ .per_device_auto = sizeof(struct gpio_dev_priv),
+};
diff --git a/roms/u-boot/drivers/gpio/gpio-uniphier.c b/roms/u-boot/drivers/gpio/gpio-uniphier.c
new file mode 100644
index 000000000..61c705b5a
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/gpio-uniphier.c
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016-2017 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/sizes.h>
+#include <linux/errno.h>
+#include <asm/global_data.h>
+#include <asm/gpio.h>
+#include <dt-bindings/gpio/uniphier-gpio.h>
+
+#define UNIPHIER_GPIO_PORT_DATA 0x0 /* data */
+#define UNIPHIER_GPIO_PORT_DIR 0x4 /* direction (1:in, 0:out) */
+#define UNIPHIER_GPIO_IRQ_EN 0x90 /* irq enable */
+
+struct uniphier_gpio_priv {
+ void __iomem *regs;
+};
+
+static unsigned int uniphier_gpio_bank_to_reg(unsigned int bank)
+{
+ unsigned int reg;
+
+ reg = (bank + 1) * 8;
+
+ /*
+ * Unfortunately, the GPIO port registers are not contiguous because
+ * offset 0x90-0x9f is used for IRQ. Add 0x10 when crossing the region.
+ */
+ if (reg >= UNIPHIER_GPIO_IRQ_EN)
+ reg += 0x10;
+
+ return reg;
+}
+
+static void uniphier_gpio_get_bank_and_mask(unsigned int offset,
+ unsigned int *bank, u32 *mask)
+{
+ *bank = offset / UNIPHIER_GPIO_LINES_PER_BANK;
+ *mask = BIT(offset % UNIPHIER_GPIO_LINES_PER_BANK);
+}
+
+static void uniphier_gpio_reg_update(struct uniphier_gpio_priv *priv,
+ unsigned int reg, u32 mask, u32 val)
+{
+ u32 tmp;
+
+ tmp = readl(priv->regs + reg);
+ tmp &= ~mask;
+ tmp |= mask & val;
+ writel(tmp, priv->regs + reg);
+}
+
+static void uniphier_gpio_bank_write(struct udevice *dev, unsigned int bank,
+ unsigned int reg, u32 mask, u32 val)
+{
+ struct uniphier_gpio_priv *priv = dev_get_priv(dev);
+
+ if (!mask)
+ return;
+
+ uniphier_gpio_reg_update(priv, uniphier_gpio_bank_to_reg(bank) + reg,
+ mask, val);
+}
+
+static void uniphier_gpio_offset_write(struct udevice *dev, unsigned int offset,
+ unsigned int reg, int val)
+{
+ unsigned int bank;
+ u32 mask;
+
+ uniphier_gpio_get_bank_and_mask(offset, &bank, &mask);
+
+ uniphier_gpio_bank_write(dev, bank, reg, mask, val ? mask : 0);
+}
+
+static int uniphier_gpio_offset_read(struct udevice *dev,
+ unsigned int offset, unsigned int reg)
+{
+ struct uniphier_gpio_priv *priv = dev_get_priv(dev);
+ unsigned int bank, reg_offset;
+ u32 mask;
+
+ uniphier_gpio_get_bank_and_mask(offset, &bank, &mask);
+ reg_offset = uniphier_gpio_bank_to_reg(bank) + reg;
+
+ return !!(readl(priv->regs + reg_offset) & mask);
+}
+
+static int uniphier_gpio_get_function(struct udevice *dev, unsigned int offset)
+{
+ return uniphier_gpio_offset_read(dev, offset, UNIPHIER_GPIO_PORT_DIR) ?
+ GPIOF_INPUT : GPIOF_OUTPUT;
+}
+
+static int uniphier_gpio_direction_input(struct udevice *dev,
+ unsigned int offset)
+{
+ uniphier_gpio_offset_write(dev, offset, UNIPHIER_GPIO_PORT_DIR, 1);
+
+ return 0;
+}
+
+static int uniphier_gpio_direction_output(struct udevice *dev,
+ unsigned int offset, int value)
+{
+ uniphier_gpio_offset_write(dev, offset, UNIPHIER_GPIO_PORT_DATA, value);
+ uniphier_gpio_offset_write(dev, offset, UNIPHIER_GPIO_PORT_DIR, 0);
+
+ return 0;
+}
+
+static int uniphier_gpio_get_value(struct udevice *dev, unsigned int offset)
+{
+ return uniphier_gpio_offset_read(dev, offset, UNIPHIER_GPIO_PORT_DATA);
+}
+
+static int uniphier_gpio_set_value(struct udevice *dev,
+ unsigned int offset, int value)
+{
+ uniphier_gpio_offset_write(dev, offset, UNIPHIER_GPIO_PORT_DATA, value);
+
+ return 0;
+}
+
+static const struct dm_gpio_ops uniphier_gpio_ops = {
+ .direction_input = uniphier_gpio_direction_input,
+ .direction_output = uniphier_gpio_direction_output,
+ .get_value = uniphier_gpio_get_value,
+ .set_value = uniphier_gpio_set_value,
+ .get_function = uniphier_gpio_get_function,
+};
+
+static int uniphier_gpio_probe(struct udevice *dev)
+{
+ struct uniphier_gpio_priv *priv = dev_get_priv(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ fdt_addr_t addr;
+
+ addr = dev_read_addr(dev);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ priv->regs = devm_ioremap(dev, addr, SZ_512);
+ if (!priv->regs)
+ return -ENOMEM;
+
+ uc_priv->gpio_count = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
+ "ngpios", 0);
+
+ return 0;
+}
+
+static const struct udevice_id uniphier_gpio_match[] = {
+ { .compatible = "socionext,uniphier-gpio" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(uniphier_gpio) = {
+ .name = "uniphier-gpio",
+ .id = UCLASS_GPIO,
+ .of_match = uniphier_gpio_match,
+ .probe = uniphier_gpio_probe,
+ .priv_auto = sizeof(struct uniphier_gpio_priv),
+ .ops = &uniphier_gpio_ops,
+};
diff --git a/roms/u-boot/drivers/gpio/hi6220_gpio.c b/roms/u-boot/drivers/gpio/hi6220_gpio.c
new file mode 100644
index 000000000..04f8d904a
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/hi6220_gpio.c
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015 Linaro
+ * Peter Griffin <peter.griffin@linaro.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <errno.h>
+#include <linux/bitops.h>
+
+static int hi6220_gpio_direction_input(struct udevice *dev, unsigned int gpio)
+{
+ struct gpio_bank *bank = dev_get_priv(dev);
+ u8 data;
+
+ data = readb(bank->base + HI6220_GPIO_DIR);
+ data &= ~(1 << gpio);
+ writeb(data, bank->base + HI6220_GPIO_DIR);
+
+ return 0;
+}
+
+static int hi6220_gpio_set_value(struct udevice *dev, unsigned gpio,
+ int value)
+{
+ struct gpio_bank *bank = dev_get_priv(dev);
+
+ writeb(!!value << gpio, bank->base + (BIT(gpio + 2)));
+ return 0;
+}
+
+static int hi6220_gpio_direction_output(struct udevice *dev, unsigned gpio,
+ int value)
+{
+ struct gpio_bank *bank = dev_get_priv(dev);
+ u8 data;
+
+ data = readb(bank->base + HI6220_GPIO_DIR);
+ data |= 1 << gpio;
+ writeb(data, bank->base + HI6220_GPIO_DIR);
+
+ hi6220_gpio_set_value(dev, gpio, value);
+
+ return 0;
+}
+
+static int hi6220_gpio_get_value(struct udevice *dev, unsigned gpio)
+{
+ struct gpio_bank *bank = dev_get_priv(dev);
+
+ return !!readb(bank->base + (BIT(gpio + 2)));
+}
+
+
+
+static const struct dm_gpio_ops gpio_hi6220_ops = {
+ .direction_input = hi6220_gpio_direction_input,
+ .direction_output = hi6220_gpio_direction_output,
+ .get_value = hi6220_gpio_get_value,
+ .set_value = hi6220_gpio_set_value,
+};
+
+static int hi6220_gpio_probe(struct udevice *dev)
+{
+ struct gpio_bank *bank = dev_get_priv(dev);
+ struct hikey_gpio_plat *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ char name[18], *str;
+
+ sprintf(name, "GPIO%d_", plat->bank_index);
+
+ str = strdup(name);
+ if (!str)
+ return -ENOMEM;
+
+ uc_priv->bank_name = str;
+ uc_priv->gpio_count = HI6220_GPIO_PER_BANK;
+
+ bank->base = (u8 *)plat->base;
+
+ return 0;
+}
+
+U_BOOT_DRIVER(gpio_hi6220) = {
+ .name = "gpio_hi6220",
+ .id = UCLASS_GPIO,
+ .ops = &gpio_hi6220_ops,
+ .probe = hi6220_gpio_probe,
+ .priv_auto = sizeof(struct gpio_bank),
+};
+
+
diff --git a/roms/u-boot/drivers/gpio/hsdk-creg-gpio.c b/roms/u-boot/drivers/gpio/hsdk-creg-gpio.c
new file mode 100644
index 000000000..66f844184
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/hsdk-creg-gpio.c
@@ -0,0 +1,169 @@
+/*
+ * Synopsys HSDK SDP Generic PLL clock driver
+ *
+ * Copyright (C) 2017 Synopsys
+ * Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <log.h>
+#include <asm-generic/gpio.h>
+#include <asm/io.h>
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <linux/bitops.h>
+#include <linux/printk.h>
+
+#define DRV_NAME "gpio_creg"
+
+struct hsdk_creg_gpio {
+ u32 *regs;
+ u8 shift;
+ u8 activate;
+ u8 deactivate;
+ u8 bit_per_gpio;
+};
+
+static int hsdk_creg_gpio_set_value(struct udevice *dev, unsigned oft, int val)
+{
+ struct hsdk_creg_gpio *hcg = dev_get_priv(dev);
+ u8 reg_shift = oft * hcg->bit_per_gpio + hcg->shift;
+ u32 reg = readl(hcg->regs);
+
+ reg &= ~(GENMASK(hcg->bit_per_gpio - 1, 0) << reg_shift);
+ reg |= ((val ? hcg->deactivate : hcg->activate) << reg_shift);
+
+ writel(reg, hcg->regs);
+
+ return 0;
+}
+
+static int hsdk_creg_gpio_direction_output(struct udevice *dev, unsigned oft,
+ int val)
+{
+ hsdk_creg_gpio_set_value(dev, oft, val);
+
+ return 0;
+}
+
+static int hsdk_creg_gpio_direction_input(struct udevice *dev, unsigned oft)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ pr_err("%s can't be used as input!\n", uc_priv->bank_name);
+
+ return -ENOTSUPP;
+}
+
+static int hsdk_creg_gpio_get_value(struct udevice *dev, unsigned int oft)
+{
+ struct hsdk_creg_gpio *hcg = dev_get_priv(dev);
+ u32 val = readl(hcg->regs);
+
+ val >>= oft * hcg->bit_per_gpio + hcg->shift;
+ val &= GENMASK(hcg->bit_per_gpio - 1, 0);
+ return (val == hcg->deactivate) ? 1 : 0;
+}
+
+static const struct dm_gpio_ops hsdk_creg_gpio_ops = {
+ .direction_output = hsdk_creg_gpio_direction_output,
+ .direction_input = hsdk_creg_gpio_direction_input,
+ .set_value = hsdk_creg_gpio_set_value,
+ .get_value = hsdk_creg_gpio_get_value,
+};
+
+static int hsdk_creg_gpio_probe(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct hsdk_creg_gpio *hcg = dev_get_priv(dev);
+ u32 shift, bit_per_gpio, activate, deactivate, gpio_count;
+ const u8 *defaults;
+
+ hcg->regs = dev_read_addr_ptr(dev);
+ gpio_count = dev_read_u32_default(dev, "gpio-count", 1);
+ shift = dev_read_u32_default(dev, "gpio-first-shift", 0);
+ bit_per_gpio = dev_read_u32_default(dev, "gpio-bit-per-line", 1);
+ activate = dev_read_u32_default(dev, "gpio-activate-val", 1);
+ deactivate = dev_read_u32_default(dev, "gpio-deactivate-val", 0);
+ defaults = dev_read_u8_array_ptr(dev, "gpio-default-val", gpio_count);
+
+ uc_priv->bank_name = dev_read_string(dev, "gpio-bank-name");
+ if (!uc_priv->bank_name)
+ uc_priv->bank_name = dev_read_name(dev);
+
+ if (!bit_per_gpio) {
+ pr_err("%s: 'gpio-bit-per-line' can't be 0\n",
+ uc_priv->bank_name);
+
+ return -EINVAL;
+ }
+
+ if (!gpio_count) {
+ pr_err("%s: 'gpio-count' can't be 0\n",
+ uc_priv->bank_name);
+
+ return -EINVAL;
+ }
+
+ if ((gpio_count * bit_per_gpio + shift) > 32) {
+ pr_err("%s: u32 io register overflow: try to use %u bits\n",
+ uc_priv->bank_name, gpio_count * bit_per_gpio + shift);
+
+ return -EINVAL;
+ }
+
+ if (GENMASK(31, bit_per_gpio) & activate) {
+ pr_err("%s: 'gpio-activate-val' can't be more than %lu\n",
+ uc_priv->bank_name, GENMASK(bit_per_gpio - 1, 0));
+
+ return -EINVAL;
+ }
+
+ if (GENMASK(31, bit_per_gpio) & deactivate) {
+ pr_err("%s: 'gpio-deactivate-val' can't be more than %lu\n",
+ uc_priv->bank_name, GENMASK(bit_per_gpio - 1, 0));
+
+ return -EINVAL;
+ }
+
+ if (activate == deactivate) {
+ pr_err("%s: 'gpio-deactivate-val' and 'gpio-activate-val' can't be equal\n",
+ uc_priv->bank_name);
+
+ return -EINVAL;
+ }
+
+ hcg->shift = (u8)shift;
+ hcg->bit_per_gpio = (u8)bit_per_gpio;
+ hcg->activate = (u8)activate;
+ hcg->deactivate = (u8)deactivate;
+ uc_priv->gpio_count = gpio_count;
+
+ /* Setup default GPIO value if we have "gpio-default-val" array */
+ if (defaults)
+ for (u8 i = 0; i < gpio_count; i++)
+ hsdk_creg_gpio_set_value(dev, i, defaults[i]);
+
+ pr_debug("%s GPIO [0x%p] controller with %d gpios probed\n",
+ uc_priv->bank_name, hcg->regs, uc_priv->gpio_count);
+
+ return 0;
+}
+
+static const struct udevice_id hsdk_creg_gpio_ids[] = {
+ { .compatible = "snps,creg-gpio" },
+ { }
+};
+
+U_BOOT_DRIVER(gpio_hsdk_creg) = {
+ .name = DRV_NAME,
+ .id = UCLASS_GPIO,
+ .ops = &hsdk_creg_gpio_ops,
+ .probe = hsdk_creg_gpio_probe,
+ .of_match = hsdk_creg_gpio_ids,
+ .plat_auto = sizeof(struct hsdk_creg_gpio),
+};
diff --git a/roms/u-boot/drivers/gpio/imx_rgpio2p.c b/roms/u-boot/drivers/gpio/imx_rgpio2p.c
new file mode 100644
index 000000000..0e2874ca9
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/imx_rgpio2p.c
@@ -0,0 +1,227 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2016 Freescale Semiconductor, Inc.
+ *
+ * RGPIO2P driver for the Freescale i.MX7ULP.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <dm/device-internal.h>
+#include <malloc.h>
+
+enum imx_rgpio2p_direction {
+ IMX_RGPIO2P_DIRECTION_IN,
+ IMX_RGPIO2P_DIRECTION_OUT,
+};
+
+#define GPIO_PER_BANK 32
+
+struct imx_rgpio2p_data {
+ struct gpio_regs *regs;
+};
+
+struct imx_rgpio2p_plat {
+ int bank_index;
+ struct gpio_regs *regs;
+};
+
+static int imx_rgpio2p_is_output(struct gpio_regs *regs, int offset)
+{
+ u32 val;
+
+ val = readl(&regs->gpio_pddr);
+
+ return val & (1 << offset) ? 1 : 0;
+}
+
+static void imx_rgpio2p_bank_direction(struct gpio_regs *regs, int offset,
+ enum imx_rgpio2p_direction direction)
+{
+ u32 l;
+
+ l = readl(&regs->gpio_pddr);
+
+ switch (direction) {
+ case IMX_RGPIO2P_DIRECTION_OUT:
+ l |= 1 << offset;
+ break;
+ case IMX_RGPIO2P_DIRECTION_IN:
+ l &= ~(1 << offset);
+ }
+ writel(l, &regs->gpio_pddr);
+}
+
+static void imx_rgpio2p_bank_set_value(struct gpio_regs *regs, int offset,
+ int value)
+{
+ if (value)
+ writel((1 << offset), &regs->gpio_psor);
+ else
+ writel((1 << offset), &regs->gpio_pcor);
+}
+
+static int imx_rgpio2p_bank_get_value(struct gpio_regs *regs, int offset)
+{
+ return (readl(&regs->gpio_pdir) >> offset) & 0x01;
+}
+
+static int imx_rgpio2p_direction_input(struct udevice *dev, unsigned offset)
+{
+ struct imx_rgpio2p_data *bank = dev_get_priv(dev);
+
+ /* Configure GPIO direction as input. */
+ imx_rgpio2p_bank_direction(bank->regs, offset, IMX_RGPIO2P_DIRECTION_IN);
+
+ return 0;
+}
+
+static int imx_rgpio2p_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct imx_rgpio2p_data *bank = dev_get_priv(dev);
+
+ /* Configure GPIO output value. */
+ imx_rgpio2p_bank_set_value(bank->regs, offset, value);
+
+ /* Configure GPIO direction as output. */
+ imx_rgpio2p_bank_direction(bank->regs, offset, IMX_RGPIO2P_DIRECTION_OUT);
+
+ return 0;
+}
+
+static int imx_rgpio2p_get_value(struct udevice *dev, unsigned offset)
+{
+ struct imx_rgpio2p_data *bank = dev_get_priv(dev);
+
+ return imx_rgpio2p_bank_get_value(bank->regs, offset);
+}
+
+static int imx_rgpio2p_set_value(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct imx_rgpio2p_data *bank = dev_get_priv(dev);
+
+ imx_rgpio2p_bank_set_value(bank->regs, offset, value);
+
+ return 0;
+}
+
+static int imx_rgpio2p_get_function(struct udevice *dev, unsigned offset)
+{
+ struct imx_rgpio2p_data *bank = dev_get_priv(dev);
+
+ /* GPIOF_FUNC is not implemented yet */
+ if (imx_rgpio2p_is_output(bank->regs, offset))
+ return GPIOF_OUTPUT;
+ else
+ return GPIOF_INPUT;
+}
+
+static const struct dm_gpio_ops imx_rgpio2p_ops = {
+ .direction_input = imx_rgpio2p_direction_input,
+ .direction_output = imx_rgpio2p_direction_output,
+ .get_value = imx_rgpio2p_get_value,
+ .set_value = imx_rgpio2p_set_value,
+ .get_function = imx_rgpio2p_get_function,
+};
+
+static int imx_rgpio2p_probe(struct udevice *dev)
+{
+ struct imx_rgpio2p_data *bank = dev_get_priv(dev);
+ struct imx_rgpio2p_plat *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ int banknum;
+ char name[18], *str;
+
+ banknum = plat->bank_index;
+ sprintf(name, "GPIO%d_", banknum + 1);
+ str = strdup(name);
+ if (!str)
+ return -ENOMEM;
+ uc_priv->bank_name = str;
+ uc_priv->gpio_count = GPIO_PER_BANK;
+ bank->regs = plat->regs;
+
+ return 0;
+}
+
+static int imx_rgpio2p_bind(struct udevice *dev)
+{
+ struct imx_rgpio2p_plat *plat = dev_get_plat(dev);
+ fdt_addr_t addr;
+
+ /*
+ * If plat already exsits, directly return.
+ * Actually only when DT is not supported, plat
+ * is statically initialized in U_BOOT_DRVINFOS.Here
+ * will return.
+ */
+ if (plat)
+ return 0;
+
+ addr = devfdt_get_addr_index(dev, 1);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ /*
+ * TODO:
+ * When every board is converted to driver model and DT is supported,
+ * this can be done by auto-alloc feature, but not using calloc
+ * to alloc memory for plat.
+ *
+ * For example imx_rgpio2p_plat uses platform data rather than device
+ * tree.
+ *
+ * NOTE: DO NOT COPY this code if you are using device tree.
+ */
+ plat = calloc(1, sizeof(*plat));
+ if (!plat)
+ return -ENOMEM;
+
+ plat->regs = (struct gpio_regs *)addr;
+ plat->bank_index = dev_seq(dev);
+ dev_set_plat(dev, plat);
+
+ return 0;
+}
+
+
+static const struct udevice_id imx_rgpio2p_ids[] = {
+ { .compatible = "fsl,imx7ulp-gpio" },
+ { }
+};
+
+U_BOOT_DRIVER(imx_rgpio2p) = {
+ .name = "imx_rgpio2p",
+ .id = UCLASS_GPIO,
+ .ops = &imx_rgpio2p_ops,
+ .probe = imx_rgpio2p_probe,
+ .priv_auto = sizeof(struct imx_rgpio2p_plat),
+ .of_match = imx_rgpio2p_ids,
+ .bind = imx_rgpio2p_bind,
+};
+
+#if !CONFIG_IS_ENABLED(OF_CONTROL)
+static const struct imx_rgpio2p_plat imx_plat[] = {
+ { 0, (struct gpio_regs *)RGPIO2P_GPIO1_BASE_ADDR },
+ { 1, (struct gpio_regs *)RGPIO2P_GPIO2_BASE_ADDR },
+ { 2, (struct gpio_regs *)RGPIO2P_GPIO3_BASE_ADDR },
+ { 3, (struct gpio_regs *)RGPIO2P_GPIO4_BASE_ADDR },
+ { 4, (struct gpio_regs *)RGPIO2P_GPIO5_BASE_ADDR },
+ { 5, (struct gpio_regs *)RGPIO2P_GPIO6_BASE_ADDR },
+};
+
+U_BOOT_DRVINFOS(imx_rgpio2ps) = {
+ { "imx_rgpio2p", &imx_plat[0] },
+ { "imx_rgpio2p", &imx_plat[1] },
+ { "imx_rgpio2p", &imx_plat[2] },
+ { "imx_rgpio2p", &imx_plat[3] },
+ { "imx_rgpio2p", &imx_plat[4] },
+ { "imx_rgpio2p", &imx_plat[5] },
+};
+#endif
diff --git a/roms/u-boot/drivers/gpio/intel_broadwell_gpio.c b/roms/u-boot/drivers/gpio/intel_broadwell_gpio.c
new file mode 100644
index 000000000..20af35de2
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/intel_broadwell_gpio.c
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2012 The Chromium OS Authors.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <pch.h>
+#include <pci.h>
+#include <syscon.h>
+#include <asm/cpu.h>
+#include <asm/global_data.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/pci.h>
+#include <asm/arch/gpio.h>
+#include <dt-bindings/gpio/x86-gpio.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * struct broadwell_bank_priv - Private driver data
+ *
+ * @regs: Pointer to GPIO registers
+ * @bank: Bank number for this bank (0, 1 or 2)
+ * @offset: GPIO offset for this bank (0, 32 or 64)
+ */
+struct broadwell_bank_priv {
+ struct pch_lp_gpio_regs *regs;
+ int bank;
+ int offset;
+};
+
+static int broadwell_gpio_request(struct udevice *dev, unsigned offset,
+ const char *label)
+{
+ struct broadwell_bank_priv *priv = dev_get_priv(dev);
+ struct pch_lp_gpio_regs *regs = priv->regs;
+ u32 val;
+
+ /*
+ * Make sure that the GPIO pin we want isn't already in use for some
+ * built-in hardware function. We have to check this for every
+ * requested pin.
+ */
+ debug("%s: request bank %d offset %d: ", __func__, priv->bank, offset);
+ val = inl(&regs->own[priv->bank]);
+ if (!(val & (1UL << offset))) {
+ debug("gpio is reserved for internal use\n");
+ return -EPERM;
+ }
+ debug("ok\n");
+
+ return 0;
+}
+
+static int broadwell_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+ struct broadwell_bank_priv *priv = dev_get_priv(dev);
+ struct pch_lp_gpio_regs *regs = priv->regs;
+
+ setio_32(&regs->config[priv->offset + offset], CONFA_DIR_INPUT);
+
+ return 0;
+}
+
+static int broadwell_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+ struct broadwell_bank_priv *priv = dev_get_priv(dev);
+ struct pch_lp_gpio_regs *regs = priv->regs;
+
+ return inl(&regs->config[priv->offset + offset]) & CONFA_LEVEL_HIGH ?
+ 1 : 0;
+}
+
+static int broadwell_gpio_set_value(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct broadwell_bank_priv *priv = dev_get_priv(dev);
+ struct pch_lp_gpio_regs *regs = priv->regs;
+
+ debug("%s: dev=%s, offset=%d, value=%d\n", __func__, dev->name, offset,
+ value);
+ clrsetio_32(&regs->config[priv->offset + offset], CONFA_OUTPUT_HIGH,
+ value ? CONFA_OUTPUT_HIGH : 0);
+
+ return 0;
+}
+
+static int broadwell_gpio_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct broadwell_bank_priv *priv = dev_get_priv(dev);
+ struct pch_lp_gpio_regs *regs = priv->regs;
+
+ broadwell_gpio_set_value(dev, offset, value);
+ clrio_32(&regs->config[priv->offset + offset], CONFA_DIR_INPUT);
+
+ return 0;
+}
+
+static int broadwell_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+ struct broadwell_bank_priv *priv = dev_get_priv(dev);
+ struct pch_lp_gpio_regs *regs = priv->regs;
+ u32 mask = 1UL << offset;
+
+ if (!(inl(&regs->own[priv->bank]) & mask))
+ return GPIOF_FUNC;
+ if (inl(&regs->config[priv->offset + offset]) & CONFA_DIR_INPUT)
+ return GPIOF_INPUT;
+ else
+ return GPIOF_OUTPUT;
+}
+
+static int broadwell_gpio_probe(struct udevice *dev)
+{
+ struct broadwell_bank_plat *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct broadwell_bank_priv *priv = dev_get_priv(dev);
+ struct udevice *pinctrl;
+ int ret;
+
+ /* Set up pin control if available */
+ ret = syscon_get_by_driver_data(X86_SYSCON_PINCONF, &pinctrl);
+ debug("%s, pinctrl=%p, ret=%d\n", __func__, pinctrl, ret);
+
+ uc_priv->gpio_count = GPIO_PER_BANK;
+ uc_priv->bank_name = plat->bank_name;
+
+ priv->regs = (struct pch_lp_gpio_regs *)(uintptr_t)plat->base_addr;
+ priv->bank = plat->bank;
+ priv->offset = priv->bank * 32;
+ debug("%s: probe done, regs %p, bank %d\n", __func__, priv->regs,
+ priv->bank);
+
+ return 0;
+}
+
+static int broadwell_gpio_of_to_plat(struct udevice *dev)
+{
+ struct broadwell_bank_plat *plat = dev_get_plat(dev);
+ u32 gpiobase;
+ int bank;
+ int ret;
+
+ ret = pch_get_gpio_base(dev->parent, &gpiobase);
+ if (ret)
+ return ret;
+
+ bank = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "reg", -1);
+ if (bank == -1) {
+ debug("%s: Invalid bank number %d\n", __func__, bank);
+ return -EINVAL;
+ }
+ plat->bank = bank;
+ plat->base_addr = gpiobase;
+ plat->bank_name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
+ "bank-name", NULL);
+
+ return 0;
+}
+
+static const struct dm_gpio_ops gpio_broadwell_ops = {
+ .request = broadwell_gpio_request,
+ .direction_input = broadwell_gpio_direction_input,
+ .direction_output = broadwell_gpio_direction_output,
+ .get_value = broadwell_gpio_get_value,
+ .set_value = broadwell_gpio_set_value,
+ .get_function = broadwell_gpio_get_function,
+};
+
+static const struct udevice_id intel_broadwell_gpio_ids[] = {
+ { .compatible = "intel,broadwell-gpio" },
+ { }
+};
+
+U_BOOT_DRIVER(gpio_broadwell) = {
+ .name = "gpio_broadwell",
+ .id = UCLASS_GPIO,
+ .of_match = intel_broadwell_gpio_ids,
+ .ops = &gpio_broadwell_ops,
+ .of_to_plat = broadwell_gpio_of_to_plat,
+ .probe = broadwell_gpio_probe,
+ .priv_auto = sizeof(struct broadwell_bank_priv),
+ .plat_auto = sizeof(struct broadwell_bank_plat),
+};
diff --git a/roms/u-boot/drivers/gpio/intel_gpio.c b/roms/u-boot/drivers/gpio/intel_gpio.c
new file mode 100644
index 000000000..f15ce7b59
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/intel_gpio.c
@@ -0,0 +1,221 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#define LOG_CATEGORY UCLASS_GPIO
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <p2sb.h>
+#include <pch.h>
+#include <pci.h>
+#include <syscon.h>
+#include <acpi/acpi_device.h>
+#include <asm/cpu.h>
+#include <asm/gpio.h>
+#include <asm/intel_pinctrl.h>
+#include <asm/intel_pinctrl_defs.h>
+#include <asm/io.h>
+#include <asm/pci.h>
+#include <asm/arch/gpio.h>
+#include <dm/acpi.h>
+#include <dm/device-internal.h>
+#include <dt-bindings/gpio/x86-gpio.h>
+
+static int intel_gpio_get_value(struct udevice *dev, uint offset)
+{
+ struct udevice *pinctrl = dev_get_parent(dev);
+ uint mode, rx_tx;
+ u32 reg;
+
+ reg = intel_pinctrl_get_config_reg(pinctrl, offset);
+ mode = (reg & PAD_CFG0_MODE_MASK) >> PAD_CFG0_MODE_SHIFT;
+ if (!mode) {
+ rx_tx = reg & (PAD_CFG0_TX_DISABLE | PAD_CFG0_RX_DISABLE);
+ if (rx_tx == PAD_CFG0_TX_DISABLE)
+ return reg & PAD_CFG0_RX_STATE ? 1 : 0;
+ else if (rx_tx == PAD_CFG0_RX_DISABLE)
+ return reg & PAD_CFG0_TX_STATE ? 1 : 0;
+ }
+
+ return 0;
+}
+
+static int intel_gpio_set_value(struct udevice *dev, unsigned int offset,
+ int value)
+{
+ struct udevice *pinctrl = dev_get_parent(dev);
+ uint config_offset;
+
+ config_offset = intel_pinctrl_get_config_reg_offset(pinctrl, offset);
+
+ pcr_clrsetbits32(pinctrl, config_offset, PAD_CFG0_TX_STATE,
+ value ? PAD_CFG0_TX_STATE : 0);
+
+ return 0;
+}
+
+static int intel_gpio_get_function(struct udevice *dev, uint offset)
+{
+ struct udevice *pinctrl = dev_get_parent(dev);
+ uint mode, rx_tx;
+ u32 reg;
+
+ reg = intel_pinctrl_get_config_reg(pinctrl, offset);
+ mode = (reg & PAD_CFG0_MODE_MASK) >> PAD_CFG0_MODE_SHIFT;
+ if (!mode) {
+ rx_tx = reg & (PAD_CFG0_TX_DISABLE | PAD_CFG0_RX_DISABLE);
+ if (rx_tx == PAD_CFG0_TX_DISABLE)
+ return GPIOF_INPUT;
+ else if (rx_tx == PAD_CFG0_RX_DISABLE)
+ return GPIOF_OUTPUT;
+ }
+
+ return GPIOF_FUNC;
+}
+
+static int intel_gpio_xlate(struct udevice *orig_dev, struct gpio_desc *desc,
+ struct ofnode_phandle_args *args)
+{
+ struct udevice *pinctrl, *dev;
+ int gpio, ret;
+
+ /*
+ * GPIO numbers are global in the device tree so it doesn't matter
+ * which @orig_dev is used
+ */
+ gpio = args->args[0];
+ ret = intel_pinctrl_get_pad(gpio, &pinctrl, &desc->offset);
+ if (ret)
+ return log_msg_ret("bad", ret);
+ device_find_first_child(pinctrl, &dev);
+ if (!dev)
+ return log_msg_ret("no child", -ENOENT);
+ desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
+ desc->dev = dev;
+
+ /*
+ * Handle the case where the wrong GPIO device was provided, since this
+ * will not have been probed by the GPIO uclass before calling here
+ * (see gpio_request_tail()).
+ */
+ if (orig_dev != dev) {
+ ret = device_probe(dev);
+ if (ret)
+ return log_msg_ret("probe", ret);
+ }
+
+ return 0;
+}
+
+static int intel_gpio_set_flags(struct udevice *dev, unsigned int offset,
+ ulong flags)
+{
+ struct udevice *pinctrl = dev_get_parent(dev);
+ u32 bic0 = 0, bic1 = 0;
+ u32 or0, or1;
+ uint config_offset;
+
+ config_offset = intel_pinctrl_get_config_reg_offset(pinctrl, offset);
+
+ if (flags & GPIOD_IS_OUT) {
+ bic0 |= PAD_CFG0_MODE_MASK | PAD_CFG0_RX_STATE |
+ PAD_CFG0_TX_DISABLE;
+ or0 |= PAD_CFG0_MODE_GPIO | PAD_CFG0_RX_DISABLE;
+ } else if (flags & GPIOD_IS_IN) {
+ bic0 |= PAD_CFG0_MODE_MASK | PAD_CFG0_TX_STATE |
+ PAD_CFG0_RX_DISABLE;
+ or0 |= PAD_CFG0_MODE_GPIO | PAD_CFG0_TX_DISABLE;
+ }
+ if (flags & GPIOD_PULL_UP) {
+ bic1 |= PAD_CFG1_PULL_MASK;
+ or1 |= PAD_CFG1_PULL_UP_20K;
+ } else if (flags & GPIOD_PULL_DOWN) {
+ bic1 |= PAD_CFG1_PULL_MASK;
+ or1 |= PAD_CFG1_PULL_DN_20K;
+ }
+
+ pcr_clrsetbits32(pinctrl, PAD_CFG0_OFFSET(config_offset), bic0, or0);
+ pcr_clrsetbits32(pinctrl, PAD_CFG1_OFFSET(config_offset), bic1, or1);
+ log_debug("%s: flags=%lx, offset=%x, config_offset=%x, %x/%x %x/%x\n",
+ dev->name, flags, offset, config_offset, bic0, or0, bic1, or1);
+
+ return 0;
+}
+
+#if CONFIG_IS_ENABLED(ACPIGEN)
+static int intel_gpio_get_acpi(const struct gpio_desc *desc,
+ struct acpi_gpio *gpio)
+{
+ struct udevice *pinctrl;
+ int ret;
+
+ if (!dm_gpio_is_valid(desc))
+ return -ENOENT;
+ pinctrl = dev_get_parent(desc->dev);
+
+ memset(gpio, '\0', sizeof(*gpio));
+
+ gpio->type = ACPI_GPIO_TYPE_IO;
+ gpio->pull = ACPI_GPIO_PULL_DEFAULT;
+ gpio->io_restrict = ACPI_GPIO_IO_RESTRICT_OUTPUT;
+ gpio->polarity = ACPI_GPIO_ACTIVE_HIGH;
+ gpio->pin_count = 1;
+ gpio->pins[0] = intel_pinctrl_get_acpi_pin(pinctrl, desc->offset);
+ gpio->pin0_addr = intel_pinctrl_get_config_reg_addr(pinctrl,
+ desc->offset);
+ ret = acpi_get_path(pinctrl, gpio->resource, sizeof(gpio->resource));
+ if (ret)
+ return log_msg_ret("resource", ret);
+
+ return 0;
+}
+#endif
+
+static int intel_gpio_probe(struct udevice *dev)
+{
+ return 0;
+}
+
+static int intel_gpio_of_to_plat(struct udevice *dev)
+{
+ struct gpio_dev_priv *upriv = dev_get_uclass_priv(dev);
+ struct intel_pinctrl_priv *pinctrl_priv = dev_get_priv(dev->parent);
+ const struct pad_community *comm = pinctrl_priv->comm;
+
+ upriv->gpio_count = comm->last_pad - comm->first_pad + 1;
+ upriv->bank_name = dev->name;
+
+ return 0;
+}
+
+static const struct dm_gpio_ops gpio_intel_ops = {
+ .get_value = intel_gpio_get_value,
+ .set_value = intel_gpio_set_value,
+ .get_function = intel_gpio_get_function,
+ .xlate = intel_gpio_xlate,
+ .set_flags = intel_gpio_set_flags,
+#if CONFIG_IS_ENABLED(ACPIGEN)
+ .get_acpi = intel_gpio_get_acpi,
+#endif
+};
+
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+static const struct udevice_id intel_intel_gpio_ids[] = {
+ { .compatible = "intel,gpio" },
+ { }
+};
+#endif
+
+U_BOOT_DRIVER(intel_gpio) = {
+ .name = "intel_gpio",
+ .id = UCLASS_GPIO,
+ .of_match = of_match_ptr(intel_intel_gpio_ids),
+ .ops = &gpio_intel_ops,
+ .of_to_plat = intel_gpio_of_to_plat,
+ .probe = intel_gpio_probe,
+};
diff --git a/roms/u-boot/drivers/gpio/intel_ich6_gpio.c b/roms/u-boot/drivers/gpio/intel_ich6_gpio.c
new file mode 100644
index 000000000..63a07b959
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/intel_ich6_gpio.c
@@ -0,0 +1,242 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2012 The Chromium OS Authors.
+ */
+
+/*
+ * This is a GPIO driver for Intel ICH6 and later. The x86 GPIOs are accessed
+ * through the PCI bus. Each PCI device has 256 bytes of configuration space,
+ * consisting of a standard header and a device-specific set of registers. PCI
+ * bus 0, device 31, function 0 gives us access to the chipset GPIOs (among
+ * other things). Within the PCI configuration space, the GPIOBASE register
+ * tells us where in the device's I/O region we can find more registers to
+ * actually access the GPIOs.
+ *
+ * PCI bus/device/function 0:1f:0 => PCI config registers
+ * PCI config register "GPIOBASE"
+ * PCI I/O space + [GPIOBASE] => start of GPIO registers
+ * GPIO registers => gpio pin function, direction, value
+ *
+ *
+ * Danger Will Robinson! Bank 0 (GPIOs 0-31) seems to be fairly stable. Most
+ * ICH versions have more, but the decoding the matrix that describes them is
+ * absurdly complex and constantly changing. We'll provide Bank 1 and Bank 2,
+ * but they will ONLY work for certain unspecified chipsets because the offset
+ * from GPIOBASE changes randomly. Even then, many GPIOs are unimplemented or
+ * reserved or subject to arcane restrictions.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <pch.h>
+#include <pci.h>
+#include <asm/cpu.h>
+#include <asm/global_data.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/pci.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define GPIO_PER_BANK 32
+
+struct ich6_bank_priv {
+ /* These are I/O addresses */
+ uint16_t use_sel;
+ uint16_t io_sel;
+ uint16_t lvl;
+ u32 lvl_write_cache;
+ bool use_lvl_write_cache;
+};
+
+#define GPIO_USESEL_OFFSET(x) (x)
+#define GPIO_IOSEL_OFFSET(x) (x + 4)
+#define GPIO_LVL_OFFSET(x) (x + 8)
+
+static int _ich6_gpio_set_value(struct ich6_bank_priv *bank, unsigned offset,
+ int value)
+{
+ u32 val;
+
+ if (bank->use_lvl_write_cache)
+ val = bank->lvl_write_cache;
+ else
+ val = inl(bank->lvl);
+
+ if (value)
+ val |= (1UL << offset);
+ else
+ val &= ~(1UL << offset);
+ outl(val, bank->lvl);
+ if (bank->use_lvl_write_cache)
+ bank->lvl_write_cache = val;
+
+ return 0;
+}
+
+static int _ich6_gpio_set_direction(uint16_t base, unsigned offset, int dir)
+{
+ u32 val;
+
+ if (!dir) {
+ val = inl(base);
+ val |= (1UL << offset);
+ outl(val, base);
+ } else {
+ val = inl(base);
+ val &= ~(1UL << offset);
+ outl(val, base);
+ }
+
+ return 0;
+}
+
+static int gpio_ich6_of_to_plat(struct udevice *dev)
+{
+ struct ich6_bank_plat *plat = dev_get_plat(dev);
+ u32 gpiobase;
+ int offset;
+ int ret;
+
+ ret = pch_get_gpio_base(dev->parent, &gpiobase);
+ if (ret)
+ return ret;
+
+ offset = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "reg", -1);
+ if (offset == -1) {
+ debug("%s: Invalid register offset %d\n", __func__, offset);
+ return -EINVAL;
+ }
+ plat->offset = offset;
+ plat->base_addr = gpiobase + offset;
+ plat->bank_name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
+ "bank-name", NULL);
+
+ return 0;
+}
+
+static int ich6_gpio_probe(struct udevice *dev)
+{
+ struct ich6_bank_plat *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct ich6_bank_priv *bank = dev_get_priv(dev);
+ const void *prop;
+
+ uc_priv->gpio_count = GPIO_PER_BANK;
+ uc_priv->bank_name = plat->bank_name;
+ bank->use_sel = plat->base_addr;
+ bank->io_sel = plat->base_addr + 4;
+ bank->lvl = plat->base_addr + 8;
+
+ prop = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
+ "use-lvl-write-cache", NULL);
+ if (prop)
+ bank->use_lvl_write_cache = true;
+ else
+ bank->use_lvl_write_cache = false;
+ bank->lvl_write_cache = 0;
+
+ return 0;
+}
+
+static int ich6_gpio_request(struct udevice *dev, unsigned offset,
+ const char *label)
+{
+ struct ich6_bank_priv *bank = dev_get_priv(dev);
+ u32 tmplong;
+
+ /*
+ * Make sure that the GPIO pin we want isn't already in use for some
+ * built-in hardware function. We have to check this for every
+ * requested pin.
+ */
+ tmplong = inl(bank->use_sel);
+ if (!(tmplong & (1UL << offset))) {
+ debug("%s: gpio %d is reserved for internal use\n", __func__,
+ offset);
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+static int ich6_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+ struct ich6_bank_priv *bank = dev_get_priv(dev);
+
+ return _ich6_gpio_set_direction(bank->io_sel, offset, 0);
+}
+
+static int ich6_gpio_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ int ret;
+ struct ich6_bank_priv *bank = dev_get_priv(dev);
+
+ ret = _ich6_gpio_set_direction(bank->io_sel, offset, 1);
+ if (ret)
+ return ret;
+
+ return _ich6_gpio_set_value(bank, offset, value);
+}
+
+static int ich6_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+ struct ich6_bank_priv *bank = dev_get_priv(dev);
+ u32 tmplong;
+ int r;
+
+ tmplong = inl(bank->lvl);
+ if (bank->use_lvl_write_cache)
+ tmplong |= bank->lvl_write_cache;
+ r = (tmplong & (1UL << offset)) ? 1 : 0;
+ return r;
+}
+
+static int ich6_gpio_set_value(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct ich6_bank_priv *bank = dev_get_priv(dev);
+ return _ich6_gpio_set_value(bank, offset, value);
+}
+
+static int ich6_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+ struct ich6_bank_priv *bank = dev_get_priv(dev);
+ u32 mask = 1UL << offset;
+
+ if (!(inl(bank->use_sel) & mask))
+ return GPIOF_FUNC;
+ if (inl(bank->io_sel) & mask)
+ return GPIOF_INPUT;
+ else
+ return GPIOF_OUTPUT;
+}
+
+static const struct dm_gpio_ops gpio_ich6_ops = {
+ .request = ich6_gpio_request,
+ .direction_input = ich6_gpio_direction_input,
+ .direction_output = ich6_gpio_direction_output,
+ .get_value = ich6_gpio_get_value,
+ .set_value = ich6_gpio_set_value,
+ .get_function = ich6_gpio_get_function,
+};
+
+static const struct udevice_id intel_ich6_gpio_ids[] = {
+ { .compatible = "intel,ich6-gpio" },
+ { }
+};
+
+U_BOOT_DRIVER(gpio_ich6) = {
+ .name = "gpio_ich6",
+ .id = UCLASS_GPIO,
+ .of_match = intel_ich6_gpio_ids,
+ .ops = &gpio_ich6_ops,
+ .of_to_plat = gpio_ich6_of_to_plat,
+ .probe = ich6_gpio_probe,
+ .priv_auto = sizeof(struct ich6_bank_priv),
+ .plat_auto = sizeof(struct ich6_bank_plat),
+};
diff --git a/roms/u-boot/drivers/gpio/iproc_gpio.c b/roms/u-boot/drivers/gpio/iproc_gpio.c
new file mode 100644
index 000000000..8c143e9b7
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/iproc_gpio.c
@@ -0,0 +1,290 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Broadcom
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <dm/pinctrl.h>
+
+/*
+ * There are five GPIO bank register. Each bank can configure max of 32 gpios.
+ * BANK0 - gpios 0 to 31
+ * BANK1 - gpios 32 to 63
+ * BANK2 - gpios 64 to 95
+ * BANK3 - gpios 96 to 127
+ * BANK4 - gpios 128 to 150
+ *
+ * Offset difference between consecutive bank register is 0x200
+ */
+#define NGPIO_PER_BANK 32
+#define GPIO_BANK_SIZE 0x200
+#define GPIO_BANK(pin) ((pin) / NGPIO_PER_BANK)
+#define GPIO_SHIFT(pin) ((pin) % NGPIO_PER_BANK)
+#define GPIO_REG(pin, reg) (GPIO_BANK_SIZE * GPIO_BANK(pin) + (reg))
+
+/* device register offset */
+#define DATA_IN_OFFSET 0x00
+#define DATA_OUT_OFFSET 0x04
+#define OUT_EN_OFFSET 0x08
+
+/**
+ * struct iproc_gpio_pctrl_map - gpio and pinctrl mapping
+ * @gpio_pin: start of gpio number in gpio-ranges
+ * @pctrl_pin: start of pinctrl number in gpio-ranges
+ * @npins: total number of pins in gpio-ranges
+ * @node: list node
+ */
+struct iproc_gpio_pctrl_map {
+ u32 gpio_pin;
+ u32 pctrl_pin;
+ u32 npins;
+ struct list_head node;
+};
+
+/**
+ * struct iproc_gpio_pctrl_map - gpio device instance
+ * @pinctrl_dev:pointer to pinctrl device
+ * @gpiomap: list node having mapping between gpio and pinctrl
+ * @base: I/O register base address of gpio device
+ * @name: gpio device name, ex GPIO0, GPIO1
+ * @ngpios: total number of gpios
+ */
+struct iproc_gpio_plat {
+ struct udevice *pinctrl_dev;
+ struct list_head gpiomap;
+ void __iomem *base;
+ char *name;
+ u32 ngpios;
+};
+
+/**
+ * iproc_gpio_set_bit - set or clear one bit in an iproc GPIO register.
+ *
+ * The bit relates to a GPIO pin.
+ *
+ * @plat: iproc GPIO device
+ * @reg: register offset
+ * @gpio: GPIO pin
+ * @set: set or clear
+ */
+static inline void iproc_gpio_set_bit(struct iproc_gpio_plat *plat,
+ u32 reg, u32 gpio, bool set)
+{
+ u32 offset = GPIO_REG(gpio, reg);
+ u32 shift = GPIO_SHIFT(gpio);
+
+ clrsetbits_le32(plat->base + offset, BIT(shift),
+ (set ? BIT(shift) : 0));
+}
+
+static inline bool iproc_gpio_get_bit(struct iproc_gpio_plat *plat,
+ u32 reg, u32 gpio)
+{
+ u32 offset = GPIO_REG(gpio, reg);
+ u32 shift = GPIO_SHIFT(gpio);
+
+ return readl(plat->base + offset) & BIT(shift);
+}
+
+/**
+ * iproc_get_gpio_pctrl_mapping() - get associated pinctrl pin from gpio pin
+ *
+ * @plat: iproc GPIO device
+ * @gpio: GPIO pin
+ */
+static u32 iproc_get_pctrl_from_gpio(struct iproc_gpio_plat *plat, u32 gpio)
+{
+ struct iproc_gpio_pctrl_map *range = NULL;
+ struct list_head *pos, *tmp;
+ u32 ret = 0;
+
+ list_for_each_safe(pos, tmp, &plat->gpiomap) {
+ range = list_entry(pos, struct iproc_gpio_pctrl_map, node);
+ if (gpio == range->gpio_pin ||
+ gpio < (range->gpio_pin + range->npins)) {
+ ret = range->pctrl_pin + (gpio - range->gpio_pin);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * iproc_get_gpio_pctrl_mapping() - get mapping between gpio and pinctrl
+ *
+ * Read dt node "gpio-ranges" to get gpio and pinctrl mapping and store
+ * in private data structure to use it later while enabling gpio.
+ *
+ * @dev: pointer to GPIO device
+ * @return 0 on success and -ENOMEM on failure
+ */
+static int iproc_get_gpio_pctrl_mapping(struct udevice *dev)
+{
+ struct iproc_gpio_plat *plat = dev_get_plat(dev);
+ struct iproc_gpio_pctrl_map *range = NULL;
+ struct ofnode_phandle_args args;
+ int index = 0, ret;
+
+ for (;; index++) {
+ ret = dev_read_phandle_with_args(dev, "gpio-ranges",
+ NULL, 3, index, &args);
+ if (ret)
+ break;
+
+ range = devm_kzalloc(dev, sizeof(*range), GFP_KERNEL);
+ if (!range)
+ return -ENOMEM;
+
+ range->gpio_pin = args.args[0];
+ range->pctrl_pin = args.args[1];
+ range->npins = args.args[2];
+ list_add_tail(&range->node, &plat->gpiomap);
+ }
+
+ return 0;
+}
+
+static int iproc_gpio_request(struct udevice *dev, u32 gpio, const char *label)
+{
+ struct iproc_gpio_plat *plat = dev_get_plat(dev);
+ u32 pctrl;
+
+ /* nothing to do if there is no corresponding pinctrl device */
+ if (!plat->pinctrl_dev)
+ return 0;
+
+ pctrl = iproc_get_pctrl_from_gpio(plat, gpio);
+
+ return pinctrl_request(plat->pinctrl_dev, pctrl, 0);
+}
+
+static int iproc_gpio_direction_input(struct udevice *dev, u32 gpio)
+{
+ struct iproc_gpio_plat *plat = dev_get_plat(dev);
+
+ iproc_gpio_set_bit(plat, OUT_EN_OFFSET, gpio, false);
+ dev_dbg(dev, "gpio:%u set input\n", gpio);
+
+ return 0;
+}
+
+static int iproc_gpio_direction_output(struct udevice *dev, u32 gpio, int value)
+{
+ struct iproc_gpio_plat *plat = dev_get_plat(dev);
+
+ iproc_gpio_set_bit(plat, OUT_EN_OFFSET, gpio, true);
+ iproc_gpio_set_bit(plat, DATA_OUT_OFFSET, gpio, value);
+ dev_dbg(dev, "gpio:%u set output, value:%d\n", gpio, value);
+
+ return 0;
+}
+
+static int iproc_gpio_get_value(struct udevice *dev, u32 gpio)
+{
+ struct iproc_gpio_plat *plat = dev_get_plat(dev);
+ int value;
+
+ value = iproc_gpio_get_bit(plat, DATA_IN_OFFSET, gpio);
+ dev_dbg(dev, "gpio:%u get, value:%d\n", gpio, value);
+
+ return value;
+}
+
+static int iproc_gpio_set_value(struct udevice *dev, u32 gpio, int value)
+{
+ struct iproc_gpio_plat *plat = dev_get_plat(dev);
+
+ if (iproc_gpio_get_bit(plat, OUT_EN_OFFSET, gpio))
+ iproc_gpio_set_bit(plat, DATA_OUT_OFFSET, gpio, value);
+
+ dev_dbg(dev, "gpio:%u set, value:%d\n", gpio, value);
+ return 0;
+}
+
+static int iproc_gpio_get_function(struct udevice *dev, u32 gpio)
+{
+ struct iproc_gpio_plat *plat = dev_get_plat(dev);
+
+ if (iproc_gpio_get_bit(plat, OUT_EN_OFFSET, gpio))
+ return GPIOF_OUTPUT;
+ else
+ return GPIOF_INPUT;
+}
+
+static int iproc_gpio_of_to_plat(struct udevice *dev)
+{
+ struct iproc_gpio_plat *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ int ret;
+ char name[10];
+
+ plat->base = dev_read_addr_ptr(dev);
+ if (!plat->base) {
+ debug("%s: Failed to get base address\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = dev_read_u32(dev, "ngpios", &plat->ngpios);
+ if (ret < 0) {
+ dev_err(dev, "%s: Failed to get ngpios\n", __func__);
+ return ret;
+ }
+
+ uclass_get_device_by_phandle(UCLASS_PINCTRL, dev, "gpio-ranges",
+ &plat->pinctrl_dev);
+ if (ret < 0) {
+ dev_err(dev, "%s: Failed to get pinctrl phandle\n", __func__);
+ return ret;
+ }
+
+ INIT_LIST_HEAD(&plat->gpiomap);
+ ret = iproc_get_gpio_pctrl_mapping(dev);
+ if (ret < 0) {
+ dev_err(dev, "%s: Failed to get gpio to pctrl map ret(%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ snprintf(name, sizeof(name), "GPIO%d", dev_seq(dev));
+ plat->name = strdup(name);
+ if (!plat->name)
+ return -ENOMEM;
+
+ uc_priv->gpio_count = plat->ngpios;
+ uc_priv->bank_name = plat->name;
+
+ dev_info(dev, ":bank name(%s) base %p, #gpios %d\n",
+ plat->name, plat->base, plat->ngpios);
+
+ return 0;
+}
+
+static const struct dm_gpio_ops iproc_gpio_ops = {
+ .request = iproc_gpio_request,
+ .direction_input = iproc_gpio_direction_input,
+ .direction_output = iproc_gpio_direction_output,
+ .get_value = iproc_gpio_get_value,
+ .set_value = iproc_gpio_set_value,
+ .get_function = iproc_gpio_get_function,
+};
+
+static const struct udevice_id iproc_gpio_ids[] = {
+ { .compatible = "brcm,iproc-gpio" },
+ { }
+};
+
+U_BOOT_DRIVER(iproc_gpio) = {
+ .name = "iproc_gpio",
+ .id = UCLASS_GPIO,
+ .of_match = iproc_gpio_ids,
+ .ops = &iproc_gpio_ops,
+ .of_to_plat = iproc_gpio_of_to_plat,
+ .plat_auto = sizeof(struct iproc_gpio_plat),
+};
diff --git a/roms/u-boot/drivers/gpio/kona_gpio.c b/roms/u-boot/drivers/gpio/kona_gpio.c
new file mode 100644
index 000000000..29791882a
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/kona_gpio.c
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2013 Broadcom Corporation.
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <asm/arch/sysmap.h>
+
+#define GPIO_BASE (void *)GPIO2_BASE_ADDR
+
+#define GPIO_PASSWD 0x00a5a501
+#define GPIO_PER_BANK 32
+#define GPIO_MAX_BANK_NUM 8
+
+#define GPIO_BANK(gpio) ((gpio) >> 5)
+#define GPIO_BITMASK(gpio) \
+ (1UL << ((gpio) & (GPIO_PER_BANK - 1)))
+
+#define GPIO_OUT_STATUS(bank) (0x00000000 + ((bank) << 2))
+#define GPIO_IN_STATUS(bank) (0x00000020 + ((bank) << 2))
+#define GPIO_OUT_SET(bank) (0x00000040 + ((bank) << 2))
+#define GPIO_OUT_CLEAR(bank) (0x00000060 + ((bank) << 2))
+#define GPIO_INT_STATUS(bank) (0x00000080 + ((bank) << 2))
+#define GPIO_INT_MASK(bank) (0x000000a0 + ((bank) << 2))
+#define GPIO_INT_MSKCLR(bank) (0x000000c0 + ((bank) << 2))
+#define GPIO_CONTROL(bank) (0x00000100 + ((bank) << 2))
+#define GPIO_PWD_STATUS(bank) (0x00000500 + ((bank) << 2))
+
+#define GPIO_GPPWR_OFFSET 0x00000520
+
+#define GPIO_GPCTR0_DBR_SHIFT 5
+#define GPIO_GPCTR0_DBR_MASK 0x000001e0
+
+#define GPIO_GPCTR0_ITR_SHIFT 3
+#define GPIO_GPCTR0_ITR_MASK 0x00000018
+#define GPIO_GPCTR0_ITR_CMD_RISING_EDGE 0x00000001
+#define GPIO_GPCTR0_ITR_CMD_FALLING_EDGE 0x00000002
+#define GPIO_GPCTR0_ITR_CMD_BOTH_EDGE 0x00000003
+
+#define GPIO_GPCTR0_IOTR_MASK 0x00000001
+#define GPIO_GPCTR0_IOTR_CMD_0UTPUT 0x00000000
+#define GPIO_GPCTR0_IOTR_CMD_INPUT 0x00000001
+
+int gpio_request(unsigned gpio, const char *label)
+{
+ unsigned int value, off;
+
+ writel(GPIO_PASSWD, GPIO_BASE + GPIO_GPPWR_OFFSET);
+ off = GPIO_PWD_STATUS(GPIO_BANK(gpio));
+ value = readl(GPIO_BASE + off) & ~GPIO_BITMASK(gpio);
+ writel(value, GPIO_BASE + off);
+
+ return 0;
+}
+
+int gpio_free(unsigned gpio)
+{
+ unsigned int value, off;
+
+ writel(GPIO_PASSWD, GPIO_BASE + GPIO_GPPWR_OFFSET);
+ off = GPIO_PWD_STATUS(GPIO_BANK(gpio));
+ value = readl(GPIO_BASE + off) | GPIO_BITMASK(gpio);
+ writel(value, GPIO_BASE + off);
+
+ return 0;
+}
+
+int gpio_direction_input(unsigned gpio)
+{
+ u32 val;
+
+ val = readl(GPIO_BASE + GPIO_CONTROL(gpio));
+ val &= ~GPIO_GPCTR0_IOTR_MASK;
+ val |= GPIO_GPCTR0_IOTR_CMD_INPUT;
+ writel(val, GPIO_BASE + GPIO_CONTROL(gpio));
+
+ return 0;
+}
+
+int gpio_direction_output(unsigned gpio, int value)
+{
+ int bank_id = GPIO_BANK(gpio);
+ int bitmask = GPIO_BITMASK(gpio);
+ u32 val, off;
+
+ val = readl(GPIO_BASE + GPIO_CONTROL(gpio));
+ val &= ~GPIO_GPCTR0_IOTR_MASK;
+ val |= GPIO_GPCTR0_IOTR_CMD_0UTPUT;
+ writel(val, GPIO_BASE + GPIO_CONTROL(gpio));
+ off = value ? GPIO_OUT_SET(bank_id) : GPIO_OUT_CLEAR(bank_id);
+
+ val = readl(GPIO_BASE + off);
+ val |= bitmask;
+ writel(val, GPIO_BASE + off);
+
+ return 0;
+}
+
+int gpio_get_value(unsigned gpio)
+{
+ int bank_id = GPIO_BANK(gpio);
+ int bitmask = GPIO_BITMASK(gpio);
+ u32 val, off;
+
+ /* determine the GPIO pin direction */
+ val = readl(GPIO_BASE + GPIO_CONTROL(gpio));
+ val &= GPIO_GPCTR0_IOTR_MASK;
+
+ /* read the GPIO bank status */
+ off = (GPIO_GPCTR0_IOTR_CMD_INPUT == val) ?
+ GPIO_IN_STATUS(bank_id) : GPIO_OUT_STATUS(bank_id);
+ val = readl(GPIO_BASE + off);
+
+ /* return the specified bit status */
+ return !!(val & bitmask);
+}
+
+void gpio_set_value(unsigned gpio, int value)
+{
+ int bank_id = GPIO_BANK(gpio);
+ int bitmask = GPIO_BITMASK(gpio);
+ u32 val, off;
+
+ /* determine the GPIO pin direction */
+ val = readl(GPIO_BASE + GPIO_CONTROL(gpio));
+ val &= GPIO_GPCTR0_IOTR_MASK;
+
+ /* this function only applies to output pin */
+ if (GPIO_GPCTR0_IOTR_CMD_INPUT == val) {
+ printf("%s: Cannot set an input pin %d\n", __func__, gpio);
+ return;
+ }
+
+ off = value ? GPIO_OUT_SET(bank_id) : GPIO_OUT_CLEAR(bank_id);
+
+ val = readl(GPIO_BASE + off);
+ val |= bitmask;
+ writel(val, GPIO_BASE + off);
+}
diff --git a/roms/u-boot/drivers/gpio/kw_gpio.c b/roms/u-boot/drivers/gpio/kw_gpio.c
new file mode 100644
index 000000000..a15769793
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/kw_gpio.c
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * arch/arm/plat-orion/gpio.c
+ *
+ * Marvell Orion SoC GPIO handling.
+ */
+
+/*
+ * Based on (mostly copied from) plat-orion based Linux 2.6 kernel driver.
+ * Removed orion_gpiochip struct and kernel level irq handling.
+ *
+ * Dieter Kiermaier dk-arm-linux@gmx.de
+ */
+
+#include <common.h>
+#include <linux/bitops.h>
+#include <asm/io.h>
+#include <asm/arch/soc.h>
+#include <asm/arch/gpio.h>
+
+static unsigned long gpio_valid_input[BITS_TO_LONGS(GPIO_MAX)];
+static unsigned long gpio_valid_output[BITS_TO_LONGS(GPIO_MAX)];
+
+void __set_direction(unsigned pin, int input)
+{
+ u32 u;
+
+ u = readl(GPIO_IO_CONF(pin));
+ if (input)
+ u |= 1 << (pin & 31);
+ else
+ u &= ~(1 << (pin & 31));
+ writel(u, GPIO_IO_CONF(pin));
+
+ u = readl(GPIO_IO_CONF(pin));
+}
+
+static void __set_level(unsigned pin, int high)
+{
+ u32 u;
+
+ u = readl(GPIO_OUT(pin));
+ if (high)
+ u |= 1 << (pin & 31);
+ else
+ u &= ~(1 << (pin & 31));
+ writel(u, GPIO_OUT(pin));
+}
+
+static void __set_blinking(unsigned pin, int blink)
+{
+ u32 u;
+
+ u = readl(GPIO_BLINK_EN(pin));
+ if (blink)
+ u |= 1 << (pin & 31);
+ else
+ u &= ~(1 << (pin & 31));
+ writel(u, GPIO_BLINK_EN(pin));
+}
+
+int kw_gpio_is_valid(unsigned pin, int mode)
+{
+ if (pin < GPIO_MAX) {
+ if ((mode & GPIO_INPUT_OK) && !test_bit(pin, gpio_valid_input))
+ goto err_out;
+
+ if ((mode & GPIO_OUTPUT_OK) && !test_bit(pin, gpio_valid_output))
+ goto err_out;
+ return 0;
+ }
+
+err_out:
+ printf("%s: invalid GPIO %d\n", __func__, pin);
+ return 1;
+}
+
+void kw_gpio_set_valid(unsigned pin, int mode)
+{
+ if (mode == 1)
+ mode = GPIO_INPUT_OK | GPIO_OUTPUT_OK;
+ if (mode & GPIO_INPUT_OK)
+ __set_bit(pin, gpio_valid_input);
+ else
+ __clear_bit(pin, gpio_valid_input);
+ if (mode & GPIO_OUTPUT_OK)
+ __set_bit(pin, gpio_valid_output);
+ else
+ __clear_bit(pin, gpio_valid_output);
+}
+/*
+ * GENERIC_GPIO primitives.
+ */
+int kw_gpio_direction_input(unsigned pin)
+{
+ if (kw_gpio_is_valid(pin, GPIO_INPUT_OK) != 0)
+ return 1;
+
+ /* Configure GPIO direction. */
+ __set_direction(pin, 1);
+
+ return 0;
+}
+
+int kw_gpio_direction_output(unsigned pin, int value)
+{
+ if (kw_gpio_is_valid(pin, GPIO_OUTPUT_OK) != 0)
+ {
+ printf("%s: invalid GPIO %d\n", __func__, pin);
+ return 1;
+ }
+
+ __set_blinking(pin, 0);
+
+ /* Configure GPIO output value. */
+ __set_level(pin, value);
+
+ /* Configure GPIO direction. */
+ __set_direction(pin, 0);
+
+ return 0;
+}
+
+int kw_gpio_get_value(unsigned pin)
+{
+ int val;
+
+ if (readl(GPIO_IO_CONF(pin)) & (1 << (pin & 31)))
+ val = readl(GPIO_DATA_IN(pin)) ^ readl(GPIO_IN_POL(pin));
+ else
+ val = readl(GPIO_OUT(pin));
+
+ return (val >> (pin & 31)) & 1;
+}
+
+void kw_gpio_set_value(unsigned pin, int value)
+{
+ /* Configure GPIO output value. */
+ __set_level(pin, value);
+}
+
+void kw_gpio_set_blink(unsigned pin, int blink)
+{
+ /* Set output value to zero. */
+ __set_level(pin, 0);
+
+ /* Set blinking. */
+ __set_blinking(pin, blink);
+}
diff --git a/roms/u-boot/drivers/gpio/lpc32xx_gpio.c b/roms/u-boot/drivers/gpio/lpc32xx_gpio.c
new file mode 100644
index 000000000..de66c765d
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/lpc32xx_gpio.c
@@ -0,0 +1,321 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * LPC32xxGPIO driver
+ *
+ * (C) Copyright 2014 DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch-lpc32xx/cpu.h>
+#include <asm/arch-lpc32xx/gpio.h>
+#include <asm-generic/gpio.h>
+#include <dm.h>
+
+/**
+ * LPC32xx GPIOs work in banks but are non-homogeneous:
+ * - each bank holds a different number of GPIOs
+ * - some GPIOs are input/ouput, some input only, some output only;
+ * - some GPIOs have different meanings as an input and as an output;
+ * - some GPIOs are controlled on a given port and bit index, but
+ * read on another one.
+*
+ * In order to keep this code simple, GPIOS are considered here as
+ * homogeneous and linear, from 0 to 159.
+ *
+ * ** WARNING #1 **
+ *
+ * Client code is responsible for properly using valid GPIO numbers,
+ * including cases where a single physical GPIO has differing numbers
+ * for setting its direction, reading it and/or writing to it.
+ *
+ * ** WARNING #2 **
+ *
+ * Please read NOTE in description of lpc32xx_gpio_get_function().
+ */
+
+#define LPC32XX_GPIOS 160
+
+struct lpc32xx_gpio_priv {
+ struct gpio_regs *regs;
+ /* GPIO FUNCTION: SEE WARNING #2 */
+ signed char function[LPC32XX_GPIOS];
+};
+
+/**
+ * We have 4 GPIO ports of 32 bits each
+ *
+ * Port mapping offset (32 bits each):
+ * - Port 0: 0
+ * - Port 1: 32
+ * - Port 2: 64
+ * - Port 3: GPO / GPIO (output): 96
+ * - Port 3: GPI: 128
+ */
+
+#define MAX_GPIO 160
+
+#define GPIO_TO_PORT(gpio) ((gpio / 32) & 7)
+#define GPIO_TO_RANK(gpio) (gpio % 32)
+#define GPIO_TO_MASK(gpio) (1 << (gpio % 32))
+
+/**
+ * Configure a GPIO number 'offset' as input
+ */
+
+static int lpc32xx_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+ int port, mask;
+ struct lpc32xx_gpio_priv *gpio_priv = dev_get_priv(dev);
+ struct gpio_regs *regs = gpio_priv->regs;
+
+ port = GPIO_TO_PORT(offset);
+ mask = GPIO_TO_MASK(offset);
+
+ switch (port) {
+ case 0:
+ writel(mask, &regs->p0_dir_clr);
+ break;
+ case 1:
+ writel(mask, &regs->p1_dir_clr);
+ break;
+ case 2:
+ /* ports 2 and 3 share a common direction */
+ writel(mask, &regs->p2_p3_dir_clr);
+ break;
+ case 3:
+ /* Setup direction only for GPIO_xx. */
+ if ((mask >= 25) && (mask <= 30))
+ writel(mask, &regs->p2_p3_dir_clr);
+ break;
+ case 4:
+ /* GPI_xx; nothing to do. */
+ break;
+ default:
+ return -1;
+ }
+
+ /* GPIO FUNCTION: SEE WARNING #2 */
+ gpio_priv->function[offset] = GPIOF_INPUT;
+
+ return 0;
+}
+
+/**
+ * Get the value of a GPIO
+ */
+
+static int lpc32xx_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+ int port, rank, mask, value;
+ struct lpc32xx_gpio_priv *gpio_priv = dev_get_priv(dev);
+ struct gpio_regs *regs = gpio_priv->regs;
+
+ port = GPIO_TO_PORT(offset);
+
+ switch (port) {
+ case 0:
+ value = readl(&regs->p0_inp_state);
+ break;
+ case 1:
+ value = readl(&regs->p1_inp_state);
+ break;
+ case 2:
+ value = readl(&regs->p2_inp_state);
+ break;
+ case 3:
+ /* Read GPO_xx and GPIO_xx (as output) using p3_outp_state. */
+ value = readl(&regs->p3_outp_state);
+ break;
+ case 4:
+ /* Read GPI_xx and GPIO_xx (as input) using p3_inp_state. */
+ value = readl(&regs->p3_inp_state);
+ break;
+ default:
+ return -1;
+ }
+
+ rank = GPIO_TO_RANK(offset);
+ mask = GPIO_TO_MASK(offset);
+
+ return (value & mask) >> rank;
+}
+
+/**
+ * Set a GPIO
+ */
+
+static int gpio_set(struct udevice *dev, unsigned gpio)
+{
+ int port, mask;
+ struct lpc32xx_gpio_priv *gpio_priv = dev_get_priv(dev);
+ struct gpio_regs *regs = gpio_priv->regs;
+
+ port = GPIO_TO_PORT(gpio);
+ mask = GPIO_TO_MASK(gpio);
+
+ switch (port) {
+ case 0:
+ writel(mask, &regs->p0_outp_set);
+ break;
+ case 1:
+ writel(mask, &regs->p1_outp_set);
+ break;
+ case 2:
+ writel(mask, &regs->p2_outp_set);
+ break;
+ case 3:
+ writel(mask, &regs->p3_outp_set);
+ break;
+ case 4:
+ /* GPI_xx; invalid. */
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * Clear a GPIO
+ */
+
+static int gpio_clr(struct udevice *dev, unsigned gpio)
+{
+ int port, mask;
+ struct lpc32xx_gpio_priv *gpio_priv = dev_get_priv(dev);
+ struct gpio_regs *regs = gpio_priv->regs;
+
+ port = GPIO_TO_PORT(gpio);
+ mask = GPIO_TO_MASK(gpio);
+
+ switch (port) {
+ case 0:
+ writel(mask, &regs->p0_outp_clr);
+ break;
+ case 1:
+ writel(mask, &regs->p1_outp_clr);
+ break;
+ case 2:
+ writel(mask, &regs->p2_outp_clr);
+ break;
+ case 3:
+ writel(mask, &regs->p3_outp_clr);
+ break;
+ case 4:
+ /* GPI_xx; invalid. */
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * Set the value of a GPIO
+ */
+
+static int lpc32xx_gpio_set_value(struct udevice *dev, unsigned offset,
+ int value)
+{
+ if (value)
+ return gpio_set(dev, offset);
+ else
+ return gpio_clr(dev, offset);
+}
+
+/**
+ * Configure a GPIO number 'offset' as output with given initial value.
+ */
+
+static int lpc32xx_gpio_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ int port, mask;
+ struct lpc32xx_gpio_priv *gpio_priv = dev_get_priv(dev);
+ struct gpio_regs *regs = gpio_priv->regs;
+
+ port = GPIO_TO_PORT(offset);
+ mask = GPIO_TO_MASK(offset);
+
+ switch (port) {
+ case 0:
+ writel(mask, &regs->p0_dir_set);
+ break;
+ case 1:
+ writel(mask, &regs->p1_dir_set);
+ break;
+ case 2:
+ /* ports 2 and 3 share a common direction */
+ writel(mask, &regs->p2_p3_dir_set);
+ break;
+ case 3:
+ /* Setup direction only for GPIO_xx. */
+ if ((mask >= 25) && (mask <= 30))
+ writel(mask, &regs->p2_p3_dir_set);
+ break;
+ case 4:
+ /* GPI_xx; invalid. */
+ default:
+ return -1;
+ }
+
+ /* GPIO FUNCTION: SEE WARNING #2 */
+ gpio_priv->function[offset] = GPIOF_OUTPUT;
+
+ return lpc32xx_gpio_set_value(dev, offset, value);
+}
+
+/**
+ * GPIO functions are supposed to be computed from their current
+ * configuration, but that's way too complicated in LPC32XX. A simpler
+ * approach is used, where the GPIO functions are cached in an array.
+ * When the GPIO is in use, its function is either "input" or "output"
+ * depending on its direction, otherwise its function is "unknown".
+ *
+ * ** NOTE **
+ *
+ * THIS APPROACH WAS CHOSEN DU TO THE COMPLEX NATURE OF THE LPC32XX
+ * GPIOS; DO NOT TAKE THIS AS AN EXAMPLE FOR NEW CODE.
+ */
+
+static int lpc32xx_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+ struct lpc32xx_gpio_priv *gpio_priv = dev_get_priv(dev);
+ return gpio_priv->function[offset];
+}
+
+static const struct dm_gpio_ops gpio_lpc32xx_ops = {
+ .direction_input = lpc32xx_gpio_direction_input,
+ .direction_output = lpc32xx_gpio_direction_output,
+ .get_value = lpc32xx_gpio_get_value,
+ .set_value = lpc32xx_gpio_set_value,
+ .get_function = lpc32xx_gpio_get_function,
+};
+
+static int lpc32xx_gpio_probe(struct udevice *dev)
+{
+ struct lpc32xx_gpio_priv *gpio_priv = dev_get_priv(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ if (dev_of_offset(dev) == -1) {
+ /* Tell the uclass how many GPIOs we have */
+ uc_priv->gpio_count = LPC32XX_GPIOS;
+ }
+
+ /* set base address for GPIO registers */
+ gpio_priv->regs = (struct gpio_regs *)GPIO_BASE;
+
+ /* all GPIO functions are unknown until requested */
+ /* GPIO FUNCTION: SEE WARNING #2 */
+ memset(gpio_priv->function, GPIOF_UNKNOWN, sizeof(gpio_priv->function));
+
+ return 0;
+}
+
+U_BOOT_DRIVER(gpio_lpc32xx) = {
+ .name = "gpio_lpc32xx",
+ .id = UCLASS_GPIO,
+ .ops = &gpio_lpc32xx_ops,
+ .probe = lpc32xx_gpio_probe,
+ .priv_auto = sizeof(struct lpc32xx_gpio_priv),
+};
diff --git a/roms/u-boot/drivers/gpio/mpc83xx_gpio.c b/roms/u-boot/drivers/gpio/mpc83xx_gpio.c
new file mode 100644
index 000000000..276a3b350
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/mpc83xx_gpio.c
@@ -0,0 +1,183 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Freescale MPC83xx GPIO handling.
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <mpc83xx.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+
+#ifndef CONFIG_MPC83XX_GPIO_0_INIT_DIRECTION
+#define CONFIG_MPC83XX_GPIO_0_INIT_DIRECTION 0
+#endif
+#ifndef CONFIG_MPC83XX_GPIO_1_INIT_DIRECTION
+#define CONFIG_MPC83XX_GPIO_1_INIT_DIRECTION 0
+#endif
+#ifndef CONFIG_MPC83XX_GPIO_0_INIT_OPEN_DRAIN
+#define CONFIG_MPC83XX_GPIO_0_INIT_OPEN_DRAIN 0
+#endif
+#ifndef CONFIG_MPC83XX_GPIO_1_INIT_OPEN_DRAIN
+#define CONFIG_MPC83XX_GPIO_1_INIT_OPEN_DRAIN 0
+#endif
+#ifndef CONFIG_MPC83XX_GPIO_0_INIT_VALUE
+#define CONFIG_MPC83XX_GPIO_0_INIT_VALUE 0
+#endif
+#ifndef CONFIG_MPC83XX_GPIO_1_INIT_VALUE
+#define CONFIG_MPC83XX_GPIO_1_INIT_VALUE 0
+#endif
+
+static unsigned int gpio_output_value[MPC83XX_GPIO_CTRLRS];
+
+/*
+ * Generic_GPIO primitives.
+ */
+
+int gpio_request(unsigned gpio, const char *label)
+{
+ if (gpio >= MAX_NUM_GPIOS)
+ return -1;
+
+ return 0;
+}
+
+int gpio_free(unsigned gpio)
+{
+ /* Do not set to input */
+ return 0;
+}
+
+/* set GPIO pin 'gpio' as an input */
+int gpio_direction_input(unsigned gpio)
+{
+ immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ unsigned int ctrlr;
+ unsigned int line;
+ unsigned int line_mask;
+
+ /* 32-bits per controller */
+ ctrlr = gpio >> 5;
+ line = gpio & (0x1F);
+
+ /* Big endian */
+ line_mask = 1 << (31 - line);
+
+ clrbits_be32(&im->gpio[ctrlr].dir, line_mask);
+
+ return 0;
+}
+
+/* set GPIO pin 'gpio' as an output, with polarity 'value' */
+int gpio_direction_output(unsigned gpio, int value)
+{
+ immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ unsigned int ctrlr;
+ unsigned int line;
+ unsigned int line_mask;
+
+ if (value != 0 && value != 1) {
+ printf("Error: Value parameter must be 0 or 1.\n");
+ return -1;
+ }
+
+ gpio_set_value(gpio, value);
+
+ /* 32-bits per controller */
+ ctrlr = gpio >> 5;
+ line = gpio & (0x1F);
+
+ /* Big endian */
+ line_mask = 1 << (31 - line);
+
+ /* Make the line output */
+ setbits_be32(&im->gpio[ctrlr].dir, line_mask);
+
+ return 0;
+}
+
+/* read GPIO IN value of pin 'gpio' */
+int gpio_get_value(unsigned gpio)
+{
+ immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ unsigned int ctrlr;
+ unsigned int line;
+ unsigned int line_mask;
+
+ /* 32-bits per controller */
+ ctrlr = gpio >> 5;
+ line = gpio & (0x1F);
+
+ /* Big endian */
+ line_mask = 1 << (31 - line);
+
+ /* Read the value and mask off the bit */
+ return (in_be32(&im->gpio[ctrlr].dat) & line_mask) != 0;
+}
+
+/* write GPIO OUT value to pin 'gpio' */
+int gpio_set_value(unsigned gpio, int value)
+{
+ immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ unsigned int ctrlr;
+ unsigned int line;
+ unsigned int line_mask;
+
+ if (value != 0 && value != 1) {
+ printf("Error: Value parameter must be 0 or 1.\n");
+ return -1;
+ }
+
+ /* 32-bits per controller */
+ ctrlr = gpio >> 5;
+ line = gpio & (0x1F);
+
+ /* Big endian */
+ line_mask = 1 << (31 - line);
+
+ /* Update the local output buffer soft copy */
+ gpio_output_value[ctrlr] =
+ (gpio_output_value[ctrlr] & ~line_mask) | \
+ (value ? line_mask : 0);
+
+ /* Write the output */
+ out_be32(&im->gpio[ctrlr].dat, gpio_output_value[ctrlr]);
+
+ return 0;
+}
+
+/* Configure GPIO registers early */
+void mpc83xx_gpio_init_f(void)
+{
+ immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+
+#if MPC83XX_GPIO_CTRLRS >= 1
+ out_be32(&im->gpio[0].dir, CONFIG_MPC83XX_GPIO_0_INIT_DIRECTION);
+ out_be32(&im->gpio[0].odr, CONFIG_MPC83XX_GPIO_0_INIT_OPEN_DRAIN);
+ out_be32(&im->gpio[0].dat, CONFIG_MPC83XX_GPIO_0_INIT_VALUE);
+ out_be32(&im->gpio[0].ier, 0xFFFFFFFF); /* Clear all events */
+ out_be32(&im->gpio[0].imr, 0);
+ out_be32(&im->gpio[0].icr, 0);
+#endif
+
+#if MPC83XX_GPIO_CTRLRS >= 2
+ out_be32(&im->gpio[1].dir, CONFIG_MPC83XX_GPIO_1_INIT_DIRECTION);
+ out_be32(&im->gpio[1].odr, CONFIG_MPC83XX_GPIO_1_INIT_OPEN_DRAIN);
+ out_be32(&im->gpio[1].dat, CONFIG_MPC83XX_GPIO_1_INIT_VALUE);
+ out_be32(&im->gpio[1].ier, 0xFFFFFFFF); /* Clear all events */
+ out_be32(&im->gpio[1].imr, 0);
+ out_be32(&im->gpio[1].icr, 0);
+#endif
+}
+
+/* Initialize GPIO soft-copies */
+void mpc83xx_gpio_init_r(void)
+{
+#if MPC83XX_GPIO_CTRLRS >= 1
+ gpio_output_value[0] = CONFIG_MPC83XX_GPIO_0_INIT_VALUE;
+#endif
+
+#if MPC83XX_GPIO_CTRLRS >= 2
+ gpio_output_value[1] = CONFIG_MPC83XX_GPIO_1_INIT_VALUE;
+#endif
+}
diff --git a/roms/u-boot/drivers/gpio/mpc83xx_spisel_boot.c b/roms/u-boot/drivers/gpio/mpc83xx_spisel_boot.c
new file mode 100644
index 000000000..fd26a36a0
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/mpc83xx_spisel_boot.c
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2019 DEIF A/S
+ *
+ * GPIO driver to set/clear SPISEL_BOOT pin on mpc83xx.
+ */
+
+#include <common.h>
+#include <log.h>
+#include <dm.h>
+#include <mapmem.h>
+#include <asm/gpio.h>
+
+struct mpc83xx_spisel_boot {
+ u32 __iomem *spi_cs;
+ ulong addr;
+ uint gpio_count;
+ ulong type;
+};
+
+static u32 gpio_mask(uint gpio)
+{
+ return (1U << (31 - (gpio)));
+}
+
+static int mpc83xx_spisel_boot_direction_input(struct udevice *dev, uint gpio)
+{
+ return -EINVAL;
+}
+
+static int mpc83xx_spisel_boot_set_value(struct udevice *dev, uint gpio, int value)
+{
+ struct mpc83xx_spisel_boot *data = dev_get_priv(dev);
+
+ debug("%s: gpio=%d, value=%u, gpio_mask=0x%08x\n", __func__,
+ gpio, value, gpio_mask(gpio));
+
+ if (value)
+ setbits_be32(data->spi_cs, gpio_mask(gpio));
+ else
+ clrbits_be32(data->spi_cs, gpio_mask(gpio));
+
+ return 0;
+}
+
+static int mpc83xx_spisel_boot_direction_output(struct udevice *dev, uint gpio, int value)
+{
+ return 0;
+}
+
+static int mpc83xx_spisel_boot_get_value(struct udevice *dev, uint gpio)
+{
+ struct mpc83xx_spisel_boot *data = dev_get_priv(dev);
+
+ return !!(in_be32(data->spi_cs) & gpio_mask(gpio));
+}
+
+static int mpc83xx_spisel_boot_get_function(struct udevice *dev, uint gpio)
+{
+ return GPIOF_OUTPUT;
+}
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+static int mpc83xx_spisel_boot_of_to_plat(struct udevice *dev)
+{
+ struct mpc8xxx_gpio_plat *plat = dev_get_plat(dev);
+ fdt_addr_t addr;
+ u32 reg[2];
+
+ dev_read_u32_array(dev, "reg", reg, 2);
+ addr = dev_translate_address(dev, reg);
+
+ plat->addr = addr;
+ plat->size = reg[1];
+ plat->ngpios = dev_read_u32_default(dev, "ngpios", 1);
+
+ return 0;
+}
+#endif
+
+static int mpc83xx_spisel_boot_plat_to_priv(struct udevice *dev)
+{
+ struct mpc83xx_spisel_boot *priv = dev_get_priv(dev);
+ struct mpc8xxx_gpio_plat *plat = dev_get_plat(dev);
+ unsigned long size = plat->size;
+ ulong driver_data = dev_get_driver_data(dev);
+
+ if (size == 0)
+ size = 0x04;
+
+ priv->addr = plat->addr;
+ priv->spi_cs = map_sysmem(plat->addr, size);
+
+ if (!priv->spi_cs)
+ return -ENOMEM;
+
+ priv->gpio_count = plat->ngpios;
+
+ priv->type = driver_data;
+
+ return 0;
+}
+
+static int mpc83xx_spisel_boot_probe(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct mpc83xx_spisel_boot *data = dev_get_priv(dev);
+ char name[32], *str;
+
+ mpc83xx_spisel_boot_plat_to_priv(dev);
+
+ snprintf(name, sizeof(name), "MPC@%lx_", data->addr);
+ str = strdup(name);
+
+ if (!str)
+ return -ENOMEM;
+
+ uc_priv->bank_name = str;
+ uc_priv->gpio_count = data->gpio_count;
+
+ return 0;
+}
+
+static const struct dm_gpio_ops mpc83xx_spisel_boot_ops = {
+ .direction_input = mpc83xx_spisel_boot_direction_input,
+ .direction_output = mpc83xx_spisel_boot_direction_output,
+ .get_value = mpc83xx_spisel_boot_get_value,
+ .set_value = mpc83xx_spisel_boot_set_value,
+ .get_function = mpc83xx_spisel_boot_get_function,
+};
+
+static const struct udevice_id mpc83xx_spisel_boot_ids[] = {
+ { .compatible = "fsl,mpc8309-spisel-boot" },
+ { .compatible = "fsl,mpc83xx-spisel-boot" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(spisel_boot_mpc83xx) = {
+ .name = "spisel_boot_mpc83xx",
+ .id = UCLASS_GPIO,
+ .ops = &mpc83xx_spisel_boot_ops,
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+ .of_to_plat = mpc83xx_spisel_boot_of_to_plat,
+ .plat_auto = sizeof(struct mpc8xxx_gpio_plat),
+ .of_match = mpc83xx_spisel_boot_ids,
+#endif
+ .probe = mpc83xx_spisel_boot_probe,
+ .priv_auto = sizeof(struct mpc83xx_spisel_boot),
+};
diff --git a/roms/u-boot/drivers/gpio/mpc8xxx_gpio.c b/roms/u-boot/drivers/gpio/mpc8xxx_gpio.c
new file mode 100644
index 000000000..f7ffd8926
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/mpc8xxx_gpio.c
@@ -0,0 +1,273 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016
+ * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
+ *
+ * based on arch/powerpc/include/asm/mpc85xx_gpio.h, which is
+ *
+ * Copyright 2010 eXMeritus, A Boeing Company
+ * Copyright 2020-2021 NXP
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <mapmem.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <dm/of_access.h>
+
+struct mpc8xxx_gpio_data {
+ /* The bank's register base in memory */
+ struct ccsr_gpio __iomem *base;
+ /* The address of the registers; used to identify the bank */
+ phys_addr_t addr;
+ /* The GPIO count of the bank */
+ uint gpio_count;
+ /* The GPDAT register cannot be used to determine the value of output
+ * pins on MPC8572/MPC8536, so we shadow it and use the shadowed value
+ * for output pins
+ */
+ u32 dat_shadow;
+ ulong type;
+ bool little_endian;
+};
+
+enum {
+ MPC8XXX_GPIO_TYPE,
+ MPC5121_GPIO_TYPE,
+};
+
+inline u32 gpio_mask(uint gpio)
+{
+ return (1U << (31 - (gpio)));
+}
+
+static inline u32 mpc8xxx_gpio_get_val(struct udevice *dev, u32 mask)
+{
+ struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
+
+ if (data->little_endian)
+ return in_le32(&data->base->gpdat) & mask;
+ else
+ return in_be32(&data->base->gpdat) & mask;
+}
+
+static inline u32 mpc8xxx_gpio_get_dir(struct udevice *dev, u32 mask)
+{
+ struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
+
+ if (data->little_endian)
+ return in_le32(&data->base->gpdir) & mask;
+ else
+ return in_be32(&data->base->gpdir) & mask;
+}
+
+static inline int mpc8xxx_gpio_open_drain_val(struct udevice *dev, u32 mask)
+{
+ struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
+
+ if (data->little_endian)
+ return in_le32(&data->base->gpodr) & mask;
+ else
+ return in_be32(&data->base->gpodr) & mask;
+}
+
+static inline void mpc8xxx_gpio_open_drain_on(struct udevice *dev, u32
+ gpios)
+{
+ struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
+ /* GPODR register 1 -> open drain on */
+ if (data->little_endian)
+ setbits_le32(&data->base->gpodr, gpios);
+ else
+ setbits_be32(&data->base->gpodr, gpios);
+}
+
+static inline void mpc8xxx_gpio_open_drain_off(struct udevice *dev,
+ u32 gpios)
+{
+ struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
+ /* GPODR register 0 -> open drain off (actively driven) */
+ if (data->little_endian)
+ clrbits_le32(&data->base->gpodr, gpios);
+ else
+ clrbits_be32(&data->base->gpodr, gpios);
+}
+
+static int mpc8xxx_gpio_direction_input(struct udevice *dev, uint gpio)
+{
+ struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
+ u32 mask = gpio_mask(gpio);
+
+ /* GPDIR register 0 -> input */
+ if (data->little_endian)
+ clrbits_le32(&data->base->gpdir, mask);
+ else
+ clrbits_be32(&data->base->gpdir, mask);
+
+ return 0;
+}
+
+static int mpc8xxx_gpio_set_value(struct udevice *dev, uint gpio, int value)
+{
+ struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
+ struct ccsr_gpio *base = data->base;
+ u32 mask = gpio_mask(gpio);
+ u32 gpdir;
+
+ if (value) {
+ data->dat_shadow |= mask;
+ } else {
+ data->dat_shadow &= ~mask;
+ }
+
+ if (data->little_endian)
+ gpdir = in_le32(&base->gpdir);
+ else
+ gpdir = in_be32(&base->gpdir);
+
+ gpdir |= gpio_mask(gpio);
+
+ if (data->little_endian) {
+ out_le32(&base->gpdat, gpdir & data->dat_shadow);
+ out_le32(&base->gpdir, gpdir);
+ } else {
+ out_be32(&base->gpdat, gpdir & data->dat_shadow);
+ out_be32(&base->gpdir, gpdir);
+ }
+
+ return 0;
+}
+
+static int mpc8xxx_gpio_direction_output(struct udevice *dev, uint gpio,
+ int value)
+{
+ struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
+
+ /* GPIO 28..31 are input only on MPC5121 */
+ if (data->type == MPC5121_GPIO_TYPE && gpio >= 28)
+ return -EINVAL;
+
+ return mpc8xxx_gpio_set_value(dev, gpio, value);
+}
+
+static int mpc8xxx_gpio_get_value(struct udevice *dev, uint gpio)
+{
+ struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
+
+ if (!!mpc8xxx_gpio_get_dir(dev, gpio_mask(gpio))) {
+ /* Output -> use shadowed value */
+ return !!(data->dat_shadow & gpio_mask(gpio));
+ }
+
+ /* Input -> read value from GPDAT register */
+ return !!mpc8xxx_gpio_get_val(dev, gpio_mask(gpio));
+}
+
+static int mpc8xxx_gpio_get_function(struct udevice *dev, uint gpio)
+{
+ int dir;
+
+ dir = !!mpc8xxx_gpio_get_dir(dev, gpio_mask(gpio));
+ return dir ? GPIOF_OUTPUT : GPIOF_INPUT;
+}
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+static int mpc8xxx_gpio_of_to_plat(struct udevice *dev)
+{
+ struct mpc8xxx_gpio_plat *plat = dev_get_plat(dev);
+ struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
+
+ if (dev_read_bool(dev, "little-endian"))
+ data->little_endian = true;
+
+ plat->addr = dev_read_addr_size_index(dev, 0, (fdt_size_t *)&plat->size);
+ plat->ngpios = dev_read_u32_default(dev, "ngpios", 32);
+
+ return 0;
+}
+#endif
+
+static int mpc8xxx_gpio_plat_to_priv(struct udevice *dev)
+{
+ struct mpc8xxx_gpio_data *priv = dev_get_priv(dev);
+ struct mpc8xxx_gpio_plat *plat = dev_get_plat(dev);
+ unsigned long size = plat->size;
+ ulong driver_data = dev_get_driver_data(dev);
+
+ if (size == 0)
+ size = 0x100;
+
+ priv->addr = plat->addr;
+ priv->base = map_sysmem(plat->addr, size);
+
+ if (!priv->base)
+ return -ENOMEM;
+
+ priv->gpio_count = plat->ngpios;
+ priv->dat_shadow = 0;
+
+ priv->type = driver_data;
+
+ return 0;
+}
+
+static int mpc8xxx_gpio_probe(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
+ char name[32], *str;
+
+ mpc8xxx_gpio_plat_to_priv(dev);
+
+ snprintf(name, sizeof(name), "MPC@%.8llx",
+ (unsigned long long)data->addr);
+ str = strdup(name);
+
+ if (!str)
+ return -ENOMEM;
+
+ if (device_is_compatible(dev, "fsl,qoriq-gpio")) {
+ if (data->little_endian)
+ out_le32(&data->base->gpibe, 0xffffffff);
+ else
+ out_be32(&data->base->gpibe, 0xffffffff);
+ }
+
+ uc_priv->bank_name = str;
+ uc_priv->gpio_count = data->gpio_count;
+
+ return 0;
+}
+
+static const struct dm_gpio_ops gpio_mpc8xxx_ops = {
+ .direction_input = mpc8xxx_gpio_direction_input,
+ .direction_output = mpc8xxx_gpio_direction_output,
+ .get_value = mpc8xxx_gpio_get_value,
+ .set_value = mpc8xxx_gpio_set_value,
+ .get_function = mpc8xxx_gpio_get_function,
+};
+
+static const struct udevice_id mpc8xxx_gpio_ids[] = {
+ { .compatible = "fsl,pq3-gpio", .data = MPC8XXX_GPIO_TYPE },
+ { .compatible = "fsl,mpc8308-gpio", .data = MPC8XXX_GPIO_TYPE },
+ { .compatible = "fsl,mpc8349-gpio", .data = MPC8XXX_GPIO_TYPE },
+ { .compatible = "fsl,mpc8572-gpio", .data = MPC8XXX_GPIO_TYPE},
+ { .compatible = "fsl,mpc8610-gpio", .data = MPC8XXX_GPIO_TYPE},
+ { .compatible = "fsl,mpc5121-gpio", .data = MPC5121_GPIO_TYPE, },
+ { .compatible = "fsl,qoriq-gpio", .data = MPC8XXX_GPIO_TYPE },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(gpio_mpc8xxx) = {
+ .name = "gpio_mpc8xxx",
+ .id = UCLASS_GPIO,
+ .ops = &gpio_mpc8xxx_ops,
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+ .of_to_plat = mpc8xxx_gpio_of_to_plat,
+ .plat_auto = sizeof(struct mpc8xxx_gpio_plat),
+ .of_match = mpc8xxx_gpio_ids,
+#endif
+ .probe = mpc8xxx_gpio_probe,
+ .priv_auto = sizeof(struct mpc8xxx_gpio_data),
+};
diff --git a/roms/u-boot/drivers/gpio/mscc_sgpio.c b/roms/u-boot/drivers/gpio/mscc_sgpio.c
new file mode 100644
index 000000000..1cbcc4348
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/mscc_sgpio.c
@@ -0,0 +1,279 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Microsemi SoCs serial gpio driver
+ *
+ * Author: <lars.povlsen@microchip.com>
+ *
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <errno.h>
+#include <clk.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+
+#define MSCC_SGPIOS_PER_BANK 32
+#define MSCC_SGPIO_BANK_DEPTH 4
+
+enum {
+ REG_INPUT_DATA,
+ REG_PORT_CONFIG,
+ REG_PORT_ENABLE,
+ REG_SIO_CONFIG,
+ REG_SIO_CLOCK,
+ MAXREG
+};
+
+struct mscc_sgpio_bf {
+ u8 beg;
+ u8 end;
+};
+
+struct mscc_sgpio_props {
+ u8 regoff[MAXREG];
+ struct mscc_sgpio_bf auto_repeat;
+ struct mscc_sgpio_bf port_width;
+ struct mscc_sgpio_bf clk_freq;
+ struct mscc_sgpio_bf bit_source;
+};
+
+#define __M(bf) GENMASK((bf).end, (bf).beg)
+#define __F(bf, x) (__M(bf) & ((x) << (bf).beg))
+#define __X(bf, x) (((x) >> (bf).beg) & GENMASK(((bf).end - (bf).beg), 0))
+
+#define MSCC_M_CFG_SIO_AUTO_REPEAT(p) BIT(p->props->auto_repeat.beg)
+#define MSCC_F_CFG_SIO_PORT_WIDTH(p, x) __F(p->props->port_width, x)
+#define MSCC_M_CFG_SIO_PORT_WIDTH(p) __M(p->props->port_width)
+#define MSCC_F_CLOCK_SIO_CLK_FREQ(p, x) __F(p->props->clk_freq, x)
+#define MSCC_M_CLOCK_SIO_CLK_FREQ(p) __M(p->props->clk_freq)
+#define MSCC_F_PORT_CFG_BIT_SOURCE(p, x) __F(p->props->bit_source, x)
+#define MSCC_X_PORT_CFG_BIT_SOURCE(p, x) __X(p->props->bit_source, x)
+
+const struct mscc_sgpio_props props_luton = {
+ .regoff = { 0x00, 0x09, 0x29, 0x2a, 0x2b },
+ .auto_repeat = { 5, 5 },
+ .port_width = { 2, 3 },
+ .clk_freq = { 0, 11 },
+ .bit_source = { 0, 11 },
+};
+
+const struct mscc_sgpio_props props_ocelot = {
+ .regoff = { 0x00, 0x06, 0x26, 0x04, 0x05 },
+ .auto_repeat = { 10, 10 },
+ .port_width = { 7, 8 },
+ .clk_freq = { 8, 19 },
+ .bit_source = { 12, 23 },
+};
+
+struct mscc_sgpio_priv {
+ u32 bitcount;
+ u32 ports;
+ u32 clock;
+ u32 mode[MSCC_SGPIOS_PER_BANK];
+ u32 __iomem *regs;
+ const struct mscc_sgpio_props *props;
+};
+
+static inline u32 sgpio_readl(struct mscc_sgpio_priv *priv, u32 rno, u32 off)
+{
+ u32 __iomem *reg = &priv->regs[priv->props->regoff[rno] + off];
+
+ return readl(reg);
+}
+
+static inline void sgpio_writel(struct mscc_sgpio_priv *priv,
+ u32 val, u32 rno, u32 off)
+{
+ u32 __iomem *reg = &priv->regs[priv->props->regoff[rno] + off];
+
+ writel(val, reg);
+}
+
+static void sgpio_clrsetbits(struct mscc_sgpio_priv *priv,
+ u32 rno, u32 off, u32 clear, u32 set)
+{
+ u32 __iomem *reg = &priv->regs[priv->props->regoff[rno] + off];
+
+ clrsetbits_le32(reg, clear, set);
+}
+
+static int mscc_sgpio_direction_input(struct udevice *dev, unsigned int gpio)
+{
+ struct mscc_sgpio_priv *priv = dev_get_priv(dev);
+
+ u32 port = gpio % MSCC_SGPIOS_PER_BANK;
+ u32 bit = gpio / MSCC_SGPIOS_PER_BANK;
+
+ priv->mode[port] |= BIT(bit);
+
+ return 0;
+}
+
+static int mscc_sgpio_direction_output(struct udevice *dev,
+ unsigned int gpio, int value)
+{
+ struct mscc_sgpio_priv *priv = dev_get_priv(dev);
+ u32 port = gpio % MSCC_SGPIOS_PER_BANK;
+ u32 bit = gpio / MSCC_SGPIOS_PER_BANK;
+ u32 mask = 3 << (3 * bit);
+
+ debug("set: port %d, bit %d, mask 0x%08x, value %d\n",
+ port, bit, mask, value);
+
+ value = (value & 3) << (3 * bit);
+ sgpio_clrsetbits(priv, REG_PORT_CONFIG, port,
+ MSCC_F_PORT_CFG_BIT_SOURCE(priv, mask),
+ MSCC_F_PORT_CFG_BIT_SOURCE(priv, value));
+ clrbits_le32(&priv->mode[port], BIT(bit));
+
+ return 0;
+}
+
+static int mscc_sgpio_get_function(struct udevice *dev, unsigned int gpio)
+{
+ struct mscc_sgpio_priv *priv = dev_get_priv(dev);
+ u32 port = gpio % MSCC_SGPIOS_PER_BANK;
+ u32 bit = gpio / MSCC_SGPIOS_PER_BANK;
+ u32 val = priv->mode[port] & BIT(bit);
+
+ if (val)
+ return GPIOF_INPUT;
+ else
+ return GPIOF_OUTPUT;
+}
+
+static int mscc_sgpio_set_value(struct udevice *dev,
+ unsigned int gpio, int value)
+{
+ return mscc_sgpio_direction_output(dev, gpio, value);
+}
+
+static int mscc_sgpio_get_value(struct udevice *dev, unsigned int gpio)
+{
+ struct mscc_sgpio_priv *priv = dev_get_priv(dev);
+ u32 port = gpio % MSCC_SGPIOS_PER_BANK;
+ u32 bit = gpio / MSCC_SGPIOS_PER_BANK;
+ int ret;
+
+ if (mscc_sgpio_get_function(dev, gpio) == GPIOF_INPUT) {
+ ret = !!(sgpio_readl(priv, REG_INPUT_DATA, bit) & BIT(port));
+ } else {
+ u32 portval = sgpio_readl(priv, REG_PORT_CONFIG, port);
+
+ ret = MSCC_X_PORT_CFG_BIT_SOURCE(priv, portval);
+ ret = !!(ret & (3 << (3 * bit)));
+ }
+
+ debug("get: gpio %d, port %d, bit %d, value %d\n",
+ gpio, port, bit, ret);
+ return ret;
+}
+
+static int mscc_sgpio_get_count(struct udevice *dev)
+{
+ struct ofnode_phandle_args args;
+ int count = 0, i = 0, ret;
+
+ ret = dev_read_phandle_with_args(dev, "gpio-ranges", NULL, 3, i, &args);
+ while (ret != -ENOENT) {
+ count += args.args[2];
+ ret = dev_read_phandle_with_args(dev, "gpio-ranges", NULL, 3,
+ ++i, &args);
+ }
+ return count;
+}
+
+static int mscc_sgpio_probe(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct mscc_sgpio_priv *priv = dev_get_priv(dev);
+ int err, div_clock = 0, port;
+ u32 val;
+ struct clk clk;
+
+ err = clk_get_by_index(dev, 0, &clk);
+ if (!err) {
+ err = clk_get_rate(&clk);
+ if (IS_ERR_VALUE(err)) {
+ dev_err(dev, "Invalid clk rate\n");
+ return -EINVAL;
+ }
+ div_clock = err;
+ } else {
+ dev_err(dev, "Failed to get clock\n");
+ return err;
+ }
+
+ priv->props = (const struct mscc_sgpio_props *)dev_get_driver_data(dev);
+ priv->ports = dev_read_u32_default(dev, "mscc,sgpio-ports", 0xFFFFFFFF);
+ priv->clock = dev_read_u32_default(dev, "mscc,sgpio-frequency",
+ 12500000);
+ if (priv->clock <= 0 || priv->clock > div_clock) {
+ dev_err(dev, "Invalid frequency %d\n", priv->clock);
+ return -EINVAL;
+ }
+
+ uc_priv->gpio_count = mscc_sgpio_get_count(dev);
+ uc_priv->gpio_count = dev_read_u32_default(dev, "ngpios",
+ uc_priv->gpio_count);
+ if (uc_priv->gpio_count < 1 || uc_priv->gpio_count >
+ (4 * MSCC_SGPIOS_PER_BANK)) {
+ dev_err(dev, "Invalid gpio count %d\n", uc_priv->gpio_count);
+ return -EINVAL;
+ }
+ priv->bitcount = DIV_ROUND_UP(uc_priv->gpio_count,
+ MSCC_SGPIOS_PER_BANK);
+ debug("probe: gpios = %d, bit-count = %d\n",
+ uc_priv->gpio_count, priv->bitcount);
+
+ priv->regs = (u32 __iomem *)dev_read_addr(dev);
+ uc_priv->bank_name = "sgpio";
+
+ sgpio_clrsetbits(priv, REG_SIO_CONFIG, 0,
+ MSCC_M_CFG_SIO_PORT_WIDTH(priv),
+ MSCC_F_CFG_SIO_PORT_WIDTH(priv, priv->bitcount - 1) |
+ MSCC_M_CFG_SIO_AUTO_REPEAT(priv));
+ val = div_clock / priv->clock;
+ debug("probe: div-clock = %d KHz, freq = %d KHz, div = %d\n",
+ div_clock / 1000, priv->clock / 1000, val);
+ sgpio_clrsetbits(priv, REG_SIO_CLOCK, 0,
+ MSCC_M_CLOCK_SIO_CLK_FREQ(priv),
+ MSCC_F_CLOCK_SIO_CLK_FREQ(priv, val));
+
+ for (port = 0; port < 32; port++)
+ sgpio_writel(priv, 0, REG_PORT_CONFIG, port);
+ sgpio_writel(priv, priv->ports, REG_PORT_ENABLE, 0);
+
+ debug("probe: sgpio regs = %p\n", priv->regs);
+
+ return 0;
+}
+
+static const struct dm_gpio_ops mscc_sgpio_ops = {
+ .direction_input = mscc_sgpio_direction_input,
+ .direction_output = mscc_sgpio_direction_output,
+ .get_function = mscc_sgpio_get_function,
+ .get_value = mscc_sgpio_get_value,
+ .set_value = mscc_sgpio_set_value,
+};
+
+static const struct udevice_id mscc_sgpio_ids[] = {
+ { .compatible = "mscc,luton-sgpio", .data = (ulong)&props_luton },
+ { .compatible = "mscc,ocelot-sgpio", .data = (ulong)&props_ocelot },
+ { }
+};
+
+U_BOOT_DRIVER(gpio_mscc_sgpio) = {
+ .name = "mscc-sgpio",
+ .id = UCLASS_GPIO,
+ .of_match = mscc_sgpio_ids,
+ .ops = &mscc_sgpio_ops,
+ .probe = mscc_sgpio_probe,
+ .priv_auto = sizeof(struct mscc_sgpio_priv),
+};
diff --git a/roms/u-boot/drivers/gpio/msm_gpio.c b/roms/u-boot/drivers/gpio/msm_gpio.c
new file mode 100644
index 000000000..e1ff84c1c
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/msm_gpio.c
@@ -0,0 +1,134 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Qualcomm GPIO driver
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/global_data.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Register offsets */
+#define GPIO_CONFIG_OFF(no) ((no) * 0x1000)
+#define GPIO_IN_OUT_OFF(no) ((no) * 0x1000 + 0x4)
+
+/* OE */
+#define GPIO_OE_DISABLE (0x0 << 9)
+#define GPIO_OE_ENABLE (0x1 << 9)
+#define GPIO_OE_MASK (0x1 << 9)
+
+/* GPIO_IN_OUT register shifts. */
+#define GPIO_IN 0
+#define GPIO_OUT 1
+
+struct msm_gpio_bank {
+ phys_addr_t base;
+};
+
+static int msm_gpio_direction_input(struct udevice *dev, unsigned int gpio)
+{
+ struct msm_gpio_bank *priv = dev_get_priv(dev);
+ phys_addr_t reg = priv->base + GPIO_CONFIG_OFF(gpio);
+
+ /* Disable OE bit */
+ clrsetbits_le32(reg, GPIO_OE_MASK, GPIO_OE_DISABLE);
+
+ return 0;
+}
+
+static int msm_gpio_set_value(struct udevice *dev, unsigned gpio, int value)
+{
+ struct msm_gpio_bank *priv = dev_get_priv(dev);
+
+ value = !!value;
+ /* set value */
+ writel(value << GPIO_OUT, priv->base + GPIO_IN_OUT_OFF(gpio));
+
+ return 0;
+}
+
+static int msm_gpio_direction_output(struct udevice *dev, unsigned gpio,
+ int value)
+{
+ struct msm_gpio_bank *priv = dev_get_priv(dev);
+ phys_addr_t reg = priv->base + GPIO_CONFIG_OFF(gpio);
+
+ value = !!value;
+ /* set value */
+ writel(value << GPIO_OUT, priv->base + GPIO_IN_OUT_OFF(gpio));
+ /* switch direction */
+ clrsetbits_le32(reg, GPIO_OE_MASK, GPIO_OE_ENABLE);
+
+ return 0;
+}
+
+static int msm_gpio_get_value(struct udevice *dev, unsigned gpio)
+{
+ struct msm_gpio_bank *priv = dev_get_priv(dev);
+
+ return !!(readl(priv->base + GPIO_IN_OUT_OFF(gpio)) >> GPIO_IN);
+}
+
+static int msm_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+ struct msm_gpio_bank *priv = dev_get_priv(dev);
+
+ if (readl(priv->base + GPIO_CONFIG_OFF(offset)) & GPIO_OE_ENABLE)
+ return GPIOF_OUTPUT;
+
+ return GPIOF_INPUT;
+}
+
+static const struct dm_gpio_ops gpio_msm_ops = {
+ .direction_input = msm_gpio_direction_input,
+ .direction_output = msm_gpio_direction_output,
+ .get_value = msm_gpio_get_value,
+ .set_value = msm_gpio_set_value,
+ .get_function = msm_gpio_get_function,
+};
+
+static int msm_gpio_probe(struct udevice *dev)
+{
+ struct msm_gpio_bank *priv = dev_get_priv(dev);
+
+ priv->base = dev_read_addr(dev);
+
+ return priv->base == FDT_ADDR_T_NONE ? -EINVAL : 0;
+}
+
+static int msm_gpio_of_to_plat(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ uc_priv->gpio_count = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
+ "gpio-count", 0);
+ uc_priv->bank_name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
+ "gpio-bank-name", NULL);
+ if (uc_priv->bank_name == NULL)
+ uc_priv->bank_name = "soc";
+
+ return 0;
+}
+
+static const struct udevice_id msm_gpio_ids[] = {
+ { .compatible = "qcom,msm8916-pinctrl" },
+ { .compatible = "qcom,apq8016-pinctrl" },
+ { .compatible = "qcom,ipq4019-pinctrl" },
+ { }
+};
+
+U_BOOT_DRIVER(gpio_msm) = {
+ .name = "gpio_msm",
+ .id = UCLASS_GPIO,
+ .of_match = msm_gpio_ids,
+ .of_to_plat = msm_gpio_of_to_plat,
+ .probe = msm_gpio_probe,
+ .ops = &gpio_msm_ops,
+ .priv_auto = sizeof(struct msm_gpio_bank),
+};
diff --git a/roms/u-boot/drivers/gpio/mt7620_gpio.c b/roms/u-boot/drivers/gpio/mt7620_gpio.c
new file mode 100644
index 000000000..713fa2ed7
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/mt7620_gpio.c
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ *
+ * GPIO controller driver for MediaTek MT7620 SoC
+ */
+
+#include <dm.h>
+#include <errno.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <asm/gpio.h>
+
+enum mt7620_regs {
+ GPIO_REG_DATA,
+ GPIO_REG_DIR,
+ GPIO_REG_SET,
+ GPIO_REG_CLR,
+
+ __GPIO_REG_MAX
+};
+
+struct mt7620_gpio_priv {
+ void __iomem *base;
+ u32 regs[__GPIO_REG_MAX];
+ u32 count;
+};
+
+static int mt7620_gpio_get_value(struct udevice *dev, unsigned int offset)
+{
+ struct mt7620_gpio_priv *priv = dev_get_priv(dev);
+
+ return !!(readl(priv->base + priv->regs[GPIO_REG_DATA]) & BIT(offset));
+}
+
+static int mt7620_gpio_set_value(struct udevice *dev, unsigned int offset,
+ int value)
+{
+ struct mt7620_gpio_priv *priv = dev_get_priv(dev);
+ u32 reg;
+
+ reg = value ? priv->regs[GPIO_REG_SET] : priv->regs[GPIO_REG_CLR];
+
+ writel(BIT(offset), priv->base + reg);
+
+ return 0;
+}
+
+static int mt7620_gpio_direction_input(struct udevice *dev, unsigned int offset)
+{
+ struct mt7620_gpio_priv *priv = dev_get_priv(dev);
+
+ clrbits_32(priv->base + priv->regs[GPIO_REG_DIR], BIT(offset));
+
+ return 0;
+}
+
+static int mt7620_gpio_direction_output(struct udevice *dev,
+ unsigned int offset, int value)
+{
+ struct mt7620_gpio_priv *priv = dev_get_priv(dev);
+
+ /* Set value first */
+ mt7620_gpio_set_value(dev, offset, value);
+
+ setbits_32(priv->base + priv->regs[GPIO_REG_DIR], BIT(offset));
+
+ return 0;
+}
+
+static int mt7620_gpio_get_function(struct udevice *dev, unsigned int offset)
+{
+ struct mt7620_gpio_priv *priv = dev_get_priv(dev);
+
+ return (readl(priv->base + priv->regs[GPIO_REG_DIR]) & BIT(offset)) ?
+ GPIOF_OUTPUT : GPIOF_INPUT;
+}
+
+static const struct dm_gpio_ops mt7620_gpio_ops = {
+ .direction_input = mt7620_gpio_direction_input,
+ .direction_output = mt7620_gpio_direction_output,
+ .get_value = mt7620_gpio_get_value,
+ .set_value = mt7620_gpio_set_value,
+ .get_function = mt7620_gpio_get_function,
+};
+
+static int mt7620_gpio_probe(struct udevice *dev)
+{
+ struct mt7620_gpio_priv *priv = dev_get_priv(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ const char *name;
+
+ name = dev_read_string(dev, "mediatek,bank-name");
+ if (!name)
+ name = dev->name;
+
+ uc_priv->gpio_count = priv->count;
+ uc_priv->bank_name = name;
+
+ return 0;
+}
+
+static int mt7620_gpio_of_to_plat(struct udevice *dev)
+{
+ struct mt7620_gpio_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ priv->base = dev_remap_addr_index(dev, 0);
+ if (!priv->base) {
+ dev_err(dev, "mt7620_gpio: unable to map registers\n");
+ return -EINVAL;
+ }
+
+ ret = dev_read_u32(dev, "mediatek,gpio-num", &priv->count);
+ if (ret) {
+ dev_err(dev, "mt7620_gpio: failed to get GPIO count\n");
+ return -EINVAL;
+ }
+
+ ret = dev_read_u32_array(dev, "mediatek,register-map", priv->regs,
+ __GPIO_REG_MAX);
+ if (ret) {
+ dev_err(dev, "mt7620_gpio: unable to get register map\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct udevice_id mt7620_gpio_ids[] = {
+ { .compatible = "mediatek,mt7620-gpio" },
+ { }
+};
+
+U_BOOT_DRIVER(mt7620_gpio) = {
+ .name = "mt7620_gpio",
+ .id = UCLASS_GPIO,
+ .ops = &mt7620_gpio_ops,
+ .of_match = mt7620_gpio_ids,
+ .probe = mt7620_gpio_probe,
+ .of_to_plat = mt7620_gpio_of_to_plat,
+ .priv_auto = sizeof(struct mt7620_gpio_priv),
+};
diff --git a/roms/u-boot/drivers/gpio/mt7621_gpio.c b/roms/u-boot/drivers/gpio/mt7621_gpio.c
new file mode 100644
index 000000000..43bb4df4d
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/mt7621_gpio.c
@@ -0,0 +1,183 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Stefan Roese <sr@denx.de>
+ *
+ * Based on the Linux driver version which is:
+ * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <malloc.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <dm/device-internal.h>
+#include <dt-bindings/gpio/gpio.h>
+
+#define MTK_MAX_BANK 3
+#define MTK_BANK_WIDTH 32
+
+enum mediatek_gpio_reg {
+ GPIO_REG_CTRL = 0,
+ GPIO_REG_POL,
+ GPIO_REG_DATA,
+ GPIO_REG_DSET,
+ GPIO_REG_DCLR,
+ GPIO_REG_REDGE,
+ GPIO_REG_FEDGE,
+ GPIO_REG_HLVL,
+ GPIO_REG_LLVL,
+ GPIO_REG_STAT,
+ GPIO_REG_EDGE,
+};
+
+static void __iomem *mediatek_gpio_membase;
+
+struct mediatek_gpio_plat {
+ char bank_name[3]; /* Name of bank, e.g. "PA", "PB" etc */
+ int gpio_count;
+ int bank;
+};
+
+static u32 reg_offs(struct mediatek_gpio_plat *plat, int reg)
+{
+ return (reg * 0x10) + (plat->bank * 0x4);
+}
+
+static int mediatek_gpio_get_value(struct udevice *dev, unsigned int offset)
+{
+ struct mediatek_gpio_plat *plat = dev_get_plat(dev);
+
+ return !!(ioread32(mediatek_gpio_membase +
+ reg_offs(plat, GPIO_REG_DATA)) & BIT(offset));
+}
+
+static int mediatek_gpio_set_value(struct udevice *dev, unsigned int offset,
+ int value)
+{
+ struct mediatek_gpio_plat *plat = dev_get_plat(dev);
+
+ iowrite32(BIT(offset), mediatek_gpio_membase +
+ reg_offs(plat, value ? GPIO_REG_DSET : GPIO_REG_DCLR));
+
+ return 0;
+}
+
+static int mediatek_gpio_direction_input(struct udevice *dev, unsigned int offset)
+{
+ struct mediatek_gpio_plat *plat = dev_get_plat(dev);
+
+ clrbits_le32(mediatek_gpio_membase + reg_offs(plat, GPIO_REG_CTRL),
+ BIT(offset));
+
+ return 0;
+}
+
+static int mediatek_gpio_direction_output(struct udevice *dev, unsigned int offset,
+ int value)
+{
+ struct mediatek_gpio_plat *plat = dev_get_plat(dev);
+
+ setbits_le32(mediatek_gpio_membase + reg_offs(plat, GPIO_REG_CTRL),
+ BIT(offset));
+ mediatek_gpio_set_value(dev, offset, value);
+
+ return 0;
+}
+
+static int mediatek_gpio_get_function(struct udevice *dev, unsigned int offset)
+{
+ struct mediatek_gpio_plat *plat = dev_get_plat(dev);
+ u32 t;
+
+ t = ioread32(mediatek_gpio_membase + reg_offs(plat, GPIO_REG_CTRL));
+ if (t & BIT(offset))
+ return GPIOF_OUTPUT;
+
+ return GPIOF_INPUT;
+}
+
+static const struct dm_gpio_ops gpio_mediatek_ops = {
+ .direction_input = mediatek_gpio_direction_input,
+ .direction_output = mediatek_gpio_direction_output,
+ .get_value = mediatek_gpio_get_value,
+ .set_value = mediatek_gpio_set_value,
+ .get_function = mediatek_gpio_get_function,
+};
+
+static int gpio_mediatek_probe(struct udevice *dev)
+{
+ struct mediatek_gpio_plat *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ /* Tell the uclass how many GPIOs we have */
+ if (plat) {
+ uc_priv->gpio_count = plat->gpio_count;
+ uc_priv->bank_name = plat->bank_name;
+ }
+
+ return 0;
+}
+
+/**
+ * We have a top-level GPIO device with no actual GPIOs. It has a child
+ * device for each Mediatek bank.
+ */
+static int gpio_mediatek_bind(struct udevice *parent)
+{
+ struct mediatek_gpio_plat *plat = dev_get_plat(parent);
+ ofnode node;
+ int bank = 0;
+ int ret;
+
+ /* If this is a child device, there is nothing to do here */
+ if (plat)
+ return 0;
+
+ mediatek_gpio_membase = dev_remap_addr(parent);
+ if (!mediatek_gpio_membase)
+ return -EINVAL;
+
+ for (node = dev_read_first_subnode(parent); ofnode_valid(node);
+ node = dev_read_next_subnode(node)) {
+ struct mediatek_gpio_plat *plat;
+ struct udevice *dev;
+
+ plat = calloc(1, sizeof(*plat));
+ if (!plat)
+ return -ENOMEM;
+ plat->bank_name[0] = 'P';
+ plat->bank_name[1] = 'A' + bank;
+ plat->bank_name[2] = '\0';
+ plat->gpio_count = MTK_BANK_WIDTH;
+ plat->bank = bank;
+
+ ret = device_bind(parent, parent->driver, plat->bank_name, plat,
+ node, &dev);
+ if (ret)
+ return ret;
+
+ bank++;
+ }
+
+ return 0;
+}
+
+static const struct udevice_id mediatek_gpio_ids[] = {
+ { .compatible = "mtk,mt7621-gpio" },
+ { }
+};
+
+U_BOOT_DRIVER(gpio_mediatek) = {
+ .name = "gpio_mediatek",
+ .id = UCLASS_GPIO,
+ .ops = &gpio_mediatek_ops,
+ .of_match = mediatek_gpio_ids,
+ .bind = gpio_mediatek_bind,
+ .probe = gpio_mediatek_probe,
+};
diff --git a/roms/u-boot/drivers/gpio/mvebu_gpio.c b/roms/u-boot/drivers/gpio/mvebu_gpio.c
new file mode 100644
index 000000000..4c1c68ee1
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/mvebu_gpio.c
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Stefan Roese <sr@denx.de>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <errno.h>
+#include <linux/bitops.h>
+
+#define MVEBU_GPIOS_PER_BANK 32
+
+struct mvebu_gpio_regs {
+ u32 data_out;
+ u32 io_conf;
+ u32 blink_en;
+ u32 in_pol;
+ u32 data_in;
+};
+
+struct mvebu_gpio_priv {
+ struct mvebu_gpio_regs *regs;
+ char name[2];
+};
+
+static int mvebu_gpio_direction_input(struct udevice *dev, unsigned int gpio)
+{
+ struct mvebu_gpio_priv *priv = dev_get_priv(dev);
+ struct mvebu_gpio_regs *regs = priv->regs;
+
+ setbits_le32(&regs->io_conf, BIT(gpio));
+
+ return 0;
+}
+
+static int mvebu_gpio_direction_output(struct udevice *dev, unsigned gpio,
+ int value)
+{
+ struct mvebu_gpio_priv *priv = dev_get_priv(dev);
+ struct mvebu_gpio_regs *regs = priv->regs;
+
+ if (value)
+ setbits_le32(&regs->data_out, BIT(gpio));
+ else
+ clrbits_le32(&regs->data_out, BIT(gpio));
+ clrbits_le32(&regs->io_conf, BIT(gpio));
+
+ return 0;
+}
+
+static int mvebu_gpio_get_function(struct udevice *dev, unsigned gpio)
+{
+ struct mvebu_gpio_priv *priv = dev_get_priv(dev);
+ struct mvebu_gpio_regs *regs = priv->regs;
+ u32 val;
+
+ val = readl(&regs->io_conf) & BIT(gpio);
+ if (val)
+ return GPIOF_INPUT;
+ else
+ return GPIOF_OUTPUT;
+}
+
+static int mvebu_gpio_set_value(struct udevice *dev, unsigned gpio,
+ int value)
+{
+ struct mvebu_gpio_priv *priv = dev_get_priv(dev);
+ struct mvebu_gpio_regs *regs = priv->regs;
+
+ if (value)
+ setbits_le32(&regs->data_out, BIT(gpio));
+ else
+ clrbits_le32(&regs->data_out, BIT(gpio));
+
+ return 0;
+}
+
+static int mvebu_gpio_get_value(struct udevice *dev, unsigned gpio)
+{
+ struct mvebu_gpio_priv *priv = dev_get_priv(dev);
+ struct mvebu_gpio_regs *regs = priv->regs;
+
+ return !!(readl(&regs->data_in) & BIT(gpio));
+}
+
+static int mvebu_gpio_probe(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct mvebu_gpio_priv *priv = dev_get_priv(dev);
+
+ priv->regs = dev_read_addr_ptr(dev);
+ uc_priv->gpio_count = MVEBU_GPIOS_PER_BANK;
+ priv->name[0] = 'A' + dev_seq(dev);
+ uc_priv->bank_name = priv->name;
+
+ return 0;
+}
+
+static const struct dm_gpio_ops mvebu_gpio_ops = {
+ .direction_input = mvebu_gpio_direction_input,
+ .direction_output = mvebu_gpio_direction_output,
+ .get_function = mvebu_gpio_get_function,
+ .get_value = mvebu_gpio_get_value,
+ .set_value = mvebu_gpio_set_value,
+};
+
+static const struct udevice_id mvebu_gpio_ids[] = {
+ { .compatible = "marvell,orion-gpio" },
+ { }
+};
+
+U_BOOT_DRIVER(gpio_mvebu) = {
+ .name = "gpio_mvebu",
+ .id = UCLASS_GPIO,
+ .of_match = mvebu_gpio_ids,
+ .ops = &mvebu_gpio_ops,
+ .probe = mvebu_gpio_probe,
+ .priv_auto = sizeof(struct mvebu_gpio_priv),
+};
diff --git a/roms/u-boot/drivers/gpio/mvgpio.c b/roms/u-boot/drivers/gpio/mvgpio.c
new file mode 100644
index 000000000..12e7197da
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/mvgpio.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2011
+ * eInfochips Ltd. <www.einfochips.com>
+ * Written-by: Ajay Bhargav <contact@8051projects.net>
+ *
+ * (C) Copyright 2010
+ * Marvell Semiconductor <www.marvell.com>
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <linux/errno.h>
+#include "mvgpio.h"
+#include <asm/gpio.h>
+
+#ifndef MV_MAX_GPIO
+#define MV_MAX_GPIO 128
+#endif
+
+int gpio_request(unsigned gpio, const char *label)
+{
+ if (gpio >= MV_MAX_GPIO) {
+ printf("%s: Invalid GPIO requested %d\n", __func__, gpio);
+ return -1;
+ }
+ return 0;
+}
+
+int gpio_free(unsigned gpio)
+{
+ return 0;
+}
+
+int gpio_direction_input(unsigned gpio)
+{
+ struct gpio_reg *gpio_reg_bank;
+
+ if (gpio >= MV_MAX_GPIO) {
+ printf("%s: Invalid GPIO %d\n", __func__, gpio);
+ return -1;
+ }
+
+ gpio_reg_bank = get_gpio_base(GPIO_TO_REG(gpio));
+ writel(GPIO_TO_BIT(gpio), &gpio_reg_bank->gcdr);
+ return 0;
+}
+
+int gpio_direction_output(unsigned gpio, int value)
+{
+ struct gpio_reg *gpio_reg_bank;
+
+ if (gpio >= MV_MAX_GPIO) {
+ printf("%s: Invalid GPIO %d\n", __func__, gpio);
+ return -1;
+ }
+
+ gpio_reg_bank = get_gpio_base(GPIO_TO_REG(gpio));
+ writel(GPIO_TO_BIT(gpio), &gpio_reg_bank->gsdr);
+ gpio_set_value(gpio, value);
+ return 0;
+}
+
+int gpio_get_value(unsigned gpio)
+{
+ struct gpio_reg *gpio_reg_bank;
+ u32 gpio_val;
+
+ if (gpio >= MV_MAX_GPIO) {
+ printf("%s: Invalid GPIO %d\n", __func__, gpio);
+ return -1;
+ }
+
+ gpio_reg_bank = get_gpio_base(GPIO_TO_REG(gpio));
+ gpio_val = readl(&gpio_reg_bank->gplr);
+
+ return GPIO_VAL(gpio, gpio_val);
+}
+
+int gpio_set_value(unsigned gpio, int value)
+{
+ struct gpio_reg *gpio_reg_bank;
+
+ if (gpio >= MV_MAX_GPIO) {
+ printf("%s: Invalid GPIO %d\n", __func__, gpio);
+ return -1;
+ }
+
+ gpio_reg_bank = get_gpio_base(GPIO_TO_REG(gpio));
+ if (value)
+ writel(GPIO_TO_BIT(gpio), &gpio_reg_bank->gpsr);
+ else
+ writel(GPIO_TO_BIT(gpio), &gpio_reg_bank->gpcr);
+
+ return 0;
+}
diff --git a/roms/u-boot/drivers/gpio/mvgpio.h b/roms/u-boot/drivers/gpio/mvgpio.h
new file mode 100644
index 000000000..d68c48e63
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/mvgpio.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2011
+ * eInfochips Ltd. <www.einfochips.com>
+ * Written-by: Ajay Bhargav <contact@8051projects.net>
+ *
+ * (C) Copyright 2010
+ * Marvell Semiconductor <www.marvell.com>
+ */
+
+#ifndef __MVGPIO_H__
+#define __MVGPIO_H__
+
+#include <common.h>
+
+/*
+ * GPIO Register map for Marvell SOCs
+ */
+struct gpio_reg {
+ u32 gplr; /* Pin Level Register - 0x0000 */
+ u32 pad0[2];
+ u32 gpdr; /* Pin Direction Register - 0x000C */
+ u32 pad1[2];
+ u32 gpsr; /* Pin Output Set Register - 0x0018 */
+ u32 pad2[2];
+ u32 gpcr; /* Pin Output Clear Register - 0x0024 */
+ u32 pad3[2];
+ u32 grer; /* Rising-Edge Detect Enable Register - 0x0030 */
+ u32 pad4[2];
+ u32 gfer; /* Falling-Edge Detect Enable Register - 0x003C */
+ u32 pad5[2];
+ u32 gedr; /* Edge Detect Status Register - 0x0048 */
+ u32 pad6[2];
+ u32 gsdr; /* Bitwise Set of GPIO Direction Register - 0x0054 */
+ u32 pad7[2];
+ u32 gcdr; /* Bitwise Clear of GPIO Direction Register - 0x0060 */
+ u32 pad8[2];
+ u32 gsrer; /* Bitwise Set of Rising-Edge Detect Enable
+ Register - 0x006C */
+ u32 pad9[2];
+ u32 gcrer; /* Bitwise Clear of Rising-Edge Detect Enable
+ Register - 0x0078 */
+ u32 pad10[2];
+ u32 gsfer; /* Bitwise Set of Falling-Edge Detect Enable
+ Register - 0x0084 */
+ u32 pad11[2];
+ u32 gcfer; /* Bitwise Clear of Falling-Edge Detect Enable
+ Register - 0x0090 */
+ u32 pad12[2];
+ u32 apmask; /* Bitwise Mask of Edge Detect Register - 0x009C */
+};
+
+#endif /* __MVGPIO_H__ */
diff --git a/roms/u-boot/drivers/gpio/mvmfp.c b/roms/u-boot/drivers/gpio/mvmfp.c
new file mode 100644
index 000000000..511042c19
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/mvmfp.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2010
+ * Marvell Semiconductor <www.marvell.com>
+ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>,
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <mvmfp.h>
+#include <asm/arch/mfp.h>
+
+/*
+ * mfp_config
+ *
+ * On most of Marvell SoCs (ex. ARMADA100) there is Multi-Funtion-Pin
+ * configuration registers to configure each GPIO/Function pin on the
+ * SoC.
+ *
+ * This function reads the array of values for
+ * MFPR_X registers and programms them into respective
+ * Multi-Function Pin registers.
+ * It supports - Alternate Function Selection programming.
+ *
+ * Whereas,
+ * The Configureation value is constructed using MFP()
+ * array consists of 32bit values as defined in MFP(xx,xx..) macro
+ */
+void mfp_config(u32 *mfp_cfgs)
+{
+ u32 *p_mfpr = NULL;
+ u32 cfg_val, val;
+
+ do {
+ cfg_val = *mfp_cfgs++;
+ /* exit if End of configuration table detected */
+ if (cfg_val == MFP_EOC)
+ break;
+
+ p_mfpr = (u32 *)(MV_MFPR_BASE
+ + MFP_REG_GET_OFFSET(cfg_val));
+
+ /* Write a mfg register as per configuration */
+ val = 0;
+ if (cfg_val & MFP_VALUE_MASK)
+ val |= cfg_val & MFP_VALUE_MASK;
+
+ writel(val, p_mfpr);
+ } while (1);
+ /*
+ * perform a read-back of any MFPR register to make sure the
+ * previous writings are finished
+ */
+ readl(p_mfpr);
+}
diff --git a/roms/u-boot/drivers/gpio/mxc_gpio.c b/roms/u-boot/drivers/gpio/mxc_gpio.c
new file mode 100644
index 000000000..06e6b2279
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/mxc_gpio.c
@@ -0,0 +1,399 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2009
+ * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de>
+ *
+ * Copyright (C) 2011
+ * Stefano Babic, DENX Software Engineering, <sbabic@denx.de>
+ */
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <malloc.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <dt-structs.h>
+#include <mapmem.h>
+
+enum mxc_gpio_direction {
+ MXC_GPIO_DIRECTION_IN,
+ MXC_GPIO_DIRECTION_OUT,
+};
+
+#define GPIO_PER_BANK 32
+
+struct mxc_gpio_plat {
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+ /* Put this first since driver model will copy the data here */
+ struct dtd_gpio_mxc dtplat;
+#endif
+ int bank_index;
+ struct gpio_regs *regs;
+};
+
+struct mxc_bank_info {
+ struct gpio_regs *regs;
+};
+
+#if !CONFIG_IS_ENABLED(DM_GPIO)
+#define GPIO_TO_PORT(n) ((n) / 32)
+
+/* GPIO port description */
+static unsigned long gpio_ports[] = {
+ [0] = GPIO1_BASE_ADDR,
+ [1] = GPIO2_BASE_ADDR,
+ [2] = GPIO3_BASE_ADDR,
+#if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX51) || \
+ defined(CONFIG_MX53) || defined(CONFIG_MX6) || \
+ defined(CONFIG_MX7) || defined(CONFIG_IMX8M) || \
+ defined(CONFIG_ARCH_IMX8) || defined(CONFIG_IMXRT1050)
+ [3] = GPIO4_BASE_ADDR,
+#endif
+#if defined(CONFIG_MX27) || defined(CONFIG_MX53) || defined(CONFIG_MX6) || \
+ defined(CONFIG_MX7) || defined(CONFIG_IMX8M) || \
+ defined(CONFIG_ARCH_IMX8) || defined(CONFIG_IMXRT1050)
+ [4] = GPIO5_BASE_ADDR,
+#if !(defined(CONFIG_MX6UL) || defined(CONFIG_MX6ULL) || \
+ defined(CONFIG_IMX8M) || defined(CONFIG_IMXRT1050))
+ [5] = GPIO6_BASE_ADDR,
+#endif
+#endif
+#if defined(CONFIG_MX53) || defined(CONFIG_MX6) || defined(CONFIG_MX7) || \
+ defined(CONFIG_ARCH_IMX8)
+#if !(defined(CONFIG_MX6UL) || defined(CONFIG_MX6ULL))
+ [6] = GPIO7_BASE_ADDR,
+#endif
+#endif
+#if defined(CONFIG_ARCH_IMX8)
+ [7] = GPIO8_BASE_ADDR,
+#endif
+};
+
+static int mxc_gpio_direction(unsigned int gpio,
+ enum mxc_gpio_direction direction)
+{
+ unsigned int port = GPIO_TO_PORT(gpio);
+ struct gpio_regs *regs;
+ u32 l;
+
+ if (port >= ARRAY_SIZE(gpio_ports))
+ return -1;
+
+ gpio &= 0x1f;
+
+ regs = (struct gpio_regs *)gpio_ports[port];
+
+ l = readl(&regs->gpio_dir);
+
+ switch (direction) {
+ case MXC_GPIO_DIRECTION_OUT:
+ l |= 1 << gpio;
+ break;
+ case MXC_GPIO_DIRECTION_IN:
+ l &= ~(1 << gpio);
+ }
+ writel(l, &regs->gpio_dir);
+
+ return 0;
+}
+
+int gpio_set_value(unsigned gpio, int value)
+{
+ unsigned int port = GPIO_TO_PORT(gpio);
+ struct gpio_regs *regs;
+ u32 l;
+
+ if (port >= ARRAY_SIZE(gpio_ports))
+ return -1;
+
+ gpio &= 0x1f;
+
+ regs = (struct gpio_regs *)gpio_ports[port];
+
+ l = readl(&regs->gpio_dr);
+ if (value)
+ l |= 1 << gpio;
+ else
+ l &= ~(1 << gpio);
+ writel(l, &regs->gpio_dr);
+
+ return 0;
+}
+
+int gpio_get_value(unsigned gpio)
+{
+ unsigned int port = GPIO_TO_PORT(gpio);
+ struct gpio_regs *regs;
+ u32 val;
+
+ if (port >= ARRAY_SIZE(gpio_ports))
+ return -1;
+
+ gpio &= 0x1f;
+
+ regs = (struct gpio_regs *)gpio_ports[port];
+
+ val = (readl(&regs->gpio_psr) >> gpio) & 0x01;
+
+ return val;
+}
+
+int gpio_request(unsigned gpio, const char *label)
+{
+ unsigned int port = GPIO_TO_PORT(gpio);
+ if (port >= ARRAY_SIZE(gpio_ports))
+ return -1;
+ return 0;
+}
+
+int gpio_free(unsigned gpio)
+{
+ return 0;
+}
+
+int gpio_direction_input(unsigned gpio)
+{
+ return mxc_gpio_direction(gpio, MXC_GPIO_DIRECTION_IN);
+}
+
+int gpio_direction_output(unsigned gpio, int value)
+{
+ int ret = gpio_set_value(gpio, value);
+
+ if (ret < 0)
+ return ret;
+
+ return mxc_gpio_direction(gpio, MXC_GPIO_DIRECTION_OUT);
+}
+#endif
+
+#if CONFIG_IS_ENABLED(DM_GPIO)
+#include <fdtdec.h>
+static int mxc_gpio_is_output(struct gpio_regs *regs, int offset)
+{
+ u32 val;
+
+ val = readl(&regs->gpio_dir);
+
+ return val & (1 << offset) ? 1 : 0;
+}
+
+static void mxc_gpio_bank_direction(struct gpio_regs *regs, int offset,
+ enum mxc_gpio_direction direction)
+{
+ u32 l;
+
+ l = readl(&regs->gpio_dir);
+
+ switch (direction) {
+ case MXC_GPIO_DIRECTION_OUT:
+ l |= 1 << offset;
+ break;
+ case MXC_GPIO_DIRECTION_IN:
+ l &= ~(1 << offset);
+ }
+ writel(l, &regs->gpio_dir);
+}
+
+static void mxc_gpio_bank_set_value(struct gpio_regs *regs, int offset,
+ int value)
+{
+ u32 l;
+
+ l = readl(&regs->gpio_dr);
+ if (value)
+ l |= 1 << offset;
+ else
+ l &= ~(1 << offset);
+ writel(l, &regs->gpio_dr);
+}
+
+static int mxc_gpio_bank_get_value(struct gpio_regs *regs, int offset)
+{
+ return (readl(&regs->gpio_psr) >> offset) & 0x01;
+}
+
+/* set GPIO pin 'gpio' as an input */
+static int mxc_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+ struct mxc_bank_info *bank = dev_get_priv(dev);
+
+ /* Configure GPIO direction as input. */
+ mxc_gpio_bank_direction(bank->regs, offset, MXC_GPIO_DIRECTION_IN);
+
+ return 0;
+}
+
+/* set GPIO pin 'gpio' as an output, with polarity 'value' */
+static int mxc_gpio_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct mxc_bank_info *bank = dev_get_priv(dev);
+
+ /* Configure GPIO output value. */
+ mxc_gpio_bank_set_value(bank->regs, offset, value);
+
+ /* Configure GPIO direction as output. */
+ mxc_gpio_bank_direction(bank->regs, offset, MXC_GPIO_DIRECTION_OUT);
+
+ return 0;
+}
+
+/* read GPIO IN value of pin 'gpio' */
+static int mxc_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+ struct mxc_bank_info *bank = dev_get_priv(dev);
+
+ return mxc_gpio_bank_get_value(bank->regs, offset);
+}
+
+/* write GPIO OUT value to pin 'gpio' */
+static int mxc_gpio_set_value(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct mxc_bank_info *bank = dev_get_priv(dev);
+
+ mxc_gpio_bank_set_value(bank->regs, offset, value);
+
+ return 0;
+}
+
+static int mxc_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+ struct mxc_bank_info *bank = dev_get_priv(dev);
+
+ /* GPIOF_FUNC is not implemented yet */
+ if (mxc_gpio_is_output(bank->regs, offset))
+ return GPIOF_OUTPUT;
+ else
+ return GPIOF_INPUT;
+}
+
+static const struct dm_gpio_ops gpio_mxc_ops = {
+ .direction_input = mxc_gpio_direction_input,
+ .direction_output = mxc_gpio_direction_output,
+ .get_value = mxc_gpio_get_value,
+ .set_value = mxc_gpio_set_value,
+ .get_function = mxc_gpio_get_function,
+};
+
+static int mxc_gpio_probe(struct udevice *dev)
+{
+ struct mxc_bank_info *bank = dev_get_priv(dev);
+ struct mxc_gpio_plat *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ int banknum;
+ char name[18], *str;
+
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+ struct dtd_gpio_mxc *dtplat = &plat->dtplat;
+
+ plat->regs = map_sysmem(dtplat->reg[0], dtplat->reg[1]);
+#endif
+
+ banknum = plat->bank_index;
+ if (IS_ENABLED(CONFIG_ARCH_IMX8))
+ sprintf(name, "GPIO%d_", banknum);
+ else
+ sprintf(name, "GPIO%d_", banknum + 1);
+ str = strdup(name);
+ if (!str)
+ return -ENOMEM;
+ uc_priv->bank_name = str;
+ uc_priv->gpio_count = GPIO_PER_BANK;
+ bank->regs = plat->regs;
+
+ return 0;
+}
+
+static int mxc_gpio_of_to_plat(struct udevice *dev)
+{
+ struct mxc_gpio_plat *plat = dev_get_plat(dev);
+ if (!CONFIG_IS_ENABLED(OF_PLATDATA)) {
+ fdt_addr_t addr;
+ addr = dev_read_addr(dev);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ plat->regs = (struct gpio_regs *)addr;
+ }
+ plat->bank_index = dev_seq(dev);
+
+ return 0;
+}
+
+static int mxc_gpio_bind(struct udevice *dev)
+{
+ return 0;
+}
+
+static const struct udevice_id mxc_gpio_ids[] = {
+ { .compatible = "fsl,imx35-gpio" },
+ { }
+};
+
+U_BOOT_DRIVER(gpio_mxc) = {
+ .name = "gpio_mxc",
+ .id = UCLASS_GPIO,
+ .ops = &gpio_mxc_ops,
+ .probe = mxc_gpio_probe,
+ .of_to_plat = mxc_gpio_of_to_plat,
+ .plat_auto = sizeof(struct mxc_gpio_plat),
+ .priv_auto = sizeof(struct mxc_bank_info),
+ .of_match = mxc_gpio_ids,
+ .bind = mxc_gpio_bind,
+};
+
+DM_DRIVER_ALIAS(gpio_mxc, fsl_imx6q_gpio)
+
+#if !CONFIG_IS_ENABLED(OF_CONTROL)
+static const struct mxc_gpio_plat mxc_plat[] = {
+ { 0, (struct gpio_regs *)GPIO1_BASE_ADDR },
+ { 1, (struct gpio_regs *)GPIO2_BASE_ADDR },
+ { 2, (struct gpio_regs *)GPIO3_BASE_ADDR },
+#if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX51) || \
+ defined(CONFIG_MX53) || defined(CONFIG_MX6) || \
+ defined(CONFIG_IMX8M) || defined(CONFIG_ARCH_IMX8)
+ { 3, (struct gpio_regs *)GPIO4_BASE_ADDR },
+#endif
+#if defined(CONFIG_MX27) || defined(CONFIG_MX53) || defined(CONFIG_MX6) || \
+ defined(CONFIG_IMX8M) || defined(CONFIG_ARCH_IMX8)
+ { 4, (struct gpio_regs *)GPIO5_BASE_ADDR },
+#ifndef CONFIG_IMX8M
+ { 5, (struct gpio_regs *)GPIO6_BASE_ADDR },
+#endif
+#endif
+#if defined(CONFIG_MX53) || defined(CONFIG_MX6) || defined(CONFIG_ARCH_IMX8)
+ { 6, (struct gpio_regs *)GPIO7_BASE_ADDR },
+#endif
+#if defined(CONFIG_ARCH_IMX8)
+ { 7, (struct gpio_regs *)GPIO8_BASE_ADDR },
+#endif
+};
+
+U_BOOT_DRVINFOS(mxc_gpios) = {
+ { "gpio_mxc", &mxc_plat[0] },
+ { "gpio_mxc", &mxc_plat[1] },
+ { "gpio_mxc", &mxc_plat[2] },
+#if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX51) || \
+ defined(CONFIG_MX53) || defined(CONFIG_MX6) || \
+ defined(CONFIG_IMX8M) || defined(CONFIG_ARCH_IMX8)
+ { "gpio_mxc", &mxc_plat[3] },
+#endif
+#if defined(CONFIG_MX27) || defined(CONFIG_MX53) || defined(CONFIG_MX6) || \
+ defined(CONFIG_IMX8M) || defined(CONFIG_ARCH_IMX8)
+ { "gpio_mxc", &mxc_plat[4] },
+#ifndef CONFIG_IMX8M
+ { "gpio_mxc", &mxc_plat[5] },
+#endif
+#endif
+#if defined(CONFIG_MX53) || defined(CONFIG_MX6) || defined(CONFIG_ARCH_IMX8)
+ { "gpio_mxc", &mxc_plat[6] },
+#endif
+#if defined(CONFIG_ARCH_IMX8)
+ { "gpio_mxc", &mxc_plat[7] },
+#endif
+};
+#endif
+#endif
diff --git a/roms/u-boot/drivers/gpio/mxs_gpio.c b/roms/u-boot/drivers/gpio/mxs_gpio.c
new file mode 100644
index 000000000..5775a22ab
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/mxs_gpio.c
@@ -0,0 +1,311 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Freescale i.MX28 GPIO control code
+ *
+ * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
+ * on behalf of DENX Software Engineering GmbH
+ */
+
+#include <common.h>
+#include <log.h>
+#include <malloc.h>
+#include <asm/global_data.h>
+#include <linux/bitops.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm/arch/iomux.h>
+#include <asm/arch/imx-regs.h>
+
+#if defined(CONFIG_MX23)
+#define PINCTRL_BANKS 3
+#define PINCTRL_DOUT(n) (0x0500 + ((n) * 0x10))
+#define PINCTRL_DIN(n) (0x0600 + ((n) * 0x10))
+#define PINCTRL_DOE(n) (0x0700 + ((n) * 0x10))
+#define PINCTRL_PIN2IRQ(n) (0x0800 + ((n) * 0x10))
+#define PINCTRL_IRQEN(n) (0x0900 + ((n) * 0x10))
+#define PINCTRL_IRQSTAT(n) (0x0c00 + ((n) * 0x10))
+#elif defined(CONFIG_MX28)
+#define PINCTRL_BANKS 5
+#define PINCTRL_DOUT(n) (0x0700 + ((n) * 0x10))
+#define PINCTRL_DIN(n) (0x0900 + ((n) * 0x10))
+#define PINCTRL_DOE(n) (0x0b00 + ((n) * 0x10))
+#define PINCTRL_PIN2IRQ(n) (0x1000 + ((n) * 0x10))
+#define PINCTRL_IRQEN(n) (0x1100 + ((n) * 0x10))
+#define PINCTRL_IRQSTAT(n) (0x1400 + ((n) * 0x10))
+#else
+#error "Please select CONFIG_MX23 or CONFIG_MX28"
+#endif
+
+#define GPIO_INT_FALL_EDGE 0x0
+#define GPIO_INT_LOW_LEV 0x1
+#define GPIO_INT_RISE_EDGE 0x2
+#define GPIO_INT_HIGH_LEV 0x3
+#define GPIO_INT_LEV_MASK (1 << 0)
+#define GPIO_INT_POL_MASK (1 << 1)
+
+void mxs_gpio_init(void)
+{
+ int i;
+
+ for (i = 0; i < PINCTRL_BANKS; i++) {
+ writel(0, MXS_PINCTRL_BASE + PINCTRL_PIN2IRQ(i));
+ writel(0, MXS_PINCTRL_BASE + PINCTRL_IRQEN(i));
+ /* Use SCT address here to clear the IRQSTAT bits */
+ writel(0xffffffff, MXS_PINCTRL_BASE + PINCTRL_IRQSTAT(i) + 8);
+ }
+}
+
+#if !CONFIG_IS_ENABLED(DM_GPIO)
+int gpio_get_value(unsigned gpio)
+{
+ uint32_t bank = PAD_BANK(gpio);
+ uint32_t offset = PINCTRL_DIN(bank);
+ struct mxs_register_32 *reg =
+ (struct mxs_register_32 *)(MXS_PINCTRL_BASE + offset);
+
+ return (readl(&reg->reg) >> PAD_PIN(gpio)) & 1;
+}
+
+void gpio_set_value(unsigned gpio, int value)
+{
+ uint32_t bank = PAD_BANK(gpio);
+ uint32_t offset = PINCTRL_DOUT(bank);
+ struct mxs_register_32 *reg =
+ (struct mxs_register_32 *)(MXS_PINCTRL_BASE + offset);
+
+ if (value)
+ writel(1 << PAD_PIN(gpio), &reg->reg_set);
+ else
+ writel(1 << PAD_PIN(gpio), &reg->reg_clr);
+}
+
+int gpio_direction_input(unsigned gpio)
+{
+ uint32_t bank = PAD_BANK(gpio);
+ uint32_t offset = PINCTRL_DOE(bank);
+ struct mxs_register_32 *reg =
+ (struct mxs_register_32 *)(MXS_PINCTRL_BASE + offset);
+
+ writel(1 << PAD_PIN(gpio), &reg->reg_clr);
+
+ return 0;
+}
+
+int gpio_direction_output(unsigned gpio, int value)
+{
+ uint32_t bank = PAD_BANK(gpio);
+ uint32_t offset = PINCTRL_DOE(bank);
+ struct mxs_register_32 *reg =
+ (struct mxs_register_32 *)(MXS_PINCTRL_BASE + offset);
+
+ gpio_set_value(gpio, value);
+
+ writel(1 << PAD_PIN(gpio), &reg->reg_set);
+
+ return 0;
+}
+
+int gpio_request(unsigned gpio, const char *label)
+{
+ if (PAD_BANK(gpio) >= PINCTRL_BANKS)
+ return -1;
+
+ return 0;
+}
+
+int gpio_free(unsigned gpio)
+{
+ return 0;
+}
+
+int name_to_gpio(const char *name)
+{
+ unsigned bank, pin;
+ char *end;
+
+ bank = simple_strtoul(name, &end, 10);
+
+ if (!*end || *end != ':')
+ return bank;
+
+ pin = simple_strtoul(end + 1, NULL, 10);
+
+ return (bank << MXS_PAD_BANK_SHIFT) | (pin << MXS_PAD_PIN_SHIFT);
+}
+#else /* DM_GPIO */
+#include <dm.h>
+#include <asm/gpio.h>
+#include <dt-structs.h>
+#include <asm/arch/gpio.h>
+#define MXS_MAX_GPIO_PER_BANK 32
+
+DECLARE_GLOBAL_DATA_PTR;
+/*
+ * According to i.MX28 Reference Manual:
+ * 'i.MX28 Applications Processor Reference Manual, Rev. 1, 2010'
+ * The i.MX28 has following number of GPIOs available:
+ * Bank 0: 0-28 -> 29 PINS
+ * Bank 1: 0-31 -> 32 PINS
+ * Bank 2: 0-27 -> 28 PINS
+ * Bank 3: 0-30 -> 31 PINS
+ * Bank 4: 0-20 -> 21 PINS
+ */
+
+struct mxs_gpio_plat {
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+ struct dtd_fsl_imx23_gpio dtplat;
+#endif
+ unsigned int bank;
+ int gpio_ranges;
+};
+
+struct mxs_gpio_priv {
+ unsigned int bank;
+};
+
+static int mxs_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+ struct mxs_gpio_priv *priv = dev_get_priv(dev);
+ struct mxs_register_32 *reg =
+ (struct mxs_register_32 *)(MXS_PINCTRL_BASE +
+ PINCTRL_DIN(priv->bank));
+
+ return (readl(&reg->reg) >> offset) & 1;
+}
+
+static int mxs_gpio_set_value(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct mxs_gpio_priv *priv = dev_get_priv(dev);
+ struct mxs_register_32 *reg =
+ (struct mxs_register_32 *)(MXS_PINCTRL_BASE +
+ PINCTRL_DOUT(priv->bank));
+ if (value)
+ writel(BIT(offset), &reg->reg_set);
+ else
+ writel(BIT(offset), &reg->reg_clr);
+
+ return 0;
+}
+
+static int mxs_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+ struct mxs_gpio_priv *priv = dev_get_priv(dev);
+ struct mxs_register_32 *reg =
+ (struct mxs_register_32 *)(MXS_PINCTRL_BASE +
+ PINCTRL_DOE(priv->bank));
+
+ writel(BIT(offset), &reg->reg_clr);
+
+ return 0;
+}
+
+static int mxs_gpio_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct mxs_gpio_priv *priv = dev_get_priv(dev);
+ struct mxs_register_32 *reg =
+ (struct mxs_register_32 *)(MXS_PINCTRL_BASE +
+ PINCTRL_DOE(priv->bank));
+
+ mxs_gpio_set_value(dev, offset, value);
+
+ writel(BIT(offset), &reg->reg_set);
+
+ return 0;
+}
+
+static int mxs_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+ struct mxs_gpio_priv *priv = dev_get_priv(dev);
+ struct mxs_register_32 *reg =
+ (struct mxs_register_32 *)(MXS_PINCTRL_BASE +
+ PINCTRL_DOE(priv->bank));
+ bool is_output = !!(readl(&reg->reg) >> offset);
+
+ return is_output ? GPIOF_OUTPUT : GPIOF_INPUT;
+}
+
+static const struct dm_gpio_ops gpio_mxs_ops = {
+ .direction_input = mxs_gpio_direction_input,
+ .direction_output = mxs_gpio_direction_output,
+ .get_value = mxs_gpio_get_value,
+ .set_value = mxs_gpio_set_value,
+ .get_function = mxs_gpio_get_function,
+};
+
+static int mxs_gpio_probe(struct udevice *dev)
+{
+ struct mxs_gpio_plat *plat = dev_get_plat(dev);
+ struct mxs_gpio_priv *priv = dev_get_priv(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ char name[16], *str;
+
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+ struct dtd_fsl_imx23_gpio *dtplat = &plat->dtplat;
+ priv->bank = (unsigned int)dtplat->reg[0];
+ uc_priv->gpio_count = dtplat->gpio_ranges[3];
+#else
+ priv->bank = (unsigned int)plat->bank;
+ uc_priv->gpio_count = plat->gpio_ranges;
+#endif
+ snprintf(name, sizeof(name), "GPIO%d_", priv->bank);
+ str = strdup(name);
+ if (!str)
+ return -ENOMEM;
+
+ uc_priv->bank_name = str;
+
+ debug("%s: %s: %d pins base: 0x%x\n", __func__, uc_priv->bank_name,
+ uc_priv->gpio_count, priv->bank);
+
+ return 0;
+}
+
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+static int mxs_of_to_plat(struct udevice *dev)
+{
+ struct mxs_gpio_plat *plat = dev_get_plat(dev);
+ struct fdtdec_phandle_args args;
+ int node = dev_of_offset(dev);
+ int ret;
+
+ plat->bank = dev_read_addr(dev);
+ if (plat->bank == FDT_ADDR_T_NONE) {
+ printf("%s: No 'reg' property defined!\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, node, "gpio-ranges",
+ NULL, 3, 0, &args);
+ if (ret)
+ printf("%s: 'gpio-ranges' not defined - using default!\n",
+ __func__);
+
+ plat->gpio_ranges = ret == 0 ? args.args[2] : MXS_MAX_GPIO_PER_BANK;
+
+ return 0;
+}
+
+static const struct udevice_id mxs_gpio_ids[] = {
+ { .compatible = "fsl,imx23-gpio" },
+ { .compatible = "fsl,imx28-gpio" },
+ { }
+};
+#endif
+
+U_BOOT_DRIVER(fsl_imx23_gpio) = {
+ .name = "fsl_imx23_gpio",
+ .id = UCLASS_GPIO,
+ .ops = &gpio_mxs_ops,
+ .probe = mxs_gpio_probe,
+ .priv_auto = sizeof(struct mxs_gpio_priv),
+ .plat_auto = sizeof(struct mxs_gpio_plat),
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+ .of_match = mxs_gpio_ids,
+ .of_to_plat = mxs_of_to_plat,
+#endif
+};
+
+DM_DRIVER_ALIAS(fsl_imx23_gpio, fsl_imx28_gpio)
+#endif /* DM_GPIO */
diff --git a/roms/u-boot/drivers/gpio/nx_gpio.c b/roms/u-boot/drivers/gpio/nx_gpio.c
new file mode 100644
index 000000000..e2565d709
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/nx_gpio.c
@@ -0,0 +1,251 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016 Nexell
+ * DeokJin, Lee <truevirtue@nexell.co.kr>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <malloc.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct nx_gpio_regs {
+ u32 data; /* Data register */
+ u32 outputenb; /* Output Enable register */
+ u32 detmode[2]; /* Detect Mode Register */
+ u32 intenb; /* Interrupt Enable Register */
+ u32 det; /* Event Detect Register */
+ u32 pad; /* Pad Status Register */
+};
+
+struct nx_alive_gpio_regs {
+ u32 pwrgate; /* Power Gating Register */
+ u32 reserved0[28]; /* Reserved0 */
+ u32 outputenb_reset;/* Alive GPIO Output Enable Reset Register */
+ u32 outputenb; /* Alive GPIO Output Enable Register */
+ u32 outputenb_read; /* Alive GPIO Output Read Register */
+ u32 reserved1[3]; /* Reserved1 */
+ u32 pad_reset; /* Alive GPIO Output Reset Register */
+ u32 data; /* Alive GPIO Output Register */
+ u32 pad_read; /* Alive GPIO Pad Read Register */
+ u32 reserved2[33]; /* Reserved2 */
+ u32 pad; /* Alive GPIO Input Value Register */
+};
+
+struct nx_gpio_plat {
+ void *regs;
+ int gpio_count;
+ const char *bank_name;
+};
+
+static int nx_alive_gpio_is_check(struct udevice *dev)
+{
+ struct nx_gpio_plat *plat = dev_get_plat(dev);
+ const char *bank_name = plat->bank_name;
+
+ if (!strcmp(bank_name, "gpio_alv"))
+ return 1;
+
+ return 0;
+}
+
+static int nx_alive_gpio_direction_input(struct udevice *dev, unsigned int pin)
+{
+ struct nx_gpio_plat *plat = dev_get_plat(dev);
+ struct nx_alive_gpio_regs *const regs = plat->regs;
+
+ setbits_le32(&regs->outputenb_reset, 1 << pin);
+
+ return 0;
+}
+
+static int nx_alive_gpio_direction_output(struct udevice *dev, unsigned int pin,
+ int val)
+{
+ struct nx_gpio_plat *plat = dev_get_plat(dev);
+ struct nx_alive_gpio_regs *const regs = plat->regs;
+
+ if (val)
+ setbits_le32(&regs->data, 1 << pin);
+ else
+ setbits_le32(&regs->pad_reset, 1 << pin);
+
+ setbits_le32(&regs->outputenb, 1 << pin);
+
+ return 0;
+}
+
+static int nx_alive_gpio_get_value(struct udevice *dev, unsigned int pin)
+{
+ struct nx_gpio_plat *plat = dev_get_plat(dev);
+ struct nx_alive_gpio_regs *const regs = plat->regs;
+ unsigned int mask = 1UL << pin;
+ unsigned int value;
+
+ value = (readl(&regs->pad_read) & mask) >> pin;
+
+ return value;
+}
+
+static int nx_alive_gpio_set_value(struct udevice *dev, unsigned int pin,
+ int val)
+{
+ struct nx_gpio_plat *plat = dev_get_plat(dev);
+ struct nx_alive_gpio_regs *const regs = plat->regs;
+
+ if (val)
+ setbits_le32(&regs->data, 1 << pin);
+ else
+ clrbits_le32(&regs->pad_reset, 1 << pin);
+
+ return 0;
+}
+
+static int nx_alive_gpio_get_function(struct udevice *dev, unsigned int pin)
+{
+ struct nx_gpio_plat *plat = dev_get_plat(dev);
+ struct nx_alive_gpio_regs *const regs = plat->regs;
+ unsigned int mask = (1UL << pin);
+ unsigned int output;
+
+ output = readl(&regs->outputenb_read) & mask;
+
+ if (output)
+ return GPIOF_OUTPUT;
+ else
+ return GPIOF_INPUT;
+}
+
+static int nx_gpio_direction_input(struct udevice *dev, unsigned int pin)
+{
+ struct nx_gpio_plat *plat = dev_get_plat(dev);
+ struct nx_gpio_regs *const regs = plat->regs;
+
+ if (nx_alive_gpio_is_check(dev))
+ return nx_alive_gpio_direction_input(dev, pin);
+
+ clrbits_le32(&regs->outputenb, 1 << pin);
+
+ return 0;
+}
+
+static int nx_gpio_direction_output(struct udevice *dev, unsigned int pin,
+ int val)
+{
+ struct nx_gpio_plat *plat = dev_get_plat(dev);
+ struct nx_gpio_regs *const regs = plat->regs;
+
+ if (nx_alive_gpio_is_check(dev))
+ return nx_alive_gpio_direction_output(dev, pin, val);
+
+ if (val)
+ setbits_le32(&regs->data, 1 << pin);
+ else
+ clrbits_le32(&regs->data, 1 << pin);
+
+ setbits_le32(&regs->outputenb, 1 << pin);
+
+ return 0;
+}
+
+static int nx_gpio_get_value(struct udevice *dev, unsigned int pin)
+{
+ struct nx_gpio_plat *plat = dev_get_plat(dev);
+ struct nx_gpio_regs *const regs = plat->regs;
+ unsigned int mask = 1UL << pin;
+ unsigned int value;
+
+ if (nx_alive_gpio_is_check(dev))
+ return nx_alive_gpio_get_value(dev, pin);
+
+ value = (readl(&regs->pad) & mask) >> pin;
+
+ return value;
+}
+
+static int nx_gpio_set_value(struct udevice *dev, unsigned int pin, int val)
+{
+ struct nx_gpio_plat *plat = dev_get_plat(dev);
+ struct nx_gpio_regs *const regs = plat->regs;
+
+ if (nx_alive_gpio_is_check(dev))
+ return nx_alive_gpio_set_value(dev, pin, val);
+
+ if (val)
+ setbits_le32(&regs->data, 1 << pin);
+ else
+ clrbits_le32(&regs->data, 1 << pin);
+
+ return 0;
+}
+
+static int nx_gpio_get_function(struct udevice *dev, unsigned int pin)
+{
+ struct nx_gpio_plat *plat = dev_get_plat(dev);
+ struct nx_gpio_regs *const regs = plat->regs;
+ unsigned int mask = (1UL << pin);
+ unsigned int output;
+
+ if (nx_alive_gpio_is_check(dev))
+ return nx_alive_gpio_get_function(dev, pin);
+
+ output = readl(&regs->outputenb) & mask;
+
+ if (output)
+ return GPIOF_OUTPUT;
+ else
+ return GPIOF_INPUT;
+}
+
+static int nx_gpio_probe(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct nx_gpio_plat *plat = dev_get_plat(dev);
+
+ uc_priv->gpio_count = plat->gpio_count;
+ uc_priv->bank_name = plat->bank_name;
+
+ return 0;
+}
+
+static int nx_gpio_of_to_plat(struct udevice *dev)
+{
+ struct nx_gpio_plat *plat = dev_get_plat(dev);
+
+ plat->regs = map_physmem(devfdt_get_addr(dev),
+ sizeof(struct nx_gpio_regs),
+ MAP_NOCACHE);
+ plat->gpio_count = dev_read_s32_default(dev, "nexell,gpio-bank-width",
+ 32);
+ plat->bank_name = dev_read_string(dev, "gpio-bank-name");
+
+ return 0;
+}
+
+static const struct dm_gpio_ops nx_gpio_ops = {
+ .direction_input = nx_gpio_direction_input,
+ .direction_output = nx_gpio_direction_output,
+ .get_value = nx_gpio_get_value,
+ .set_value = nx_gpio_set_value,
+ .get_function = nx_gpio_get_function,
+};
+
+static const struct udevice_id nx_gpio_ids[] = {
+ { .compatible = "nexell,nexell-gpio" },
+ { }
+};
+
+U_BOOT_DRIVER(nx_gpio) = {
+ .name = "nx_gpio",
+ .id = UCLASS_GPIO,
+ .of_match = nx_gpio_ids,
+ .ops = &nx_gpio_ops,
+ .of_to_plat = nx_gpio_of_to_plat,
+ .plat_auto = sizeof(struct nx_gpio_plat),
+ .probe = nx_gpio_probe,
+};
diff --git a/roms/u-boot/drivers/gpio/octeon_gpio.c b/roms/u-boot/drivers/gpio/octeon_gpio.c
new file mode 100644
index 000000000..42eae79d8
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/octeon_gpio.c
@@ -0,0 +1,242 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * (C) Copyright 2011
+ * eInfochips Ltd. <www.einfochips.com>
+ * Written-by: Ajay Bhargav <ajay.bhargav@einfochips.com>
+ *
+ * (C) Copyright 2010
+ * Marvell Semiconductor <www.marvell.com>
+ */
+
+#include <dm.h>
+#include <pci.h>
+#include <pci_ids.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <linux/bitfield.h>
+#include <linux/compat.h>
+#include <dt-bindings/gpio/gpio.h>
+
+/* Returns the bit value to write or read based on the offset */
+#define GPIO_BIT(x) BIT_ULL((x) & 0x3f)
+
+#define GPIO_RX_DAT 0x00
+#define GPIO_TX_SET 0x08
+#define GPIO_TX_CLR 0x10
+#define GPIO_CONST 0x90 /* OcteonTX only */
+
+/* Offset to register-set for 2nd GPIOs (> 63), OcteonTX only */
+#define GPIO1_OFFSET 0x1400
+
+/* GPIO_CONST register bits */
+#define GPIO_CONST_GPIOS_MASK GENMASK_ULL(7, 0)
+
+/* GPIO_BIT_CFG register bits */
+#define GPIO_BIT_CFG_TX_OE BIT_ULL(0)
+#define GPIO_BIT_CFG_PIN_XOR BIT_ULL(1)
+#define GPIO_BIT_CFG_INT_EN BIT_ULL(2)
+#define GPIO_BIT_CFG_PIN_SEL_MASK GENMASK_ULL(26, 16)
+
+enum {
+ PROBE_PCI = 0, /* PCI based probing */
+ PROBE_DT, /* DT based probing */
+};
+
+struct octeon_gpio_data {
+ int probe;
+ u32 reg_offs;
+ u32 gpio_bit_cfg_offs;
+};
+
+struct octeon_gpio {
+ void __iomem *base;
+ const struct octeon_gpio_data *data;
+};
+
+/* Returns the offset to the output register based on the offset and value */
+static u32 gpio_tx_reg(int offset, int value)
+{
+ u32 ret;
+
+ ret = value ? GPIO_TX_SET : GPIO_TX_CLR;
+ if (offset > 63)
+ ret += GPIO1_OFFSET;
+
+ return ret;
+}
+
+/* Returns the offset to the input data register based on the offset */
+static u32 gpio_rx_dat_reg(int offset)
+{
+ u32 ret;
+
+ ret = GPIO_RX_DAT;
+ if (offset > 63)
+ ret += GPIO1_OFFSET;
+
+ return ret;
+}
+
+static int octeon_gpio_dir_input(struct udevice *dev, unsigned int offset)
+{
+ struct octeon_gpio *gpio = dev_get_priv(dev);
+
+ debug("%s(%s, %u)\n", __func__, dev->name, offset);
+ clrbits_64(gpio->base + gpio->data->gpio_bit_cfg_offs + 8 * offset,
+ GPIO_BIT_CFG_TX_OE | GPIO_BIT_CFG_PIN_XOR |
+ GPIO_BIT_CFG_INT_EN | GPIO_BIT_CFG_PIN_SEL_MASK);
+
+ return 0;
+}
+
+static int octeon_gpio_dir_output(struct udevice *dev, unsigned int offset,
+ int value)
+{
+ struct octeon_gpio *gpio = dev_get_priv(dev);
+
+ debug("%s(%s, %u, %d)\n", __func__, dev->name, offset, value);
+ writeq(GPIO_BIT(offset), gpio->base + gpio->data->reg_offs +
+ gpio_tx_reg(offset, value));
+
+ clrsetbits_64(gpio->base + gpio->data->gpio_bit_cfg_offs + 8 * offset,
+ GPIO_BIT_CFG_PIN_SEL_MASK | GPIO_BIT_CFG_INT_EN,
+ GPIO_BIT_CFG_TX_OE);
+
+ return 0;
+}
+
+static int octeon_gpio_get_value(struct udevice *dev, unsigned int offset)
+{
+ struct octeon_gpio *gpio = dev_get_priv(dev);
+ u64 reg = readq(gpio->base + gpio->data->reg_offs +
+ gpio_rx_dat_reg(offset));
+
+ debug("%s(%s, %u): value: %d\n", __func__, dev->name, offset,
+ !!(reg & GPIO_BIT(offset)));
+
+ return !!(reg & GPIO_BIT(offset));
+}
+
+static int octeon_gpio_set_value(struct udevice *dev,
+ unsigned int offset, int value)
+{
+ struct octeon_gpio *gpio = dev_get_priv(dev);
+
+ debug("%s(%s, %u, %d)\n", __func__, dev->name, offset, value);
+ writeq(GPIO_BIT(offset), gpio->base + gpio->data->reg_offs +
+ gpio_tx_reg(offset, value));
+
+ return 0;
+}
+
+static int octeon_gpio_get_function(struct udevice *dev, unsigned int offset)
+{
+ struct octeon_gpio *gpio = dev_get_priv(dev);
+ u64 val = readq(gpio->base + gpio->data->gpio_bit_cfg_offs +
+ 8 * offset);
+ int pin_sel;
+
+ debug("%s(%s, %u): GPIO_BIT_CFG: 0x%llx\n", __func__, dev->name,
+ offset, val);
+ pin_sel = FIELD_GET(GPIO_BIT_CFG_PIN_SEL_MASK, val);
+ if (pin_sel)
+ return GPIOF_FUNC;
+ else if (val & GPIO_BIT_CFG_TX_OE)
+ return GPIOF_OUTPUT;
+ else
+ return GPIOF_INPUT;
+}
+
+static int octeon_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
+ struct ofnode_phandle_args *args)
+{
+ if (args->args_count < 1)
+ return -EINVAL;
+
+ desc->offset = args->args[0];
+ desc->flags = 0;
+ if (args->args_count > 1) {
+ if (args->args[1] & GPIO_ACTIVE_LOW)
+ desc->flags |= GPIOD_ACTIVE_LOW;
+ /* In the future add tri-state flag support */
+ }
+ return 0;
+}
+
+static const struct dm_gpio_ops octeon_gpio_ops = {
+ .direction_input = octeon_gpio_dir_input,
+ .direction_output = octeon_gpio_dir_output,
+ .get_value = octeon_gpio_get_value,
+ .set_value = octeon_gpio_set_value,
+ .get_function = octeon_gpio_get_function,
+ .xlate = octeon_gpio_xlate,
+};
+
+static int octeon_gpio_probe(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct octeon_gpio *priv = dev_get_priv(dev);
+ char *end;
+
+ priv->data = (const struct octeon_gpio_data *)dev_get_driver_data(dev);
+
+ if (priv->data->probe == PROBE_PCI) {
+ priv->base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
+ PCI_REGION_MEM);
+ uc_priv->gpio_count = readq(priv->base +
+ priv->data->reg_offs + GPIO_CONST) &
+ GPIO_CONST_GPIOS_MASK;
+ } else {
+ priv->base = dev_remap_addr(dev);
+ uc_priv->gpio_count = ofnode_read_u32_default(dev_ofnode(dev),
+ "nr-gpios", 32);
+ }
+
+ if (!priv->base) {
+ debug("%s(%s): Could not get base address\n",
+ __func__, dev->name);
+ return -ENODEV;
+ }
+
+ uc_priv->bank_name = strdup(dev->name);
+ end = strchr(uc_priv->bank_name, '@');
+ end[0] = 'A' + dev_seq(dev);
+ end[1] = '\0';
+
+ debug("%s(%s): base address: %p, pin count: %d\n",
+ __func__, dev->name, priv->base, uc_priv->gpio_count);
+
+ return 0;
+}
+
+static const struct octeon_gpio_data gpio_octeon_data = {
+ .probe = PROBE_DT,
+ .reg_offs = 0x80,
+ .gpio_bit_cfg_offs = 0x100,
+};
+
+static const struct octeon_gpio_data gpio_octeontx_data = {
+ .probe = PROBE_PCI,
+ .reg_offs = 0x00,
+ .gpio_bit_cfg_offs = 0x400,
+};
+
+static const struct udevice_id octeon_gpio_ids[] = {
+ { .compatible = "cavium,thunder-8890-gpio",
+ .data = (ulong)&gpio_octeontx_data },
+ { .compatible = "cavium,octeon-7890-gpio",
+ .data = (ulong)&gpio_octeon_data },
+ { }
+};
+
+U_BOOT_DRIVER(octeon_gpio) = {
+ .name = "octeon_gpio",
+ .id = UCLASS_GPIO,
+ .of_match = of_match_ptr(octeon_gpio_ids),
+ .probe = octeon_gpio_probe,
+ .priv_auto = sizeof(struct octeon_gpio),
+ .ops = &octeon_gpio_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/roms/u-boot/drivers/gpio/omap_gpio.c b/roms/u-boot/drivers/gpio/omap_gpio.c
new file mode 100644
index 000000000..316a28efa
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/omap_gpio.c
@@ -0,0 +1,381 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * This work is derived from the linux 2.6.27 kernel source
+ * To fetch, use the kernel repository
+ * git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
+ * Use the v2.6.27 tag.
+ *
+ * Below is the original's header including its copyright
+ *
+ * linux/arch/arm/plat-omap/gpio.c
+ *
+ * Support functions for OMAP GPIO
+ *
+ * Copyright (C) 2003-2005 Nokia Corporation
+ * Written by Juha Yrjölä <juha.yrjola@nokia.com>
+ */
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <asm/global_data.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <dm/device-internal.h>
+#include <linux/errno.h>
+#include <malloc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define OMAP_GPIO_DIR_OUT 0
+#define OMAP_GPIO_DIR_IN 1
+
+#if CONFIG_IS_ENABLED(DM_GPIO)
+
+#define GPIO_PER_BANK 32
+
+struct gpio_bank {
+ /* TODO(sjg@chromium.org): Can we use a struct here? */
+ void *base; /* address of registers in physical memory */
+};
+
+#endif
+
+int gpio_is_valid(int gpio)
+{
+ return (gpio >= 0) && (gpio < OMAP_MAX_GPIO);
+}
+
+static void _set_gpio_direction(const struct gpio_bank *bank, int gpio,
+ int is_input)
+{
+ void *reg = bank->base;
+ u32 l;
+
+ reg += OMAP_GPIO_OE;
+
+ l = __raw_readl(reg);
+ if (is_input)
+ l |= 1 << gpio;
+ else
+ l &= ~(1 << gpio);
+ __raw_writel(l, reg);
+}
+
+/**
+ * Get the direction of the GPIO by reading the GPIO_OE register
+ * corresponding to the specified bank.
+ */
+static int _get_gpio_direction(const struct gpio_bank *bank, int gpio)
+{
+ void *reg = bank->base;
+ u32 v;
+
+ reg += OMAP_GPIO_OE;
+
+ v = __raw_readl(reg);
+
+ if (v & (1 << gpio))
+ return OMAP_GPIO_DIR_IN;
+ else
+ return OMAP_GPIO_DIR_OUT;
+}
+
+static void _set_gpio_dataout(const struct gpio_bank *bank, int gpio,
+ int enable)
+{
+ void *reg = bank->base;
+ u32 l = 0;
+
+ if (enable)
+ reg += OMAP_GPIO_SETDATAOUT;
+ else
+ reg += OMAP_GPIO_CLEARDATAOUT;
+
+ l = 1 << gpio;
+ __raw_writel(l, reg);
+}
+
+static int _get_gpio_value(const struct gpio_bank *bank, int gpio)
+{
+ void *reg = bank->base;
+ int input;
+
+ input = _get_gpio_direction(bank, gpio);
+ switch (input) {
+ case OMAP_GPIO_DIR_IN:
+ reg += OMAP_GPIO_DATAIN;
+ break;
+ case OMAP_GPIO_DIR_OUT:
+ reg += OMAP_GPIO_DATAOUT;
+ break;
+ default:
+ return -1;
+ }
+
+ return (__raw_readl(reg) & (1 << gpio)) != 0;
+}
+
+#if !CONFIG_IS_ENABLED(DM_GPIO)
+static inline int get_gpio_index(int gpio)
+{
+ return gpio & 0x1f;
+}
+
+static inline const struct gpio_bank *get_gpio_bank(int gpio)
+{
+ return &omap_gpio_bank[gpio >> 5];
+}
+
+static int check_gpio(int gpio)
+{
+ if (!gpio_is_valid(gpio)) {
+ printf("ERROR : check_gpio: invalid GPIO %d\n", gpio);
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * Set value of the specified gpio
+ */
+int gpio_set_value(unsigned gpio, int value)
+{
+ const struct gpio_bank *bank;
+
+ if (check_gpio(gpio) < 0)
+ return -1;
+ bank = get_gpio_bank(gpio);
+ _set_gpio_dataout(bank, get_gpio_index(gpio), value);
+
+ return 0;
+}
+
+/**
+ * Get value of the specified gpio
+ */
+int gpio_get_value(unsigned gpio)
+{
+ const struct gpio_bank *bank;
+
+ if (check_gpio(gpio) < 0)
+ return -1;
+ bank = get_gpio_bank(gpio);
+
+ return _get_gpio_value(bank, get_gpio_index(gpio));
+}
+
+/**
+ * Set gpio direction as input
+ */
+int gpio_direction_input(unsigned gpio)
+{
+ const struct gpio_bank *bank;
+
+ if (check_gpio(gpio) < 0)
+ return -1;
+
+ bank = get_gpio_bank(gpio);
+ _set_gpio_direction(bank, get_gpio_index(gpio), 1);
+
+ return 0;
+}
+
+/**
+ * Set gpio direction as output
+ */
+int gpio_direction_output(unsigned gpio, int value)
+{
+ const struct gpio_bank *bank;
+
+ if (check_gpio(gpio) < 0)
+ return -1;
+
+ bank = get_gpio_bank(gpio);
+ _set_gpio_dataout(bank, get_gpio_index(gpio), value);
+ _set_gpio_direction(bank, get_gpio_index(gpio), 0);
+
+ return 0;
+}
+
+/**
+ * Request a gpio before using it.
+ *
+ * NOTE: Argument 'label' is unused.
+ */
+int gpio_request(unsigned gpio, const char *label)
+{
+ if (check_gpio(gpio) < 0)
+ return -1;
+
+ return 0;
+}
+
+/**
+ * Reset and free the gpio after using it.
+ */
+int gpio_free(unsigned gpio)
+{
+ return 0;
+}
+
+#else /* new driver model interface CONFIG_DM_GPIO */
+
+/* set GPIO pin 'gpio' as an input */
+static int omap_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+ struct gpio_bank *bank = dev_get_priv(dev);
+
+ /* Configure GPIO direction as input. */
+ _set_gpio_direction(bank, offset, 1);
+
+ return 0;
+}
+
+/* set GPIO pin 'gpio' as an output, with polarity 'value' */
+static int omap_gpio_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct gpio_bank *bank = dev_get_priv(dev);
+
+ _set_gpio_dataout(bank, offset, value);
+ _set_gpio_direction(bank, offset, 0);
+
+ return 0;
+}
+
+/* read GPIO IN value of pin 'gpio' */
+static int omap_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+ struct gpio_bank *bank = dev_get_priv(dev);
+
+ return _get_gpio_value(bank, offset);
+}
+
+/* write GPIO OUT value to pin 'gpio' */
+static int omap_gpio_set_value(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct gpio_bank *bank = dev_get_priv(dev);
+
+ _set_gpio_dataout(bank, offset, value);
+
+ return 0;
+}
+
+static int omap_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+ struct gpio_bank *bank = dev_get_priv(dev);
+
+ /* GPIOF_FUNC is not implemented yet */
+ if (_get_gpio_direction(bank, offset) == OMAP_GPIO_DIR_OUT)
+ return GPIOF_OUTPUT;
+ else
+ return GPIOF_INPUT;
+}
+
+static const struct dm_gpio_ops gpio_omap_ops = {
+ .direction_input = omap_gpio_direction_input,
+ .direction_output = omap_gpio_direction_output,
+ .get_value = omap_gpio_get_value,
+ .set_value = omap_gpio_set_value,
+ .get_function = omap_gpio_get_function,
+};
+
+static int omap_gpio_probe(struct udevice *dev)
+{
+ struct gpio_bank *bank = dev_get_priv(dev);
+ struct omap_gpio_plat *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ char name[18], *str;
+
+ sprintf(name, "gpio@%4x_", (unsigned int)plat->base);
+ str = strdup(name);
+ if (!str)
+ return -ENOMEM;
+ uc_priv->bank_name = str;
+ uc_priv->gpio_count = GPIO_PER_BANK;
+ bank->base = (void *)plat->base;
+ return 0;
+}
+
+#if !CONFIG_IS_ENABLED(OF_CONTROL)
+static int omap_gpio_bind(struct udevice *dev)
+{
+ struct omap_gpio_plat *plat = dev_get_plat(dev);
+ fdt_addr_t base_addr;
+
+ if (plat)
+ return 0;
+
+ base_addr = dev_read_addr(dev);
+ if (base_addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ /*
+ * TODO:
+ * When every board is converted to driver model and DT is
+ * supported, this can be done by auto-alloc feature, but
+ * not using calloc to alloc memory for plat.
+ *
+ * For example am33xx_gpio uses platform data rather than device tree.
+ *
+ * NOTE: DO NOT COPY this code if you are using device tree.
+ */
+ plat = calloc(1, sizeof(*plat));
+ if (!plat)
+ return -ENOMEM;
+
+ plat->base = base_addr;
+ plat->port_name = fdt_get_name(gd->fdt_blob, dev_of_offset(dev), NULL);
+ dev_set_plat(dev, plat);
+
+ return 0;
+}
+#endif
+
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+static const struct udevice_id omap_gpio_ids[] = {
+ { .compatible = "ti,omap3-gpio" },
+ { .compatible = "ti,omap4-gpio" },
+ { .compatible = "ti,am4372-gpio" },
+ { }
+};
+
+static int omap_gpio_of_to_plat(struct udevice *dev)
+{
+ struct omap_gpio_plat *plat = dev_get_plat(dev);
+ fdt_addr_t addr;
+
+ addr = dev_read_addr(dev);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ plat->base = addr;
+ return 0;
+}
+#endif
+
+U_BOOT_DRIVER(gpio_omap) = {
+ .name = "gpio_omap",
+ .id = UCLASS_GPIO,
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+ .of_match = omap_gpio_ids,
+ .of_to_plat = of_match_ptr(omap_gpio_of_to_plat),
+ .plat_auto = sizeof(struct omap_gpio_plat),
+#endif
+#else
+ .bind = omap_gpio_bind,
+#endif
+ .ops = &gpio_omap_ops,
+ .probe = omap_gpio_probe,
+ .priv_auto = sizeof(struct gpio_bank),
+#if !CONFIG_IS_ENABLED(OF_CONTROL)
+ .flags = DM_FLAG_PRE_RELOC,
+#endif
+};
+
+#endif /* !DM_GPIO */
diff --git a/roms/u-boot/drivers/gpio/pca953x.c b/roms/u-boot/drivers/gpio/pca953x.c
new file mode 100644
index 000000000..4ab8cee2d
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/pca953x.c
@@ -0,0 +1,295 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2008 Extreme Engineering Solutions, Inc.
+ */
+
+/*
+ * Driver for NXP's 4, 8 and 16 bit I2C gpio expanders (eg pca9537, pca9557,
+ * pca9539, etc)
+ */
+
+#include <common.h>
+#include <command.h>
+#include <i2c.h>
+#include <pca953x.h>
+
+/* Default to an address that hopefully won't corrupt other i2c devices */
+#ifndef CONFIG_SYS_I2C_PCA953X_ADDR
+#define CONFIG_SYS_I2C_PCA953X_ADDR (~0)
+#endif
+
+enum {
+ PCA953X_CMD_INFO,
+ PCA953X_CMD_DEVICE,
+ PCA953X_CMD_OUTPUT,
+ PCA953X_CMD_INPUT,
+ PCA953X_CMD_INVERT,
+};
+
+#ifdef CONFIG_SYS_I2C_PCA953X_WIDTH
+struct pca953x_chip_ngpio {
+ uint8_t chip;
+ uint8_t ngpio;
+};
+
+static struct pca953x_chip_ngpio pca953x_chip_ngpios[] =
+ CONFIG_SYS_I2C_PCA953X_WIDTH;
+
+/*
+ * Determine the number of GPIO pins supported. If we don't know we assume
+ * 8 pins.
+ */
+static int pca953x_ngpio(uint8_t chip)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pca953x_chip_ngpios); i++)
+ if (pca953x_chip_ngpios[i].chip == chip)
+ return pca953x_chip_ngpios[i].ngpio;
+
+ return 8;
+}
+#else
+static int pca953x_ngpio(uint8_t chip)
+{
+ return 8;
+}
+#endif
+
+/*
+ * Modify masked bits in register
+ */
+static int pca953x_reg_write(uint8_t chip, uint addr, uint mask, uint data)
+{
+ uint8_t valb;
+ uint16_t valw;
+
+ if (pca953x_ngpio(chip) <= 8) {
+ if (i2c_read(chip, addr, 1, &valb, 1))
+ return -1;
+
+ valb &= ~mask;
+ valb |= data;
+
+ return i2c_write(chip, addr, 1, &valb, 1);
+ } else {
+ if (i2c_read(chip, addr << 1, 1, (u8*)&valw, 2))
+ return -1;
+
+ valw = le16_to_cpu(valw);
+ valw &= ~mask;
+ valw |= data;
+ valw = cpu_to_le16(valw);
+
+ return i2c_write(chip, addr << 1, 1, (u8*)&valw, 2);
+ }
+}
+
+static int pca953x_reg_read(uint8_t chip, uint addr, uint *data)
+{
+ uint8_t valb;
+ uint16_t valw;
+
+ if (pca953x_ngpio(chip) <= 8) {
+ if (i2c_read(chip, addr, 1, &valb, 1))
+ return -1;
+ *data = (int)valb;
+ } else {
+ if (i2c_read(chip, addr << 1, 1, (u8*)&valw, 2))
+ return -1;
+ *data = (uint)le16_to_cpu(valw);
+ }
+ return 0;
+}
+
+/*
+ * Set output value of IO pins in 'mask' to corresponding value in 'data'
+ * 0 = low, 1 = high
+ */
+int pca953x_set_val(uint8_t chip, uint mask, uint data)
+{
+ return pca953x_reg_write(chip, PCA953X_OUT, mask, data);
+}
+
+/*
+ * Set read polarity of IO pins in 'mask' to corresponding value in 'data'
+ * 0 = read pin value, 1 = read inverted pin value
+ */
+int pca953x_set_pol(uint8_t chip, uint mask, uint data)
+{
+ return pca953x_reg_write(chip, PCA953X_POL, mask, data);
+}
+
+/*
+ * Set direction of IO pins in 'mask' to corresponding value in 'data'
+ * 0 = output, 1 = input
+ */
+int pca953x_set_dir(uint8_t chip, uint mask, uint data)
+{
+ return pca953x_reg_write(chip, PCA953X_CONF, mask, data);
+}
+
+/*
+ * Read current logic level of all IO pins
+ */
+int pca953x_get_val(uint8_t chip)
+{
+ uint val;
+
+ if (pca953x_reg_read(chip, PCA953X_IN, &val) < 0)
+ return -1;
+
+ return (int)val;
+}
+
+#if defined(CONFIG_CMD_PCA953X) && !defined(CONFIG_SPL_BUILD)
+/*
+ * Display pca953x information
+ */
+static int pca953x_info(uint8_t chip)
+{
+ int i;
+ uint data;
+ int nr_gpio = pca953x_ngpio(chip);
+ int msb = nr_gpio - 1;
+
+ printf("pca953x@ 0x%x (%d pins):\n\n", chip, nr_gpio);
+ printf("gpio pins: ");
+ for (i = msb; i >= 0; i--)
+ printf("%x", i);
+ printf("\n");
+ for (i = 11 + nr_gpio; i > 0; i--)
+ printf("-");
+ printf("\n");
+
+ if (pca953x_reg_read(chip, PCA953X_CONF, &data) < 0)
+ return -1;
+ printf("conf: ");
+ for (i = msb; i >= 0; i--)
+ printf("%c", data & (1 << i) ? 'i' : 'o');
+ printf("\n");
+
+ if (pca953x_reg_read(chip, PCA953X_POL, &data) < 0)
+ return -1;
+ printf("invert: ");
+ for (i = msb; i >= 0; i--)
+ printf("%c", data & (1 << i) ? '1' : '0');
+ printf("\n");
+
+ if (pca953x_reg_read(chip, PCA953X_IN, &data) < 0)
+ return -1;
+ printf("input: ");
+ for (i = msb; i >= 0; i--)
+ printf("%c", data & (1 << i) ? '1' : '0');
+ printf("\n");
+
+ if (pca953x_reg_read(chip, PCA953X_OUT, &data) < 0)
+ return -1;
+ printf("output: ");
+ for (i = msb; i >= 0; i--)
+ printf("%c", data & (1 << i) ? '1' : '0');
+ printf("\n");
+
+ return 0;
+}
+
+static struct cmd_tbl cmd_pca953x[] = {
+ U_BOOT_CMD_MKENT(device, 3, 0, (void *)PCA953X_CMD_DEVICE, "", ""),
+ U_BOOT_CMD_MKENT(output, 4, 0, (void *)PCA953X_CMD_OUTPUT, "", ""),
+ U_BOOT_CMD_MKENT(input, 3, 0, (void *)PCA953X_CMD_INPUT, "", ""),
+ U_BOOT_CMD_MKENT(invert, 4, 0, (void *)PCA953X_CMD_INVERT, "", ""),
+ U_BOOT_CMD_MKENT(info, 2, 0, (void *)PCA953X_CMD_INFO, "", ""),
+};
+
+static int do_pca953x(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ static uint8_t chip = CONFIG_SYS_I2C_PCA953X_ADDR;
+ int ret = CMD_RET_USAGE, val;
+ ulong ul_arg2 = 0;
+ ulong ul_arg3 = 0;
+ struct cmd_tbl *c;
+
+ c = find_cmd_tbl(argv[1], cmd_pca953x, ARRAY_SIZE(cmd_pca953x));
+
+ /* All commands but "device" require 'maxargs' arguments */
+ if (!c || !((argc == (c->maxargs)) ||
+ (((long)c->cmd == PCA953X_CMD_DEVICE) &&
+ (argc == (c->maxargs - 1))))) {
+ return CMD_RET_USAGE;
+ }
+
+ /* arg2 used as chip number or pin number */
+ if (argc > 2)
+ ul_arg2 = simple_strtoul(argv[2], NULL, 16);
+
+ /* arg3 used as pin or invert value */
+ if (argc > 3)
+ ul_arg3 = simple_strtoul(argv[3], NULL, 16) & 0x1;
+
+ switch ((long)c->cmd) {
+ case PCA953X_CMD_INFO:
+ ret = pca953x_info(chip);
+ if (ret)
+ ret = CMD_RET_FAILURE;
+ break;
+
+ case PCA953X_CMD_DEVICE:
+ if (argc == 3)
+ chip = (uint8_t)ul_arg2;
+ printf("Current device address: 0x%x\n", chip);
+ ret = CMD_RET_SUCCESS;
+ break;
+
+ case PCA953X_CMD_INPUT:
+ ret = pca953x_set_dir(chip, (1 << ul_arg2),
+ PCA953X_DIR_IN << ul_arg2);
+ val = (pca953x_get_val(chip) & (1 << ul_arg2)) != 0;
+
+ if (ret)
+ ret = CMD_RET_FAILURE;
+ else
+ printf("chip 0x%02x, pin 0x%lx = %d\n", chip, ul_arg2,
+ val);
+ break;
+
+ case PCA953X_CMD_OUTPUT:
+ ret = pca953x_set_dir(chip, (1 << ul_arg2),
+ (PCA953X_DIR_OUT << ul_arg2));
+ if (!ret)
+ ret = pca953x_set_val(chip, (1 << ul_arg2),
+ (ul_arg3 << ul_arg2));
+ if (ret)
+ ret = CMD_RET_FAILURE;
+ break;
+
+ case PCA953X_CMD_INVERT:
+ ret = pca953x_set_pol(chip, (1 << ul_arg2),
+ (ul_arg3 << ul_arg2));
+ if (ret)
+ ret = CMD_RET_FAILURE;
+ break;
+ }
+
+ if (ret == CMD_RET_FAILURE)
+ eprintf("Error talking to chip at 0x%x\n", chip);
+
+ return ret;
+}
+
+U_BOOT_CMD(
+ pca953x, 5, 1, do_pca953x,
+ "pca953x gpio access",
+ "device [dev]\n"
+ " - show or set current device address\n"
+ "pca953x info\n"
+ " - display info for current chip\n"
+ "pca953x output pin 0|1\n"
+ " - set pin as output and drive low or high\n"
+ "pca953x invert pin 0|1\n"
+ " - disable/enable polarity inversion for reads\n"
+ "pca953x input pin\n"
+ " - set pin as input and read value"
+);
+
+#endif /* CONFIG_CMD_PCA953X */
diff --git a/roms/u-boot/drivers/gpio/pca953x_gpio.c b/roms/u-boot/drivers/gpio/pca953x_gpio.c
new file mode 100644
index 000000000..dc8911a8e
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/pca953x_gpio.c
@@ -0,0 +1,390 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Take linux kernel driver drivers/gpio/gpio-pca953x.c for reference.
+ *
+ * Copyright (C) 2016 Peng Fan <van.freenix@gmail.com>
+ *
+ */
+
+/*
+ * Note:
+ * The driver's compatible table is borrowed from Linux Kernel,
+ * but now max supported gpio pins is 24 and only PCA953X_TYPE
+ * is supported. PCA957X_TYPE is not supported now.
+ * Also the Polarity Inversion feature is not supported now.
+ *
+ * TODO:
+ * 1. Support PCA957X_TYPE
+ * 2. Support Polarity Inversion
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <i2c.h>
+#include <malloc.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <linux/bitops.h>
+
+#define PCA953X_INPUT 0
+#define PCA953X_OUTPUT 1
+#define PCA953X_INVERT 2
+#define PCA953X_DIRECTION 3
+
+#define PCA_GPIO_MASK 0x00FF
+#define PCA_INT 0x0100
+#define PCA953X_TYPE 0x1000
+#define PCA957X_TYPE 0x2000
+#define PCA_TYPE_MASK 0xF000
+#define PCA_CHIP_TYPE(x) ((x) & PCA_TYPE_MASK)
+
+enum {
+ PCA953X_DIRECTION_IN,
+ PCA953X_DIRECTION_OUT,
+};
+
+#define MAX_BANK 5
+#define BANK_SZ 8
+
+/*
+ * struct pca953x_info - Data for pca953x
+ *
+ * @dev: udevice structure for the device
+ * @addr: i2c slave address
+ * @invert: Polarity inversion or not
+ * @gpio_count: the number of gpio pins that the device supports
+ * @chip_type: indicate the chip type,PCA953X or PCA957X
+ * @bank_count: the number of banks that the device supports
+ * @reg_output: array to hold the value of output registers
+ * @reg_direction: array to hold the value of direction registers
+ */
+struct pca953x_info {
+ struct udevice *dev;
+ int addr;
+ int invert;
+ int gpio_count;
+ int chip_type;
+ int bank_count;
+ u8 reg_output[MAX_BANK];
+ u8 reg_direction[MAX_BANK];
+};
+
+static int pca953x_write_single(struct udevice *dev, int reg, u8 val,
+ int offset)
+{
+ struct pca953x_info *info = dev_get_plat(dev);
+ int bank_shift = fls((info->gpio_count - 1) / BANK_SZ);
+ int off = offset / BANK_SZ;
+ int ret = 0;
+
+ ret = dm_i2c_write(dev, (reg << bank_shift) + off, &val, 1);
+ if (ret) {
+ dev_err(dev, "%s error\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int pca953x_read_single(struct udevice *dev, int reg, u8 *val,
+ int offset)
+{
+ struct pca953x_info *info = dev_get_plat(dev);
+ int bank_shift = fls((info->gpio_count - 1) / BANK_SZ);
+ int off = offset / BANK_SZ;
+ int ret;
+ u8 byte;
+
+ ret = dm_i2c_read(dev, (reg << bank_shift) + off, &byte, 1);
+ if (ret) {
+ dev_err(dev, "%s error\n", __func__);
+ return ret;
+ }
+
+ *val = byte;
+
+ return 0;
+}
+
+static int pca953x_read_regs(struct udevice *dev, int reg, u8 *val)
+{
+ struct pca953x_info *info = dev_get_plat(dev);
+ int ret = 0;
+
+ if (info->gpio_count <= 8) {
+ ret = dm_i2c_read(dev, reg, val, 1);
+ } else if (info->gpio_count <= 16) {
+ ret = dm_i2c_read(dev, reg << 1, val, info->bank_count);
+ } else if (info->gpio_count <= 24) {
+ /* Auto increment */
+ ret = dm_i2c_read(dev, (reg << 2) | 0x80, val,
+ info->bank_count);
+ } else if (info->gpio_count == 40) {
+ /* Auto increment */
+ ret = dm_i2c_read(dev, (reg << 3) | 0x80, val,
+ info->bank_count);
+ } else {
+ dev_err(dev, "Unsupported now\n");
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static int pca953x_write_regs(struct udevice *dev, int reg, u8 *val)
+{
+ struct pca953x_info *info = dev_get_plat(dev);
+ int ret = 0;
+
+ if (info->gpio_count <= 8) {
+ ret = dm_i2c_write(dev, reg, val, 1);
+ } else if (info->gpio_count <= 16) {
+ ret = dm_i2c_write(dev, reg << 1, val, info->bank_count);
+ } else if (info->gpio_count <= 24) {
+ /* Auto increment */
+ ret = dm_i2c_write(dev, (reg << 2) | 0x80, val,
+ info->bank_count);
+ } else if (info->gpio_count == 40) {
+ /* Auto increment */
+ ret = dm_i2c_write(dev, (reg << 3) | 0x80, val, info->bank_count);
+ } else {
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static int pca953x_is_output(struct udevice *dev, int offset)
+{
+ struct pca953x_info *info = dev_get_plat(dev);
+
+ int bank = offset / BANK_SZ;
+ int off = offset % BANK_SZ;
+
+ /*0: output; 1: input */
+ return !(info->reg_direction[bank] & (1 << off));
+}
+
+static int pca953x_get_value(struct udevice *dev, uint offset)
+{
+ int ret;
+ u8 val = 0;
+
+ int off = offset % BANK_SZ;
+
+ ret = pca953x_read_single(dev, PCA953X_INPUT, &val, offset);
+ if (ret)
+ return ret;
+
+ return (val >> off) & 0x1;
+}
+
+static int pca953x_set_value(struct udevice *dev, uint offset, int value)
+{
+ struct pca953x_info *info = dev_get_plat(dev);
+ int bank = offset / BANK_SZ;
+ int off = offset % BANK_SZ;
+ u8 val;
+ int ret;
+
+ if (value)
+ val = info->reg_output[bank] | (1 << off);
+ else
+ val = info->reg_output[bank] & ~(1 << off);
+
+ ret = pca953x_write_single(dev, PCA953X_OUTPUT, val, offset);
+ if (ret)
+ return ret;
+
+ info->reg_output[bank] = val;
+
+ return 0;
+}
+
+static int pca953x_set_direction(struct udevice *dev, uint offset, int dir)
+{
+ struct pca953x_info *info = dev_get_plat(dev);
+ int bank = offset / BANK_SZ;
+ int off = offset % BANK_SZ;
+ u8 val;
+ int ret;
+
+ if (dir == PCA953X_DIRECTION_IN)
+ val = info->reg_direction[bank] | (1 << off);
+ else
+ val = info->reg_direction[bank] & ~(1 << off);
+
+ ret = pca953x_write_single(dev, PCA953X_DIRECTION, val, offset);
+ if (ret)
+ return ret;
+
+ info->reg_direction[bank] = val;
+
+ return 0;
+}
+
+static int pca953x_direction_input(struct udevice *dev, uint offset)
+{
+ return pca953x_set_direction(dev, offset, PCA953X_DIRECTION_IN);
+}
+
+static int pca953x_direction_output(struct udevice *dev, uint offset, int value)
+{
+ /* Configure output value. */
+ pca953x_set_value(dev, offset, value);
+
+ /* Configure direction as output. */
+ pca953x_set_direction(dev, offset, PCA953X_DIRECTION_OUT);
+
+ return 0;
+}
+
+static int pca953x_get_function(struct udevice *dev, uint offset)
+{
+ if (pca953x_is_output(dev, offset))
+ return GPIOF_OUTPUT;
+ else
+ return GPIOF_INPUT;
+}
+
+static int pca953x_xlate(struct udevice *dev, struct gpio_desc *desc,
+ struct ofnode_phandle_args *args)
+{
+ desc->offset = args->args[0];
+ desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
+
+ return 0;
+}
+
+static const struct dm_gpio_ops pca953x_ops = {
+ .direction_input = pca953x_direction_input,
+ .direction_output = pca953x_direction_output,
+ .get_value = pca953x_get_value,
+ .set_value = pca953x_set_value,
+ .get_function = pca953x_get_function,
+ .xlate = pca953x_xlate,
+};
+
+static int pca953x_probe(struct udevice *dev)
+{
+ struct pca953x_info *info = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ char name[32], label[8], *str;
+ int addr;
+ ulong driver_data;
+ int ret;
+ int size;
+ const u8 *tmp;
+ u8 val[MAX_BANK];
+
+ addr = dev_read_addr(dev);
+ if (addr == 0)
+ return -ENODEV;
+
+ info->addr = addr;
+
+ driver_data = dev_get_driver_data(dev);
+
+ info->gpio_count = driver_data & PCA_GPIO_MASK;
+ if (info->gpio_count > MAX_BANK * BANK_SZ) {
+ dev_err(dev, "Max support %d pins now\n", MAX_BANK * BANK_SZ);
+ return -EINVAL;
+ }
+
+ info->chip_type = PCA_CHIP_TYPE(driver_data);
+ if (info->chip_type != PCA953X_TYPE) {
+ dev_err(dev, "Only support PCA953X chip type now.\n");
+ return -EINVAL;
+ }
+
+ info->bank_count = DIV_ROUND_UP(info->gpio_count, BANK_SZ);
+
+ ret = pca953x_read_regs(dev, PCA953X_OUTPUT, info->reg_output);
+ if (ret) {
+ dev_err(dev, "Error reading output register\n");
+ return ret;
+ }
+
+ ret = pca953x_read_regs(dev, PCA953X_DIRECTION, info->reg_direction);
+ if (ret) {
+ dev_err(dev, "Error reading direction register\n");
+ return ret;
+ }
+
+ tmp = dev_read_prop(dev, "label", &size);
+
+ if (tmp) {
+ memcpy(label, tmp, sizeof(label) - 1);
+ label[sizeof(label) - 1] = '\0';
+ snprintf(name, sizeof(name), "%s@%x_", label, info->addr);
+ } else {
+ snprintf(name, sizeof(name), "gpio@%x_", info->addr);
+ }
+
+ /* Clear the polarity registers to no invert */
+ memset(val, 0, MAX_BANK);
+ ret = pca953x_write_regs(dev, PCA953X_INVERT, val);
+ if (ret < 0) {
+ dev_err(dev, "Error writing invert register\n");
+ return ret;
+ }
+
+ str = strdup(name);
+ if (!str)
+ return -ENOMEM;
+ uc_priv->bank_name = str;
+ uc_priv->gpio_count = info->gpio_count;
+
+ dev_dbg(dev, "%s is ready\n", str);
+
+ return 0;
+}
+
+#define OF_953X(__nrgpio, __int) (ulong)(__nrgpio | PCA953X_TYPE | __int)
+#define OF_957X(__nrgpio, __int) (ulong)(__nrgpio | PCA957X_TYPE | __int)
+
+static const struct udevice_id pca953x_ids[] = {
+ { .compatible = "nxp,pca9505", .data = OF_953X(40, PCA_INT), },
+ { .compatible = "nxp,pca9534", .data = OF_953X(8, PCA_INT), },
+ { .compatible = "nxp,pca9535", .data = OF_953X(16, PCA_INT), },
+ { .compatible = "nxp,pca9536", .data = OF_953X(4, 0), },
+ { .compatible = "nxp,pca9537", .data = OF_953X(4, PCA_INT), },
+ { .compatible = "nxp,pca9538", .data = OF_953X(8, PCA_INT), },
+ { .compatible = "nxp,pca9539", .data = OF_953X(16, PCA_INT), },
+ { .compatible = "nxp,pca9554", .data = OF_953X(8, PCA_INT), },
+ { .compatible = "nxp,pca9555", .data = OF_953X(16, PCA_INT), },
+ { .compatible = "nxp,pca9556", .data = OF_953X(8, 0), },
+ { .compatible = "nxp,pca9557", .data = OF_953X(8, 0), },
+ { .compatible = "nxp,pca9574", .data = OF_957X(8, PCA_INT), },
+ { .compatible = "nxp,pca9575", .data = OF_957X(16, PCA_INT), },
+ { .compatible = "nxp,pca9698", .data = OF_953X(40, 0), },
+
+ { .compatible = "maxim,max7310", .data = OF_953X(8, 0), },
+ { .compatible = "maxim,max7312", .data = OF_953X(16, PCA_INT), },
+ { .compatible = "maxim,max7313", .data = OF_953X(16, PCA_INT), },
+ { .compatible = "maxim,max7315", .data = OF_953X(8, PCA_INT), },
+
+ { .compatible = "ti,pca6107", .data = OF_953X(8, PCA_INT), },
+ { .compatible = "ti,tca6408", .data = OF_953X(8, PCA_INT), },
+ { .compatible = "ti,tca6416", .data = OF_953X(16, PCA_INT), },
+ { .compatible = "ti,tca6424", .data = OF_953X(24, PCA_INT), },
+ { .compatible = "ti,tca9539", .data = OF_953X(16, PCA_INT), },
+
+ { .compatible = "onsemi,pca9654", .data = OF_953X(8, PCA_INT), },
+
+ { .compatible = "exar,xra1202", .data = OF_953X(8, 0), },
+ { }
+};
+
+U_BOOT_DRIVER(pca953x) = {
+ .name = "pca953x",
+ .id = UCLASS_GPIO,
+ .ops = &pca953x_ops,
+ .probe = pca953x_probe,
+ .plat_auto = sizeof(struct pca953x_info),
+ .of_match = pca953x_ids,
+};
diff --git a/roms/u-boot/drivers/gpio/pca9698.c b/roms/u-boot/drivers/gpio/pca9698.c
new file mode 100644
index 000000000..11274c781
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/pca9698.c
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2011
+ * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc
+ */
+
+/*
+ * Driver for NXP's pca9698 40 bit I2C gpio expander
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <malloc.h>
+#include <linux/errno.h>
+#include <pca9698.h>
+
+/*
+ * The pca9698 registers
+ */
+
+#define PCA9698_REG_INPUT 0x00
+#define PCA9698_REG_OUTPUT 0x08
+#define PCA9698_REG_POLARITY 0x10
+#define PCA9698_REG_CONFIG 0x18
+
+#define PCA9698_BUFFER_SIZE 5
+#define PCA9698_GPIO_COUNT 40
+
+static int pca9698_read40(u8 addr, u8 offset, u8 *buffer)
+{
+ u8 command = offset | 0x80; /* autoincrement */
+
+ return i2c_read(addr, command, 1, buffer, PCA9698_BUFFER_SIZE);
+}
+
+static int pca9698_write40(u8 addr, u8 offset, u8 *buffer)
+{
+ u8 command = offset | 0x80; /* autoincrement */
+
+ return i2c_write(addr, command, 1, buffer, PCA9698_BUFFER_SIZE);
+}
+
+static void pca9698_set_bit(unsigned gpio, u8 *buffer, unsigned value)
+{
+ unsigned byte = gpio / 8;
+ unsigned bit = gpio % 8;
+
+ if (value)
+ buffer[byte] |= (1 << bit);
+ else
+ buffer[byte] &= ~(1 << bit);
+}
+
+int pca9698_request(unsigned gpio, const char *label)
+{
+ if (gpio >= PCA9698_GPIO_COUNT)
+ return -EINVAL;
+
+ return 0;
+}
+
+void pca9698_free(unsigned gpio)
+{
+}
+
+int pca9698_direction_input(u8 addr, unsigned gpio)
+{
+ u8 data[PCA9698_BUFFER_SIZE];
+ int res;
+
+ res = pca9698_read40(addr, PCA9698_REG_CONFIG, data);
+ if (res)
+ return res;
+
+ pca9698_set_bit(gpio, data, 1);
+
+ return pca9698_write40(addr, PCA9698_REG_CONFIG, data);
+}
+
+int pca9698_direction_output(u8 addr, unsigned gpio, int value)
+{
+ u8 data[PCA9698_BUFFER_SIZE];
+ int res;
+
+ res = pca9698_set_value(addr, gpio, value);
+ if (res)
+ return res;
+
+ res = pca9698_read40(addr, PCA9698_REG_CONFIG, data);
+ if (res)
+ return res;
+
+ pca9698_set_bit(gpio, data, 0);
+
+ return pca9698_write40(addr, PCA9698_REG_CONFIG, data);
+}
+
+int pca9698_get_value(u8 addr, unsigned gpio)
+{
+ unsigned config_byte = gpio / 8;
+ unsigned config_bit = gpio % 8;
+ unsigned value;
+ u8 data[PCA9698_BUFFER_SIZE];
+ int res;
+
+ res = pca9698_read40(addr, PCA9698_REG_INPUT, data);
+ if (res)
+ return -1;
+
+ value = data[config_byte] & (1 << config_bit);
+
+ return !!value;
+}
+
+int pca9698_set_value(u8 addr, unsigned gpio, int value)
+{
+ u8 data[PCA9698_BUFFER_SIZE];
+ int res;
+
+ res = pca9698_read40(addr, PCA9698_REG_OUTPUT, data);
+ if (res)
+ return res;
+
+ pca9698_set_bit(gpio, data, value);
+
+ return pca9698_write40(addr, PCA9698_REG_OUTPUT, data);
+}
diff --git a/roms/u-boot/drivers/gpio/pcf8575_gpio.c b/roms/u-boot/drivers/gpio/pcf8575_gpio.c
new file mode 100644
index 000000000..359646266
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/pcf8575_gpio.c
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PCF8575 I2C GPIO EXPANDER DRIVER
+ *
+ * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * Vignesh R <vigneshr@ti.com>
+ *
+ *
+ * Driver for TI PCF-8575 16-bit I2C gpio expander. Based on
+ * gpio-pcf857x Linux Kernel(v4.7) driver.
+ *
+ * Copyright (C) 2007 David Brownell
+ *
+ */
+
+/*
+ * NOTE: The driver and devicetree bindings are borrowed from Linux
+ * Kernel, but driver does not support all PCF857x devices. It currently
+ * supports PCF8575 16-bit expander by TI and NXP.
+ *
+ * TODO(vigneshr@ti.com):
+ * Support 8 bit PCF857x compatible expanders.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <log.h>
+#include <asm-generic/gpio.h>
+#include <asm/global_data.h>
+#include <linux/bitops.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct pcf8575_chip {
+ int gpio_count; /* No. GPIOs supported by the chip */
+
+ /* NOTE: these chips have strange "quasi-bidirectional" I/O pins.
+ * We can't actually know whether a pin is configured (a) as output
+ * and driving the signal low, or (b) as input and reporting a low
+ * value ... without knowing the last value written since the chip
+ * came out of reset (if any). We can't read the latched output.
+ * In short, the only reliable solution for setting up pin direction
+ * is to do it explicitly.
+ *
+ * Using "out" avoids that trouble. When left initialized to zero,
+ * our software copy of the "latch" then matches the chip's all-ones
+ * reset state. Otherwise it flags pins to be driven low.
+ */
+ unsigned int out; /* software latch */
+ const char *bank_name; /* Name of the expander bank */
+};
+
+/* Read/Write to 16-bit I/O expander */
+
+static int pcf8575_i2c_write_le16(struct udevice *dev, unsigned int word)
+{
+ struct dm_i2c_chip *chip = dev_get_parent_plat(dev);
+ u8 buf[2] = { word & 0xff, word >> 8, };
+ int ret;
+
+ ret = dm_i2c_write(dev, 0, buf, 2);
+ if (ret)
+ printf("%s i2c write failed to addr %x\n", __func__,
+ chip->chip_addr);
+
+ return ret;
+}
+
+static int pcf8575_i2c_read_le16(struct udevice *dev)
+{
+ struct dm_i2c_chip *chip = dev_get_parent_plat(dev);
+ u8 buf[2];
+ int ret;
+
+ ret = dm_i2c_read(dev, 0, buf, 2);
+ if (ret) {
+ printf("%s i2c read failed from addr %x\n", __func__,
+ chip->chip_addr);
+ return ret;
+ }
+
+ return (buf[1] << 8) | buf[0];
+}
+
+static int pcf8575_direction_input(struct udevice *dev, unsigned offset)
+{
+ struct pcf8575_chip *plat = dev_get_plat(dev);
+ int status;
+
+ plat->out |= BIT(offset);
+ status = pcf8575_i2c_write_le16(dev, plat->out);
+
+ return status;
+}
+
+static int pcf8575_direction_output(struct udevice *dev,
+ unsigned int offset, int value)
+{
+ struct pcf8575_chip *plat = dev_get_plat(dev);
+ int ret;
+
+ if (value)
+ plat->out |= BIT(offset);
+ else
+ plat->out &= ~BIT(offset);
+
+ ret = pcf8575_i2c_write_le16(dev, plat->out);
+
+ return ret;
+}
+
+static int pcf8575_get_value(struct udevice *dev, unsigned int offset)
+{
+ int value;
+
+ value = pcf8575_i2c_read_le16(dev);
+
+ return (value < 0) ? value : ((value & BIT(offset)) >> offset);
+}
+
+static int pcf8575_set_value(struct udevice *dev, unsigned int offset,
+ int value)
+{
+ return pcf8575_direction_output(dev, offset, value);
+}
+
+static int pcf8575_ofdata_plat(struct udevice *dev)
+{
+ struct pcf8575_chip *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ int n_latch;
+
+ uc_priv->gpio_count = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
+ "gpio-count", 16);
+ uc_priv->bank_name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
+ "gpio-bank-name", NULL);
+ if (!uc_priv->bank_name)
+ uc_priv->bank_name = fdt_get_name(gd->fdt_blob,
+ dev_of_offset(dev), NULL);
+
+ n_latch = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
+ "lines-initial-states", 0);
+ plat->out = ~n_latch;
+
+ return 0;
+}
+
+static int pcf8575_gpio_probe(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ debug("%s GPIO controller with %d gpios probed\n",
+ uc_priv->bank_name, uc_priv->gpio_count);
+
+ return 0;
+}
+
+static const struct dm_gpio_ops pcf8575_gpio_ops = {
+ .direction_input = pcf8575_direction_input,
+ .direction_output = pcf8575_direction_output,
+ .get_value = pcf8575_get_value,
+ .set_value = pcf8575_set_value,
+};
+
+static const struct udevice_id pcf8575_gpio_ids[] = {
+ { .compatible = "nxp,pcf8575" },
+ { .compatible = "ti,pcf8575" },
+ { }
+};
+
+U_BOOT_DRIVER(gpio_pcf8575) = {
+ .name = "gpio_pcf8575",
+ .id = UCLASS_GPIO,
+ .ops = &pcf8575_gpio_ops,
+ .of_match = pcf8575_gpio_ids,
+ .of_to_plat = pcf8575_ofdata_plat,
+ .probe = pcf8575_gpio_probe,
+ .plat_auto = sizeof(struct pcf8575_chip),
+};
diff --git a/roms/u-boot/drivers/gpio/pic32_gpio.c b/roms/u-boot/drivers/gpio/pic32_gpio.c
new file mode 100644
index 000000000..975a2af3c
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/pic32_gpio.c
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2015 Microchip Technology Inc
+ * Purna Chandra Mandal <purna.mandal@microchip.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <malloc.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <linux/bitops.h>
+#include <linux/compat.h>
+#include <mach/pic32.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Peripheral Pin Control */
+struct pic32_reg_port {
+ struct pic32_reg_atomic ansel;
+ struct pic32_reg_atomic tris;
+ struct pic32_reg_atomic port;
+ struct pic32_reg_atomic lat;
+ struct pic32_reg_atomic open_drain;
+ struct pic32_reg_atomic cnpu;
+ struct pic32_reg_atomic cnpd;
+ struct pic32_reg_atomic cncon;
+};
+
+enum {
+ MICROCHIP_GPIO_DIR_OUT,
+ MICROCHIP_GPIO_DIR_IN,
+ MICROCHIP_GPIOS_PER_BANK = 16,
+};
+
+struct pic32_gpio_priv {
+ struct pic32_reg_port *regs;
+ char name[2];
+};
+
+static int pic32_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+ struct pic32_gpio_priv *priv = dev_get_priv(dev);
+
+ return !!(readl(&priv->regs->port.raw) & BIT(offset));
+}
+
+static int pic32_gpio_set_value(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct pic32_gpio_priv *priv = dev_get_priv(dev);
+ int mask = BIT(offset);
+
+ if (value)
+ writel(mask, &priv->regs->port.set);
+ else
+ writel(mask, &priv->regs->port.clr);
+
+ return 0;
+}
+
+static int pic32_gpio_direction(struct udevice *dev, unsigned offset)
+{
+ struct pic32_gpio_priv *priv = dev_get_priv(dev);
+
+ /* pin in analog mode ? */
+ if (readl(&priv->regs->ansel.raw) & BIT(offset))
+ return -EPERM;
+
+ if (readl(&priv->regs->tris.raw) & BIT(offset))
+ return MICROCHIP_GPIO_DIR_IN;
+ else
+ return MICROCHIP_GPIO_DIR_OUT;
+}
+
+static int pic32_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+ struct pic32_gpio_priv *priv = dev_get_priv(dev);
+ int mask = BIT(offset);
+
+ writel(mask, &priv->regs->ansel.clr);
+ writel(mask, &priv->regs->tris.set);
+
+ return 0;
+}
+
+static int pic32_gpio_direction_output(struct udevice *dev,
+ unsigned offset, int value)
+{
+ struct pic32_gpio_priv *priv = dev_get_priv(dev);
+ int mask = BIT(offset);
+
+ writel(mask, &priv->regs->ansel.clr);
+ writel(mask, &priv->regs->tris.clr);
+
+ pic32_gpio_set_value(dev, offset, value);
+ return 0;
+}
+
+static int pic32_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+ int ret = GPIOF_UNUSED;
+
+ switch (pic32_gpio_direction(dev, offset)) {
+ case MICROCHIP_GPIO_DIR_OUT:
+ ret = GPIOF_OUTPUT;
+ break;
+ case MICROCHIP_GPIO_DIR_IN:
+ ret = GPIOF_INPUT;
+ break;
+ default:
+ ret = GPIOF_UNUSED;
+ break;
+ }
+ return ret;
+}
+
+static const struct dm_gpio_ops gpio_pic32_ops = {
+ .direction_input = pic32_gpio_direction_input,
+ .direction_output = pic32_gpio_direction_output,
+ .get_value = pic32_gpio_get_value,
+ .set_value = pic32_gpio_set_value,
+ .get_function = pic32_gpio_get_function,
+};
+
+static int pic32_gpio_probe(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct pic32_gpio_priv *priv = dev_get_priv(dev);
+ fdt_addr_t addr;
+ fdt_size_t size;
+ char *end;
+ int bank;
+
+ addr = fdtdec_get_addr_size(gd->fdt_blob, dev_of_offset(dev), "reg",
+ &size);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ priv->regs = ioremap(addr, size);
+
+ uc_priv->gpio_count = MICROCHIP_GPIOS_PER_BANK;
+ /* extract bank name */
+ end = strrchr(dev->name, '@');
+ bank = trailing_strtoln(dev->name, end);
+ priv->name[0] = 'A' + bank;
+ uc_priv->bank_name = priv->name;
+
+ return 0;
+}
+
+static const struct udevice_id pic32_gpio_ids[] = {
+ { .compatible = "microchip,pic32mzda-gpio" },
+ { }
+};
+
+U_BOOT_DRIVER(gpio_pic32) = {
+ .name = "gpio_pic32",
+ .id = UCLASS_GPIO,
+ .of_match = pic32_gpio_ids,
+ .ops = &gpio_pic32_ops,
+ .probe = pic32_gpio_probe,
+ .priv_auto = sizeof(struct pic32_gpio_priv),
+};
diff --git a/roms/u-boot/drivers/gpio/pm8916_gpio.c b/roms/u-boot/drivers/gpio/pm8916_gpio.c
new file mode 100644
index 000000000..40b0f2578
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/pm8916_gpio.c
@@ -0,0 +1,301 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Qualcomm pm8916 pmic gpio driver - part of Qualcomm PM8916 PMIC
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <power/pmic.h>
+#include <spmi/spmi.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <linux/bitops.h>
+
+/* Register offset for each gpio */
+#define REG_OFFSET(x) ((x) * 0x100)
+
+/* Register maps */
+
+/* Type and subtype are shared for all pm8916 peripherals */
+#define REG_TYPE 0x4
+#define REG_SUBTYPE 0x5
+
+#define REG_STATUS 0x08
+#define REG_STATUS_VAL_MASK 0x1
+
+/* MODE_CTL */
+#define REG_CTL 0x40
+#define REG_CTL_MODE_MASK 0x70
+#define REG_CTL_MODE_INPUT 0x00
+#define REG_CTL_MODE_INOUT 0x20
+#define REG_CTL_MODE_OUTPUT 0x10
+#define REG_CTL_OUTPUT_MASK 0x0F
+
+#define REG_DIG_VIN_CTL 0x41
+#define REG_DIG_VIN_VIN0 0
+
+#define REG_DIG_PULL_CTL 0x42
+#define REG_DIG_PULL_NO_PU 0x5
+
+#define REG_DIG_OUT_CTL 0x45
+#define REG_DIG_OUT_CTL_CMOS (0x0 << 4)
+#define REG_DIG_OUT_CTL_DRIVE_L 0x1
+
+#define REG_EN_CTL 0x46
+#define REG_EN_CTL_ENABLE (1 << 7)
+
+struct pm8916_gpio_bank {
+ uint32_t pid; /* Peripheral ID on SPMI bus */
+};
+
+static int pm8916_gpio_set_direction(struct udevice *dev, unsigned offset,
+ bool input, int value)
+{
+ struct pm8916_gpio_bank *priv = dev_get_priv(dev);
+ uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
+ int ret;
+
+ /* Disable the GPIO */
+ ret = pmic_clrsetbits(dev->parent, gpio_base + REG_EN_CTL,
+ REG_EN_CTL_ENABLE, 0);
+ if (ret < 0)
+ return ret;
+
+ /* Select the mode */
+ if (input)
+ ret = pmic_reg_write(dev->parent, gpio_base + REG_CTL,
+ REG_CTL_MODE_INPUT);
+ else
+ ret = pmic_reg_write(dev->parent, gpio_base + REG_CTL,
+ REG_CTL_MODE_INOUT | (value ? 1 : 0));
+ if (ret < 0)
+ return ret;
+
+ /* Set the right pull (no pull) */
+ ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_PULL_CTL,
+ REG_DIG_PULL_NO_PU);
+ if (ret < 0)
+ return ret;
+
+ /* Configure output pin drivers if needed */
+ if (!input) {
+ /* Select the VIN - VIN0, pin is input so it doesn't matter */
+ ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_VIN_CTL,
+ REG_DIG_VIN_VIN0);
+ if (ret < 0)
+ return ret;
+
+ /* Set the right dig out control */
+ ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_OUT_CTL,
+ REG_DIG_OUT_CTL_CMOS |
+ REG_DIG_OUT_CTL_DRIVE_L);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* Enable the GPIO */
+ return pmic_clrsetbits(dev->parent, gpio_base + REG_EN_CTL, 0,
+ REG_EN_CTL_ENABLE);
+}
+
+static int pm8916_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+ return pm8916_gpio_set_direction(dev, offset, true, 0);
+}
+
+static int pm8916_gpio_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ return pm8916_gpio_set_direction(dev, offset, false, value);
+}
+
+static int pm8916_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+ struct pm8916_gpio_bank *priv = dev_get_priv(dev);
+ uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
+ int reg;
+
+ /* Set the output value of the gpio */
+ reg = pmic_reg_read(dev->parent, gpio_base + REG_CTL);
+ if (reg < 0)
+ return reg;
+
+ switch (reg & REG_CTL_MODE_MASK) {
+ case REG_CTL_MODE_INPUT:
+ return GPIOF_INPUT;
+ case REG_CTL_MODE_INOUT: /* Fallthrough */
+ case REG_CTL_MODE_OUTPUT:
+ return GPIOF_OUTPUT;
+ default:
+ return GPIOF_UNKNOWN;
+ }
+}
+
+static int pm8916_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+ struct pm8916_gpio_bank *priv = dev_get_priv(dev);
+ uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
+ int reg;
+
+ reg = pmic_reg_read(dev->parent, gpio_base + REG_STATUS);
+ if (reg < 0)
+ return reg;
+
+ return !!(reg & REG_STATUS_VAL_MASK);
+}
+
+static int pm8916_gpio_set_value(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct pm8916_gpio_bank *priv = dev_get_priv(dev);
+ uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
+
+ /* Set the output value of the gpio */
+ return pmic_clrsetbits(dev->parent, gpio_base + REG_CTL,
+ REG_CTL_OUTPUT_MASK, !!value);
+}
+
+static const struct dm_gpio_ops pm8916_gpio_ops = {
+ .direction_input = pm8916_gpio_direction_input,
+ .direction_output = pm8916_gpio_direction_output,
+ .get_value = pm8916_gpio_get_value,
+ .set_value = pm8916_gpio_set_value,
+ .get_function = pm8916_gpio_get_function,
+};
+
+static int pm8916_gpio_probe(struct udevice *dev)
+{
+ struct pm8916_gpio_bank *priv = dev_get_priv(dev);
+ int reg;
+
+ priv->pid = dev_read_addr(dev);
+ if (priv->pid == FDT_ADDR_T_NONE)
+ return log_msg_ret("bad address", -EINVAL);
+
+ /* Do a sanity check */
+ reg = pmic_reg_read(dev->parent, priv->pid + REG_TYPE);
+ if (reg != 0x10)
+ return log_msg_ret("bad type", -ENXIO);
+
+ reg = pmic_reg_read(dev->parent, priv->pid + REG_SUBTYPE);
+ if (reg != 0x5 && reg != 0x1)
+ return log_msg_ret("bad subtype", -ENXIO);
+
+ return 0;
+}
+
+static int pm8916_gpio_of_to_plat(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ uc_priv->gpio_count = dev_read_u32_default(dev, "gpio-count", 0);
+ uc_priv->bank_name = dev_read_string(dev, "gpio-bank-name");
+ if (uc_priv->bank_name == NULL)
+ uc_priv->bank_name = "pm8916";
+
+ return 0;
+}
+
+static const struct udevice_id pm8916_gpio_ids[] = {
+ { .compatible = "qcom,pm8916-gpio" },
+ { .compatible = "qcom,pm8994-gpio" }, /* 22 GPIO's */
+ { }
+};
+
+U_BOOT_DRIVER(gpio_pm8916) = {
+ .name = "gpio_pm8916",
+ .id = UCLASS_GPIO,
+ .of_match = pm8916_gpio_ids,
+ .of_to_plat = pm8916_gpio_of_to_plat,
+ .probe = pm8916_gpio_probe,
+ .ops = &pm8916_gpio_ops,
+ .priv_auto = sizeof(struct pm8916_gpio_bank),
+};
+
+
+/* Add pmic buttons as GPIO as well - there is no generic way for now */
+#define PON_INT_RT_STS 0x10
+#define KPDPWR_ON_INT_BIT 0
+#define RESIN_ON_INT_BIT 1
+
+static int pm8941_pwrkey_get_function(struct udevice *dev, unsigned offset)
+{
+ return GPIOF_INPUT;
+}
+
+static int pm8941_pwrkey_get_value(struct udevice *dev, unsigned offset)
+{
+ struct pm8916_gpio_bank *priv = dev_get_priv(dev);
+
+ int reg = pmic_reg_read(dev->parent, priv->pid + PON_INT_RT_STS);
+
+ if (reg < 0)
+ return 0;
+
+ switch (offset) {
+ case 0: /* Power button */
+ return (reg & BIT(KPDPWR_ON_INT_BIT)) != 0;
+ break;
+ case 1: /* Reset button */
+ default:
+ return (reg & BIT(RESIN_ON_INT_BIT)) != 0;
+ break;
+ }
+}
+
+static const struct dm_gpio_ops pm8941_pwrkey_ops = {
+ .get_value = pm8941_pwrkey_get_value,
+ .get_function = pm8941_pwrkey_get_function,
+};
+
+static int pm8941_pwrkey_probe(struct udevice *dev)
+{
+ struct pm8916_gpio_bank *priv = dev_get_priv(dev);
+ int reg;
+
+ priv->pid = dev_read_addr(dev);
+ if (priv->pid == FDT_ADDR_T_NONE)
+ return log_msg_ret("bad address", -EINVAL);
+
+ /* Do a sanity check */
+ reg = pmic_reg_read(dev->parent, priv->pid + REG_TYPE);
+ if (reg != 0x1)
+ return log_msg_ret("bad type", -ENXIO);
+
+ reg = pmic_reg_read(dev->parent, priv->pid + REG_SUBTYPE);
+ if (reg != 0x1)
+ return log_msg_ret("bad subtype", -ENXIO);
+
+ return 0;
+}
+
+static int pm8941_pwrkey_of_to_plat(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ uc_priv->gpio_count = 2;
+ uc_priv->bank_name = dev_read_string(dev, "gpio-bank-name");
+ if (uc_priv->bank_name == NULL)
+ uc_priv->bank_name = "pm8916_key";
+
+ return 0;
+}
+
+static const struct udevice_id pm8941_pwrkey_ids[] = {
+ { .compatible = "qcom,pm8916-pwrkey" },
+ { .compatible = "qcom,pm8994-pwrkey" },
+ { }
+};
+
+U_BOOT_DRIVER(pwrkey_pm8941) = {
+ .name = "pwrkey_pm8916",
+ .id = UCLASS_GPIO,
+ .of_match = pm8941_pwrkey_ids,
+ .of_to_plat = pm8941_pwrkey_of_to_plat,
+ .probe = pm8941_pwrkey_probe,
+ .ops = &pm8941_pwrkey_ops,
+ .priv_auto = sizeof(struct pm8916_gpio_bank),
+};
diff --git a/roms/u-boot/drivers/gpio/rk_gpio.c b/roms/u-boot/drivers/gpio/rk_gpio.c
new file mode 100644
index 000000000..68f30157a
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/rk_gpio.c
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2015 Google, Inc
+ *
+ * (C) Copyright 2008-2014 Rockchip Electronics
+ * Peter, Software Engineering, <superpeter.cai@gmail.com>.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <syscon.h>
+#include <linux/errno.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/gpio.h>
+#include <dm/pinctrl.h>
+#include <dt-bindings/clock/rk3288-cru.h>
+
+enum {
+ ROCKCHIP_GPIOS_PER_BANK = 32,
+};
+
+#define OFFSET_TO_BIT(bit) (1UL << (bit))
+
+struct rockchip_gpio_priv {
+ struct rockchip_gpio_regs *regs;
+ struct udevice *pinctrl;
+ int bank;
+ char name[2];
+};
+
+static int rockchip_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+ struct rockchip_gpio_priv *priv = dev_get_priv(dev);
+ struct rockchip_gpio_regs *regs = priv->regs;
+
+ clrbits_le32(&regs->swport_ddr, OFFSET_TO_BIT(offset));
+
+ return 0;
+}
+
+static int rockchip_gpio_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct rockchip_gpio_priv *priv = dev_get_priv(dev);
+ struct rockchip_gpio_regs *regs = priv->regs;
+ int mask = OFFSET_TO_BIT(offset);
+
+ clrsetbits_le32(&regs->swport_dr, mask, value ? mask : 0);
+ setbits_le32(&regs->swport_ddr, mask);
+
+ return 0;
+}
+
+static int rockchip_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+ struct rockchip_gpio_priv *priv = dev_get_priv(dev);
+ struct rockchip_gpio_regs *regs = priv->regs;
+
+ return readl(&regs->ext_port) & OFFSET_TO_BIT(offset) ? 1 : 0;
+}
+
+static int rockchip_gpio_set_value(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct rockchip_gpio_priv *priv = dev_get_priv(dev);
+ struct rockchip_gpio_regs *regs = priv->regs;
+ int mask = OFFSET_TO_BIT(offset);
+
+ clrsetbits_le32(&regs->swport_dr, mask, value ? mask : 0);
+
+ return 0;
+}
+
+static int rockchip_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+#ifdef CONFIG_SPL_BUILD
+ return -ENODATA;
+#else
+ struct rockchip_gpio_priv *priv = dev_get_priv(dev);
+ struct rockchip_gpio_regs *regs = priv->regs;
+ bool is_output;
+ int ret;
+
+ ret = pinctrl_get_gpio_mux(priv->pinctrl, priv->bank, offset);
+ if (ret)
+ return ret;
+ is_output = readl(&regs->swport_ddr) & OFFSET_TO_BIT(offset);
+
+ return is_output ? GPIOF_OUTPUT : GPIOF_INPUT;
+#endif
+}
+
+/* Simple SPL interface to GPIOs */
+#ifdef CONFIG_SPL_BUILD
+
+enum {
+ PULL_NONE_1V8 = 0,
+ PULL_DOWN_1V8 = 1,
+ PULL_UP_1V8 = 3,
+};
+
+int spl_gpio_set_pull(void *vregs, uint gpio, int pull)
+{
+ u32 *regs = vregs;
+ uint val;
+
+ regs += gpio >> GPIO_BANK_SHIFT;
+ gpio &= GPIO_OFFSET_MASK;
+ switch (pull) {
+ case GPIO_PULL_UP:
+ val = PULL_UP_1V8;
+ break;
+ case GPIO_PULL_DOWN:
+ val = PULL_DOWN_1V8;
+ break;
+ case GPIO_PULL_NORMAL:
+ default:
+ val = PULL_NONE_1V8;
+ break;
+ }
+ clrsetbits_le32(regs, 3 << (gpio * 2), val << (gpio * 2));
+
+ return 0;
+}
+
+int spl_gpio_output(void *vregs, uint gpio, int value)
+{
+ struct rockchip_gpio_regs * const regs = vregs;
+
+ clrsetbits_le32(&regs->swport_dr, 1 << gpio, value << gpio);
+
+ /* Set direction */
+ clrsetbits_le32(&regs->swport_ddr, 1 << gpio, 1 << gpio);
+
+ return 0;
+}
+#endif /* CONFIG_SPL_BUILD */
+
+static int rockchip_gpio_probe(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct rockchip_gpio_priv *priv = dev_get_priv(dev);
+ char *end;
+ int ret;
+
+ priv->regs = dev_read_addr_ptr(dev);
+ ret = uclass_first_device_err(UCLASS_PINCTRL, &priv->pinctrl);
+ if (ret)
+ return ret;
+
+ uc_priv->gpio_count = ROCKCHIP_GPIOS_PER_BANK;
+ end = strrchr(dev->name, '@');
+ priv->bank = trailing_strtoln(dev->name, end);
+ priv->name[0] = 'A' + priv->bank;
+ uc_priv->bank_name = priv->name;
+
+ return 0;
+}
+
+static const struct dm_gpio_ops gpio_rockchip_ops = {
+ .direction_input = rockchip_gpio_direction_input,
+ .direction_output = rockchip_gpio_direction_output,
+ .get_value = rockchip_gpio_get_value,
+ .set_value = rockchip_gpio_set_value,
+ .get_function = rockchip_gpio_get_function,
+};
+
+static const struct udevice_id rockchip_gpio_ids[] = {
+ { .compatible = "rockchip,gpio-bank" },
+ { }
+};
+
+U_BOOT_DRIVER(rockchip_gpio_bank) = {
+ .name = "rockchip_gpio_bank",
+ .id = UCLASS_GPIO,
+ .of_match = rockchip_gpio_ids,
+ .ops = &gpio_rockchip_ops,
+ .priv_auto = sizeof(struct rockchip_gpio_priv),
+ .probe = rockchip_gpio_probe,
+};
diff --git a/roms/u-boot/drivers/gpio/s5p_gpio.c b/roms/u-boot/drivers/gpio/s5p_gpio.c
new file mode 100644
index 000000000..76f35ac5d
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/s5p_gpio.c
@@ -0,0 +1,372 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2009 Samsung Electronics
+ * Minkyu Kang <mk7.kang@samsung.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <malloc.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <dm/device-internal.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define S5P_GPIO_GET_PIN(x) (x % GPIO_PER_BANK)
+
+#define CON_MASK(val) (0xf << ((val) << 2))
+#define CON_SFR(gpio, cfg) ((cfg) << ((gpio) << 2))
+#define CON_SFR_UNSHIFT(val, gpio) ((val) >> ((gpio) << 2))
+
+#define DAT_MASK(gpio) (0x1 << (gpio))
+#define DAT_SET(gpio) (0x1 << (gpio))
+
+#define PULL_MASK(gpio) (0x3 << ((gpio) << 1))
+#define PULL_MODE(gpio, pull) ((pull) << ((gpio) << 1))
+
+#define DRV_MASK(gpio) (0x3 << ((gpio) << 1))
+#define DRV_SET(gpio, mode) ((mode) << ((gpio) << 1))
+#define RATE_MASK(gpio) (0x1 << (gpio + 16))
+#define RATE_SET(gpio) (0x1 << (gpio + 16))
+
+/* Platform data for each bank */
+struct exynos_gpio_plat {
+ struct s5p_gpio_bank *bank;
+ const char *bank_name; /* Name of port, e.g. 'gpa0" */
+};
+
+/* Information about each bank at run-time */
+struct exynos_bank_info {
+ struct s5p_gpio_bank *bank;
+};
+
+static struct s5p_gpio_bank *s5p_gpio_get_bank(unsigned int gpio)
+{
+ const struct gpio_info *data;
+ unsigned int upto;
+ int i, count;
+
+ data = get_gpio_data();
+ count = get_bank_num();
+ upto = 0;
+
+ for (i = 0; i < count; i++) {
+ debug("i=%d, upto=%d\n", i, upto);
+ if (gpio < data->max_gpio) {
+ struct s5p_gpio_bank *bank;
+ bank = (struct s5p_gpio_bank *)data->reg_addr;
+ bank += (gpio - upto) / GPIO_PER_BANK;
+ debug("gpio=%d, bank=%p\n", gpio, bank);
+ return bank;
+ }
+
+ upto = data->max_gpio;
+ data++;
+ }
+
+ return NULL;
+}
+
+static void s5p_gpio_cfg_pin(struct s5p_gpio_bank *bank, int gpio, int cfg)
+{
+ unsigned int value;
+
+ value = readl(&bank->con);
+ value &= ~CON_MASK(gpio);
+ value |= CON_SFR(gpio, cfg);
+ writel(value, &bank->con);
+}
+
+static void s5p_gpio_set_value(struct s5p_gpio_bank *bank, int gpio, int en)
+{
+ unsigned int value;
+
+ value = readl(&bank->dat);
+ value &= ~DAT_MASK(gpio);
+ if (en)
+ value |= DAT_SET(gpio);
+ writel(value, &bank->dat);
+}
+
+#ifdef CONFIG_SPL_BUILD
+/* Common GPIO API - SPL does not support driver model yet */
+int gpio_set_value(unsigned gpio, int value)
+{
+ s5p_gpio_set_value(s5p_gpio_get_bank(gpio),
+ s5p_gpio_get_pin(gpio), value);
+
+ return 0;
+}
+#else
+static int s5p_gpio_get_cfg_pin(struct s5p_gpio_bank *bank, int gpio)
+{
+ unsigned int value;
+
+ value = readl(&bank->con);
+ value &= CON_MASK(gpio);
+ return CON_SFR_UNSHIFT(value, gpio);
+}
+
+static unsigned int s5p_gpio_get_value(struct s5p_gpio_bank *bank, int gpio)
+{
+ unsigned int value;
+
+ value = readl(&bank->dat);
+ return !!(value & DAT_MASK(gpio));
+}
+#endif /* CONFIG_SPL_BUILD */
+
+static void s5p_gpio_set_pull(struct s5p_gpio_bank *bank, int gpio, int mode)
+{
+ unsigned int value;
+
+ value = readl(&bank->pull);
+ value &= ~PULL_MASK(gpio);
+
+ switch (mode) {
+ case S5P_GPIO_PULL_DOWN:
+ case S5P_GPIO_PULL_UP:
+ value |= PULL_MODE(gpio, mode);
+ break;
+ default:
+ break;
+ }
+
+ writel(value, &bank->pull);
+}
+
+static void s5p_gpio_set_drv(struct s5p_gpio_bank *bank, int gpio, int mode)
+{
+ unsigned int value;
+
+ value = readl(&bank->drv);
+ value &= ~DRV_MASK(gpio);
+
+ switch (mode) {
+ case S5P_GPIO_DRV_1X:
+ case S5P_GPIO_DRV_2X:
+ case S5P_GPIO_DRV_3X:
+ case S5P_GPIO_DRV_4X:
+ value |= DRV_SET(gpio, mode);
+ break;
+ default:
+ return;
+ }
+
+ writel(value, &bank->drv);
+}
+
+static void s5p_gpio_set_rate(struct s5p_gpio_bank *bank, int gpio, int mode)
+{
+ unsigned int value;
+
+ value = readl(&bank->drv);
+ value &= ~RATE_MASK(gpio);
+
+ switch (mode) {
+ case S5P_GPIO_DRV_FAST:
+ case S5P_GPIO_DRV_SLOW:
+ value |= RATE_SET(gpio);
+ break;
+ default:
+ return;
+ }
+
+ writel(value, &bank->drv);
+}
+
+int s5p_gpio_get_pin(unsigned gpio)
+{
+ return S5P_GPIO_GET_PIN(gpio);
+}
+
+/* Driver model interface */
+#ifndef CONFIG_SPL_BUILD
+/* set GPIO pin 'gpio' as an input */
+static int exynos_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+ struct exynos_bank_info *state = dev_get_priv(dev);
+
+ /* Configure GPIO direction as input. */
+ s5p_gpio_cfg_pin(state->bank, offset, S5P_GPIO_INPUT);
+
+ return 0;
+}
+
+/* set GPIO pin 'gpio' as an output, with polarity 'value' */
+static int exynos_gpio_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct exynos_bank_info *state = dev_get_priv(dev);
+
+ /* Configure GPIO output value. */
+ s5p_gpio_set_value(state->bank, offset, value);
+
+ /* Configure GPIO direction as output. */
+ s5p_gpio_cfg_pin(state->bank, offset, S5P_GPIO_OUTPUT);
+
+ return 0;
+}
+
+/* read GPIO IN value of pin 'gpio' */
+static int exynos_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+ struct exynos_bank_info *state = dev_get_priv(dev);
+
+ return s5p_gpio_get_value(state->bank, offset);
+}
+
+/* write GPIO OUT value to pin 'gpio' */
+static int exynos_gpio_set_value(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct exynos_bank_info *state = dev_get_priv(dev);
+
+ s5p_gpio_set_value(state->bank, offset, value);
+
+ return 0;
+}
+#endif /* nCONFIG_SPL_BUILD */
+
+/*
+ * There is no common GPIO API for pull, drv, pin, rate (yet). These
+ * functions are kept here to preserve function ordering for review.
+ */
+void gpio_set_pull(int gpio, int mode)
+{
+ s5p_gpio_set_pull(s5p_gpio_get_bank(gpio),
+ s5p_gpio_get_pin(gpio), mode);
+}
+
+void gpio_set_drv(int gpio, int mode)
+{
+ s5p_gpio_set_drv(s5p_gpio_get_bank(gpio),
+ s5p_gpio_get_pin(gpio), mode);
+}
+
+void gpio_cfg_pin(int gpio, int cfg)
+{
+ s5p_gpio_cfg_pin(s5p_gpio_get_bank(gpio),
+ s5p_gpio_get_pin(gpio), cfg);
+}
+
+void gpio_set_rate(int gpio, int mode)
+{
+ s5p_gpio_set_rate(s5p_gpio_get_bank(gpio),
+ s5p_gpio_get_pin(gpio), mode);
+}
+
+#ifndef CONFIG_SPL_BUILD
+static int exynos_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+ struct exynos_bank_info *state = dev_get_priv(dev);
+ int cfg;
+
+ cfg = s5p_gpio_get_cfg_pin(state->bank, offset);
+ if (cfg == S5P_GPIO_OUTPUT)
+ return GPIOF_OUTPUT;
+ else if (cfg == S5P_GPIO_INPUT)
+ return GPIOF_INPUT;
+ else
+ return GPIOF_FUNC;
+}
+
+static const struct dm_gpio_ops gpio_exynos_ops = {
+ .direction_input = exynos_gpio_direction_input,
+ .direction_output = exynos_gpio_direction_output,
+ .get_value = exynos_gpio_get_value,
+ .set_value = exynos_gpio_set_value,
+ .get_function = exynos_gpio_get_function,
+};
+
+static int gpio_exynos_probe(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct exynos_bank_info *priv = dev_get_priv(dev);
+ struct exynos_gpio_plat *plat = dev_get_plat(dev);
+
+ /* Only child devices have ports */
+ if (!plat)
+ return 0;
+
+ priv->bank = plat->bank;
+
+ uc_priv->gpio_count = GPIO_PER_BANK;
+ uc_priv->bank_name = plat->bank_name;
+
+ return 0;
+}
+
+/**
+ * We have a top-level GPIO device with no actual GPIOs. It has a child
+ * device for each Exynos GPIO bank.
+ */
+static int gpio_exynos_bind(struct udevice *parent)
+{
+ struct exynos_gpio_plat *plat = dev_get_plat(parent);
+ struct s5p_gpio_bank *bank, *base;
+ const void *blob = gd->fdt_blob;
+ int node;
+
+ /* If this is a child device, there is nothing to do here */
+ if (plat)
+ return 0;
+
+ base = dev_read_addr_ptr(parent);
+ for (node = fdt_first_subnode(blob, dev_of_offset(parent)), bank = base;
+ node > 0;
+ node = fdt_next_subnode(blob, node), bank++) {
+ struct exynos_gpio_plat *plat;
+ struct udevice *dev;
+ fdt_addr_t reg;
+ int ret;
+
+ if (!fdtdec_get_bool(blob, node, "gpio-controller"))
+ continue;
+ plat = calloc(1, sizeof(*plat));
+ if (!plat)
+ return -ENOMEM;
+
+ plat->bank_name = fdt_get_name(blob, node, NULL);
+ ret = device_bind(parent, parent->driver, plat->bank_name, plat,
+ offset_to_ofnode(node), &dev);
+ if (ret)
+ return ret;
+
+ reg = dev_read_addr(dev);
+ if (reg != FDT_ADDR_T_NONE)
+ bank = (struct s5p_gpio_bank *)((ulong)base + reg);
+
+ plat->bank = bank;
+
+ debug("dev at %p: %s\n", bank, plat->bank_name);
+ }
+
+ return 0;
+}
+
+static const struct udevice_id exynos_gpio_ids[] = {
+ { .compatible = "samsung,s5pc100-pinctrl" },
+ { .compatible = "samsung,s5pc110-pinctrl" },
+ { .compatible = "samsung,exynos4210-pinctrl" },
+ { .compatible = "samsung,exynos4x12-pinctrl" },
+ { .compatible = "samsung,exynos5250-pinctrl" },
+ { .compatible = "samsung,exynos5420-pinctrl" },
+ { }
+};
+
+U_BOOT_DRIVER(gpio_exynos) = {
+ .name = "gpio_exynos",
+ .id = UCLASS_GPIO,
+ .of_match = exynos_gpio_ids,
+ .bind = gpio_exynos_bind,
+ .probe = gpio_exynos_probe,
+ .priv_auto = sizeof(struct exynos_bank_info),
+ .ops = &gpio_exynos_ops,
+};
+#endif
diff --git a/roms/u-boot/drivers/gpio/sandbox.c b/roms/u-boot/drivers/gpio/sandbox.c
new file mode 100644
index 000000000..d008fdd22
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/sandbox.c
@@ -0,0 +1,581 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <malloc.h>
+#include <acpi/acpi_device.h>
+#include <asm/gpio.h>
+#include <dm/acpi.h>
+#include <dm/device-internal.h>
+#include <dm/device_compat.h>
+#include <dm/lists.h>
+#include <dm/of.h>
+#include <dm/pinctrl.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/gpio/sandbox-gpio.h>
+
+struct gpio_state {
+ const char *label; /* label given by requester */
+ ulong flags; /* flags (GPIOD_...) */
+};
+
+/* Access routines for GPIO info */
+static struct gpio_state *get_gpio_state(struct udevice *dev, uint offset)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct gpio_state *state = dev_get_priv(dev);
+
+ if (offset >= uc_priv->gpio_count) {
+ printf("sandbox_gpio: error: invalid gpio %u\n", offset);
+ return NULL;
+ }
+
+ return &state[offset];
+}
+
+/* Access routines for GPIO flags */
+static ulong *get_gpio_flags(struct udevice *dev, unsigned int offset)
+{
+ struct gpio_state *state = get_gpio_state(dev, offset);
+
+ if (!state)
+ return NULL;
+
+ return &state->flags;
+
+}
+
+static int get_gpio_flag(struct udevice *dev, unsigned int offset, ulong flag)
+{
+ return (*get_gpio_flags(dev, offset) & flag) != 0;
+}
+
+static int set_gpio_flag(struct udevice *dev, unsigned int offset, ulong flag,
+ int value)
+{
+ struct gpio_state *state = get_gpio_state(dev, offset);
+
+ if (value)
+ state->flags |= flag;
+ else
+ state->flags &= ~flag;
+
+ return 0;
+}
+
+/*
+ * Back-channel sandbox-internal-only access to GPIO state
+ */
+
+int sandbox_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+ struct gpio_state *state = get_gpio_state(dev, offset);
+ bool val;
+
+ if (get_gpio_flag(dev, offset, GPIOD_IS_OUT))
+ debug("sandbox_gpio: get_value on output gpio %u\n", offset);
+
+ if (state->flags & GPIOD_EXT_DRIVEN) {
+ val = state->flags & GPIOD_EXT_HIGH;
+ } else {
+ if (state->flags & GPIOD_EXT_PULL_UP)
+ val = true;
+ else if (state->flags & GPIOD_EXT_PULL_DOWN)
+ val = false;
+ else
+ val = state->flags & GPIOD_PULL_UP;
+ }
+
+ return val;
+}
+
+int sandbox_gpio_set_value(struct udevice *dev, unsigned offset, int value)
+{
+ set_gpio_flag(dev, offset, GPIOD_EXT_DRIVEN | GPIOD_EXT_HIGH, value);
+
+ return 0;
+}
+
+int sandbox_gpio_get_direction(struct udevice *dev, unsigned offset)
+{
+ return get_gpio_flag(dev, offset, GPIOD_IS_OUT);
+}
+
+int sandbox_gpio_set_direction(struct udevice *dev, unsigned offset, int output)
+{
+ set_gpio_flag(dev, offset, GPIOD_IS_OUT, output);
+ set_gpio_flag(dev, offset, GPIOD_IS_IN, !output);
+
+ return 0;
+}
+
+ulong sandbox_gpio_get_flags(struct udevice *dev, uint offset)
+{
+ ulong flags = *get_gpio_flags(dev, offset);
+
+ return flags & ~GPIOD_SANDBOX_MASK;
+}
+
+int sandbox_gpio_set_flags(struct udevice *dev, uint offset, ulong flags)
+{
+ struct gpio_state *state = get_gpio_state(dev, offset);
+
+ state->flags = flags;
+
+ return 0;
+}
+
+/*
+ * These functions implement the public interface within U-Boot
+ */
+
+/* set GPIO port 'offset' as an input */
+static int sb_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+ debug("%s: offset:%u\n", __func__, offset);
+
+ return sandbox_gpio_set_direction(dev, offset, 0);
+}
+
+/* set GPIO port 'offset' as an output, with polarity 'value' */
+static int sb_gpio_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ int ret;
+
+ debug("%s: offset:%u, value = %d\n", __func__, offset, value);
+
+ ret = sandbox_gpio_set_direction(dev, offset, 1);
+ if (ret)
+ return ret;
+ ret = set_gpio_flag(dev, offset, GPIOD_IS_OUT_ACTIVE |
+ GPIOD_EXT_DRIVEN | GPIOD_EXT_HIGH, value);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+/* read GPIO IN value of port 'offset' */
+static int sb_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+ debug("%s: offset:%u\n", __func__, offset);
+
+ return sandbox_gpio_get_value(dev, offset);
+}
+
+/* write GPIO OUT value to port 'offset' */
+static int sb_gpio_set_value(struct udevice *dev, unsigned offset, int value)
+{
+ int ret;
+
+ debug("%s: offset:%u, value = %d\n", __func__, offset, value);
+
+ if (!sandbox_gpio_get_direction(dev, offset)) {
+ printf("sandbox_gpio: error: set_value on input gpio %u\n",
+ offset);
+ return -1;
+ }
+
+ ret = set_gpio_flag(dev, offset, GPIOD_IS_OUT_ACTIVE |
+ GPIOD_EXT_DRIVEN | GPIOD_EXT_HIGH, value);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int sb_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+ if (get_gpio_flag(dev, offset, GPIOD_IS_OUT))
+ return GPIOF_OUTPUT;
+ if (get_gpio_flag(dev, offset, GPIOD_IS_IN))
+ return GPIOF_INPUT;
+
+ return GPIOF_INPUT; /*GPIO is not configurated */
+}
+
+static int sb_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
+ struct ofnode_phandle_args *args)
+{
+ desc->offset = args->args[0];
+ if (args->args_count < 2)
+ return 0;
+ /* treat generic binding with gpio uclass */
+ gpio_xlate_offs_flags(dev, desc, args);
+
+ /* sandbox test specific, not defined in gpio.h */
+ if (args->args[1] & GPIO_IN)
+ desc->flags |= GPIOD_IS_IN;
+
+ if (args->args[1] & GPIO_OUT)
+ desc->flags |= GPIOD_IS_OUT;
+
+ if (args->args[1] & GPIO_OUT_ACTIVE)
+ desc->flags |= GPIOD_IS_OUT_ACTIVE;
+
+ return 0;
+}
+
+static int sb_gpio_set_flags(struct udevice *dev, unsigned int offset,
+ ulong flags)
+{
+ debug("%s: offset:%u, flags = %lx\n", __func__, offset, flags);
+ struct gpio_state *state = get_gpio_state(dev, offset);
+
+ if (flags & GPIOD_IS_OUT) {
+ flags |= GPIOD_EXT_DRIVEN;
+ if (flags & GPIOD_IS_OUT_ACTIVE)
+ flags |= GPIOD_EXT_HIGH;
+ else
+ flags &= ~GPIOD_EXT_HIGH;
+ } else {
+ flags |= state->flags & GPIOD_SANDBOX_MASK;
+ }
+ state->flags = flags;
+
+ return 0;
+}
+
+static int sb_gpio_get_flags(struct udevice *dev, uint offset, ulong *flagsp)
+{
+ debug("%s: offset:%u\n", __func__, offset);
+ *flagsp = *get_gpio_flags(dev, offset) & ~GPIOD_SANDBOX_MASK;
+
+ return 0;
+}
+
+#if CONFIG_IS_ENABLED(ACPIGEN)
+static int sb_gpio_get_acpi(const struct gpio_desc *desc,
+ struct acpi_gpio *gpio)
+{
+ int ret;
+
+ /* Note that gpio_get_acpi() zeroes *gpio before calling here */
+ gpio->pin_count = 1;
+ gpio->pins[0] = desc->offset;
+ ret = acpi_device_scope(desc->dev, gpio->resource,
+ sizeof(gpio->resource));
+ if (ret)
+ return log_ret(ret);
+
+ /* All of these values are just used for testing */
+ if (desc->flags & GPIOD_ACTIVE_LOW) {
+ gpio->pin0_addr = 0x80012 + desc->offset;
+ gpio->type = ACPI_GPIO_TYPE_INTERRUPT;
+ gpio->pull = ACPI_GPIO_PULL_DOWN;
+ gpio->interrupt_debounce_timeout = 4321;
+
+ /* We use the GpioInt part */
+ gpio->irq.pin = desc->offset;
+ gpio->irq.polarity = ACPI_IRQ_ACTIVE_BOTH;
+ gpio->irq.shared = ACPI_IRQ_SHARED;
+ gpio->irq.wake = ACPI_IRQ_WAKE;
+
+ /* The GpioIo part is only used for testing */
+ gpio->polarity = ACPI_GPIO_ACTIVE_LOW;
+ } else {
+ gpio->pin0_addr = 0xc00dc + desc->offset;
+ gpio->type = ACPI_GPIO_TYPE_IO;
+ gpio->pull = ACPI_GPIO_PULL_UP;
+ gpio->interrupt_debounce_timeout = 0;
+
+ /* The GpioInt part is not used */
+
+ /* We use the GpioIo part */
+ gpio->output_drive_strength = 1234;
+ gpio->io_shared = true;
+ gpio->io_restrict = ACPI_GPIO_IO_RESTRICT_INPUT;
+ gpio->polarity = 0;
+ }
+
+ return 0;
+}
+
+static int sb_gpio_get_name(const struct udevice *dev, char *out_name)
+{
+ return acpi_copy_name(out_name, "GPIO");
+}
+
+struct acpi_ops gpio_sandbox_acpi_ops = {
+ .get_name = sb_gpio_get_name,
+};
+#endif /* ACPIGEN */
+
+static const struct dm_gpio_ops gpio_sandbox_ops = {
+ .direction_input = sb_gpio_direction_input,
+ .direction_output = sb_gpio_direction_output,
+ .get_value = sb_gpio_get_value,
+ .set_value = sb_gpio_set_value,
+ .get_function = sb_gpio_get_function,
+ .xlate = sb_gpio_xlate,
+ .set_flags = sb_gpio_set_flags,
+ .get_flags = sb_gpio_get_flags,
+#if CONFIG_IS_ENABLED(ACPIGEN)
+ .get_acpi = sb_gpio_get_acpi,
+#endif
+};
+
+static int sandbox_gpio_of_to_plat(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ uc_priv->gpio_count = dev_read_u32_default(dev, "sandbox,gpio-count",
+ 0);
+ uc_priv->bank_name = dev_read_string(dev, "gpio-bank-name");
+
+ return 0;
+}
+
+static int gpio_sandbox_probe(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ if (!dev_has_ofnode(dev))
+ /* Tell the uclass how many GPIOs we have */
+ uc_priv->gpio_count = CONFIG_SANDBOX_GPIO_COUNT;
+
+ dev_set_priv(dev,
+ calloc(sizeof(struct gpio_state), uc_priv->gpio_count));
+
+ return 0;
+}
+
+static int gpio_sandbox_remove(struct udevice *dev)
+{
+ free(dev_get_priv(dev));
+
+ return 0;
+}
+
+static const struct udevice_id sandbox_gpio_ids[] = {
+ { .compatible = "sandbox,gpio" },
+ { }
+};
+
+U_BOOT_DRIVER(sandbox_gpio) = {
+ .name = "sandbox_gpio",
+ .id = UCLASS_GPIO,
+ .of_match = sandbox_gpio_ids,
+ .of_to_plat = sandbox_gpio_of_to_plat,
+ .probe = gpio_sandbox_probe,
+ .remove = gpio_sandbox_remove,
+ .ops = &gpio_sandbox_ops,
+ ACPI_OPS_PTR(&gpio_sandbox_acpi_ops)
+};
+
+DM_DRIVER_ALIAS(sandbox_gpio, sandbox_gpio_alias)
+
+/* pincontrol: used only to check GPIO pin configuration (pinmux command) */
+
+struct sb_pinctrl_priv {
+ int pinctrl_ngpios;
+ struct list_head gpio_dev;
+};
+
+struct sb_gpio_bank {
+ struct udevice *gpio_dev;
+ struct list_head list;
+};
+
+static int sb_populate_gpio_dev_list(struct udevice *dev)
+{
+ struct sb_pinctrl_priv *priv = dev_get_priv(dev);
+ struct udevice *gpio_dev;
+ struct udevice *child;
+ struct sb_gpio_bank *gpio_bank;
+ int ret;
+
+ /*
+ * parse pin-controller sub-nodes (ie gpio bank nodes) and fill
+ * a list with all gpio device reference which belongs to the
+ * current pin-controller. This list is used to find pin_name and
+ * pin muxing
+ */
+ list_for_each_entry(child, &dev->child_head, sibling_node) {
+ ret = uclass_get_device_by_name(UCLASS_GPIO, child->name,
+ &gpio_dev);
+ if (ret < 0)
+ continue;
+
+ gpio_bank = malloc(sizeof(*gpio_bank));
+ if (!gpio_bank) {
+ dev_err(dev, "Not enough memory\n");
+ return -ENOMEM;
+ }
+
+ gpio_bank->gpio_dev = gpio_dev;
+ list_add_tail(&gpio_bank->list, &priv->gpio_dev);
+ }
+
+ return 0;
+}
+
+static int sb_pinctrl_get_pins_count(struct udevice *dev)
+{
+ struct sb_pinctrl_priv *priv = dev_get_priv(dev);
+ struct gpio_dev_priv *uc_priv;
+ struct sb_gpio_bank *gpio_bank;
+
+ /*
+ * if get_pins_count has already been executed once on this
+ * pin-controller, no need to run it again
+ */
+ if (priv->pinctrl_ngpios)
+ return priv->pinctrl_ngpios;
+
+ if (list_empty(&priv->gpio_dev))
+ sb_populate_gpio_dev_list(dev);
+ /*
+ * walk through all banks to retrieve the pin-controller
+ * pins number
+ */
+ list_for_each_entry(gpio_bank, &priv->gpio_dev, list) {
+ uc_priv = dev_get_uclass_priv(gpio_bank->gpio_dev);
+
+ priv->pinctrl_ngpios += uc_priv->gpio_count;
+ }
+
+ return priv->pinctrl_ngpios;
+}
+
+static struct udevice *sb_pinctrl_get_gpio_dev(struct udevice *dev,
+ unsigned int selector,
+ unsigned int *idx)
+{
+ struct sb_pinctrl_priv *priv = dev_get_priv(dev);
+ struct sb_gpio_bank *gpio_bank;
+ struct gpio_dev_priv *uc_priv;
+ int pin_count = 0;
+
+ if (list_empty(&priv->gpio_dev))
+ sb_populate_gpio_dev_list(dev);
+
+ /* look up for the bank which owns the requested pin */
+ list_for_each_entry(gpio_bank, &priv->gpio_dev, list) {
+ uc_priv = dev_get_uclass_priv(gpio_bank->gpio_dev);
+
+ if (selector < (pin_count + uc_priv->gpio_count)) {
+ /*
+ * we found the bank, convert pin selector to
+ * gpio bank index
+ */
+ *idx = selector - pin_count;
+
+ return gpio_bank->gpio_dev;
+ }
+ pin_count += uc_priv->gpio_count;
+ }
+
+ return NULL;
+}
+
+static const char *sb_pinctrl_get_pin_name(struct udevice *dev,
+ unsigned int selector)
+{
+ struct gpio_dev_priv *uc_priv;
+ struct udevice *gpio_dev;
+ unsigned int gpio_idx;
+ static char pin_name[PINNAME_SIZE];
+
+ /* look up for the bank which owns the requested pin */
+ gpio_dev = sb_pinctrl_get_gpio_dev(dev, selector, &gpio_idx);
+ if (!gpio_dev) {
+ snprintf(pin_name, PINNAME_SIZE, "Error");
+ } else {
+ uc_priv = dev_get_uclass_priv(gpio_dev);
+
+ snprintf(pin_name, PINNAME_SIZE, "%s%d",
+ uc_priv->bank_name,
+ gpio_idx);
+ }
+
+ return pin_name;
+}
+
+static char *get_flags_string(ulong flags)
+{
+ if (flags & GPIOD_OPEN_DRAIN)
+ return "drive-open-drain";
+ if (flags & GPIOD_OPEN_SOURCE)
+ return "drive-open-source";
+ if (flags & GPIOD_PULL_UP)
+ return "bias-pull-up";
+ if (flags & GPIOD_PULL_DOWN)
+ return "bias-pull-down";
+ return ".";
+}
+
+static int sb_pinctrl_get_pin_muxing(struct udevice *dev,
+ unsigned int selector,
+ char *buf, int size)
+{
+ struct udevice *gpio_dev;
+ unsigned int gpio_idx;
+ ulong flags;
+ int function;
+
+ /* look up for the bank which owns the requested pin */
+ gpio_dev = sb_pinctrl_get_gpio_dev(dev, selector, &gpio_idx);
+ if (!gpio_dev) {
+ snprintf(buf, size, "Error");
+ } else {
+ function = sb_gpio_get_function(gpio_dev, gpio_idx);
+ flags = *get_gpio_flags(gpio_dev, gpio_idx);
+
+ snprintf(buf, size, "gpio %s %s",
+ function == GPIOF_OUTPUT ? "output" : "input",
+ get_flags_string(flags));
+ }
+
+ return 0;
+}
+
+#if CONFIG_IS_ENABLED(ACPIGEN)
+static int sb_pinctrl_get_name(const struct udevice *dev, char *out_name)
+{
+ return acpi_copy_name(out_name, "PINC");
+}
+#endif
+
+static int sandbox_pinctrl_probe(struct udevice *dev)
+{
+ struct sb_pinctrl_priv *priv = dev_get_priv(dev);
+
+ INIT_LIST_HEAD(&priv->gpio_dev);
+
+ return 0;
+}
+
+static struct pinctrl_ops sandbox_pinctrl_gpio_ops = {
+ .get_pin_name = sb_pinctrl_get_pin_name,
+ .get_pins_count = sb_pinctrl_get_pins_count,
+ .get_pin_muxing = sb_pinctrl_get_pin_muxing,
+};
+
+#if CONFIG_IS_ENABLED(ACPIGEN)
+struct acpi_ops pinctrl_sandbox_acpi_ops = {
+ .get_name = sb_pinctrl_get_name,
+};
+#endif
+
+static const struct udevice_id sandbox_pinctrl_gpio_match[] = {
+ { .compatible = "sandbox,pinctrl-gpio" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(sandbox_pinctrl_gpio) = {
+ .name = "sandbox_pinctrl_gpio",
+ .id = UCLASS_PINCTRL,
+ .of_match = sandbox_pinctrl_gpio_match,
+ .ops = &sandbox_pinctrl_gpio_ops,
+ .bind = dm_scan_fdt_dev,
+ .probe = sandbox_pinctrl_probe,
+ .priv_auto = sizeof(struct sb_pinctrl_priv),
+ ACPI_OPS_PTR(&pinctrl_sandbox_acpi_ops)
+};
diff --git a/roms/u-boot/drivers/gpio/sh_pfc.c b/roms/u-boot/drivers/gpio/sh_pfc.c
new file mode 100644
index 000000000..0653171af
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/sh_pfc.c
@@ -0,0 +1,639 @@
+/*
+ * Pinmuxed GPIO support for SuperH.
+ * Copy from linux kernel driver/sh/pfc.c
+ *
+ * Copyright (C) 2008 Magnus Damm
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <common.h>
+#include <log.h>
+#include <malloc.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <sh_pfc.h>
+#include <linux/bitops.h>
+#include <linux/bug.h>
+
+static struct pinmux_info *gpioc;
+
+#define pfc_phys_to_virt(p, a) ((void *)a)
+
+static int enum_in_range(pinmux_enum_t enum_id, struct pinmux_range *r)
+{
+ if (enum_id < r->begin)
+ return 0;
+
+ if (enum_id > r->end)
+ return 0;
+
+ return 1;
+}
+
+static unsigned long gpio_read_raw_reg(void *mapped_reg,
+ unsigned long reg_width)
+{
+ switch (reg_width) {
+
+ case 8:
+ return readb(mapped_reg);
+ case 16:
+ return readw(mapped_reg);
+ case 32:
+ return readl(mapped_reg);
+ }
+
+ BUG();
+ return 0;
+}
+
+static void gpio_write_raw_reg(void *mapped_reg,
+ unsigned long reg_width,
+ unsigned long data)
+{
+ switch (reg_width) {
+ case 8:
+ writeb(data, mapped_reg);
+ return;
+ case 16:
+ writew(data, mapped_reg);
+ return;
+ case 32:
+ writel(data, mapped_reg);
+ return;
+ }
+
+ BUG();
+}
+
+static int gpio_read_bit(struct pinmux_data_reg *dr,
+ unsigned long offset,
+ unsigned long in_pos)
+{
+ unsigned long pos;
+
+ pos = dr->reg_width - (in_pos + 1);
+
+ debug("read_bit: addr = %lx, pos = %ld, r_width = %ld\n",
+ dr->reg + offset, pos, dr->reg_width);
+
+ return (gpio_read_raw_reg(dr->mapped_reg + offset,
+ dr->reg_width) >> pos) & 1;
+}
+
+static void gpio_write_bit(struct pinmux_data_reg *dr,
+ unsigned long in_pos, unsigned long value)
+{
+ unsigned long pos;
+
+ pos = dr->reg_width - (in_pos + 1);
+
+ debug("write_bit addr = %lx, value = %d, pos = %ld, "
+ "r_width = %ld\n",
+ dr->reg, !!value, pos, dr->reg_width);
+
+ if (value)
+ __set_bit(pos, &dr->reg_shadow);
+ else
+ __clear_bit(pos, &dr->reg_shadow);
+
+ gpio_write_raw_reg(dr->mapped_reg, dr->reg_width, dr->reg_shadow);
+}
+
+static void config_reg_helper(struct pinmux_info *gpioc,
+ struct pinmux_cfg_reg *crp,
+ unsigned long in_pos,
+#if 0
+ void __iomem **mapped_regp,
+#else
+ void **mapped_regp,
+#endif
+ unsigned long *maskp,
+ unsigned long *posp)
+{
+ int k;
+
+ *mapped_regp = pfc_phys_to_virt(gpioc, crp->reg);
+
+ if (crp->field_width) {
+ *maskp = (1 << crp->field_width) - 1;
+ *posp = crp->reg_width - ((in_pos + 1) * crp->field_width);
+ } else {
+ *maskp = (1 << crp->var_field_width[in_pos]) - 1;
+ *posp = crp->reg_width;
+ for (k = 0; k <= in_pos; k++)
+ *posp -= crp->var_field_width[k];
+ }
+}
+
+static int read_config_reg(struct pinmux_info *gpioc,
+ struct pinmux_cfg_reg *crp,
+ unsigned long field)
+{
+ void *mapped_reg;
+
+ unsigned long mask, pos;
+
+ config_reg_helper(gpioc, crp, field, &mapped_reg, &mask, &pos);
+
+ debug("read_reg: addr = %lx, field = %ld, "
+ "r_width = %ld, f_width = %ld\n",
+ crp->reg, field, crp->reg_width, crp->field_width);
+
+ return (gpio_read_raw_reg(mapped_reg, crp->reg_width) >> pos) & mask;
+}
+
+static void write_config_reg(struct pinmux_info *gpioc,
+ struct pinmux_cfg_reg *crp,
+ unsigned long field, unsigned long value)
+{
+ void *mapped_reg;
+ unsigned long mask, pos, data;
+
+ config_reg_helper(gpioc, crp, field, &mapped_reg, &mask, &pos);
+
+ debug("write_reg addr = %lx, value = %ld, field = %ld, "
+ "r_width = %ld, f_width = %ld\n",
+ crp->reg, value, field, crp->reg_width, crp->field_width);
+
+ mask = ~(mask << pos);
+ value = value << pos;
+
+ data = gpio_read_raw_reg(mapped_reg, crp->reg_width);
+ data &= mask;
+ data |= value;
+
+ if (gpioc->unlock_reg)
+ gpio_write_raw_reg(pfc_phys_to_virt(gpioc, gpioc->unlock_reg),
+ 32, ~data);
+
+ gpio_write_raw_reg(mapped_reg, crp->reg_width, data);
+}
+
+static int setup_data_reg(struct pinmux_info *gpioc, unsigned gpio)
+{
+ struct pinmux_gpio *gpiop = &gpioc->gpios[gpio];
+ struct pinmux_data_reg *data_reg;
+ int k, n;
+
+ if (!enum_in_range(gpiop->enum_id, &gpioc->data))
+ return -1;
+
+ k = 0;
+ while (1) {
+ data_reg = gpioc->data_regs + k;
+
+ if (!data_reg->reg_width)
+ break;
+
+ data_reg->mapped_reg = pfc_phys_to_virt(gpioc, data_reg->reg);
+
+ for (n = 0; n < data_reg->reg_width; n++) {
+ if (data_reg->enum_ids[n] == gpiop->enum_id) {
+ gpiop->flags &= ~PINMUX_FLAG_DREG;
+ gpiop->flags |= (k << PINMUX_FLAG_DREG_SHIFT);
+ gpiop->flags &= ~PINMUX_FLAG_DBIT;
+ gpiop->flags |= (n << PINMUX_FLAG_DBIT_SHIFT);
+ return 0;
+ }
+ }
+ k++;
+ }
+
+ BUG();
+
+ return -1;
+}
+
+static void setup_data_regs(struct pinmux_info *gpioc)
+{
+ struct pinmux_data_reg *drp;
+ int k;
+
+ for (k = gpioc->first_gpio; k <= gpioc->last_gpio; k++)
+ setup_data_reg(gpioc, k);
+
+ k = 0;
+ while (1) {
+ drp = gpioc->data_regs + k;
+
+ if (!drp->reg_width)
+ break;
+
+ drp->reg_shadow = gpio_read_raw_reg(drp->mapped_reg,
+ drp->reg_width);
+ k++;
+ }
+}
+
+static int get_data_reg(struct pinmux_info *gpioc, unsigned gpio,
+ struct pinmux_data_reg **drp, int *bitp)
+{
+ struct pinmux_gpio *gpiop = &gpioc->gpios[gpio];
+ int k, n;
+
+ if (!enum_in_range(gpiop->enum_id, &gpioc->data))
+ return -1;
+
+ k = (gpiop->flags & PINMUX_FLAG_DREG) >> PINMUX_FLAG_DREG_SHIFT;
+ n = (gpiop->flags & PINMUX_FLAG_DBIT) >> PINMUX_FLAG_DBIT_SHIFT;
+ *drp = gpioc->data_regs + k;
+ *bitp = n;
+ return 0;
+}
+
+static int get_config_reg(struct pinmux_info *gpioc, pinmux_enum_t enum_id,
+ struct pinmux_cfg_reg **crp,
+ int *fieldp, int *valuep,
+ unsigned long **cntp)
+{
+ struct pinmux_cfg_reg *config_reg;
+ unsigned long r_width, f_width, curr_width, ncomb;
+ int k, m, n, pos, bit_pos;
+
+ k = 0;
+ while (1) {
+ config_reg = gpioc->cfg_regs + k;
+
+ r_width = config_reg->reg_width;
+ f_width = config_reg->field_width;
+
+ if (!r_width)
+ break;
+
+ pos = 0;
+ m = 0;
+ for (bit_pos = 0; bit_pos < r_width; bit_pos += curr_width) {
+ if (f_width)
+ curr_width = f_width;
+ else
+ curr_width = config_reg->var_field_width[m];
+
+ ncomb = 1 << curr_width;
+ for (n = 0; n < ncomb; n++) {
+ if (config_reg->enum_ids[pos + n] == enum_id) {
+ *crp = config_reg;
+ *fieldp = m;
+ *valuep = n;
+ *cntp = &config_reg->cnt[m];
+ return 0;
+ }
+ }
+ pos += ncomb;
+ m++;
+ }
+ k++;
+ }
+
+ return -1;
+}
+
+static int get_gpio_enum_id(struct pinmux_info *gpioc, unsigned gpio,
+ int pos, pinmux_enum_t *enum_idp)
+{
+ pinmux_enum_t enum_id = gpioc->gpios[gpio].enum_id;
+ pinmux_enum_t *data = gpioc->gpio_data;
+ int k;
+
+ if (!enum_in_range(enum_id, &gpioc->data)) {
+ if (!enum_in_range(enum_id, &gpioc->mark)) {
+ debug("non data/mark enum_id for gpio %d\n", gpio);
+ return -1;
+ }
+ }
+
+ if (pos) {
+ *enum_idp = data[pos + 1];
+ return pos + 1;
+ }
+
+ for (k = 0; k < gpioc->gpio_data_size; k++) {
+ if (data[k] == enum_id) {
+ *enum_idp = data[k + 1];
+ return k + 1;
+ }
+ }
+
+ debug("cannot locate data/mark enum_id for gpio %d\n", gpio);
+ return -1;
+}
+
+enum { GPIO_CFG_DRYRUN, GPIO_CFG_REQ, GPIO_CFG_FREE };
+
+static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio,
+ int pinmux_type, int cfg_mode)
+{
+ struct pinmux_cfg_reg *cr = NULL;
+ pinmux_enum_t enum_id;
+ struct pinmux_range *range;
+ int in_range, pos, field, value;
+ unsigned long *cntp;
+
+ switch (pinmux_type) {
+
+ case PINMUX_TYPE_FUNCTION:
+ range = NULL;
+ break;
+
+ case PINMUX_TYPE_OUTPUT:
+ range = &gpioc->output;
+ break;
+
+ case PINMUX_TYPE_INPUT:
+ range = &gpioc->input;
+ break;
+
+ case PINMUX_TYPE_INPUT_PULLUP:
+ range = &gpioc->input_pu;
+ break;
+
+ case PINMUX_TYPE_INPUT_PULLDOWN:
+ range = &gpioc->input_pd;
+ break;
+
+ default:
+ goto out_err;
+ }
+
+ pos = 0;
+ enum_id = 0;
+ field = 0;
+ value = 0;
+ while (1) {
+ pos = get_gpio_enum_id(gpioc, gpio, pos, &enum_id);
+ if (pos <= 0)
+ goto out_err;
+
+ if (!enum_id)
+ break;
+
+ /* first check if this is a function enum */
+ in_range = enum_in_range(enum_id, &gpioc->function);
+ if (!in_range) {
+ /* not a function enum */
+ if (range) {
+ /*
+ * other range exists, so this pin is
+ * a regular GPIO pin that now is being
+ * bound to a specific direction.
+ *
+ * for this case we only allow function enums
+ * and the enums that match the other range.
+ */
+ in_range = enum_in_range(enum_id, range);
+
+ /*
+ * special case pass through for fixed
+ * input-only or output-only pins without
+ * function enum register association.
+ */
+ if (in_range && enum_id == range->force)
+ continue;
+ } else {
+ /*
+ * no other range exists, so this pin
+ * must then be of the function type.
+ *
+ * allow function type pins to select
+ * any combination of function/in/out
+ * in their MARK lists.
+ */
+ in_range = 1;
+ }
+ }
+
+ if (!in_range)
+ continue;
+
+ if (get_config_reg(gpioc, enum_id, &cr,
+ &field, &value, &cntp) != 0)
+ goto out_err;
+
+ switch (cfg_mode) {
+ case GPIO_CFG_DRYRUN:
+ if (!*cntp ||
+ (read_config_reg(gpioc, cr, field) != value))
+ continue;
+ break;
+
+ case GPIO_CFG_REQ:
+ write_config_reg(gpioc, cr, field, value);
+ *cntp = *cntp + 1;
+ break;
+
+ case GPIO_CFG_FREE:
+ *cntp = *cntp - 1;
+ break;
+ }
+ }
+
+ return 0;
+ out_err:
+ return -1;
+}
+
+#if 0
+static DEFINE_SPINLOCK(gpio_lock);
+static struct pinmux_info *chip_to_pinmux(struct gpio_chip *chip)
+{
+ return container_of(chip, struct pinmux_info, chip);
+}
+#endif
+
+static int sh_gpio_request(unsigned offset)
+{
+ struct pinmux_data_reg *dummy;
+ int i, ret, pinmux_type;
+
+ ret = -1;
+
+ if (!gpioc)
+ goto err_out;
+
+ if ((gpioc->gpios[offset].flags & PINMUX_FLAG_TYPE) != PINMUX_TYPE_NONE)
+ goto err_out;
+
+ /* setup pin function here if no data is associated with pin */
+
+ if (get_data_reg(gpioc, offset, &dummy, &i) != 0)
+ pinmux_type = PINMUX_TYPE_FUNCTION;
+ else
+ pinmux_type = PINMUX_TYPE_GPIO;
+
+ if (pinmux_type == PINMUX_TYPE_FUNCTION) {
+ if (pinmux_config_gpio(gpioc, offset,
+ pinmux_type,
+ GPIO_CFG_DRYRUN) != 0)
+ goto err_out;
+
+ if (pinmux_config_gpio(gpioc, offset,
+ pinmux_type,
+ GPIO_CFG_REQ) != 0)
+ BUG();
+ }
+
+ gpioc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE;
+ gpioc->gpios[offset].flags |= pinmux_type;
+
+ ret = 0;
+err_out:
+ return ret;
+}
+
+static void sh_gpio_free(unsigned offset)
+{
+ int pinmux_type;
+
+ if (!gpioc)
+ return;
+
+ pinmux_type = gpioc->gpios[offset].flags & PINMUX_FLAG_TYPE;
+ pinmux_config_gpio(gpioc, offset, pinmux_type, GPIO_CFG_FREE);
+ gpioc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE;
+ gpioc->gpios[offset].flags |= PINMUX_TYPE_NONE;
+}
+
+static int pinmux_direction(struct pinmux_info *gpioc,
+ unsigned gpio, int new_pinmux_type)
+{
+ int pinmux_type;
+ int ret = -1;
+
+ if (!gpioc)
+ goto err_out;
+
+ pinmux_type = gpioc->gpios[gpio].flags & PINMUX_FLAG_TYPE;
+
+ switch (pinmux_type) {
+ case PINMUX_TYPE_GPIO:
+ break;
+ case PINMUX_TYPE_OUTPUT:
+ case PINMUX_TYPE_INPUT:
+ case PINMUX_TYPE_INPUT_PULLUP:
+ case PINMUX_TYPE_INPUT_PULLDOWN:
+ pinmux_config_gpio(gpioc, gpio, pinmux_type, GPIO_CFG_FREE);
+ break;
+ default:
+ goto err_out;
+ }
+
+ if (pinmux_config_gpio(gpioc, gpio,
+ new_pinmux_type,
+ GPIO_CFG_DRYRUN) != 0)
+ goto err_out;
+
+ if (pinmux_config_gpio(gpioc, gpio,
+ new_pinmux_type,
+ GPIO_CFG_REQ) != 0)
+ BUG();
+
+ gpioc->gpios[gpio].flags &= ~PINMUX_FLAG_TYPE;
+ gpioc->gpios[gpio].flags |= new_pinmux_type;
+
+ ret = 0;
+ err_out:
+ return ret;
+}
+
+static int sh_gpio_direction_input(unsigned offset)
+{
+ return pinmux_direction(gpioc, offset, PINMUX_TYPE_INPUT);
+}
+
+static void sh_gpio_set_value(struct pinmux_info *gpioc,
+ unsigned gpio, int value)
+{
+ struct pinmux_data_reg *dr = NULL;
+ int bit = 0;
+
+ if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0)
+ BUG();
+ else
+ gpio_write_bit(dr, bit, value);
+}
+
+static int sh_gpio_direction_output(unsigned offset, int value)
+{
+ sh_gpio_set_value(gpioc, offset, value);
+ return pinmux_direction(gpioc, offset, PINMUX_TYPE_OUTPUT);
+}
+
+static int sh_gpio_get_value(struct pinmux_info *gpioc, unsigned gpio)
+{
+ struct pinmux_data_reg *dr = NULL;
+ int bit = 0, offset = 0;
+
+ if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0)
+ return -1;
+#if defined(CONFIG_RCAR_GEN3)
+ if ((gpioc->gpios[gpio].flags & PINMUX_FLAG_TYPE) == PINMUX_TYPE_INPUT)
+ offset += 4;
+#endif
+
+ return gpio_read_bit(dr, offset, bit);
+}
+
+static int sh_gpio_get(unsigned offset)
+{
+ return sh_gpio_get_value(gpioc, offset);
+}
+
+static void sh_gpio_set(unsigned offset, int value)
+{
+ sh_gpio_set_value(gpioc, offset, value);
+}
+
+int register_pinmux(struct pinmux_info *pip)
+{
+ if (pip != NULL) {
+ gpioc = pip;
+ debug("%s deregistering\n", pip->name);
+ setup_data_regs(gpioc);
+ }
+ return 0;
+}
+
+int unregister_pinmux(struct pinmux_info *pip)
+{
+ debug("%s deregistering\n", pip->name);
+ if (gpioc != pip)
+ return -1;
+
+ gpioc = NULL;
+ return 0;
+}
+
+int gpio_request(unsigned gpio, const char *label)
+{
+ sh_gpio_request(gpio);
+ return 0;
+}
+
+int gpio_free(unsigned gpio)
+{
+ sh_gpio_free(gpio);
+ return 0;
+}
+
+int gpio_direction_input(unsigned gpio)
+{
+ return sh_gpio_direction_input(gpio);
+}
+
+int gpio_direction_output(unsigned gpio, int value)
+{
+ return sh_gpio_direction_output(gpio, value);
+}
+
+void gpio_set_value(unsigned gpio, int value)
+{
+ sh_gpio_set(gpio, value);
+}
+
+int gpio_get_value(unsigned gpio)
+{
+ return sh_gpio_get(gpio);
+}
diff --git a/roms/u-boot/drivers/gpio/sifive-gpio.c b/roms/u-boot/drivers/gpio/sifive-gpio.c
new file mode 100644
index 000000000..abd1f629b
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/sifive-gpio.c
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * SiFive GPIO driver
+ *
+ * Copyright (C) 2019 SiFive, Inc.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <asm/arch/gpio.h>
+#include <asm/io.h>
+#include <errno.h>
+#include <asm/gpio.h>
+#include <linux/bitops.h>
+
+static int sifive_gpio_probe(struct udevice *dev)
+{
+ struct sifive_gpio_plat *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ char name[18], *str;
+
+ sprintf(name, "gpio@%4lx_", (uintptr_t)plat->base);
+ str = strdup(name);
+ if (!str)
+ return -ENOMEM;
+ uc_priv->bank_name = str;
+
+ /*
+ * Use the gpio count mentioned in device tree,
+ * if not specified in dt, set NR_GPIOS as default
+ */
+ uc_priv->gpio_count = dev_read_u32_default(dev, "ngpios", NR_GPIOS);
+
+ return 0;
+}
+
+static void sifive_update_gpio_reg(void *bptr, u32 offset, bool value)
+{
+ void __iomem *ptr = (void __iomem *)bptr;
+
+ u32 bit = BIT(offset);
+ u32 old = readl(ptr);
+
+ if (value)
+ writel(old | bit, ptr);
+ else
+ writel(old & ~bit, ptr);
+}
+
+static int sifive_gpio_direction_input(struct udevice *dev, u32 offset)
+{
+ struct sifive_gpio_plat *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ if (offset > uc_priv->gpio_count)
+ return -EINVAL;
+
+ /* Configure gpio direction as input */
+ sifive_update_gpio_reg(plat->base + GPIO_INPUT_EN, offset, true);
+ sifive_update_gpio_reg(plat->base + GPIO_OUTPUT_EN, offset, false);
+
+ return 0;
+}
+
+static int sifive_gpio_direction_output(struct udevice *dev, u32 offset,
+ int value)
+{
+ struct sifive_gpio_plat *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ if (offset > uc_priv->gpio_count)
+ return -EINVAL;
+
+ /* Configure gpio direction as output */
+ sifive_update_gpio_reg(plat->base + GPIO_OUTPUT_EN, offset, true);
+ sifive_update_gpio_reg(plat->base + GPIO_INPUT_EN, offset, false);
+
+ /* Set the output state of the pin */
+ sifive_update_gpio_reg(plat->base + GPIO_OUTPUT_VAL, offset, value);
+
+ return 0;
+}
+
+static int sifive_gpio_get_value(struct udevice *dev, u32 offset)
+{
+ struct sifive_gpio_plat *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ int val;
+ int dir;
+
+ if (offset > uc_priv->gpio_count)
+ return -EINVAL;
+
+ /* Get direction of the pin */
+ dir = !(readl(plat->base + GPIO_OUTPUT_EN) & BIT(offset));
+
+ if (dir)
+ val = readl(plat->base + GPIO_INPUT_VAL) & BIT(offset);
+ else
+ val = readl(plat->base + GPIO_OUTPUT_VAL) & BIT(offset);
+
+ return val ? HIGH : LOW;
+}
+
+static int sifive_gpio_set_value(struct udevice *dev, u32 offset, int value)
+{
+ struct sifive_gpio_plat *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ if (offset > uc_priv->gpio_count)
+ return -EINVAL;
+
+ sifive_update_gpio_reg(plat->base + GPIO_OUTPUT_VAL, offset, value);
+
+ return 0;
+}
+
+static int sifive_gpio_get_function(struct udevice *dev, unsigned int offset)
+{
+ struct sifive_gpio_plat *plat = dev_get_plat(dev);
+ u32 outdir, indir, val;
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ if (offset > uc_priv->gpio_count)
+ return -1;
+
+ /* Get direction of the pin */
+ outdir = readl(plat->base + GPIO_OUTPUT_EN) & BIT(offset);
+ indir = readl(plat->base + GPIO_INPUT_EN) & BIT(offset);
+
+ if (outdir)
+ /* Pin at specified offset is configured as output */
+ val = GPIOF_OUTPUT;
+ else if (indir)
+ /* Pin at specified offset is configured as input */
+ val = GPIOF_INPUT;
+ else
+ /*The requested GPIO is not set as input or output */
+ val = GPIOF_UNUSED;
+
+ return val;
+}
+
+static const struct udevice_id sifive_gpio_match[] = {
+ { .compatible = "sifive,gpio0" },
+ { }
+};
+
+static const struct dm_gpio_ops sifive_gpio_ops = {
+ .direction_input = sifive_gpio_direction_input,
+ .direction_output = sifive_gpio_direction_output,
+ .get_value = sifive_gpio_get_value,
+ .set_value = sifive_gpio_set_value,
+ .get_function = sifive_gpio_get_function,
+};
+
+static int sifive_gpio_of_to_plat(struct udevice *dev)
+{
+ struct sifive_gpio_plat *plat = dev_get_plat(dev);
+ fdt_addr_t addr;
+
+ addr = dev_read_addr(dev);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ plat->base = (void *)addr;
+ return 0;
+}
+
+U_BOOT_DRIVER(gpio_sifive) = {
+ .name = "gpio_sifive",
+ .id = UCLASS_GPIO,
+ .of_match = sifive_gpio_match,
+ .of_to_plat = of_match_ptr(sifive_gpio_of_to_plat),
+ .plat_auto = sizeof(struct sifive_gpio_plat),
+ .ops = &sifive_gpio_ops,
+ .probe = sifive_gpio_probe,
+};
diff --git a/roms/u-boot/drivers/gpio/spear_gpio.c b/roms/u-boot/drivers/gpio/spear_gpio.c
new file mode 100644
index 000000000..4e4cd1254
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/spear_gpio.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2012 Stefan Roese <sr@denx.de>
+ */
+
+/*
+ * Driver for SPEAr600 GPIO controller
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <asm/arch/hardware.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <errno.h>
+
+static int gpio_direction(unsigned gpio,
+ enum gpio_direction direction)
+{
+ struct gpio_regs *regs = (struct gpio_regs *)CONFIG_GPIO_BASE;
+ u32 val;
+
+ val = readl(&regs->gpiodir);
+
+ if (direction == GPIO_DIRECTION_OUT)
+ val |= 1 << gpio;
+ else
+ val &= ~(1 << gpio);
+
+ writel(val, &regs->gpiodir);
+
+ return 0;
+}
+
+int gpio_set_value(unsigned gpio, int value)
+{
+ struct gpio_regs *regs = (struct gpio_regs *)CONFIG_GPIO_BASE;
+
+ if (value)
+ writel(1 << gpio, &regs->gpiodata[DATA_REG_ADDR(gpio)]);
+ else
+ writel(0, &regs->gpiodata[DATA_REG_ADDR(gpio)]);
+
+ return 0;
+}
+
+int gpio_get_value(unsigned gpio)
+{
+ struct gpio_regs *regs = (struct gpio_regs *)CONFIG_GPIO_BASE;
+ u32 val;
+
+ val = readl(&regs->gpiodata[DATA_REG_ADDR(gpio)]);
+
+ return !!val;
+}
+
+int gpio_request(unsigned gpio, const char *label)
+{
+ if (gpio >= SPEAR_GPIO_COUNT)
+ return -EINVAL;
+
+ return 0;
+}
+
+int gpio_free(unsigned gpio)
+{
+ return 0;
+}
+
+void gpio_toggle_value(unsigned gpio)
+{
+ gpio_set_value(gpio, !gpio_get_value(gpio));
+}
+
+int gpio_direction_input(unsigned gpio)
+{
+ return gpio_direction(gpio, GPIO_DIRECTION_IN);
+}
+
+int gpio_direction_output(unsigned gpio, int value)
+{
+ int ret = gpio_direction(gpio, GPIO_DIRECTION_OUT);
+
+ if (ret < 0)
+ return ret;
+
+ gpio_set_value(gpio, value);
+ return 0;
+}
diff --git a/roms/u-boot/drivers/gpio/stm32_gpio.c b/roms/u-boot/drivers/gpio/stm32_gpio.c
new file mode 100644
index 000000000..125c23755
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/stm32_gpio.c
@@ -0,0 +1,349 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
+ * Author(s): Vikas Manocha, <vikas.manocha@st.com> for STMicroelectronics.
+ */
+
+#define LOG_CATEGORY UCLASS_GPIO
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/stm32.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+
+#define STM32_GPIOS_PER_BANK 16
+
+#define MODE_BITS(gpio_pin) ((gpio_pin) * 2)
+#define MODE_BITS_MASK 3
+#define BSRR_BIT(gpio_pin, value) BIT((gpio_pin) + (value ? 0 : 16))
+
+#define PUPD_BITS(gpio_pin) ((gpio_pin) * 2)
+#define PUPD_MASK 3
+
+#define OTYPE_BITS(gpio_pin) (gpio_pin)
+#define OTYPE_MSK 1
+
+static void stm32_gpio_set_moder(struct stm32_gpio_regs *regs,
+ int idx,
+ int mode)
+{
+ int bits_index;
+ int mask;
+
+ bits_index = MODE_BITS(idx);
+ mask = MODE_BITS_MASK << bits_index;
+
+ clrsetbits_le32(&regs->moder, mask, mode << bits_index);
+}
+
+static int stm32_gpio_get_moder(struct stm32_gpio_regs *regs, int idx)
+{
+ return (readl(&regs->moder) >> MODE_BITS(idx)) & MODE_BITS_MASK;
+}
+
+static void stm32_gpio_set_otype(struct stm32_gpio_regs *regs,
+ int idx,
+ enum stm32_gpio_otype otype)
+{
+ int bits;
+
+ bits = OTYPE_BITS(idx);
+ clrsetbits_le32(&regs->otyper, OTYPE_MSK << bits, otype << bits);
+}
+
+static enum stm32_gpio_otype stm32_gpio_get_otype(struct stm32_gpio_regs *regs,
+ int idx)
+{
+ return (readl(&regs->otyper) >> OTYPE_BITS(idx)) & OTYPE_MSK;
+}
+
+static void stm32_gpio_set_pupd(struct stm32_gpio_regs *regs,
+ int idx,
+ enum stm32_gpio_pupd pupd)
+{
+ int bits;
+
+ bits = PUPD_BITS(idx);
+ clrsetbits_le32(&regs->pupdr, PUPD_MASK << bits, pupd << bits);
+}
+
+static enum stm32_gpio_pupd stm32_gpio_get_pupd(struct stm32_gpio_regs *regs,
+ int idx)
+{
+ return (readl(&regs->pupdr) >> PUPD_BITS(idx)) & PUPD_MASK;
+}
+
+/*
+ * convert gpio offset to gpio index taking into account gpio holes
+ * into gpio bank
+ */
+int stm32_offset_to_index(struct udevice *dev, unsigned int offset)
+{
+ struct stm32_gpio_priv *priv = dev_get_priv(dev);
+ unsigned int idx = 0;
+ int i;
+
+ for (i = 0; i < STM32_GPIOS_PER_BANK; i++) {
+ if (priv->gpio_range & BIT(i)) {
+ if (idx == offset)
+ return idx;
+ idx++;
+ }
+ }
+ /* shouldn't happen */
+ return -EINVAL;
+}
+
+static int stm32_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+ struct stm32_gpio_priv *priv = dev_get_priv(dev);
+ struct stm32_gpio_regs *regs = priv->regs;
+ int idx;
+
+ idx = stm32_offset_to_index(dev, offset);
+ if (idx < 0)
+ return idx;
+
+ stm32_gpio_set_moder(regs, idx, STM32_GPIO_MODE_IN);
+
+ return 0;
+}
+
+static int stm32_gpio_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct stm32_gpio_priv *priv = dev_get_priv(dev);
+ struct stm32_gpio_regs *regs = priv->regs;
+ int idx;
+
+ idx = stm32_offset_to_index(dev, offset);
+ if (idx < 0)
+ return idx;
+
+ stm32_gpio_set_moder(regs, idx, STM32_GPIO_MODE_OUT);
+
+ writel(BSRR_BIT(idx, value), &regs->bsrr);
+
+ return 0;
+}
+
+static int stm32_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+ struct stm32_gpio_priv *priv = dev_get_priv(dev);
+ struct stm32_gpio_regs *regs = priv->regs;
+ int idx;
+
+ idx = stm32_offset_to_index(dev, offset);
+ if (idx < 0)
+ return idx;
+
+ return readl(&regs->idr) & BIT(idx) ? 1 : 0;
+}
+
+static int stm32_gpio_set_value(struct udevice *dev, unsigned offset, int value)
+{
+ struct stm32_gpio_priv *priv = dev_get_priv(dev);
+ struct stm32_gpio_regs *regs = priv->regs;
+ int idx;
+
+ idx = stm32_offset_to_index(dev, offset);
+ if (idx < 0)
+ return idx;
+
+ writel(BSRR_BIT(idx, value), &regs->bsrr);
+
+ return 0;
+}
+
+static int stm32_gpio_get_function(struct udevice *dev, unsigned int offset)
+{
+ struct stm32_gpio_priv *priv = dev_get_priv(dev);
+ struct stm32_gpio_regs *regs = priv->regs;
+ int bits_index;
+ int mask;
+ int idx;
+ u32 mode;
+
+ idx = stm32_offset_to_index(dev, offset);
+ if (idx < 0)
+ return idx;
+
+ bits_index = MODE_BITS(idx);
+ mask = MODE_BITS_MASK << bits_index;
+
+ mode = (readl(&regs->moder) & mask) >> bits_index;
+ if (mode == STM32_GPIO_MODE_OUT)
+ return GPIOF_OUTPUT;
+ if (mode == STM32_GPIO_MODE_IN)
+ return GPIOF_INPUT;
+ if (mode == STM32_GPIO_MODE_AN)
+ return GPIOF_UNUSED;
+
+ return GPIOF_FUNC;
+}
+
+static int stm32_gpio_set_flags(struct udevice *dev, unsigned int offset,
+ ulong flags)
+{
+ struct stm32_gpio_priv *priv = dev_get_priv(dev);
+ struct stm32_gpio_regs *regs = priv->regs;
+ int idx;
+
+ idx = stm32_offset_to_index(dev, offset);
+ if (idx < 0)
+ return idx;
+
+ if (flags & GPIOD_IS_OUT) {
+ bool value = flags & GPIOD_IS_OUT_ACTIVE;
+
+ if (flags & GPIOD_OPEN_DRAIN)
+ stm32_gpio_set_otype(regs, idx, STM32_GPIO_OTYPE_OD);
+ else
+ stm32_gpio_set_otype(regs, idx, STM32_GPIO_OTYPE_PP);
+
+ stm32_gpio_set_moder(regs, idx, STM32_GPIO_MODE_OUT);
+ writel(BSRR_BIT(idx, value), &regs->bsrr);
+
+ } else if (flags & GPIOD_IS_IN) {
+ stm32_gpio_set_moder(regs, idx, STM32_GPIO_MODE_IN);
+ }
+ if (flags & GPIOD_PULL_UP)
+ stm32_gpio_set_pupd(regs, idx, STM32_GPIO_PUPD_UP);
+ else if (flags & GPIOD_PULL_DOWN)
+ stm32_gpio_set_pupd(regs, idx, STM32_GPIO_PUPD_DOWN);
+
+ return 0;
+}
+
+static int stm32_gpio_get_flags(struct udevice *dev, unsigned int offset,
+ ulong *flagsp)
+{
+ struct stm32_gpio_priv *priv = dev_get_priv(dev);
+ struct stm32_gpio_regs *regs = priv->regs;
+ int idx;
+ ulong dir_flags = 0;
+
+ idx = stm32_offset_to_index(dev, offset);
+ if (idx < 0)
+ return idx;
+
+ switch (stm32_gpio_get_moder(regs, idx)) {
+ case STM32_GPIO_MODE_OUT:
+ dir_flags |= GPIOD_IS_OUT;
+ if (stm32_gpio_get_otype(regs, idx) == STM32_GPIO_OTYPE_OD)
+ dir_flags |= GPIOD_OPEN_DRAIN;
+ if (readl(&regs->idr) & BIT(idx))
+ dir_flags |= GPIOD_IS_OUT_ACTIVE;
+ break;
+ case STM32_GPIO_MODE_IN:
+ dir_flags |= GPIOD_IS_IN;
+ break;
+ default:
+ break;
+ }
+ switch (stm32_gpio_get_pupd(regs, idx)) {
+ case STM32_GPIO_PUPD_UP:
+ dir_flags |= GPIOD_PULL_UP;
+ break;
+ case STM32_GPIO_PUPD_DOWN:
+ dir_flags |= GPIOD_PULL_DOWN;
+ break;
+ default:
+ break;
+ }
+ *flagsp = dir_flags;
+
+ return 0;
+}
+
+static const struct dm_gpio_ops gpio_stm32_ops = {
+ .direction_input = stm32_gpio_direction_input,
+ .direction_output = stm32_gpio_direction_output,
+ .get_value = stm32_gpio_get_value,
+ .set_value = stm32_gpio_set_value,
+ .get_function = stm32_gpio_get_function,
+ .set_flags = stm32_gpio_set_flags,
+ .get_flags = stm32_gpio_get_flags,
+};
+
+static int gpio_stm32_probe(struct udevice *dev)
+{
+ struct stm32_gpio_priv *priv = dev_get_priv(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct ofnode_phandle_args args;
+ const char *name;
+ struct clk clk;
+ fdt_addr_t addr;
+ int ret, i;
+
+ addr = dev_read_addr(dev);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ priv->regs = (struct stm32_gpio_regs *)addr;
+
+ name = dev_read_string(dev, "st,bank-name");
+ if (!name)
+ return -EINVAL;
+ uc_priv->bank_name = name;
+
+ i = 0;
+ ret = dev_read_phandle_with_args(dev, "gpio-ranges",
+ NULL, 3, i, &args);
+
+ if (!ret && args.args_count < 3)
+ return -EINVAL;
+
+ if (ret == -ENOENT) {
+ uc_priv->gpio_count = STM32_GPIOS_PER_BANK;
+ priv->gpio_range = GENMASK(STM32_GPIOS_PER_BANK - 1, 0);
+ }
+
+ while (ret != -ENOENT) {
+ priv->gpio_range |= GENMASK(args.args[2] + args.args[0] - 1,
+ args.args[0]);
+
+ uc_priv->gpio_count += args.args[2];
+
+ ret = dev_read_phandle_with_args(dev, "gpio-ranges", NULL, 3,
+ ++i, &args);
+ if (!ret && args.args_count < 3)
+ return -EINVAL;
+ }
+
+ dev_dbg(dev, "addr = 0x%p bank_name = %s gpio_count = %d gpio_range = 0x%x\n",
+ (u32 *)priv->regs, uc_priv->bank_name, uc_priv->gpio_count,
+ priv->gpio_range);
+
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_enable(&clk);
+
+ if (ret) {
+ dev_err(dev, "failed to enable clock\n");
+ return ret;
+ }
+ dev_dbg(dev, "clock enabled\n");
+
+ return 0;
+}
+
+U_BOOT_DRIVER(gpio_stm32) = {
+ .name = "gpio_stm32",
+ .id = UCLASS_GPIO,
+ .probe = gpio_stm32_probe,
+ .ops = &gpio_stm32_ops,
+ .flags = DM_UC_FLAG_SEQ_ALIAS,
+ .priv_auto = sizeof(struct stm32_gpio_priv),
+};
diff --git a/roms/u-boot/drivers/gpio/sunxi_gpio.c b/roms/u-boot/drivers/gpio/sunxi_gpio.c
new file mode 100644
index 000000000..24cb604e3
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/sunxi_gpio.c
@@ -0,0 +1,378 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2012 Henrik Nordstrom <henrik@henriknordstrom.net>
+ *
+ * Based on earlier arch/arm/cpu/armv7/sunxi/gpio.c:
+ *
+ * (C) Copyright 2007-2011
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * Tom Cubie <tangliang@allwinnertech.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <malloc.h>
+#include <asm/arch/gpio.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <dm/device-internal.h>
+#include <dt-bindings/gpio/gpio.h>
+
+#define SUNXI_GPIOS_PER_BANK SUNXI_GPIO_A_NR
+
+struct sunxi_gpio_plat {
+ struct sunxi_gpio *regs;
+ const char *bank_name; /* Name of bank, e.g. "B" */
+ int gpio_count;
+};
+
+#if !CONFIG_IS_ENABLED(DM_GPIO)
+static int sunxi_gpio_output(u32 pin, u32 val)
+{
+ u32 dat;
+ u32 bank = GPIO_BANK(pin);
+ u32 num = GPIO_NUM(pin);
+ struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
+
+ dat = readl(&pio->dat);
+ if (val)
+ dat |= 0x1 << num;
+ else
+ dat &= ~(0x1 << num);
+
+ writel(dat, &pio->dat);
+
+ return 0;
+}
+
+static int sunxi_gpio_input(u32 pin)
+{
+ u32 dat;
+ u32 bank = GPIO_BANK(pin);
+ u32 num = GPIO_NUM(pin);
+ struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
+
+ dat = readl(&pio->dat);
+ dat >>= num;
+
+ return dat & 0x1;
+}
+
+int gpio_request(unsigned gpio, const char *label)
+{
+ return 0;
+}
+
+int gpio_free(unsigned gpio)
+{
+ return 0;
+}
+
+int gpio_direction_input(unsigned gpio)
+{
+ sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_INPUT);
+
+ return 0;
+}
+
+int gpio_direction_output(unsigned gpio, int value)
+{
+ sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_OUTPUT);
+
+ return sunxi_gpio_output(gpio, value);
+}
+
+int gpio_get_value(unsigned gpio)
+{
+ return sunxi_gpio_input(gpio);
+}
+
+int gpio_set_value(unsigned gpio, int value)
+{
+ return sunxi_gpio_output(gpio, value);
+}
+
+int sunxi_name_to_gpio(const char *name)
+{
+ int group = 0;
+ int groupsize = 9 * 32;
+ long pin;
+ char *eptr;
+
+ if (*name == 'P' || *name == 'p')
+ name++;
+ if (*name >= 'A') {
+ group = *name - (*name > 'a' ? 'a' : 'A');
+ groupsize = 32;
+ name++;
+ }
+
+ pin = simple_strtol(name, &eptr, 10);
+ if (!*name || *eptr)
+ return -1;
+ if (pin < 0 || pin > groupsize || group >= 9)
+ return -1;
+ return group * 32 + pin;
+}
+#endif /* DM_GPIO */
+
+int sunxi_name_to_gpio_bank(const char *name)
+{
+ int group = 0;
+
+ if (*name == 'P' || *name == 'p')
+ name++;
+ if (*name >= 'A') {
+ group = *name - (*name > 'a' ? 'a' : 'A');
+ return group;
+ }
+
+ return -1;
+}
+
+#if CONFIG_IS_ENABLED(DM_GPIO)
+/* TODO(sjg@chromium.org): Remove this function and use device tree */
+int sunxi_name_to_gpio(const char *name)
+{
+ unsigned int gpio;
+ int ret;
+#if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO
+ char lookup[8];
+
+ if (strcasecmp(name, "AXP0-VBUS-DETECT") == 0) {
+ sprintf(lookup, SUNXI_GPIO_AXP0_PREFIX "%d",
+ SUNXI_GPIO_AXP0_VBUS_DETECT);
+ name = lookup;
+ } else if (strcasecmp(name, "AXP0-VBUS-ENABLE") == 0) {
+ sprintf(lookup, SUNXI_GPIO_AXP0_PREFIX "%d",
+ SUNXI_GPIO_AXP0_VBUS_ENABLE);
+ name = lookup;
+ }
+#endif
+ ret = gpio_lookup_name(name, NULL, NULL, &gpio);
+
+ return ret ? ret : gpio;
+}
+
+static int sunxi_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+ struct sunxi_gpio_plat *plat = dev_get_plat(dev);
+
+ sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_INPUT);
+
+ return 0;
+}
+
+static int sunxi_gpio_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct sunxi_gpio_plat *plat = dev_get_plat(dev);
+ u32 num = GPIO_NUM(offset);
+
+ sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_OUTPUT);
+ clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0);
+
+ return 0;
+}
+
+static int sunxi_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+ struct sunxi_gpio_plat *plat = dev_get_plat(dev);
+ u32 num = GPIO_NUM(offset);
+ unsigned dat;
+
+ dat = readl(&plat->regs->dat);
+ dat >>= num;
+
+ return dat & 0x1;
+}
+
+static int sunxi_gpio_set_value(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct sunxi_gpio_plat *plat = dev_get_plat(dev);
+ u32 num = GPIO_NUM(offset);
+
+ clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0);
+ return 0;
+}
+
+static int sunxi_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+ struct sunxi_gpio_plat *plat = dev_get_plat(dev);
+ int func;
+
+ func = sunxi_gpio_get_cfgbank(plat->regs, offset);
+ if (func == SUNXI_GPIO_OUTPUT)
+ return GPIOF_OUTPUT;
+ else if (func == SUNXI_GPIO_INPUT)
+ return GPIOF_INPUT;
+ else
+ return GPIOF_FUNC;
+}
+
+static int sunxi_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
+ struct ofnode_phandle_args *args)
+{
+ int ret;
+
+ ret = device_get_child(dev, args->args[0], &desc->dev);
+ if (ret)
+ return ret;
+ desc->offset = args->args[1];
+ desc->flags = args->args[2] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
+
+ return 0;
+}
+
+static const struct dm_gpio_ops gpio_sunxi_ops = {
+ .direction_input = sunxi_gpio_direction_input,
+ .direction_output = sunxi_gpio_direction_output,
+ .get_value = sunxi_gpio_get_value,
+ .set_value = sunxi_gpio_set_value,
+ .get_function = sunxi_gpio_get_function,
+ .xlate = sunxi_gpio_xlate,
+};
+
+/**
+ * Returns the name of a GPIO bank
+ *
+ * GPIO banks are named A, B, C, ...
+ *
+ * @bank: Bank number (0, 1..n-1)
+ * @return allocated string containing the name
+ */
+static char *gpio_bank_name(int bank)
+{
+ char *name;
+
+ name = malloc(3);
+ if (name) {
+ name[0] = 'P';
+ name[1] = 'A' + bank;
+ name[2] = '\0';
+ }
+
+ return name;
+}
+
+static int gpio_sunxi_probe(struct udevice *dev)
+{
+ struct sunxi_gpio_plat *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ /* Tell the uclass how many GPIOs we have */
+ if (plat) {
+ uc_priv->gpio_count = plat->gpio_count;
+ uc_priv->bank_name = plat->bank_name;
+ }
+
+ return 0;
+}
+
+struct sunxi_gpio_soc_data {
+ int start;
+ int no_banks;
+};
+
+/**
+ * We have a top-level GPIO device with no actual GPIOs. It has a child
+ * device for each Sunxi bank.
+ */
+static int gpio_sunxi_bind(struct udevice *parent)
+{
+ struct sunxi_gpio_soc_data *soc_data =
+ (struct sunxi_gpio_soc_data *)dev_get_driver_data(parent);
+ struct sunxi_gpio_plat *plat = dev_get_plat(parent);
+ struct sunxi_gpio_reg *ctlr;
+ int bank, ret;
+
+ /* If this is a child device, there is nothing to do here */
+ if (plat)
+ return 0;
+
+ ctlr = dev_read_addr_ptr(parent);
+ for (bank = 0; bank < soc_data->no_banks; bank++) {
+ struct sunxi_gpio_plat *plat;
+ struct udevice *dev;
+
+ plat = calloc(1, sizeof(*plat));
+ if (!plat)
+ return -ENOMEM;
+ plat->regs = &ctlr->gpio_bank[bank];
+ plat->bank_name = gpio_bank_name(soc_data->start + bank);
+ plat->gpio_count = SUNXI_GPIOS_PER_BANK;
+
+ ret = device_bind(parent, parent->driver, plat->bank_name, plat,
+ dev_ofnode(parent), &dev);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct sunxi_gpio_soc_data soc_data_a_all = {
+ .start = 0,
+ .no_banks = SUNXI_GPIO_BANKS,
+};
+
+static const struct sunxi_gpio_soc_data soc_data_l_1 = {
+ .start = 'L' - 'A',
+ .no_banks = 1,
+};
+
+static const struct sunxi_gpio_soc_data soc_data_l_2 = {
+ .start = 'L' - 'A',
+ .no_banks = 2,
+};
+
+static const struct sunxi_gpio_soc_data soc_data_l_3 = {
+ .start = 'L' - 'A',
+ .no_banks = 3,
+};
+
+#define ID(_compat_, _soc_data_) \
+ { .compatible = _compat_, .data = (ulong)&soc_data_##_soc_data_ }
+
+static const struct udevice_id sunxi_gpio_ids[] = {
+ ID("allwinner,sun4i-a10-pinctrl", a_all),
+ ID("allwinner,sun5i-a10s-pinctrl", a_all),
+ ID("allwinner,sun5i-a13-pinctrl", a_all),
+ ID("allwinner,sun50i-h5-pinctrl", a_all),
+ ID("allwinner,sun6i-a31-pinctrl", a_all),
+ ID("allwinner,sun6i-a31s-pinctrl", a_all),
+ ID("allwinner,sun7i-a20-pinctrl", a_all),
+ ID("allwinner,sun8i-a23-pinctrl", a_all),
+ ID("allwinner,sun8i-a33-pinctrl", a_all),
+ ID("allwinner,sun8i-a83t-pinctrl", a_all),
+ ID("allwinner,sun8i-h3-pinctrl", a_all),
+ ID("allwinner,sun8i-r40-pinctrl", a_all),
+ ID("allwinner,sun8i-v3-pinctrl", a_all),
+ ID("allwinner,sun8i-v3s-pinctrl", a_all),
+ ID("allwinner,sun9i-a80-pinctrl", a_all),
+ ID("allwinner,sun50i-a64-pinctrl", a_all),
+ ID("allwinner,sun50i-h6-pinctrl", a_all),
+ ID("allwinner,sun50i-h616-pinctrl", a_all),
+ ID("allwinner,sun6i-a31-r-pinctrl", l_2),
+ ID("allwinner,sun8i-a23-r-pinctrl", l_1),
+ ID("allwinner,sun8i-a83t-r-pinctrl", l_1),
+ ID("allwinner,sun8i-h3-r-pinctrl", l_1),
+ ID("allwinner,sun9i-a80-r-pinctrl", l_3),
+ ID("allwinner,sun50i-a64-r-pinctrl", l_1),
+ ID("allwinner,sun50i-h6-r-pinctrl", l_2),
+ ID("allwinner,sun50i-h616-r-pinctrl", l_1),
+ { }
+};
+
+U_BOOT_DRIVER(gpio_sunxi) = {
+ .name = "gpio_sunxi",
+ .id = UCLASS_GPIO,
+ .ops = &gpio_sunxi_ops,
+ .of_match = sunxi_gpio_ids,
+ .bind = gpio_sunxi_bind,
+ .probe = gpio_sunxi_probe,
+};
+#endif /* DM_GPIO */
diff --git a/roms/u-boot/drivers/gpio/tca642x.c b/roms/u-boot/drivers/gpio/tca642x.c
new file mode 100644
index 000000000..7007c7a00
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/tca642x.c
@@ -0,0 +1,356 @@
+/*
+ * Copyright 2013 Texas Instruments, Inc.
+ * Author: Dan Murphy <dmurphy@ti.com>
+ *
+ * Derived work from the pca953x.c driver
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <i2c.h>
+#include <tca642x.h>
+
+/* tca642x register address definitions */
+struct tca642x_bank_info tca642x_regs[] = {
+ { .input_reg = 0x00,
+ .output_reg = 0x04,
+ .polarity_reg = 0x08,
+ .configuration_reg = 0x0c },
+ { .input_reg = 0x01,
+ .output_reg = 0x05,
+ .polarity_reg = 0x09,
+ .configuration_reg = 0x0d },
+ { .input_reg = 0x02,
+ .output_reg = 0x06,
+ .polarity_reg = 0x0a,
+ .configuration_reg = 0x0e },
+};
+
+/*
+ * Modify masked bits in register
+ */
+static int tca642x_reg_write(uchar chip, uint8_t addr,
+ uint8_t reg_bit, uint8_t data)
+{
+ uint8_t valw;
+ int org_bus_num;
+ int ret;
+
+ org_bus_num = i2c_get_bus_num();
+ i2c_set_bus_num(CONFIG_SYS_I2C_TCA642X_BUS_NUM);
+
+ if (i2c_read(chip, addr, 1, (uint8_t *)&valw, 1)) {
+ printf("Could not read before writing\n");
+ ret = -1;
+ goto error;
+ }
+ valw &= ~reg_bit;
+ valw |= data;
+
+ ret = i2c_write(chip, addr, 1, (u8 *)&valw, 1);
+
+error:
+ i2c_set_bus_num(org_bus_num);
+ return ret;
+}
+
+static int tca642x_reg_read(uchar chip, uint8_t addr, uint8_t *data)
+{
+ uint8_t valw;
+ int org_bus_num;
+ int ret = 0;
+
+ org_bus_num = i2c_get_bus_num();
+ i2c_set_bus_num(CONFIG_SYS_I2C_TCA642X_BUS_NUM);
+ if (i2c_read(chip, addr, 1, (u8 *)&valw, 1)) {
+ ret = -1;
+ goto error;
+ }
+
+ *data = valw;
+
+error:
+ i2c_set_bus_num(org_bus_num);
+ return ret;
+}
+
+/*
+ * Set output value of IO pins in 'reg_bit' to corresponding value in 'data'
+ * 0 = low, 1 = high
+ */
+int tca642x_set_val(uchar chip, uint8_t gpio_bank,
+ uint8_t reg_bit, uint8_t data)
+{
+ uint8_t out_reg = tca642x_regs[gpio_bank].output_reg;
+
+ return tca642x_reg_write(chip, out_reg, reg_bit, data);
+}
+
+/*
+ * Set read polarity of IO pins in 'reg_bit' to corresponding value in 'data'
+ * 0 = read pin value, 1 = read inverted pin value
+ */
+int tca642x_set_pol(uchar chip, uint8_t gpio_bank,
+ uint8_t reg_bit, uint8_t data)
+{
+ uint8_t pol_reg = tca642x_regs[gpio_bank].polarity_reg;
+
+ return tca642x_reg_write(chip, pol_reg, reg_bit, data);
+}
+
+/*
+ * Set direction of IO pins in 'reg_bit' to corresponding value in 'data'
+ * 0 = output, 1 = input
+ */
+int tca642x_set_dir(uchar chip, uint8_t gpio_bank,
+ uint8_t reg_bit, uint8_t data)
+{
+ uint8_t config_reg = tca642x_regs[gpio_bank].configuration_reg;
+
+ return tca642x_reg_write(chip, config_reg, reg_bit, data);
+}
+
+/*
+ * Read current logic level of all IO pins
+ */
+int tca642x_get_val(uchar chip, uint8_t gpio_bank)
+{
+ uint8_t val;
+ uint8_t in_reg = tca642x_regs[gpio_bank].input_reg;
+
+ if (tca642x_reg_read(chip, in_reg, &val) < 0)
+ return -1;
+
+ return (int)val;
+}
+
+/*
+ * Set the inital register states for the tca642x gpio expander
+ */
+int tca642x_set_inital_state(uchar chip, struct tca642x_bank_info init_data[])
+{
+ int i, ret;
+ uint8_t config_reg;
+ uint8_t polarity_reg;
+ uint8_t output_reg;
+
+ for (i = 0; i < 3; i++) {
+ config_reg = tca642x_regs[i].configuration_reg;
+ ret = tca642x_reg_write(chip, config_reg, 0xff,
+ init_data[i].configuration_reg);
+ polarity_reg = tca642x_regs[i].polarity_reg;
+ ret = tca642x_reg_write(chip, polarity_reg, 0xff,
+ init_data[i].polarity_reg);
+ output_reg = tca642x_regs[i].output_reg;
+ ret = tca642x_reg_write(chip, output_reg, 0xff,
+ init_data[i].output_reg);
+ }
+
+ return ret;
+}
+
+#if defined(CONFIG_CMD_TCA642X) && !defined(CONFIG_SPL_BUILD)
+/*
+ * Display tca642x information
+ */
+static int tca642x_info(uchar chip)
+{
+ int i, j;
+ uint8_t data;
+
+ printf("tca642x@ 0x%x (%d pins):\n", chip, 24);
+ for (i = 0; i < 3; i++) {
+ printf("Bank %i\n", i);
+ if (tca642x_reg_read(chip,
+ tca642x_regs[i].configuration_reg,
+ &data) < 0)
+ return -1;
+ printf("\tConfiguration: ");
+ for (j = 7; j >= 0; j--)
+ printf("%c", data & (1 << j) ? 'i' : 'o');
+ printf("\n");
+
+ if (tca642x_reg_read(chip,
+ tca642x_regs[i].polarity_reg, &data) < 0)
+ return -1;
+ printf("\tPolarity: ");
+ for (j = 7; j >= 0; j--)
+ printf("%c", data & (1 << j) ? '1' : '0');
+ printf("\n");
+
+ if (tca642x_reg_read(chip,
+ tca642x_regs[i].input_reg, &data) < 0)
+ return -1;
+ printf("\tInput value: ");
+ for (j = 7; j >= 0; j--)
+ printf("%c", data & (1 << j) ? '1' : '0');
+ printf("\n");
+
+ if (tca642x_reg_read(chip,
+ tca642x_regs[i].output_reg, &data) < 0)
+ return -1;
+ printf("\tOutput value: ");
+ for (j = 7; j >= 0; j--)
+ printf("%c", data & (1 << j) ? '1' : '0');
+ printf("\n");
+ }
+
+ return 0;
+}
+
+static int tca642x_get_bank(int pin)
+{
+ int gpio_bank;
+
+ if (pin <= 7) {
+ gpio_bank = 0;
+ } else if ((pin >= 10) && (pin <= 17)) {
+ gpio_bank = 1;
+ } else if ((pin >= 20) && (pin <= 27)) {
+ gpio_bank = 2;
+ } else {
+ printf("Requested pin is not available\n");
+ gpio_bank = -1;
+ }
+
+ return gpio_bank;
+}
+
+static struct cmd_tbl cmd_tca642x[] = {
+ U_BOOT_CMD_MKENT(device, 3, 0, (void *)TCA642X_CMD_DEVICE, "", ""),
+ U_BOOT_CMD_MKENT(output, 4, 0, (void *)TCA642X_CMD_OUTPUT, "", ""),
+ U_BOOT_CMD_MKENT(input, 3, 0, (void *)TCA642X_CMD_INPUT, "", ""),
+ U_BOOT_CMD_MKENT(invert, 4, 0, (void *)TCA642X_CMD_INVERT, "", ""),
+ U_BOOT_CMD_MKENT(info, 2, 0, (void *)TCA642X_CMD_INFO, "", ""),
+};
+
+static int do_tca642x(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ static uchar chip = CONFIG_SYS_I2C_TCA642X_ADDR;
+ int ret = CMD_RET_USAGE, val;
+ int gpio_bank = 0;
+ uint8_t bank_shift;
+ ulong ul_arg2 = 0;
+ ulong ul_arg3 = 0;
+ struct cmd_tbl *c;
+
+ c = find_cmd_tbl(argv[1], cmd_tca642x, ARRAY_SIZE(cmd_tca642x));
+
+ /* All commands but "device" require 'maxargs' arguments */
+ if (!c ||
+ !((argc == (c->maxargs)) ||
+ (((int)c->cmd == TCA642X_CMD_DEVICE) &&
+ (argc == (c->maxargs - 1))))) {
+ return CMD_RET_USAGE;
+ }
+
+ /* arg2 used as chip number or pin number */
+ if (argc > 2)
+ ul_arg2 = simple_strtoul(argv[2], NULL, 10);
+
+ /* arg3 used as pin or invert value */
+ if (argc > 3)
+ ul_arg3 = simple_strtoul(argv[3], NULL, 10) & 0x1;
+
+ switch ((int)c->cmd) {
+ case TCA642X_CMD_INFO:
+ ret = tca642x_info(chip);
+ if (ret)
+ ret = CMD_RET_FAILURE;
+ break;
+
+ case TCA642X_CMD_DEVICE:
+ if (argc == 3)
+ chip = (uint8_t)ul_arg2;
+ printf("Current device address: 0x%x\n", chip);
+ ret = CMD_RET_SUCCESS;
+ break;
+
+ case TCA642X_CMD_INPUT:
+ gpio_bank = tca642x_get_bank(ul_arg2);
+ if (gpio_bank < 0) {
+ ret = CMD_RET_FAILURE;
+ goto error;
+ }
+ bank_shift = ul_arg2 - (gpio_bank * 10);
+ ret = tca642x_set_dir(chip, gpio_bank, (1 << bank_shift),
+ TCA642X_DIR_IN << bank_shift);
+ val = (tca642x_get_val(chip, gpio_bank) &
+ (1 << bank_shift)) != 0;
+
+ if (ret)
+ ret = CMD_RET_FAILURE;
+ else
+ printf("chip 0x%02x, pin 0x%lx = %d\n", chip,
+ ul_arg2, val);
+ break;
+
+ case TCA642X_CMD_OUTPUT:
+ gpio_bank = tca642x_get_bank(ul_arg2);
+ if (gpio_bank < 0) {
+ ret = CMD_RET_FAILURE;
+ goto error;
+ }
+ bank_shift = ul_arg2 - (gpio_bank * 10);
+ ret = tca642x_set_dir(chip, gpio_bank, (1 << bank_shift),
+ (TCA642X_DIR_OUT << bank_shift));
+ if (!ret)
+ ret = tca642x_set_val(chip,
+ gpio_bank, (1 << bank_shift),
+ (ul_arg3 << bank_shift));
+ if (ret)
+ ret = CMD_RET_FAILURE;
+ break;
+
+ case TCA642X_CMD_INVERT:
+ gpio_bank = tca642x_get_bank(ul_arg2);
+ if (gpio_bank < 0) {
+ ret = CMD_RET_FAILURE;
+ goto error;
+ }
+ bank_shift = ul_arg2 - (gpio_bank * 10);
+ ret = tca642x_set_pol(chip, gpio_bank, (1 << bank_shift),
+ (ul_arg3 << bank_shift));
+ if (ret)
+ ret = CMD_RET_FAILURE;
+ break;
+ }
+error:
+ if (ret == CMD_RET_FAILURE)
+ eprintf("Error talking to chip at 0x%x\n", chip);
+
+ return ret;
+}
+
+U_BOOT_CMD(
+ tca642x, 5, 1, do_tca642x,
+ "tca642x gpio access",
+ "device [dev]\n"
+ " - show or set current device address\n"
+ "tca642x info\n"
+ " - display info for current chip\n"
+ "tca642x output pin 0|1\n"
+ " - set pin as output and drive low or high\n"
+ "tca642x invert pin 0|1\n"
+ " - disable/enable polarity inversion for reads\n"
+ "tca642x input pin\n"
+ " - set pin as input and read value"
+);
+
+#endif /* CONFIG_CMD_TCA642X */
diff --git a/roms/u-boot/drivers/gpio/tegra186_gpio.c b/roms/u-boot/drivers/gpio/tegra186_gpio.c
new file mode 100644
index 000000000..82dcaf963
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/tegra186_gpio.c
@@ -0,0 +1,283 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2010-2016, NVIDIA CORPORATION.
+ * (based on tegra_gpio.c)
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <malloc.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/gpio.h>
+#include <dm/device-internal.h>
+#include <dt-bindings/gpio/gpio.h>
+#include "tegra186_gpio_priv.h"
+
+struct tegra186_gpio_port_data {
+ const char *name;
+ uint32_t offset;
+};
+
+struct tegra186_gpio_ctlr_data {
+ const struct tegra186_gpio_port_data *ports;
+ uint32_t port_count;
+};
+
+struct tegra186_gpio_plat {
+ const char *name;
+ uint32_t *regs;
+};
+
+static uint32_t *tegra186_gpio_reg(struct udevice *dev, uint32_t reg,
+ uint32_t gpio)
+{
+ struct tegra186_gpio_plat *plat = dev_get_plat(dev);
+ uint32_t index = (reg + (gpio * TEGRA186_GPIO_PER_GPIO_STRIDE)) / 4;
+
+ return &(plat->regs[index]);
+}
+
+static int tegra186_gpio_set_out(struct udevice *dev, unsigned offset,
+ bool output)
+{
+ uint32_t *reg;
+ uint32_t rval;
+
+ reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_OUTPUT_CONTROL, offset);
+ rval = readl(reg);
+ if (output)
+ rval &= ~TEGRA186_GPIO_OUTPUT_CONTROL_FLOATED;
+ else
+ rval |= TEGRA186_GPIO_OUTPUT_CONTROL_FLOATED;
+ writel(rval, reg);
+
+ reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_ENABLE_CONFIG, offset);
+ rval = readl(reg);
+ if (output)
+ rval |= TEGRA186_GPIO_ENABLE_CONFIG_OUT;
+ else
+ rval &= ~TEGRA186_GPIO_ENABLE_CONFIG_OUT;
+ rval |= TEGRA186_GPIO_ENABLE_CONFIG_ENABLE;
+ writel(rval, reg);
+
+ return 0;
+}
+
+static int tegra186_gpio_set_val(struct udevice *dev, unsigned offset, bool val)
+{
+ uint32_t *reg;
+ uint32_t rval;
+
+ reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_OUTPUT_VALUE, offset);
+ rval = readl(reg);
+ if (val)
+ rval |= TEGRA186_GPIO_OUTPUT_VALUE_HIGH;
+ else
+ rval &= ~TEGRA186_GPIO_OUTPUT_VALUE_HIGH;
+ writel(rval, reg);
+
+ return 0;
+}
+
+static int tegra186_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+ return tegra186_gpio_set_out(dev, offset, false);
+}
+
+static int tegra186_gpio_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ int ret;
+
+ ret = tegra186_gpio_set_val(dev, offset, value != 0);
+ if (ret)
+ return ret;
+ return tegra186_gpio_set_out(dev, offset, true);
+}
+
+static int tegra186_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+ uint32_t *reg;
+ uint32_t rval;
+
+ reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_ENABLE_CONFIG, offset);
+ rval = readl(reg);
+
+ if (rval & TEGRA186_GPIO_ENABLE_CONFIG_OUT)
+ reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_OUTPUT_VALUE,
+ offset);
+ else
+ reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_INPUT, offset);
+
+ rval = readl(reg);
+ return !!rval;
+}
+
+static int tegra186_gpio_set_value(struct udevice *dev, unsigned offset,
+ int value)
+{
+ return tegra186_gpio_set_val(dev, offset, value != 0);
+}
+
+static int tegra186_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+ uint32_t *reg;
+ uint32_t rval;
+
+ reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_ENABLE_CONFIG, offset);
+ rval = readl(reg);
+ if (rval & TEGRA186_GPIO_ENABLE_CONFIG_OUT)
+ return GPIOF_OUTPUT;
+ else
+ return GPIOF_INPUT;
+}
+
+static int tegra186_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
+ struct ofnode_phandle_args *args)
+{
+ int gpio, port, ret;
+
+ gpio = args->args[0];
+ port = gpio / TEGRA186_GPIO_PER_GPIO_COUNT;
+ ret = device_get_child(dev, port, &desc->dev);
+ if (ret)
+ return ret;
+ desc->offset = gpio % TEGRA186_GPIO_PER_GPIO_COUNT;
+ desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
+
+ return 0;
+}
+
+static const struct dm_gpio_ops tegra186_gpio_ops = {
+ .direction_input = tegra186_gpio_direction_input,
+ .direction_output = tegra186_gpio_direction_output,
+ .get_value = tegra186_gpio_get_value,
+ .set_value = tegra186_gpio_set_value,
+ .get_function = tegra186_gpio_get_function,
+ .xlate = tegra186_gpio_xlate,
+};
+
+/**
+ * We have a top-level GPIO device with no actual GPIOs. It has a child device
+ * for each port within the controller.
+ */
+static int tegra186_gpio_bind(struct udevice *parent)
+{
+ struct tegra186_gpio_plat *parent_plat = dev_get_plat(parent);
+ struct tegra186_gpio_ctlr_data *ctlr_data =
+ (struct tegra186_gpio_ctlr_data *)dev_get_driver_data(parent);
+ uint32_t *regs;
+ int port, ret;
+
+ /* If this is a child device, there is nothing to do here */
+ if (parent_plat)
+ return 0;
+
+ regs = (uint32_t *)devfdt_get_addr_name(parent, "gpio");
+ if (regs == (uint32_t *)FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ for (port = 0; port < ctlr_data->port_count; port++) {
+ struct tegra186_gpio_plat *plat;
+ struct udevice *dev;
+
+ plat = calloc(1, sizeof(*plat));
+ if (!plat)
+ return -ENOMEM;
+ plat->name = ctlr_data->ports[port].name;
+ plat->regs = &(regs[ctlr_data->ports[port].offset / 4]);
+
+ ret = device_bind(parent, parent->driver, plat->name, plat,
+ dev_ofnode(parent), &dev);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int tegra186_gpio_probe(struct udevice *dev)
+{
+ struct tegra186_gpio_plat *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ /* Only child devices have ports */
+ if (!plat)
+ return 0;
+
+ uc_priv->gpio_count = TEGRA186_GPIO_PER_GPIO_COUNT;
+ uc_priv->bank_name = plat->name;
+
+ return 0;
+}
+
+static const struct tegra186_gpio_port_data tegra186_gpio_main_ports[] = {
+ {"A", 0x2000},
+ {"B", 0x3000},
+ {"C", 0x3200},
+ {"D", 0x3400},
+ {"E", 0x2200},
+ {"F", 0x2400},
+ {"G", 0x4200},
+ {"H", 0x1000},
+ {"I", 0x0800},
+ {"J", 0x5000},
+ {"K", 0x5200},
+ {"L", 0x1200},
+ {"M", 0x5600},
+ {"N", 0x0000},
+ {"O", 0x0200},
+ {"P", 0x4000},
+ {"Q", 0x0400},
+ {"R", 0x0a00},
+ {"T", 0x0600},
+ {"X", 0x1400},
+ {"Y", 0x1600},
+ {"BB", 0x2600},
+ {"CC", 0x5400},
+};
+
+static const struct tegra186_gpio_ctlr_data tegra186_gpio_main_data = {
+ .ports = tegra186_gpio_main_ports,
+ .port_count = ARRAY_SIZE(tegra186_gpio_main_ports),
+};
+
+static const struct tegra186_gpio_port_data tegra186_gpio_aon_ports[] = {
+ {"S", 0x0200},
+ {"U", 0x0400},
+ {"V", 0x0800},
+ {"W", 0x0a00},
+ {"Z", 0x0e00},
+ {"AA", 0x0c00},
+ {"EE", 0x0600},
+ {"FF", 0x0000},
+};
+
+static const struct tegra186_gpio_ctlr_data tegra186_gpio_aon_data = {
+ .ports = tegra186_gpio_aon_ports,
+ .port_count = ARRAY_SIZE(tegra186_gpio_aon_ports),
+};
+
+static const struct udevice_id tegra186_gpio_ids[] = {
+ {
+ .compatible = "nvidia,tegra186-gpio",
+ .data = (ulong)&tegra186_gpio_main_data,
+ },
+ {
+ .compatible = "nvidia,tegra186-gpio-aon",
+ .data = (ulong)&tegra186_gpio_aon_data,
+ },
+ { }
+};
+
+U_BOOT_DRIVER(tegra186_gpio) = {
+ .name = "tegra186_gpio",
+ .id = UCLASS_GPIO,
+ .of_match = tegra186_gpio_ids,
+ .bind = tegra186_gpio_bind,
+ .probe = tegra186_gpio_probe,
+ .ops = &tegra186_gpio_ops,
+};
diff --git a/roms/u-boot/drivers/gpio/tegra186_gpio_priv.h b/roms/u-boot/drivers/gpio/tegra186_gpio_priv.h
new file mode 100644
index 000000000..3e686beed
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/tegra186_gpio_priv.h
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2016, NVIDIA CORPORATION.
+ */
+
+#ifndef _TEGRA186_GPIO_PRIV_H_
+#define _TEGRA186_GPIO_PRIV_H_
+
+/*
+ * For each GPIO, there are a set of registers than affect it, all packed
+ * back-to-back.
+ */
+#include <linux/bitops.h>
+#define TEGRA186_GPIO_ENABLE_CONFIG 0x00
+#define TEGRA186_GPIO_ENABLE_CONFIG_ENABLE BIT(0)
+#define TEGRA186_GPIO_ENABLE_CONFIG_OUT BIT(1)
+#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SHIFT 2
+#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_MASK 3
+#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_NONE 0
+#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_LEVEL 1
+#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE 2
+#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_DOUBLE_EDGE 3
+#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL_HIGH_RISING BIT(4)
+#define TEGRA186_GPIO_ENABLE_CONFIG_DEBOUNCE_ENABLE BIT(5)
+#define TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT_ENABLE BIT(6)
+#define TEGRA186_GPIO_ENABLE_CONFIG_TIMESTAMPING_ENABLE BIT(7)
+
+#define TEGRA186_GPIO_DEBOUNCE_THRESHOLD 0x04
+
+#define TEGRA186_GPIO_INPUT 0x08
+
+#define TEGRA186_GPIO_OUTPUT_CONTROL 0x0c
+#define TEGRA186_GPIO_OUTPUT_CONTROL_FLOATED BIT(0)
+
+#define TEGRA186_GPIO_OUTPUT_VALUE 0x10
+#define TEGRA186_GPIO_OUTPUT_VALUE_HIGH 1
+
+#define TEGRA186_GPIO_INTERRUPT_CLEAR 0x14
+
+/*
+ * 8 GPIOs are packed into a port. Their registers appear back-to-back in the
+ * port's address space.
+ */
+#define TEGRA186_GPIO_PER_GPIO_STRIDE 0x20
+#define TEGRA186_GPIO_PER_GPIO_COUNT 8
+
+/*
+ * Per-port registers are packed immediately following all of a port's
+ * per-GPIO registers.
+ */
+#define TEGRA186_GPIO_INTERRUPT_STATUS_G 0x100
+#define TEGRA186_GPIO_INTERRUPT_STATUS_G_STRIDE 4
+#define TEGRA186_GPIO_INTERRUPT_STATUS_G_COUNT 8
+
+/*
+ * The registers for multiple ports are packed together back-to-back to form
+ * the overall controller.
+ */
+#define TEGRA186_GPIO_PER_PORT_STRIDE 0x200
+
+#endif
diff --git a/roms/u-boot/drivers/gpio/tegra_gpio.c b/roms/u-boot/drivers/gpio/tegra_gpio.c
new file mode 100644
index 000000000..5d3af8a01
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/tegra_gpio.c
@@ -0,0 +1,382 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * NVIDIA Tegra20 GPIO handling.
+ * (C) Copyright 2010-2012,2015
+ * NVIDIA Corporation <www.nvidia.com>
+ */
+
+/*
+ * Based on (mostly copied from) kw_gpio.c based Linux 2.6 kernel driver.
+ * Tom Warren (twarren@nvidia.com)
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <malloc.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/arch/tegra.h>
+#include <asm/gpio.h>
+#include <dm/device-internal.h>
+#include <dt-bindings/gpio/gpio.h>
+
+static const int CONFIG_SFIO = 0;
+static const int CONFIG_GPIO = 1;
+static const int DIRECTION_INPUT = 0;
+static const int DIRECTION_OUTPUT = 1;
+
+struct tegra_gpio_plat {
+ struct gpio_ctlr_bank *bank;
+ const char *port_name; /* Name of port, e.g. "B" */
+ int base_gpio; /* Port number for this port (0, 1,.., n-1) */
+};
+
+/* Information about each port at run-time */
+struct tegra_port_info {
+ struct gpio_ctlr_bank *bank;
+ int base_gpio; /* Port number for this port (0, 1,.., n-1) */
+};
+
+/* Return config of pin 'gpio' as GPIO (1) or SFIO (0) */
+static int get_config(unsigned gpio)
+{
+ struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE;
+ struct gpio_ctlr_bank *bank = &ctlr->gpio_bank[GPIO_BANK(gpio)];
+ u32 u;
+ int type;
+
+ u = readl(&bank->gpio_config[GPIO_PORT(gpio)]);
+ type = (u >> GPIO_BIT(gpio)) & 1;
+
+ debug("get_config: port = %d, bit = %d is %s\n",
+ GPIO_FULLPORT(gpio), GPIO_BIT(gpio), type ? "GPIO" : "SFPIO");
+
+ return type ? CONFIG_GPIO : CONFIG_SFIO;
+}
+
+/* Config pin 'gpio' as GPIO or SFIO, based on 'type' */
+static void set_config(unsigned gpio, int type)
+{
+ struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE;
+ struct gpio_ctlr_bank *bank = &ctlr->gpio_bank[GPIO_BANK(gpio)];
+ u32 u;
+
+ debug("set_config: port = %d, bit = %d, %s\n",
+ GPIO_FULLPORT(gpio), GPIO_BIT(gpio), type ? "GPIO" : "SFPIO");
+
+ u = readl(&bank->gpio_config[GPIO_PORT(gpio)]);
+ if (type != CONFIG_SFIO)
+ u |= 1 << GPIO_BIT(gpio);
+ else
+ u &= ~(1 << GPIO_BIT(gpio));
+ writel(u, &bank->gpio_config[GPIO_PORT(gpio)]);
+}
+
+/* Return GPIO pin 'gpio' direction - 0 = input or 1 = output */
+static int get_direction(unsigned gpio)
+{
+ struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE;
+ struct gpio_ctlr_bank *bank = &ctlr->gpio_bank[GPIO_BANK(gpio)];
+ u32 u;
+ int dir;
+
+ u = readl(&bank->gpio_dir_out[GPIO_PORT(gpio)]);
+ dir = (u >> GPIO_BIT(gpio)) & 1;
+
+ debug("get_direction: port = %d, bit = %d, %s\n",
+ GPIO_FULLPORT(gpio), GPIO_BIT(gpio), dir ? "OUT" : "IN");
+
+ return dir ? DIRECTION_OUTPUT : DIRECTION_INPUT;
+}
+
+/* Config GPIO pin 'gpio' as input or output (OE) as per 'output' */
+static void set_direction(unsigned gpio, int output)
+{
+ struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE;
+ struct gpio_ctlr_bank *bank = &ctlr->gpio_bank[GPIO_BANK(gpio)];
+ u32 u;
+
+ debug("set_direction: port = %d, bit = %d, %s\n",
+ GPIO_FULLPORT(gpio), GPIO_BIT(gpio), output ? "OUT" : "IN");
+
+ u = readl(&bank->gpio_dir_out[GPIO_PORT(gpio)]);
+ if (output != DIRECTION_INPUT)
+ u |= 1 << GPIO_BIT(gpio);
+ else
+ u &= ~(1 << GPIO_BIT(gpio));
+ writel(u, &bank->gpio_dir_out[GPIO_PORT(gpio)]);
+}
+
+/* set GPIO pin 'gpio' output bit as 0 or 1 as per 'high' */
+static void set_level(unsigned gpio, int high)
+{
+ struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE;
+ struct gpio_ctlr_bank *bank = &ctlr->gpio_bank[GPIO_BANK(gpio)];
+ u32 u;
+
+ debug("set_level: port = %d, bit %d == %d\n",
+ GPIO_FULLPORT(gpio), GPIO_BIT(gpio), high);
+
+ u = readl(&bank->gpio_out[GPIO_PORT(gpio)]);
+ if (high)
+ u |= 1 << GPIO_BIT(gpio);
+ else
+ u &= ~(1 << GPIO_BIT(gpio));
+ writel(u, &bank->gpio_out[GPIO_PORT(gpio)]);
+}
+
+/*
+ * Generic_GPIO primitives.
+ */
+
+/* set GPIO pin 'gpio' as an input */
+static int tegra_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+ struct tegra_port_info *state = dev_get_priv(dev);
+
+ /* Configure GPIO direction as input. */
+ set_direction(state->base_gpio + offset, DIRECTION_INPUT);
+
+ /* Enable the pin as a GPIO */
+ set_config(state->base_gpio + offset, 1);
+
+ return 0;
+}
+
+/* set GPIO pin 'gpio' as an output, with polarity 'value' */
+static int tegra_gpio_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct tegra_port_info *state = dev_get_priv(dev);
+ int gpio = state->base_gpio + offset;
+
+ /* Configure GPIO output value. */
+ set_level(gpio, value);
+
+ /* Configure GPIO direction as output. */
+ set_direction(gpio, DIRECTION_OUTPUT);
+
+ /* Enable the pin as a GPIO */
+ set_config(state->base_gpio + offset, 1);
+
+ return 0;
+}
+
+/* read GPIO IN value of pin 'gpio' */
+static int tegra_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+ struct tegra_port_info *state = dev_get_priv(dev);
+ int gpio = state->base_gpio + offset;
+ int val;
+
+ debug("%s: pin = %d (port %d:bit %d)\n", __func__,
+ gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio));
+
+ if (get_direction(gpio) == DIRECTION_INPUT)
+ val = readl(&state->bank->gpio_in[GPIO_PORT(gpio)]);
+ else
+ val = readl(&state->bank->gpio_out[GPIO_PORT(gpio)]);
+
+ return (val >> GPIO_BIT(gpio)) & 1;
+}
+
+/* write GPIO OUT value to pin 'gpio' */
+static int tegra_gpio_set_value(struct udevice *dev, unsigned offset, int value)
+{
+ struct tegra_port_info *state = dev_get_priv(dev);
+ int gpio = state->base_gpio + offset;
+
+ debug("gpio_set_value: pin = %d (port %d:bit %d), value = %d\n",
+ gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio), value);
+
+ /* Configure GPIO output value. */
+ set_level(gpio, value);
+
+ return 0;
+}
+
+void gpio_config_table(const struct tegra_gpio_config *config, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ switch (config[i].init) {
+ case TEGRA_GPIO_INIT_IN:
+ set_direction(config[i].gpio, DIRECTION_INPUT);
+ break;
+ case TEGRA_GPIO_INIT_OUT0:
+ set_level(config[i].gpio, 0);
+ set_direction(config[i].gpio, DIRECTION_OUTPUT);
+ break;
+ case TEGRA_GPIO_INIT_OUT1:
+ set_level(config[i].gpio, 1);
+ set_direction(config[i].gpio, DIRECTION_OUTPUT);
+ break;
+ }
+ set_config(config[i].gpio, CONFIG_GPIO);
+ }
+}
+
+static int tegra_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+ struct tegra_port_info *state = dev_get_priv(dev);
+ int gpio = state->base_gpio + offset;
+
+ if (!get_config(gpio))
+ return GPIOF_FUNC;
+ else if (get_direction(gpio))
+ return GPIOF_OUTPUT;
+ else
+ return GPIOF_INPUT;
+}
+
+static int tegra_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
+ struct ofnode_phandle_args *args)
+{
+ int gpio, port, ret;
+
+ gpio = args->args[0];
+ port = gpio / TEGRA_GPIOS_PER_PORT;
+ ret = device_get_child(dev, port, &desc->dev);
+ if (ret)
+ return ret;
+ desc->offset = gpio % TEGRA_GPIOS_PER_PORT;
+ desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
+
+ return 0;
+}
+
+static const struct dm_gpio_ops gpio_tegra_ops = {
+ .direction_input = tegra_gpio_direction_input,
+ .direction_output = tegra_gpio_direction_output,
+ .get_value = tegra_gpio_get_value,
+ .set_value = tegra_gpio_set_value,
+ .get_function = tegra_gpio_get_function,
+ .xlate = tegra_gpio_xlate,
+};
+
+/**
+ * Returns the name of a GPIO port
+ *
+ * GPIOs are named A, B, C, ..., Z, AA, BB, CC, ...
+ *
+ * @base_port: Base port number (0, 1..n-1)
+ * @return allocated string containing the name
+ */
+static char *gpio_port_name(int base_port)
+{
+ char *name, *s;
+
+ name = malloc(3);
+ if (name) {
+ s = name;
+ *s++ = 'A' + (base_port % 26);
+ if (base_port >= 26)
+ *s++ = *name;
+ *s = '\0';
+ }
+
+ return name;
+}
+
+static const struct udevice_id tegra_gpio_ids[] = {
+ { .compatible = "nvidia,tegra30-gpio" },
+ { .compatible = "nvidia,tegra20-gpio" },
+ { }
+};
+
+static int gpio_tegra_probe(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct tegra_port_info *priv = dev_get_priv(dev);
+ struct tegra_gpio_plat *plat = dev_get_plat(dev);
+
+ /* Only child devices have ports */
+ if (!plat)
+ return 0;
+
+ priv->bank = plat->bank;
+ priv->base_gpio = plat->base_gpio;
+
+ uc_priv->gpio_count = TEGRA_GPIOS_PER_PORT;
+ uc_priv->bank_name = plat->port_name;
+
+ return 0;
+}
+
+/**
+ * We have a top-level GPIO device with no actual GPIOs. It has a child
+ * device for each Tegra port.
+ */
+static int gpio_tegra_bind(struct udevice *parent)
+{
+ struct tegra_gpio_plat *plat = dev_get_plat(parent);
+ struct gpio_ctlr *ctlr;
+ int bank_count;
+ int bank;
+ int ret;
+
+ /* If this is a child device, there is nothing to do here */
+ if (plat)
+ return 0;
+
+ /* TODO(sjg@chromium.org): Remove once SPL supports device tree */
+#ifdef CONFIG_SPL_BUILD
+ ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE;
+ bank_count = TEGRA_GPIO_BANKS;
+#else
+ {
+ int len;
+
+ /*
+ * This driver does not make use of interrupts, other than to figure
+ * out the number of GPIO banks
+ */
+ len = dev_read_size(parent, "interrupts");
+ if (len < 0)
+ return len;
+ bank_count = len / 3 / sizeof(u32);
+ ctlr = (struct gpio_ctlr *)dev_read_addr(parent);
+ if ((ulong)ctlr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+ }
+#endif
+ for (bank = 0; bank < bank_count; bank++) {
+ int port;
+
+ for (port = 0; port < TEGRA_PORTS_PER_BANK; port++) {
+ struct tegra_gpio_plat *plat;
+ struct udevice *dev;
+ int base_port;
+
+ plat = calloc(1, sizeof(*plat));
+ if (!plat)
+ return -ENOMEM;
+ plat->bank = &ctlr->gpio_bank[bank];
+ base_port = bank * TEGRA_PORTS_PER_BANK + port;
+ plat->base_gpio = TEGRA_GPIOS_PER_PORT * base_port;
+ plat->port_name = gpio_port_name(base_port);
+
+ ret = device_bind(parent, parent->driver,
+ plat->port_name, plat,
+ dev_ofnode(parent), &dev);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+U_BOOT_DRIVER(gpio_tegra) = {
+ .name = "gpio_tegra",
+ .id = UCLASS_GPIO,
+ .of_match = tegra_gpio_ids,
+ .bind = gpio_tegra_bind,
+ .probe = gpio_tegra_probe,
+ .priv_auto = sizeof(struct tegra_port_info),
+ .ops = &gpio_tegra_ops,
+};
diff --git a/roms/u-boot/drivers/gpio/vybrid_gpio.c b/roms/u-boot/drivers/gpio/vybrid_gpio.c
new file mode 100644
index 000000000..339392dcd
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/vybrid_gpio.c
@@ -0,0 +1,138 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015
+ * Bhuvanchandra DV, Toradex, Inc.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <asm/global_data.h>
+#include <asm/gpio.h>
+#include <asm/mach-imx/iomux-v3.h>
+#include <asm/io.h>
+#include <malloc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct vybrid_gpios {
+ unsigned int chip;
+ struct vybrid_gpio_regs *reg;
+};
+
+static int vybrid_gpio_direction_input(struct udevice *dev, unsigned gpio)
+{
+ const struct vybrid_gpios *gpios = dev_get_priv(dev);
+
+ gpio = gpio + (gpios->chip * VYBRID_GPIO_COUNT);
+ imx_iomux_gpio_set_direction(gpio, VF610_GPIO_DIRECTION_IN);
+
+ return 0;
+}
+
+static int vybrid_gpio_direction_output(struct udevice *dev, unsigned gpio,
+ int value)
+{
+ const struct vybrid_gpios *gpios = dev_get_priv(dev);
+
+ gpio = gpio + (gpios->chip * VYBRID_GPIO_COUNT);
+ gpio_set_value(gpio, value);
+ imx_iomux_gpio_set_direction(gpio, VF610_GPIO_DIRECTION_OUT);
+
+ return 0;
+}
+
+static int vybrid_gpio_get_value(struct udevice *dev, unsigned gpio)
+{
+ const struct vybrid_gpios *gpios = dev_get_priv(dev);
+
+ return ((readl(&gpios->reg->gpio_pdir) & (1 << gpio))) ? 1 : 0;
+}
+
+static int vybrid_gpio_set_value(struct udevice *dev, unsigned gpio,
+ int value)
+{
+ const struct vybrid_gpios *gpios = dev_get_priv(dev);
+ if (value)
+ writel((1 << gpio), &gpios->reg->gpio_psor);
+ else
+ writel((1 << gpio), &gpios->reg->gpio_pcor);
+
+ return 0;
+}
+
+static int vybrid_gpio_get_function(struct udevice *dev, unsigned gpio)
+{
+ const struct vybrid_gpios *gpios = dev_get_priv(dev);
+ u32 g_state = 0;
+
+ gpio = gpio + (gpios->chip * VYBRID_GPIO_COUNT);
+
+ imx_iomux_gpio_get_function(gpio, &g_state);
+
+ if (((g_state & (0x07 << PAD_MUX_MODE_SHIFT)) >> PAD_MUX_MODE_SHIFT) > 0)
+ return GPIOF_FUNC;
+ if (g_state & PAD_CTL_OBE_ENABLE)
+ return GPIOF_OUTPUT;
+ if (g_state & PAD_CTL_IBE_ENABLE)
+ return GPIOF_INPUT;
+ if (!(g_state & PAD_CTL_OBE_IBE_ENABLE))
+ return GPIOF_UNUSED;
+
+ return GPIOF_UNKNOWN;
+}
+
+static const struct dm_gpio_ops gpio_vybrid_ops = {
+ .direction_input = vybrid_gpio_direction_input,
+ .direction_output = vybrid_gpio_direction_output,
+ .get_value = vybrid_gpio_get_value,
+ .set_value = vybrid_gpio_set_value,
+ .get_function = vybrid_gpio_get_function,
+};
+
+static int vybrid_gpio_probe(struct udevice *dev)
+{
+ struct vybrid_gpios *gpios = dev_get_priv(dev);
+ struct vybrid_gpio_plat *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ uc_priv->bank_name = plat->port_name;
+ uc_priv->gpio_count = VYBRID_GPIO_COUNT;
+ gpios->reg = (struct vybrid_gpio_regs *)plat->base;
+ gpios->chip = plat->chip;
+
+ return 0;
+}
+
+static int vybrid_gpio_odata_to_plat(struct udevice *dev)
+{
+ struct vybrid_gpio_plat *plat = dev_get_plat(dev);
+ fdt_addr_t base_addr;
+
+ base_addr = dev_read_addr(dev);
+ if (base_addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ plat->base = base_addr;
+ plat->chip = dev_seq(dev);
+ plat->port_name = fdt_get_name(gd->fdt_blob, dev_of_offset(dev), NULL);
+
+ return 0;
+}
+
+static const struct udevice_id vybrid_gpio_ids[] = {
+ { .compatible = "fsl,vf610-gpio" },
+ { }
+};
+
+U_BOOT_DRIVER(gpio_vybrid) = {
+ .name = "gpio_vybrid",
+ .id = UCLASS_GPIO,
+ .ops = &gpio_vybrid_ops,
+ .of_match = vybrid_gpio_ids,
+ .of_to_plat = vybrid_gpio_odata_to_plat,
+ .probe = vybrid_gpio_probe,
+ .priv_auto = sizeof(struct vybrid_gpios),
+ .plat_auto = sizeof(struct vybrid_gpio_plat),
+};
diff --git a/roms/u-boot/drivers/gpio/xilinx_gpio.c b/roms/u-boot/drivers/gpio/xilinx_gpio.c
new file mode 100644
index 000000000..510838d2f
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/xilinx_gpio.c
@@ -0,0 +1,308 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2013 - 2018 Xilinx, Michal Simek
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <log.h>
+#include <malloc.h>
+#include <linux/list.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <dm.h>
+#include <dt-bindings/gpio/gpio.h>
+
+#define XILINX_GPIO_MAX_BANK 2
+
+/* Gpio simple map */
+struct gpio_regs {
+ u32 gpiodata;
+ u32 gpiodir;
+};
+
+struct xilinx_gpio_plat {
+ struct gpio_regs *regs;
+ int bank_max[XILINX_GPIO_MAX_BANK];
+ int bank_input[XILINX_GPIO_MAX_BANK];
+ int bank_output[XILINX_GPIO_MAX_BANK];
+ u32 dout_default[XILINX_GPIO_MAX_BANK];
+};
+
+struct xilinx_gpio_privdata {
+ u32 output_val[XILINX_GPIO_MAX_BANK];
+};
+
+static int xilinx_gpio_get_bank_pin(unsigned offset, u32 *bank_num,
+ u32 *bank_pin_num, struct udevice *dev)
+{
+ struct xilinx_gpio_plat *plat = dev_get_plat(dev);
+ u32 bank, max_pins;
+ /* the first gpio is 0 not 1 */
+ u32 pin_num = offset;
+
+ for (bank = 0; bank < XILINX_GPIO_MAX_BANK; bank++) {
+ max_pins = plat->bank_max[bank];
+ if (pin_num < max_pins) {
+ debug("%s: found at bank 0x%x pin 0x%x\n", __func__,
+ bank, pin_num);
+ *bank_num = bank;
+ *bank_pin_num = pin_num;
+ return 0;
+ }
+ pin_num -= max_pins;
+ }
+
+ return -EINVAL;
+}
+
+static int xilinx_gpio_set_value(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct xilinx_gpio_plat *plat = dev_get_plat(dev);
+ struct xilinx_gpio_privdata *priv = dev_get_priv(dev);
+ int val, ret;
+ u32 bank, pin;
+
+ ret = xilinx_gpio_get_bank_pin(offset, &bank, &pin, dev);
+ if (ret)
+ return ret;
+
+ val = priv->output_val[bank];
+
+ debug("%s: regs: %lx, value: %x, gpio: %x, bank %x, pin %x, out %x\n",
+ __func__, (ulong)plat->regs, value, offset, bank, pin, val);
+
+ if (value)
+ val = val | (1 << pin);
+ else
+ val = val & ~(1 << pin);
+
+ writel(val, &plat->regs->gpiodata + bank * 2);
+
+ priv->output_val[bank] = val;
+
+ return 0;
+};
+
+static int xilinx_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+ struct xilinx_gpio_plat *plat = dev_get_plat(dev);
+ struct xilinx_gpio_privdata *priv = dev_get_priv(dev);
+ int val, ret;
+ u32 bank, pin;
+
+ ret = xilinx_gpio_get_bank_pin(offset, &bank, &pin, dev);
+ if (ret)
+ return ret;
+
+ debug("%s: regs: %lx, gpio: %x, bank %x, pin %x\n", __func__,
+ (ulong)plat->regs, offset, bank, pin);
+
+ if (plat->bank_output[bank]) {
+ debug("%s: Read saved output value\n", __func__);
+ val = priv->output_val[bank];
+ } else {
+ debug("%s: Read input value from reg\n", __func__);
+ val = readl(&plat->regs->gpiodata + bank * 2);
+ }
+
+ val = !!(val & (1 << pin));
+
+ return val;
+};
+
+static int xilinx_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+ struct xilinx_gpio_plat *plat = dev_get_plat(dev);
+ int val, ret;
+ u32 bank, pin;
+
+ ret = xilinx_gpio_get_bank_pin(offset, &bank, &pin, dev);
+ if (ret)
+ return ret;
+
+ /* Check if all pins are inputs */
+ if (plat->bank_input[bank])
+ return GPIOF_INPUT;
+
+ /* Check if all pins are outputs */
+ if (plat->bank_output[bank])
+ return GPIOF_OUTPUT;
+
+ /* FIXME test on dual */
+ val = readl(&plat->regs->gpiodir + bank * 2);
+ val = !(val & (1 << pin));
+
+ /* input is 1 in reg but GPIOF_INPUT is 0 */
+ /* output is 0 in reg but GPIOF_OUTPUT is 1 */
+
+ return val;
+}
+
+static int xilinx_gpio_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct xilinx_gpio_plat *plat = dev_get_plat(dev);
+ int val, ret;
+ u32 bank, pin;
+
+ ret = xilinx_gpio_get_bank_pin(offset, &bank, &pin, dev);
+ if (ret)
+ return ret;
+
+ /* can't change it if all is input by default */
+ if (plat->bank_input[bank])
+ return -EINVAL;
+
+ xilinx_gpio_set_value(dev, offset, value);
+
+ if (!plat->bank_output[bank]) {
+ val = readl(&plat->regs->gpiodir + bank * 2);
+ val = val & ~(1 << pin);
+ writel(val, &plat->regs->gpiodir + bank * 2);
+ }
+
+ return 0;
+}
+
+static int xilinx_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+ struct xilinx_gpio_plat *plat = dev_get_plat(dev);
+ int val, ret;
+ u32 bank, pin;
+
+ ret = xilinx_gpio_get_bank_pin(offset, &bank, &pin, dev);
+ if (ret)
+ return ret;
+
+ /* Already input */
+ if (plat->bank_input[bank])
+ return 0;
+
+ /* can't change it if all is output by default */
+ if (plat->bank_output[bank])
+ return -EINVAL;
+
+ val = readl(&plat->regs->gpiodir + bank * 2);
+ val = val | (1 << pin);
+ writel(val, &plat->regs->gpiodir + bank * 2);
+
+ return 0;
+}
+
+static int xilinx_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
+ struct ofnode_phandle_args *args)
+{
+ struct xilinx_gpio_plat *plat = dev_get_plat(dev);
+
+ desc->offset = args->args[0];
+
+ debug("%s: argc: %x, [0]: %x, [1]: %x, [2]: %x\n", __func__,
+ args->args_count, args->args[0], args->args[1], args->args[2]);
+
+ /*
+ * The second cell is channel offset:
+ * 0 is first channel, 8 is second channel
+ *
+ * U-Boot driver just combine channels together that's why simply
+ * add amount of pins in second channel if present.
+ */
+ if (args->args[1]) {
+ if (!plat->bank_max[1]) {
+ printf("%s: %s has no second channel\n",
+ __func__, dev->name);
+ return -EINVAL;
+ }
+
+ desc->offset += plat->bank_max[0];
+ }
+
+ /* The third cell is optional */
+ if (args->args_count > 2)
+ desc->flags = (args->args[2] &
+ GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0);
+
+ debug("%s: offset %x, flags %lx\n",
+ __func__, desc->offset, desc->flags);
+ return 0;
+}
+
+static const struct dm_gpio_ops xilinx_gpio_ops = {
+ .direction_input = xilinx_gpio_direction_input,
+ .direction_output = xilinx_gpio_direction_output,
+ .get_value = xilinx_gpio_get_value,
+ .set_value = xilinx_gpio_set_value,
+ .get_function = xilinx_gpio_get_function,
+ .xlate = xilinx_gpio_xlate,
+};
+
+static int xilinx_gpio_probe(struct udevice *dev)
+{
+ struct xilinx_gpio_plat *plat = dev_get_plat(dev);
+ struct xilinx_gpio_privdata *priv = dev_get_priv(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ const void *label_ptr;
+
+ label_ptr = dev_read_prop(dev, "label", NULL);
+ if (label_ptr) {
+ uc_priv->bank_name = strdup(label_ptr);
+ if (!uc_priv->bank_name)
+ return -ENOMEM;
+ } else {
+ uc_priv->bank_name = dev->name;
+ }
+
+ uc_priv->gpio_count = plat->bank_max[0] + plat->bank_max[1];
+
+ priv->output_val[0] = plat->dout_default[0];
+
+ if (plat->bank_max[1])
+ priv->output_val[1] = plat->dout_default[1];
+
+ return 0;
+}
+
+static int xilinx_gpio_of_to_plat(struct udevice *dev)
+{
+ struct xilinx_gpio_plat *plat = dev_get_plat(dev);
+ int is_dual;
+
+ plat->regs = (struct gpio_regs *)dev_read_addr(dev);
+
+ plat->bank_max[0] = dev_read_u32_default(dev, "xlnx,gpio-width", 0);
+ plat->bank_input[0] = dev_read_u32_default(dev, "xlnx,all-inputs", 0);
+ plat->bank_output[0] = dev_read_u32_default(dev, "xlnx,all-outputs", 0);
+ plat->dout_default[0] = dev_read_u32_default(dev, "xlnx,dout-default",
+ 0);
+
+ is_dual = dev_read_u32_default(dev, "xlnx,is-dual", 0);
+ if (is_dual) {
+ plat->bank_max[1] = dev_read_u32_default(dev,
+ "xlnx,gpio2-width", 0);
+ plat->bank_input[1] = dev_read_u32_default(dev,
+ "xlnx,all-inputs-2", 0);
+ plat->bank_output[1] = dev_read_u32_default(dev,
+ "xlnx,all-outputs-2", 0);
+ plat->dout_default[1] = dev_read_u32_default(dev,
+ "xlnx,dout-default-2", 0);
+ }
+
+ return 0;
+}
+
+static const struct udevice_id xilinx_gpio_ids[] = {
+ { .compatible = "xlnx,xps-gpio-1.00.a",},
+ { }
+};
+
+U_BOOT_DRIVER(xilinx_gpio) = {
+ .name = "xlnx_gpio",
+ .id = UCLASS_GPIO,
+ .ops = &xilinx_gpio_ops,
+ .of_match = xilinx_gpio_ids,
+ .of_to_plat = xilinx_gpio_of_to_plat,
+ .probe = xilinx_gpio_probe,
+ .plat_auto = sizeof(struct xilinx_gpio_plat),
+ .priv_auto = sizeof(struct xilinx_gpio_privdata),
+};
diff --git a/roms/u-boot/drivers/gpio/zynq_gpio.c b/roms/u-boot/drivers/gpio/zynq_gpio.c
new file mode 100644
index 000000000..71a56127c
--- /dev/null
+++ b/roms/u-boot/drivers/gpio/zynq_gpio.c
@@ -0,0 +1,411 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Xilinx Zynq GPIO device driver
+ *
+ * Copyright (C) 2015 DAVE Embedded Systems <devel@dave.eu>
+ *
+ * Most of code taken from linux kernel driver (linux/drivers/gpio/gpio-zynq.c)
+ * Copyright (C) 2009 - 2014 Xilinx, Inc.
+ */
+
+#include <common.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+#include <linux/errno.h>
+#include <dm.h>
+#include <fdtdec.h>
+
+/* Maximum banks */
+#define ZYNQ_GPIO_MAX_BANK 4
+
+#define ZYNQ_GPIO_BANK0_NGPIO 32
+#define ZYNQ_GPIO_BANK1_NGPIO 22
+#define ZYNQ_GPIO_BANK2_NGPIO 32
+#define ZYNQ_GPIO_BANK3_NGPIO 32
+
+#define ZYNQ_GPIO_NR_GPIOS (ZYNQ_GPIO_BANK0_NGPIO + \
+ ZYNQ_GPIO_BANK1_NGPIO + \
+ ZYNQ_GPIO_BANK2_NGPIO + \
+ ZYNQ_GPIO_BANK3_NGPIO)
+
+#define ZYNQMP_GPIO_MAX_BANK 6
+
+#define ZYNQMP_GPIO_BANK0_NGPIO 26
+#define ZYNQMP_GPIO_BANK1_NGPIO 26
+#define ZYNQMP_GPIO_BANK2_NGPIO 26
+#define ZYNQMP_GPIO_BANK3_NGPIO 32
+#define ZYNQMP_GPIO_BANK4_NGPIO 32
+#define ZYNQMP_GPIO_BANK5_NGPIO 32
+
+#define ZYNQMP_GPIO_NR_GPIOS 174
+
+#define ZYNQ_GPIO_BANK0_PIN_MIN(str) 0
+#define ZYNQ_GPIO_BANK0_PIN_MAX(str) (ZYNQ_GPIO_BANK0_PIN_MIN(str) + \
+ ZYNQ##str##_GPIO_BANK0_NGPIO - 1)
+#define ZYNQ_GPIO_BANK1_PIN_MIN(str) (ZYNQ_GPIO_BANK0_PIN_MAX(str) + 1)
+#define ZYNQ_GPIO_BANK1_PIN_MAX(str) (ZYNQ_GPIO_BANK1_PIN_MIN(str) + \
+ ZYNQ##str##_GPIO_BANK1_NGPIO - 1)
+#define ZYNQ_GPIO_BANK2_PIN_MIN(str) (ZYNQ_GPIO_BANK1_PIN_MAX(str) + 1)
+#define ZYNQ_GPIO_BANK2_PIN_MAX(str) (ZYNQ_GPIO_BANK2_PIN_MIN(str) + \
+ ZYNQ##str##_GPIO_BANK2_NGPIO - 1)
+#define ZYNQ_GPIO_BANK3_PIN_MIN(str) (ZYNQ_GPIO_BANK2_PIN_MAX(str) + 1)
+#define ZYNQ_GPIO_BANK3_PIN_MAX(str) (ZYNQ_GPIO_BANK3_PIN_MIN(str) + \
+ ZYNQ##str##_GPIO_BANK3_NGPIO - 1)
+#define ZYNQ_GPIO_BANK4_PIN_MIN(str) (ZYNQ_GPIO_BANK3_PIN_MAX(str) + 1)
+#define ZYNQ_GPIO_BANK4_PIN_MAX(str) (ZYNQ_GPIO_BANK4_PIN_MIN(str) + \
+ ZYNQ##str##_GPIO_BANK4_NGPIO - 1)
+#define ZYNQ_GPIO_BANK5_PIN_MIN(str) (ZYNQ_GPIO_BANK4_PIN_MAX(str) + 1)
+#define ZYNQ_GPIO_BANK5_PIN_MAX(str) (ZYNQ_GPIO_BANK5_PIN_MIN(str) + \
+ ZYNQ##str##_GPIO_BANK5_NGPIO - 1)
+
+/* Register offsets for the GPIO device */
+/* LSW Mask & Data -WO */
+#define ZYNQ_GPIO_DATA_LSW_OFFSET(BANK) (0x000 + (8 * BANK))
+/* MSW Mask & Data -WO */
+#define ZYNQ_GPIO_DATA_MSW_OFFSET(BANK) (0x004 + (8 * BANK))
+/* Data Register-RW */
+#define ZYNQ_GPIO_DATA_RO_OFFSET(BANK) (0x060 + (4 * BANK))
+/* Direction mode reg-RW */
+#define ZYNQ_GPIO_DIRM_OFFSET(BANK) (0x204 + (0x40 * BANK))
+/* Output enable reg-RW */
+#define ZYNQ_GPIO_OUTEN_OFFSET(BANK) (0x208 + (0x40 * BANK))
+/* Interrupt mask reg-RO */
+#define ZYNQ_GPIO_INTMASK_OFFSET(BANK) (0x20C + (0x40 * BANK))
+/* Interrupt enable reg-WO */
+#define ZYNQ_GPIO_INTEN_OFFSET(BANK) (0x210 + (0x40 * BANK))
+/* Interrupt disable reg-WO */
+#define ZYNQ_GPIO_INTDIS_OFFSET(BANK) (0x214 + (0x40 * BANK))
+/* Interrupt status reg-RO */
+#define ZYNQ_GPIO_INTSTS_OFFSET(BANK) (0x218 + (0x40 * BANK))
+/* Interrupt type reg-RW */
+#define ZYNQ_GPIO_INTTYPE_OFFSET(BANK) (0x21C + (0x40 * BANK))
+/* Interrupt polarity reg-RW */
+#define ZYNQ_GPIO_INTPOL_OFFSET(BANK) (0x220 + (0x40 * BANK))
+/* Interrupt on any, reg-RW */
+#define ZYNQ_GPIO_INTANY_OFFSET(BANK) (0x224 + (0x40 * BANK))
+
+/* Disable all interrupts mask */
+#define ZYNQ_GPIO_IXR_DISABLE_ALL 0xFFFFFFFF
+
+/* Mid pin number of a bank */
+#define ZYNQ_GPIO_MID_PIN_NUM 16
+
+/* GPIO upper 16 bit mask */
+#define ZYNQ_GPIO_UPPER_MASK 0xFFFF0000
+
+#define PMC_GPIO_NR_GPIOS 116
+#define PMC_GPIO_MAX_BANK 5
+
+struct zynq_gpio_plat {
+ phys_addr_t base;
+ const struct zynq_platform_data *p_data;
+};
+
+/**
+ * struct zynq_platform_data - zynq gpio platform data structure
+ * @label: string to store in gpio->label
+ * @ngpio: max number of gpio pins
+ * @max_bank: maximum number of gpio banks
+ * @bank_min: this array represents bank's min pin
+ * @bank_max: this array represents bank's max pin
+ */
+struct zynq_platform_data {
+ const char *label;
+ u16 ngpio;
+ u32 max_bank;
+ u32 bank_min[ZYNQMP_GPIO_MAX_BANK];
+ u32 bank_max[ZYNQMP_GPIO_MAX_BANK];
+};
+
+#define VERSAL_GPIO_NR_GPIOS 58
+#define VERSAL_GPIO_MAX_BANK 4
+
+static const struct zynq_platform_data versal_gpio_def = {
+ .label = "versal_gpio",
+ .ngpio = VERSAL_GPIO_NR_GPIOS,
+ .max_bank = VERSAL_GPIO_MAX_BANK,
+ .bank_min[0] = 0,
+ .bank_max[0] = 25,
+ .bank_min[3] = 26,
+ .bank_max[3] = 57,
+};
+
+static const struct zynq_platform_data pmc_gpio_def = {
+ .label = "pmc_gpio",
+ .ngpio = PMC_GPIO_NR_GPIOS,
+ .max_bank = PMC_GPIO_MAX_BANK,
+ .bank_min[0] = 0,
+ .bank_max[0] = 25,
+ .bank_min[1] = 26,
+ .bank_max[1] = 51,
+ .bank_min[3] = 52,
+ .bank_max[3] = 83,
+ .bank_min[4] = 84,
+ .bank_max[4] = 115,
+};
+
+static const struct zynq_platform_data zynqmp_gpio_def = {
+ .label = "zynqmp_gpio",
+ .ngpio = ZYNQMP_GPIO_NR_GPIOS,
+ .max_bank = ZYNQMP_GPIO_MAX_BANK,
+ .bank_min[0] = ZYNQ_GPIO_BANK0_PIN_MIN(MP),
+ .bank_max[0] = ZYNQ_GPIO_BANK0_PIN_MAX(MP),
+ .bank_min[1] = ZYNQ_GPIO_BANK1_PIN_MIN(MP),
+ .bank_max[1] = ZYNQ_GPIO_BANK1_PIN_MAX(MP),
+ .bank_min[2] = ZYNQ_GPIO_BANK2_PIN_MIN(MP),
+ .bank_max[2] = ZYNQ_GPIO_BANK2_PIN_MAX(MP),
+ .bank_min[3] = ZYNQ_GPIO_BANK3_PIN_MIN(MP),
+ .bank_max[3] = ZYNQ_GPIO_BANK3_PIN_MAX(MP),
+ .bank_min[4] = ZYNQ_GPIO_BANK4_PIN_MIN(MP),
+ .bank_max[4] = ZYNQ_GPIO_BANK4_PIN_MAX(MP),
+ .bank_min[5] = ZYNQ_GPIO_BANK5_PIN_MIN(MP),
+ .bank_max[5] = ZYNQ_GPIO_BANK5_PIN_MAX(MP),
+};
+
+static const struct zynq_platform_data zynq_gpio_def = {
+ .label = "zynq_gpio",
+ .ngpio = ZYNQ_GPIO_NR_GPIOS,
+ .max_bank = ZYNQ_GPIO_MAX_BANK,
+ .bank_min[0] = ZYNQ_GPIO_BANK0_PIN_MIN(),
+ .bank_max[0] = ZYNQ_GPIO_BANK0_PIN_MAX(),
+ .bank_min[1] = ZYNQ_GPIO_BANK1_PIN_MIN(),
+ .bank_max[1] = ZYNQ_GPIO_BANK1_PIN_MAX(),
+ .bank_min[2] = ZYNQ_GPIO_BANK2_PIN_MIN(),
+ .bank_max[2] = ZYNQ_GPIO_BANK2_PIN_MAX(),
+ .bank_min[3] = ZYNQ_GPIO_BANK3_PIN_MIN(),
+ .bank_max[3] = ZYNQ_GPIO_BANK3_PIN_MAX(),
+};
+
+/**
+ * zynq_gpio_get_bank_pin - Get the bank number and pin number within that bank
+ * for a given pin in the GPIO device
+ * @pin_num: gpio pin number within the device
+ * @bank_num: an output parameter used to return the bank number of the gpio
+ * pin
+ * @bank_pin_num: an output parameter used to return pin number within a bank
+ * for the given gpio pin
+ *
+ * Returns the bank number and pin offset within the bank.
+ */
+static inline void zynq_gpio_get_bank_pin(unsigned int pin_num,
+ unsigned int *bank_num,
+ unsigned int *bank_pin_num,
+ struct udevice *dev)
+{
+ struct zynq_gpio_plat *plat = dev_get_plat(dev);
+ u32 bank;
+
+ for (bank = 0; bank < plat->p_data->max_bank; bank++) {
+ if (pin_num >= plat->p_data->bank_min[bank] &&
+ pin_num <= plat->p_data->bank_max[bank]) {
+ *bank_num = bank;
+ *bank_pin_num = pin_num -
+ plat->p_data->bank_min[bank];
+ return;
+ }
+ }
+
+ if (bank >= plat->p_data->max_bank) {
+ printf("Invalid bank and pin num\n");
+ *bank_num = 0;
+ *bank_pin_num = 0;
+ }
+}
+
+static int gpio_is_valid(unsigned gpio, struct udevice *dev)
+{
+ struct zynq_gpio_plat *plat = dev_get_plat(dev);
+
+ return gpio < plat->p_data->ngpio;
+}
+
+static int check_gpio(unsigned gpio, struct udevice *dev)
+{
+ if (!gpio_is_valid(gpio, dev)) {
+ printf("ERROR : check_gpio: invalid GPIO %d\n", gpio);
+ return -1;
+ }
+ return 0;
+}
+
+static int zynq_gpio_get_value(struct udevice *dev, unsigned gpio)
+{
+ u32 data;
+ unsigned int bank_num, bank_pin_num;
+ struct zynq_gpio_plat *plat = dev_get_plat(dev);
+
+ if (check_gpio(gpio, dev) < 0)
+ return -1;
+
+ zynq_gpio_get_bank_pin(gpio, &bank_num, &bank_pin_num, dev);
+
+ data = readl(plat->base +
+ ZYNQ_GPIO_DATA_RO_OFFSET(bank_num));
+
+ return (data >> bank_pin_num) & 1;
+}
+
+static int zynq_gpio_set_value(struct udevice *dev, unsigned gpio, int value)
+{
+ unsigned int reg_offset, bank_num, bank_pin_num;
+ struct zynq_gpio_plat *plat = dev_get_plat(dev);
+
+ if (check_gpio(gpio, dev) < 0)
+ return -1;
+
+ zynq_gpio_get_bank_pin(gpio, &bank_num, &bank_pin_num, dev);
+
+ if (bank_pin_num >= ZYNQ_GPIO_MID_PIN_NUM) {
+ /* only 16 data bits in bit maskable reg */
+ bank_pin_num -= ZYNQ_GPIO_MID_PIN_NUM;
+ reg_offset = ZYNQ_GPIO_DATA_MSW_OFFSET(bank_num);
+ } else {
+ reg_offset = ZYNQ_GPIO_DATA_LSW_OFFSET(bank_num);
+ }
+
+ /*
+ * get the 32 bit value to be written to the mask/data register where
+ * the upper 16 bits is the mask and lower 16 bits is the data
+ */
+ value = !!value;
+ value = ~(1 << (bank_pin_num + ZYNQ_GPIO_MID_PIN_NUM)) &
+ ((value << bank_pin_num) | ZYNQ_GPIO_UPPER_MASK);
+
+ writel(value, plat->base + reg_offset);
+
+ return 0;
+}
+
+static int zynq_gpio_direction_input(struct udevice *dev, unsigned gpio)
+{
+ u32 reg;
+ unsigned int bank_num, bank_pin_num;
+ struct zynq_gpio_plat *plat = dev_get_plat(dev);
+
+ if (check_gpio(gpio, dev) < 0)
+ return -1;
+
+ zynq_gpio_get_bank_pin(gpio, &bank_num, &bank_pin_num, dev);
+
+ /* bank 0 pins 7 and 8 are special and cannot be used as inputs */
+ if (bank_num == 0 && (bank_pin_num == 7 || bank_pin_num == 8))
+ return -1;
+
+ /* clear the bit in direction mode reg to set the pin as input */
+ reg = readl(plat->base + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
+ reg &= ~BIT(bank_pin_num);
+ writel(reg, plat->base + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
+
+ return 0;
+}
+
+static int zynq_gpio_direction_output(struct udevice *dev, unsigned gpio,
+ int value)
+{
+ u32 reg;
+ unsigned int bank_num, bank_pin_num;
+ struct zynq_gpio_plat *plat = dev_get_plat(dev);
+
+ if (check_gpio(gpio, dev) < 0)
+ return -1;
+
+ zynq_gpio_get_bank_pin(gpio, &bank_num, &bank_pin_num, dev);
+
+ /* set the GPIO pin as output */
+ reg = readl(plat->base + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
+ reg |= BIT(bank_pin_num);
+ writel(reg, plat->base + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
+
+ /* configure the output enable reg for the pin */
+ reg = readl(plat->base + ZYNQ_GPIO_OUTEN_OFFSET(bank_num));
+ reg |= BIT(bank_pin_num);
+ writel(reg, plat->base + ZYNQ_GPIO_OUTEN_OFFSET(bank_num));
+
+ /* set the state of the pin */
+ zynq_gpio_set_value(dev, gpio, value);
+ return 0;
+}
+
+static int zynq_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+ u32 reg;
+ unsigned int bank_num, bank_pin_num;
+ struct zynq_gpio_plat *plat = dev_get_plat(dev);
+
+ if (check_gpio(offset, dev) < 0)
+ return -1;
+
+ zynq_gpio_get_bank_pin(offset, &bank_num, &bank_pin_num, dev);
+
+ /* set the GPIO pin as output */
+ reg = readl(plat->base + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
+ reg &= BIT(bank_pin_num);
+ if (reg)
+ return GPIOF_OUTPUT;
+ else
+ return GPIOF_INPUT;
+}
+
+static const struct dm_gpio_ops gpio_zynq_ops = {
+ .direction_input = zynq_gpio_direction_input,
+ .direction_output = zynq_gpio_direction_output,
+ .get_value = zynq_gpio_get_value,
+ .set_value = zynq_gpio_set_value,
+ .get_function = zynq_gpio_get_function,
+};
+
+static const struct udevice_id zynq_gpio_ids[] = {
+ { .compatible = "xlnx,zynq-gpio-1.0",
+ .data = (ulong)&zynq_gpio_def},
+ { .compatible = "xlnx,zynqmp-gpio-1.0",
+ .data = (ulong)&zynqmp_gpio_def},
+ { .compatible = "xlnx,versal-gpio-1.0",
+ .data = (ulong)&versal_gpio_def},
+ { .compatible = "xlnx,pmc-gpio-1.0",
+ .data = (ulong)&pmc_gpio_def },
+ { }
+};
+
+static int zynq_gpio_probe(struct udevice *dev)
+{
+ struct zynq_gpio_plat *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ const void *label_ptr;
+
+ label_ptr = dev_read_prop(dev, "label", NULL);
+ if (label_ptr) {
+ uc_priv->bank_name = strdup(label_ptr);
+ if (!uc_priv->bank_name)
+ return -ENOMEM;
+ } else {
+ uc_priv->bank_name = dev->name;
+ }
+
+ if (plat->p_data)
+ uc_priv->gpio_count = plat->p_data->ngpio;
+
+ return 0;
+}
+
+static int zynq_gpio_of_to_plat(struct udevice *dev)
+{
+ struct zynq_gpio_plat *plat = dev_get_plat(dev);
+
+ plat->base = (phys_addr_t)dev_read_addr(dev);
+
+ plat->p_data =
+ (struct zynq_platform_data *)dev_get_driver_data(dev);
+
+ return 0;
+}
+
+U_BOOT_DRIVER(gpio_zynq) = {
+ .name = "gpio_zynq",
+ .id = UCLASS_GPIO,
+ .ops = &gpio_zynq_ops,
+ .of_match = zynq_gpio_ids,
+ .of_to_plat = zynq_gpio_of_to_plat,
+ .probe = zynq_gpio_probe,
+ .plat_auto = sizeof(struct zynq_gpio_plat),
+};