aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/clk/clk-uclass.c6
-rw-r--r--drivers/clk/clk_stm32mp1.c1
-rw-r--r--drivers/clk/uniphier/clk-uniphier-sys.c3
-rw-r--r--drivers/core/dump.c7
-rw-r--r--drivers/core/regmap.c1
-rw-r--r--drivers/gpio/Kconfig8
-rw-r--r--drivers/gpio/Makefile2
-rw-r--r--drivers/gpio/db8500_gpio.c221
-rw-r--r--drivers/gpio/nmk_gpio.c125
-rw-r--r--drivers/misc/cros_ec_sandbox.c12
-rw-r--r--drivers/misc/i2c_eeprom.c1
-rw-r--r--drivers/mmc/mmc.c7
-rw-r--r--drivers/mmc/sunxi_mmc.c160
-rw-r--r--drivers/net/sandbox-raw.c2
-rw-r--r--drivers/pci/Kconfig10
-rw-r--r--drivers/pci/Makefile1
-rw-r--r--drivers/pci/pci-aardvark.c9
-rw-r--r--drivers/pci/pci-uclass.c39
-rw-r--r--drivers/pci/pcie_uniphier.c424
-rw-r--r--drivers/phy/Kconfig6
-rw-r--r--drivers/phy/Makefile1
-rw-r--r--drivers/phy/allwinner/phy-sun4i-usb.c14
-rw-r--r--drivers/phy/phy-ab8500-usb.c52
-rw-r--r--drivers/phy/socionext/Kconfig12
-rw-r--r--drivers/phy/socionext/Makefile6
-rw-r--r--drivers/phy/socionext/phy-uniphier-pcie.c59
-rw-r--r--drivers/pinctrl/pinctrl-single.c1
-rw-r--r--drivers/power/pmic/Kconfig10
-rw-r--r--drivers/power/pmic/Makefile1
-rw-r--r--drivers/power/pmic/ab8500.c268
-rw-r--r--drivers/reset/reset-uclass.c2
-rw-r--r--drivers/reset/reset-uniphier.c3
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/m41t62.c4
-rw-r--r--drivers/rtc/rtc-lib.c77
-rw-r--r--drivers/serial/Kconfig1
-rw-r--r--drivers/spi/ich.c4
-rw-r--r--drivers/timer/nomadik-mtu-timer.c7
-rw-r--r--drivers/tpm/cr50_i2c.c2
-rw-r--r--drivers/usb/musb-new/Kconfig11
-rw-r--r--drivers/usb/musb-new/Makefile1
-rw-r--r--drivers/usb/musb-new/musb_core.c2
-rw-r--r--drivers/usb/musb-new/ux500.c179
-rw-r--r--drivers/video/pwm_backlight.c6
-rw-r--r--drivers/watchdog/designware_wdt.c19
-rw-r--r--drivers/watchdog/wdt-uclass.c2
48 files changed, 1388 insertions, 405 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index b1ada1cb7f..c9c812b752 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -80,6 +80,8 @@ source "drivers/phy/allwinner/Kconfig"
source "drivers/phy/marvell/Kconfig"
+source "drivers/phy/socionext/Kconfig"
+
source "drivers/pinctrl/Kconfig"
source "drivers/power/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 3510daba29..4081289104 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -96,6 +96,7 @@ obj-$(CONFIG_PCH) += pch/
obj-y += phy/allwinner/
obj-y += phy/marvell/
obj-y += phy/rockchip/
+obj-y += phy/socionext/
obj-y += rtc/
obj-y += scsi/
obj-y += sound/
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index f049e36380..cea38a4c6e 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -847,13 +847,17 @@ void devm_clk_put(struct udevice *dev, struct clk *clk)
int clk_uclass_post_probe(struct udevice *dev)
{
+ int ret;
+
/*
* when a clock provider is probed. Call clk_set_defaults()
* also after the device is probed. This takes care of cases
* where the DT is used to setup default parents and rates
* using assigned-clocks
*/
- clk_set_defaults(dev, CLK_DEFAULTS_POST);
+ ret = clk_set_defaults(dev, CLK_DEFAULTS_POST);
+ if (ret)
+ return log_ret(ret);
return 0;
}
diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c
index 0c0ef366a1..48c9514ba0 100644
--- a/drivers/clk/clk_stm32mp1.c
+++ b/drivers/clk/clk_stm32mp1.c
@@ -540,6 +540,7 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = {
STM32MP1_CLK_SET_CLR(RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL),
STM32MP1_CLK_SET_CLR_F(RCC_MP_APB3ENSETR, 13, VREF, _PCLK3),
+ STM32MP1_CLK_SET_CLR_F(RCC_MP_APB3ENSETR, 11, SYSCFG, _UNKNOWN_SEL),
STM32MP1_CLK_SET_CLR_F(RCC_MP_APB4ENSETR, 0, LTDC_PX, _PLL4_Q),
STM32MP1_CLK_SET_CLR_F(RCC_MP_APB4ENSETR, 4, DSI_PX, _PLL4_Q),
diff --git a/drivers/clk/uniphier/clk-uniphier-sys.c b/drivers/clk/uniphier/clk-uniphier-sys.c
index c627a4bf85..ff5d364f59 100644
--- a/drivers/clk/uniphier/clk-uniphier-sys.c
+++ b/drivers/clk/uniphier/clk-uniphier-sys.c
@@ -29,6 +29,7 @@ const struct uniphier_clk_data uniphier_pxs2_sys_clk_data[] = {
UNIPHIER_CLK_GATE_SIMPLE(15, 0x2104, 17), /* usb31 (Pro4, Pro5, PXs2) */
UNIPHIER_CLK_GATE_SIMPLE(16, 0x2104, 19), /* usb30-phy (PXs2) */
UNIPHIER_CLK_GATE_SIMPLE(20, 0x2104, 20), /* usb31-phy (PXs2) */
+ UNIPHIER_CLK_GATE_SIMPLE(24, 0x2108, 2), /* pcie (Pro5) */
{ /* sentinel */ }
#endif
};
@@ -43,6 +44,7 @@ const struct uniphier_clk_data uniphier_ld20_sys_clk_data[] = {
UNIPHIER_CLK_GATE_SIMPLE(14, 0x210c, 14), /* usb30 (LD20) */
UNIPHIER_CLK_GATE_SIMPLE(16, 0x210c, 12), /* usb30-phy0 (LD20) */
UNIPHIER_CLK_GATE_SIMPLE(17, 0x210c, 13), /* usb30-phy1 (LD20) */
+ UNIPHIER_CLK_GATE_SIMPLE(24, 0x210c, 4), /* pcie */
{ /* sentinel */ }
#endif
};
@@ -62,6 +64,7 @@ const struct uniphier_clk_data uniphier_pxs3_sys_clk_data[] = {
UNIPHIER_CLK_GATE_SIMPLE(18, 0x210c, 20), /* usb30-phy2 */
UNIPHIER_CLK_GATE_SIMPLE(20, 0x210c, 17), /* usb31-phy0 */
UNIPHIER_CLK_GATE_SIMPLE(21, 0x210c, 19), /* usb31-phy1 */
+ UNIPHIER_CLK_GATE_SIMPLE(24, 0x210c, 3), /* pcie */
{ /* sentinel */ }
#endif
};
diff --git a/drivers/core/dump.c b/drivers/core/dump.c
index f8afea30a9..f2f9cacc56 100644
--- a/drivers/core/dump.c
+++ b/drivers/core/dump.c
@@ -130,18 +130,19 @@ void dm_dump_drivers(void)
struct driver *entry;
struct udevice *udev;
struct uclass *uc;
+ int ret;
int i;
puts("Driver uid uclass Devices\n");
puts("----------------------------------------------------------\n");
for (entry = d; entry < d + n_ents; entry++) {
- uclass_get(entry->id, &uc);
+ ret = uclass_get(entry->id, &uc);
printf("%-25.25s %-3.3d %-20.20s ", entry->name, entry->id,
- uc ? uc->uc_drv->name : "<no uclass>");
+ !ret ? uc->uc_drv->name : "<no uclass>");
- if (!uc) {
+ if (ret) {
puts("\n");
continue;
}
diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c
index 3206f3d112..5f98f85cfc 100644
--- a/drivers/core/regmap.c
+++ b/drivers/core/regmap.c
@@ -293,6 +293,7 @@ struct regmap *devm_regmap_init(struct udevice *dev,
int rc;
struct regmap **mapp, *map;
+ /* this looks like a leak, but devres takes care of it */
mapp = devres_alloc(devm_regmap_release, sizeof(struct regmap *),
__GFP_ZERO);
if (unlikely(!mapp))
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index de4dc51d4b..0817b12c5f 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -495,4 +495,12 @@ config NX_GPIO
The GPIOs for a device are defined in the device tree with one node
for each bank.
+config NOMADIK_GPIO
+ bool "Nomadik GPIO driver"
+ depends on DM_GPIO
+ help
+ Support GPIO access on ST-Ericsson Ux500 SoCs. The GPIOs are arranged
+ into a number of banks 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/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 06dfc32fa5..16b09fb1b5 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -43,7 +43,6 @@ 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
@@ -68,3 +67,4 @@ 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
+obj-$(CONFIG_NOMADIK_GPIO) += nmk_gpio.o
diff --git a/drivers/gpio/db8500_gpio.c b/drivers/gpio/db8500_gpio.c
deleted file mode 100644
index eefb56d83f..0000000000
--- a/drivers/gpio/db8500_gpio.c
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * 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/drivers/gpio/nmk_gpio.c b/drivers/gpio/nmk_gpio.c
new file mode 100644
index 0000000000..e1bb41b196
--- /dev/null
+++ b/drivers/gpio/nmk_gpio.c
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (C) 2019 Stephan Gerhold */
+
+#include <common.h>
+#include <dm.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+
+struct nmk_gpio_regs {
+ u32 dat; /* data */
+ u32 dats; /* data set */
+ u32 datc; /* data clear */
+ u32 pdis; /* pull disable */
+ u32 dir; /* direction */
+ u32 dirs; /* direction set */
+ u32 dirc; /* direction clear */
+ u32 slpm; /* sleep mode */
+ u32 afsla; /* alternate function select A */
+ u32 afslb; /* alternate function select B */
+ u32 lowemi; /* low EMI mode */
+};
+
+struct nmk_gpio {
+ struct nmk_gpio_regs *regs;
+};
+
+static int nmk_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+ struct nmk_gpio *priv = dev_get_priv(dev);
+
+ return !!(readl(&priv->regs->dat) & BIT(offset));
+}
+
+static int nmk_gpio_set_value(struct udevice *dev, unsigned offset, int value)
+{
+ struct nmk_gpio *priv = dev_get_priv(dev);
+
+ if (value)
+ writel(BIT(offset), &priv->regs->dats);
+ else
+ writel(BIT(offset), &priv->regs->datc);
+
+ return 0;
+}
+
+static int nmk_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+ struct nmk_gpio *priv = dev_get_priv(dev);
+
+ if (readl(&priv->regs->afsla) & BIT(offset) ||
+ readl(&priv->regs->afslb) & BIT(offset))
+ return GPIOF_FUNC;
+
+ if (readl(&priv->regs->dir) & BIT(offset))
+ return GPIOF_OUTPUT;
+ else
+ return GPIOF_INPUT;
+}
+
+static int nmk_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+ struct nmk_gpio *priv = dev_get_priv(dev);
+
+ writel(BIT(offset), &priv->regs->dirc);
+ return 0;
+}
+
+static int nmk_gpio_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct nmk_gpio *priv = dev_get_priv(dev);
+
+ writel(BIT(offset), &priv->regs->dirs);
+ return nmk_gpio_set_value(dev, offset, value);
+}
+
+static const struct dm_gpio_ops nmk_gpio_ops = {
+ .get_value = nmk_gpio_get_value,
+ .set_value = nmk_gpio_set_value,
+ .get_function = nmk_gpio_get_function,
+ .direction_input = nmk_gpio_direction_input,
+ .direction_output = nmk_gpio_direction_output,
+};
+
+static int nmk_gpio_probe(struct udevice *dev)
+{
+ struct nmk_gpio *priv = dev_get_priv(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ char buf[20];
+ u32 bank;
+ int ret;
+
+ priv->regs = dev_read_addr_ptr(dev);
+ if (!priv->regs)
+ return -EINVAL;
+
+ ret = dev_read_u32(dev, "gpio-bank", &bank);
+ if (ret < 0) {
+ printf("nmk_gpio(%s): Failed to read gpio-bank\n", dev->name);
+ return ret;
+ }
+
+ sprintf(buf, "nmk%u-gpio", bank);
+ uc_priv->bank_name = strdup(buf);
+ if (!uc_priv->bank_name)
+ return -ENOMEM;
+
+ uc_priv->gpio_count = sizeof(priv->regs->dat) * BITS_PER_BYTE;
+
+ return 0;
+}
+
+static const struct udevice_id nmk_gpio_ids[] = {
+ { .compatible = "st,nomadik-gpio" },
+ { }
+};
+
+U_BOOT_DRIVER(gpio_nmk) = {
+ .name = "nmk_gpio",
+ .id = UCLASS_GPIO,
+ .of_match = nmk_gpio_ids,
+ .probe = nmk_gpio_probe,
+ .ops = &nmk_gpio_ops,
+ .priv_auto = sizeof(struct nmk_gpio),
+};
diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c
index db5e3b0f51..beea47caa3 100644
--- a/drivers/misc/cros_ec_sandbox.c
+++ b/drivers/misc/cros_ec_sandbox.c
@@ -5,6 +5,8 @@
* Copyright (c) 2013 The Chromium OS Authors.
*/
+#define LOG_CATEGORY UCLASS_CROS_EC
+
#include <common.h>
#include <cros_ec.h>
#include <dm.h>
@@ -221,11 +223,12 @@ static int keyscan_read_fdt_matrix(struct ec_state *ec, ofnode node)
int len;
cell = ofnode_get_property(node, "linux,keymap", &len);
+ if (!cell)
+ return log_msg_ret("prop", -EINVAL);
ec->matrix_count = len / 4;
ec->matrix = calloc(ec->matrix_count, sizeof(*ec->matrix));
if (!ec->matrix) {
- debug("%s: Out of memory for key matrix\n", __func__);
- return -1;
+ return log_msg_ret("mem", -ENOMEM);
}
/* Now read the data */
@@ -243,13 +246,12 @@ static int keyscan_read_fdt_matrix(struct ec_state *ec, ofnode node)
matrix->col >= KEYBOARD_COLS) {
debug("%s: Matrix pos out of range (%d,%d)\n",
__func__, matrix->row, matrix->col);
- return -1;
+ return log_msg_ret("matrix", -ERANGE);
}
}
if (upto != ec->matrix_count) {
- debug("%s: Read mismatch from key matrix\n", __func__);
- return -1;
+ return log_msg_ret("matrix", -E2BIG);
}
return 0;
diff --git a/drivers/misc/i2c_eeprom.c b/drivers/misc/i2c_eeprom.c
index 3b249842f8..89a450d0f8 100644
--- a/drivers/misc/i2c_eeprom.c
+++ b/drivers/misc/i2c_eeprom.c
@@ -264,6 +264,7 @@ static const struct i2c_eeprom_drv_data atmel24c512_data = {
static const struct udevice_id i2c_eeprom_std_ids[] = {
{ .compatible = "i2c-eeprom", (ulong)&eeprom_data },
{ .compatible = "microchip,24aa02e48", (ulong)&mc24aa02e48_data },
+ { .compatible = "atmel,24c01", (ulong)&atmel24c01a_data },
{ .compatible = "atmel,24c01a", (ulong)&atmel24c01a_data },
{ .compatible = "atmel,24c02", (ulong)&atmel24c02_data },
{ .compatible = "atmel,24c04", (ulong)&atmel24c04_data },
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 1e83007286..8078a89f18 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -2766,7 +2766,7 @@ static int mmc_power_cycle(struct mmc *mmc)
return mmc_power_on(mmc);
}
-int mmc_get_op_cond(struct mmc *mmc)
+int mmc_get_op_cond(struct mmc *mmc, bool quiet)
{
bool uhs_en = supports_uhs(mmc->cfg->host_caps);
int err;
@@ -2842,7 +2842,8 @@ retry:
if (err) {
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
- pr_err("Card did not respond to voltage select! : %d\n", err);
+ if (!quiet)
+ pr_err("Card did not respond to voltage select! : %d\n", err);
#endif
return -EOPNOTSUPP;
}
@@ -2882,7 +2883,7 @@ int mmc_start_init(struct mmc *mmc)
return -ENOMEDIUM;
}
- err = mmc_get_op_cond(mmc);
+ err = mmc_get_op_cond(mmc, false);
if (!err)
mmc->init_in_progress = 1;
diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c
index 3503ccdb2e..178b8cf106 100644
--- a/drivers/mmc/sunxi_mmc.c
+++ b/drivers/mmc/sunxi_mmc.c
@@ -23,6 +23,10 @@
#include <asm-generic/gpio.h>
#include <linux/delay.h>
+#ifndef CCM_MMC_CTRL_MODE_SEL_NEW
+#define CCM_MMC_CTRL_MODE_SEL_NEW 0
+#endif
+
struct sunxi_mmc_plat {
struct mmc_config cfg;
struct mmc mmc;
@@ -33,7 +37,6 @@ struct sunxi_mmc_priv {
uint32_t *mclkreg;
unsigned fatal_err;
struct gpio_desc cd_gpio; /* Change Detect GPIO */
- int cd_inverted; /* Inverted Card Detect */
struct sunxi_mmc *reg;
struct mmc_config cfg;
};
@@ -99,24 +102,29 @@ static int mmc_resource_init(int sdc_no)
}
#endif
+/*
+ * All A64 and later MMC controllers feature auto-calibration. This would
+ * normally be detected via the compatible string, but we need something
+ * which works in the SPL as well.
+ */
+static bool sunxi_mmc_can_calibrate(void)
+{
+ return IS_ENABLED(CONFIG_MACH_SUN50I) ||
+ IS_ENABLED(CONFIG_MACH_SUN50I_H5) ||
+ IS_ENABLED(CONFIG_SUN50I_GEN_H6) ||
+ IS_ENABLED(CONFIG_MACH_SUN8I_R40);
+}
+
static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz)
{
unsigned int pll, pll_hz, div, n, oclk_dly, sclk_dly;
- bool new_mode = true;
- bool calibrate = false;
+ bool new_mode = IS_ENABLED(CONFIG_MMC_SUNXI_HAS_NEW_MODE);
u32 val = 0;
- if (!IS_ENABLED(CONFIG_MMC_SUNXI_HAS_NEW_MODE))
- new_mode = false;
-
/* A83T support new mode only on eMMC */
if (IS_ENABLED(CONFIG_MACH_SUN8I_A83T) && priv->mmc_no != 2)
new_mode = false;
-#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_SUN50I_GEN_H6)
- calibrate = true;
-#endif
-
if (hz <= 24000000) {
pll = CCM_MMC_CTRL_OSCM24;
pll_hz = 24000000;
@@ -124,10 +132,14 @@ static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz)
#ifdef CONFIG_MACH_SUN9I
pll = CCM_MMC_CTRL_PLL_PERIPH0;
pll_hz = clock_get_pll4_periph0();
-#elif defined(CONFIG_SUN50I_GEN_H6)
- pll = CCM_MMC_CTRL_PLL6X2;
- pll_hz = clock_get_pll6() * 2;
#else
+ /*
+ * SoCs since the A64 (H5, H6, H616) actually use the doubled
+ * rate of PLL6/PERIPH0 as an input clock, but compensate for
+ * that with a fixed post-divider of 2 in the mod clock.
+ * This cancels each other out, so for simplicity we just
+ * pretend it's always PLL6 without a post divider here.
+ */
pll = CCM_MMC_CTRL_PLL6;
pll_hz = clock_get_pll6();
#endif
@@ -156,33 +168,27 @@ static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz)
} else if (hz <= 25000000) {
oclk_dly = 0;
sclk_dly = 5;
-#ifdef CONFIG_MACH_SUN9I
- } else if (hz <= 52000000) {
- oclk_dly = 5;
- sclk_dly = 4;
} else {
- /* hz > 52000000 */
- oclk_dly = 2;
- sclk_dly = 4;
-#else
- } else if (hz <= 52000000) {
- oclk_dly = 3;
- sclk_dly = 4;
- } else {
- /* hz > 52000000 */
- oclk_dly = 1;
+ if (IS_ENABLED(CONFIG_MACH_SUN9I)) {
+ if (hz <= 52000000)
+ oclk_dly = 5;
+ else
+ oclk_dly = 2;
+ } else {
+ if (hz <= 52000000)
+ oclk_dly = 3;
+ else
+ oclk_dly = 1;
+ }
sclk_dly = 4;
-#endif
}
if (new_mode) {
-#ifdef CONFIG_MMC_SUNXI_HAS_NEW_MODE
-#ifdef CONFIG_MMC_SUNXI_HAS_MODE_SWITCH
- val = CCM_MMC_CTRL_MODE_SEL_NEW;
-#endif
+ val |= CCM_MMC_CTRL_MODE_SEL_NEW;
setbits_le32(&priv->reg->ntsr, SUNXI_MMC_NTSR_MODE_SEL_NEW);
-#endif
- } else if (!calibrate) {
+ }
+
+ if (!sunxi_mmc_can_calibrate()) {
/*
* Use hardcoded delay values if controller doesn't support
* calibration
@@ -240,14 +246,15 @@ static int mmc_config_clock(struct sunxi_mmc_priv *priv, struct mmc *mmc)
rval &= ~SUNXI_MMC_CLK_DIVIDER_MASK;
writel(rval, &priv->reg->clkcr);
-#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_SUN50I_GEN_H6)
+#if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6)
/* A64 supports calibration of delays on MMC controller and we
* have to set delay of zero before starting calibration.
* Allwinner BSP driver sets a delay only in the case of
* using HS400 which is not supported by mainline U-Boot or
* Linux at the moment
*/
- writel(SUNXI_MMC_CAL_DL_SW_EN, &priv->reg->samp_dl);
+ if (sunxi_mmc_can_calibrate())
+ writel(SUNXI_MMC_CAL_DL_SW_EN, &priv->reg->samp_dl);
#endif
/* Re-enable Clock */
@@ -303,8 +310,9 @@ static int mmc_trans_data_by_cpu(struct sunxi_mmc_priv *priv, struct mmc *mmc,
SUNXI_MMC_STATUS_FIFO_FULL;
unsigned i;
unsigned *buff = (unsigned int *)(reading ? data->dest : data->src);
- unsigned byte_cnt = data->blocksize * data->blocks;
- unsigned timeout_msecs = byte_cnt >> 8;
+ unsigned word_cnt = (data->blocksize * data->blocks) >> 2;
+ unsigned timeout_msecs = word_cnt >> 6;
+ uint32_t status;
unsigned long start;
if (timeout_msecs < 2000)
@@ -315,16 +323,38 @@ static int mmc_trans_data_by_cpu(struct sunxi_mmc_priv *priv, struct mmc *mmc,
start = get_timer(0);
- for (i = 0; i < (byte_cnt >> 2); i++) {
- while (readl(&priv->reg->status) & status_bit) {
+ for (i = 0; i < word_cnt;) {
+ unsigned int in_fifo;
+
+ while ((status = readl(&priv->reg->status)) & status_bit) {
if (get_timer(start) > timeout_msecs)
return -1;
}
- if (reading)
- buff[i] = readl(&priv->reg->fifo);
- else
- writel(buff[i], &priv->reg->fifo);
+ /*
+ * For writing we do not easily know the FIFO size, so have
+ * to check the FIFO status after every word written.
+ * TODO: For optimisation we could work out a minimum FIFO
+ * size across all SoCs, and use that together with the current
+ * fill level to write chunks of words.
+ */
+ if (!reading) {
+ writel(buff[i++], &priv->reg->fifo);
+ continue;
+ }
+
+ /*
+ * The status register holds the current FIFO level, so we
+ * can be sure to collect as many words from the FIFO
+ * register without checking the status register after every
+ * read. That saves half of the costly MMIO reads, effectively
+ * doubling the read performance.
+ */
+ for (in_fifo = SUNXI_MMC_STATUS_FIFO_LEVEL(status);
+ in_fifo > 0;
+ in_fifo--)
+ buff[i++] = readl_relaxed(&priv->reg->fifo);
+ dmb();
}
return 0;
@@ -521,10 +551,11 @@ struct mmc *sunxi_mmc_init(int sdc_no)
cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
cfg->host_caps = MMC_MODE_4BIT;
-#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN8I) || defined(CONFIG_SUN50I_GEN_H6)
- if (sdc_no == 2)
+
+ if ((IS_ENABLED(CONFIG_MACH_SUN50I) || IS_ENABLED(CONFIG_MACH_SUN8I) ||
+ IS_ENABLED(CONFIG_SUN50I_GEN_H6)) && (sdc_no == 2))
cfg->host_caps = MMC_MODE_8BIT;
-#endif
+
cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
@@ -580,12 +611,21 @@ static int sunxi_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
static int sunxi_mmc_getcd(struct udevice *dev)
{
+ struct mmc *mmc = mmc_get_mmc_dev(dev);
struct sunxi_mmc_priv *priv = dev_get_priv(dev);
+ /* If polling, assume that the card is always present. */
+ if ((mmc->cfg->host_caps & MMC_CAP_NONREMOVABLE) ||
+ (mmc->cfg->host_caps & MMC_CAP_NEEDS_POLL))
+ return 1;
+
if (dm_gpio_is_valid(&priv->cd_gpio)) {
int cd_state = dm_gpio_get_value(&priv->cd_gpio);
- return cd_state ^ priv->cd_inverted;
+ if (mmc->cfg->host_caps & MMC_CAP_CD_ACTIVE_HIGH)
+ return !cd_state;
+ else
+ return cd_state;
}
return 1;
}
@@ -617,31 +657,29 @@ static int sunxi_mmc_probe(struct udevice *dev)
struct mmc_config *cfg = &plat->cfg;
struct ofnode_phandle_args args;
u32 *ccu_reg;
- int bus_width, ret;
+ int ret;
cfg->name = dev->name;
- bus_width = dev_read_u32_default(dev, "bus-width", 1);
cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
- cfg->host_caps = 0;
- if (bus_width == 8)
- cfg->host_caps |= MMC_MODE_8BIT;
- if (bus_width >= 4)
- cfg->host_caps |= MMC_MODE_4BIT;
- cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
+ cfg->host_caps = MMC_MODE_HS_52MHz | MMC_MODE_HS;
cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
cfg->f_min = 400000;
cfg->f_max = 52000000;
- priv->reg = (void *)dev_read_addr(dev);
+ ret = mmc_of_parse(dev, cfg);
+ if (ret)
+ return ret;
+
+ priv->reg = dev_read_addr_ptr(dev);
/* We don't have a sunxi clock driver so find the clock address here */
ret = dev_read_phandle_with_args(dev, "clocks", "#clock-cells", 0,
1, &args);
if (ret)
return ret;
- ccu_reg = (u32 *)ofnode_get_addr(args.node);
+ ccu_reg = (u32 *)(uintptr_t)ofnode_get_addr(args.node);
priv->mmc_no = ((uintptr_t)priv->reg - SUNXI_MMC0_BASE) / 0x1000;
priv->mclkreg = (void *)ccu_reg + get_mclk_offset() + priv->mmc_no * 4;
@@ -659,17 +697,13 @@ static int sunxi_mmc_probe(struct udevice *dev)
return ret;
/* This GPIO is optional */
- if (!dev_read_bool(dev, "non-removable") &&
- !gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio,
+ if (!gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio,
GPIOD_IS_IN)) {
int cd_pin = gpio_get_number(&priv->cd_gpio);
sunxi_gpio_set_pull(cd_pin, SUNXI_GPIO_PULL_UP);
}
- /* Check if card detect is inverted */
- priv->cd_inverted = dev_read_bool(dev, "cd-inverted");
-
upriv->mmc = &plat->mmc;
/* Reset controller */
diff --git a/drivers/net/sandbox-raw.c b/drivers/net/sandbox-raw.c
index ce66ff781f..99eb7a3bbf 100644
--- a/drivers/net/sandbox-raw.c
+++ b/drivers/net/sandbox-raw.c
@@ -161,7 +161,7 @@ static int sb_eth_raw_of_to_plat(struct udevice *dev)
ifname = dev_read_string(dev, "host-raw-interface");
if (ifname) {
- strncpy(priv->host_ifname, ifname, IFNAMSIZ);
+ strlcpy(priv->host_ifname, ifname, IFNAMSIZ);
printf(": Using %s from DT\n", priv->host_ifname);
}
if (dev_read_u32(dev, "host-raw-interface-idx",
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 782179eb0f..517cf956ea 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -340,4 +340,14 @@ config PCI_BRCMSTB
on Broadcom set-top-box (STB) SoCs.
This driver currently supports only BCM2711 SoC and RC mode
of the controller.
+
+config PCIE_UNIPHIER
+ bool "Socionext UniPhier PCIe driver"
+ depends on DM_PCI
+ depends on ARCH_UNIPHIER
+ select PHY_UNIPHIER_PCIE
+ help
+ Say Y here if you want to enable PCIe controller support on
+ UniPhier SoCs.
+
endif
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 6568dc9a08..ec8ee9dda7 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -56,3 +56,4 @@ obj-$(CONFIG_PCI_BRCMSTB) += pcie_brcmstb.o
obj-$(CONFIG_PCI_OCTEONTX) += pci_octeontx.o
obj-$(CONFIG_PCIE_OCTEON) += pcie_octeon.o
obj-$(CONFIG_PCIE_DW_SIFIVE) += pcie_dw_sifive.o
+obj-$(CONFIG_PCIE_UNIPHIER) += pcie_uniphier.o
diff --git a/drivers/pci/pci-aardvark.c b/drivers/pci/pci-aardvark.c
index 96aa039bdc..1b9bae7cca 100644
--- a/drivers/pci/pci-aardvark.c
+++ b/drivers/pci/pci-aardvark.c
@@ -605,25 +605,26 @@ static void pcie_advk_set_ob_region(struct pcie_advk *pcie, int *wins,
/*
* The n-th PCIe window is configured by tuple (match, remap, mask)
- * and an access to address A uses this window it if A matches the
+ * and an access to address A uses this window if A matches the
* match with given mask.
* So every PCIe window size must be a power of two and every start
* address must be aligned to window size. Minimal size is 64 KiB
- * because lower 16 bits of mask must be zero.
+ * because lower 16 bits of mask must be zero. Remapped address
+ * may have set only bits from the mask.
*/
while (*wins < OB_WIN_COUNT && size > 0) {
/* Calculate the largest aligned window size */
win_size = (1ULL << (fls64(size) - 1)) |
(phys_start ? (1ULL << __ffs64(phys_start)) : 0);
win_size = 1ULL << __ffs64(win_size);
- if (win_size < 0x10000)
+ win_mask = ~(win_size - 1);
+ if (win_size < 0x10000 || (bus_start & ~win_mask))
break;
dev_dbg(pcie->dev,
"Configuring PCIe window %d: [0x%llx-0x%llx] as 0x%x\n",
*wins, (u64)phys_start, (u64)phys_start + win_size,
actions);
- win_mask = ~(win_size - 1) & ~0xffff;
pcie_advk_set_ob_win(pcie, *wins, phys_start, bus_start,
win_mask, actions);
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c
index cb9aa81835..fb12732926 100644
--- a/drivers/pci/pci-uclass.c
+++ b/drivers/pci/pci-uclass.c
@@ -21,6 +21,7 @@
#if defined(CONFIG_X86) && defined(CONFIG_HAVE_FSP)
#include <asm/fsp/fsp_support.h>
#endif
+#include <dt-bindings/pci/pci.h>
#include <linux/delay.h>
#include "pci_internal.h"
@@ -164,7 +165,7 @@ int dm_pci_bus_find_bdf(pci_dev_t bdf, struct udevice **devp)
}
static int pci_device_matches_ids(struct udevice *dev,
- struct pci_device_id *ids)
+ const struct pci_device_id *ids)
{
struct pci_child_plat *pplat;
int i;
@@ -181,7 +182,7 @@ static int pci_device_matches_ids(struct udevice *dev,
return -EINVAL;
}
-int pci_bus_find_devices(struct udevice *bus, struct pci_device_id *ids,
+int pci_bus_find_devices(struct udevice *bus, const struct pci_device_id *ids,
int *indexp, struct udevice **devp)
{
struct udevice *dev;
@@ -201,7 +202,7 @@ int pci_bus_find_devices(struct udevice *bus, struct pci_device_id *ids,
return -ENODEV;
}
-int pci_find_device_id(struct pci_device_id *ids, int index,
+int pci_find_device_id(const struct pci_device_id *ids, int index,
struct udevice **devp)
{
struct udevice *bus;
@@ -682,6 +683,34 @@ static bool pci_match_one_id(const struct pci_device_id *id,
}
/**
+ * pci_need_device_pre_reloc() - Check if a device should be bound
+ *
+ * This checks a list of vendor/device-ID values indicating devices that should
+ * be bound before relocation.
+ *
+ * @bus: Bus to check
+ * @vendor: Vendor ID to check
+ * @device: Device ID to check
+ * @return true if the vendor/device is in the list, false if not
+ */
+static bool pci_need_device_pre_reloc(struct udevice *bus, uint vendor,
+ uint device)
+{
+ u32 vendev;
+ int index;
+
+ for (index = 0;
+ !dev_read_u32_index(bus, "u-boot,pci-pre-reloc", index,
+ &vendev);
+ index++) {
+ if (vendev == PCI_VENDEV(vendor, device))
+ return true;
+ }
+
+ return false;
+}
+
+/**
* pci_find_and_bind_driver() - Find and bind the right PCI driver
*
* This only looks at certain fields in the descriptor.
@@ -769,7 +798,9 @@ static int pci_find_and_bind_driver(struct udevice *parent,
* precious memory space as on some platforms as that space is pretty
* limited (ie: using Cache As RAM).
*/
- if (!(gd->flags & GD_FLG_RELOC) && !bridge)
+ if (!(gd->flags & GD_FLG_RELOC) && !bridge &&
+ !pci_need_device_pre_reloc(parent, find_id->vendor,
+ find_id->device))
return log_msg_ret("notbr", -EPERM);
/* Bind a generic driver so that the device can be used */
diff --git a/drivers/pci/pcie_uniphier.c b/drivers/pci/pcie_uniphier.c
new file mode 100644
index 0000000000..f2edea9899
--- /dev/null
+++ b/drivers/pci/pcie_uniphier.c
@@ -0,0 +1,424 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * pcie_uniphier.c - Socionext UniPhier PCIe driver
+ * Copyright 2019-2021 Socionext, Inc.
+ */
+
+#include <clk.h>
+#include <common.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <generic-phy.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/compat.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <pci.h>
+#include <reset.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* DBI registers */
+#define PCIE_LINK_STATUS_REG 0x0080
+#define PCIE_LINK_STATUS_WIDTH_MASK GENMASK(25, 20)
+#define PCIE_LINK_STATUS_SPEED_MASK GENMASK(19, 16)
+
+#define PCIE_MISC_CONTROL_1_OFF 0x08BC
+#define PCIE_DBI_RO_WR_EN BIT(0)
+
+/* DBI iATU registers */
+#define PCIE_ATU_VIEWPORT 0x0900
+#define PCIE_ATU_REGION_INBOUND BIT(31)
+#define PCIE_ATU_REGION_OUTBOUND 0
+#define PCIE_ATU_REGION_INDEX_MASK GENMASK(3, 0)
+
+#define PCIE_ATU_CR1 0x0904
+#define PCIE_ATU_TYPE_MEM 0
+#define PCIE_ATU_TYPE_IO 2
+#define PCIE_ATU_TYPE_CFG0 4
+#define PCIE_ATU_TYPE_CFG1 5
+
+#define PCIE_ATU_CR2 0x0908
+#define PCIE_ATU_ENABLE BIT(31)
+#define PCIE_ATU_MATCH_MODE BIT(30)
+#define PCIE_ATU_BAR_NUM_MASK GENMASK(10, 8)
+
+#define PCIE_ATU_LOWER_BASE 0x090C
+#define PCIE_ATU_UPPER_BASE 0x0910
+#define PCIE_ATU_LIMIT 0x0914
+#define PCIE_ATU_LOWER_TARGET 0x0918
+#define PCIE_ATU_BUS(x) FIELD_PREP(GENMASK(31, 24), x)
+#define PCIE_ATU_DEV(x) FIELD_PREP(GENMASK(23, 19), x)
+#define PCIE_ATU_FUNC(x) FIELD_PREP(GENMASK(18, 16), x)
+#define PCIE_ATU_UPPER_TARGET 0x091C
+
+/* Link Glue registers */
+#define PCL_PINCTRL0 0x002c
+#define PCL_PERST_PLDN_REGEN BIT(12)
+#define PCL_PERST_NOE_REGEN BIT(11)
+#define PCL_PERST_OUT_REGEN BIT(8)
+#define PCL_PERST_PLDN_REGVAL BIT(4)
+#define PCL_PERST_NOE_REGVAL BIT(3)
+#define PCL_PERST_OUT_REGVAL BIT(0)
+
+#define PCL_MODE 0x8000
+#define PCL_MODE_REGEN BIT(8)
+#define PCL_MODE_REGVAL BIT(0)
+
+#define PCL_APP_READY_CTRL 0x8008
+#define PCL_APP_LTSSM_ENABLE BIT(0)
+
+#define PCL_APP_PM0 0x8078
+#define PCL_SYS_AUX_PWR_DET BIT(8)
+
+#define PCL_STATUS_LINK 0x8140
+#define PCL_RDLH_LINK_UP BIT(1)
+#define PCL_XMLH_LINK_UP BIT(0)
+
+#define LINK_UP_TIMEOUT_MS 100
+
+struct uniphier_pcie_priv {
+ void *base;
+ void *dbi_base;
+ void *cfg_base;
+ fdt_size_t cfg_size;
+ struct fdt_resource link_res;
+ struct fdt_resource dbi_res;
+ struct fdt_resource cfg_res;
+
+ struct clk clk;
+ struct reset_ctl rst;
+ struct phy phy;
+
+ struct pci_region io;
+ struct pci_region mem;
+};
+
+static int pcie_dw_get_link_speed(struct uniphier_pcie_priv *priv)
+{
+ u32 val = readl(priv->dbi_base + PCIE_LINK_STATUS_REG);
+
+ return FIELD_GET(PCIE_LINK_STATUS_SPEED_MASK, val);
+}
+
+static int pcie_dw_get_link_width(struct uniphier_pcie_priv *priv)
+{
+ u32 val = readl(priv->dbi_base + PCIE_LINK_STATUS_REG);
+
+ return FIELD_GET(PCIE_LINK_STATUS_WIDTH_MASK, val);
+}
+
+static void pcie_dw_prog_outbound_atu(struct uniphier_pcie_priv *priv,
+ int index, int type, u64 cpu_addr,
+ u64 pci_addr, u32 size)
+{
+ writel(PCIE_ATU_REGION_OUTBOUND
+ | FIELD_PREP(PCIE_ATU_REGION_INDEX_MASK, index),
+ priv->dbi_base + PCIE_ATU_VIEWPORT);
+ writel(lower_32_bits(cpu_addr),
+ priv->dbi_base + PCIE_ATU_LOWER_BASE);
+ writel(upper_32_bits(cpu_addr),
+ priv->dbi_base + PCIE_ATU_UPPER_BASE);
+ writel(lower_32_bits(cpu_addr + size - 1),
+ priv->dbi_base + PCIE_ATU_LIMIT);
+ writel(lower_32_bits(pci_addr),
+ priv->dbi_base + PCIE_ATU_LOWER_TARGET);
+ writel(upper_32_bits(pci_addr),
+ priv->dbi_base + PCIE_ATU_UPPER_TARGET);
+
+ writel(type, priv->dbi_base + PCIE_ATU_CR1);
+ writel(PCIE_ATU_ENABLE, priv->dbi_base + PCIE_ATU_CR2);
+}
+
+static int uniphier_pcie_addr_valid(pci_dev_t bdf, int first_busno)
+{
+ /* accept only device {0,1} on first bus */
+ if ((PCI_BUS(bdf) != first_busno) || (PCI_DEV(bdf) > 1))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int uniphier_pcie_conf_address(const struct udevice *dev, pci_dev_t bdf,
+ uint offset, void **paddr)
+{
+ struct uniphier_pcie_priv *priv = dev_get_priv(dev);
+ u32 busdev;
+ int seq = dev_seq(dev);
+ int ret;
+
+ ret = uniphier_pcie_addr_valid(bdf, seq);
+ if (ret)
+ return ret;
+
+ if ((PCI_BUS(bdf) == seq) && !PCI_DEV(bdf)) {
+ *paddr = (void *)(priv->dbi_base + offset);
+ return 0;
+ }
+
+ busdev = PCIE_ATU_BUS(PCI_BUS(bdf) - seq)
+ | PCIE_ATU_DEV(PCI_DEV(bdf))
+ | PCIE_ATU_FUNC(PCI_FUNC(bdf));
+
+ pcie_dw_prog_outbound_atu(priv, 0,
+ PCIE_ATU_TYPE_CFG0, (u64)priv->cfg_base,
+ busdev, priv->cfg_size);
+ *paddr = (void *)(priv->cfg_base + offset);
+
+ return 0;
+}
+
+static int uniphier_pcie_read_config(const struct udevice *dev, pci_dev_t bdf,
+ uint offset, ulong *valp,
+ enum pci_size_t size)
+{
+ return pci_generic_mmap_read_config(dev, uniphier_pcie_conf_address,
+ bdf, offset, valp, size);
+}
+
+static int uniphier_pcie_write_config(struct udevice *dev, pci_dev_t bdf,
+ uint offset, ulong val,
+ enum pci_size_t size)
+{
+ return pci_generic_mmap_write_config(dev, uniphier_pcie_conf_address,
+ bdf, offset, val, size);
+}
+
+static void uniphier_pcie_ltssm_enable(struct uniphier_pcie_priv *priv,
+ bool enable)
+{
+ u32 val;
+
+ val = readl(priv->base + PCL_APP_READY_CTRL);
+ if (enable)
+ val |= PCL_APP_LTSSM_ENABLE;
+ else
+ val &= ~PCL_APP_LTSSM_ENABLE;
+ writel(val, priv->base + PCL_APP_READY_CTRL);
+}
+
+static int uniphier_pcie_link_up(struct uniphier_pcie_priv *priv)
+{
+ u32 val, mask;
+
+ val = readl(priv->base + PCL_STATUS_LINK);
+ mask = PCL_RDLH_LINK_UP | PCL_XMLH_LINK_UP;
+
+ return (val & mask) == mask;
+}
+
+static int uniphier_pcie_wait_link(struct uniphier_pcie_priv *priv)
+{
+ unsigned long timeout;
+
+ timeout = get_timer(0) + LINK_UP_TIMEOUT_MS;
+
+ while (get_timer(0) < timeout) {
+ if (uniphier_pcie_link_up(priv))
+ return 0;
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int uniphier_pcie_establish_link(struct uniphier_pcie_priv *priv)
+{
+ if (uniphier_pcie_link_up(priv))
+ return 0;
+
+ uniphier_pcie_ltssm_enable(priv, true);
+
+ return uniphier_pcie_wait_link(priv);
+}
+
+static void uniphier_pcie_init_rc(struct uniphier_pcie_priv *priv)
+{
+ u32 val;
+
+ /* set RC mode */
+ val = readl(priv->base + PCL_MODE);
+ val |= PCL_MODE_REGEN;
+ val &= ~PCL_MODE_REGVAL;
+ writel(val, priv->base + PCL_MODE);
+
+ /* use auxiliary power detection */
+ val = readl(priv->base + PCL_APP_PM0);
+ val |= PCL_SYS_AUX_PWR_DET;
+ writel(val, priv->base + PCL_APP_PM0);
+
+ /* assert PERST# */
+ val = readl(priv->base + PCL_PINCTRL0);
+ val &= ~(PCL_PERST_NOE_REGVAL | PCL_PERST_OUT_REGVAL
+ | PCL_PERST_PLDN_REGVAL);
+ val |= PCL_PERST_NOE_REGEN | PCL_PERST_OUT_REGEN
+ | PCL_PERST_PLDN_REGEN;
+ writel(val, priv->base + PCL_PINCTRL0);
+
+ uniphier_pcie_ltssm_enable(priv, false);
+
+ mdelay(100);
+
+ /* deassert PERST# */
+ val = readl(priv->base + PCL_PINCTRL0);
+ val |= PCL_PERST_OUT_REGVAL | PCL_PERST_OUT_REGEN;
+ writel(val, priv->base + PCL_PINCTRL0);
+}
+
+static void uniphier_pcie_setup_rc(struct uniphier_pcie_priv *priv,
+ struct pci_controller *hose)
+{
+ /* Store the IO and MEM windows settings for future use by the ATU */
+ priv->io.phys_start = hose->regions[0].phys_start; /* IO base */
+ priv->io.bus_start = hose->regions[0].bus_start; /* IO_bus_addr */
+ priv->io.size = hose->regions[0].size; /* IO size */
+ priv->mem.phys_start = hose->regions[1].phys_start; /* MEM base */
+ priv->mem.bus_start = hose->regions[1].bus_start; /* MEM_bus_addr */
+ priv->mem.size = hose->regions[1].size; /* MEM size */
+
+ /* outbound: IO */
+ pcie_dw_prog_outbound_atu(priv, 0,
+ PCIE_ATU_TYPE_IO, priv->io.phys_start,
+ priv->io.bus_start, priv->io.size);
+
+ /* outbound: MEM */
+ pcie_dw_prog_outbound_atu(priv, 1,
+ PCIE_ATU_TYPE_MEM, priv->mem.phys_start,
+ priv->mem.bus_start, priv->mem.size);
+}
+
+static int uniphier_pcie_probe(struct udevice *dev)
+{
+ struct uniphier_pcie_priv *priv = dev_get_priv(dev);
+ struct udevice *ctlr = pci_get_controller(dev);
+ struct pci_controller *hose = dev_get_uclass_priv(ctlr);
+ int ret;
+
+ priv->base = map_physmem(priv->link_res.start,
+ fdt_resource_size(&priv->link_res),
+ MAP_NOCACHE);
+ priv->dbi_base = map_physmem(priv->dbi_res.start,
+ fdt_resource_size(&priv->dbi_res),
+ MAP_NOCACHE);
+ priv->cfg_size = fdt_resource_size(&priv->cfg_res);
+ priv->cfg_base = map_physmem(priv->cfg_res.start,
+ priv->cfg_size, MAP_NOCACHE);
+
+ ret = clk_enable(&priv->clk);
+ if (ret) {
+ dev_err(dev, "Failed to enable clk: %d\n", ret);
+ return ret;
+ }
+ ret = reset_deassert(&priv->rst);
+ if (ret) {
+ dev_err(dev, "Failed to deassert reset: %d\n", ret);
+ goto out_clk_release;
+ }
+
+ ret = generic_phy_init(&priv->phy);
+ if (ret) {
+ dev_err(dev, "Failed to initialize phy: %d\n", ret);
+ goto out_reset_release;
+ }
+
+ ret = generic_phy_power_on(&priv->phy);
+ if (ret) {
+ dev_err(dev, "Failed to power on phy: %d\n", ret);
+ goto out_phy_exit;
+ }
+
+ uniphier_pcie_init_rc(priv);
+
+ /* set DBI to read only */
+ writel(0, priv->dbi_base + PCIE_MISC_CONTROL_1_OFF);
+
+ uniphier_pcie_setup_rc(priv, hose);
+
+ if (uniphier_pcie_establish_link(priv)) {
+ printf("PCIE-%d: Link down\n", dev_seq(dev));
+ } else {
+ printf("PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n",
+ dev_seq(dev), pcie_dw_get_link_speed(priv),
+ pcie_dw_get_link_width(priv), hose->first_busno);
+ }
+
+ return 0;
+
+out_phy_exit:
+ generic_phy_exit(&priv->phy);
+out_reset_release:
+ reset_release_all(&priv->rst, 1);
+out_clk_release:
+ clk_release_all(&priv->clk, 1);
+
+ return ret;
+}
+
+static int uniphier_pcie_of_to_plat(struct udevice *dev)
+{
+ struct uniphier_pcie_priv *priv = dev_get_priv(dev);
+ const void *fdt = gd->fdt_blob;
+ int node = dev_of_offset(dev);
+ int ret;
+
+ ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
+ "link", &priv->link_res);
+ if (ret) {
+ dev_err(dev, "Failed to get link regs: %d\n", ret);
+ return ret;
+ }
+
+ ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
+ "dbi", &priv->dbi_res);
+ if (ret) {
+ dev_err(dev, "Failed to get dbi regs: %d\n", ret);
+ return ret;
+ }
+
+ ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
+ "config", &priv->cfg_res);
+ if (ret) {
+ dev_err(dev, "Failed to get config regs: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_get_by_index(dev, 0, &priv->clk);
+ if (ret) {
+ dev_err(dev, "Failed to get clocks property: %d\n", ret);
+ return ret;
+ }
+
+ ret = reset_get_by_index(dev, 0, &priv->rst);
+ if (ret) {
+ dev_err(dev, "Failed to get resets property: %d\n", ret);
+ return ret;
+ }
+
+ ret = generic_phy_get_by_index(dev, 0, &priv->phy);
+ if (ret) {
+ dev_err(dev, "Failed to get phy property: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct dm_pci_ops uniphier_pcie_ops = {
+ .read_config = uniphier_pcie_read_config,
+ .write_config = uniphier_pcie_write_config,
+};
+
+static const struct udevice_id uniphier_pcie_ids[] = {
+ { .compatible = "socionext,uniphier-pcie", },
+ { /* Sentinel */ }
+};
+
+U_BOOT_DRIVER(pcie_uniphier) = {
+ .name = "uniphier-pcie",
+ .id = UCLASS_PCI,
+ .of_match = uniphier_pcie_ids,
+ .probe = uniphier_pcie_probe,
+ .ops = &uniphier_pcie_ops,
+ .of_to_plat = uniphier_pcie_of_to_plat,
+ .priv_auto = sizeof(struct uniphier_pcie_priv),
+};
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 09cb744276..80ae1af329 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -64,6 +64,12 @@ config MIPI_DPHY_HELPERS
help
Provides a number of helpers a core functions for MIPI D-PHY drivers.
+config AB8500_USB_PHY
+ bool "AB8500 USB PHY Driver"
+ depends on PHY && PMIC_AB8500
+ help
+ Support for the USB OTG PHY in ST-Ericsson AB8500.
+
config BCM6318_USBH_PHY
bool "BCM6318 USBH PHY support"
depends on PHY && ARCH_BMIPS
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index c6ad3b1b26..0f2b63ae3c 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -6,6 +6,7 @@
obj-$(CONFIG_$(SPL_)PHY) += phy-uclass.o
obj-$(CONFIG_$(SPL_)NOP_PHY) += nop-phy.o
obj-$(CONFIG_MIPI_DPHY_HELPERS) += phy-core-mipi-dphy.o
+obj-$(CONFIG_AB8500_USB_PHY) += phy-ab8500-usb.o
obj-$(CONFIG_BCM6318_USBH_PHY) += bcm6318-usbh-phy.o
obj-$(CONFIG_BCM6348_USBH_PHY) += bcm6348-usbh-phy.o
obj-$(CONFIG_BCM6358_USBH_PHY) += bcm6358-usbh-phy.o
diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c
index 5723c98032..82713b8381 100644
--- a/drivers/phy/allwinner/phy-sun4i-usb.c
+++ b/drivers/phy/allwinner/phy-sun4i-usb.c
@@ -313,9 +313,21 @@ static int sun4i_usb_phy_init(struct phy *phy)
data->cfg->disc_thresh, PHY_DISCON_TH_LEN);
}
+#ifdef CONFIG_USB_MUSB_SUNXI
+ /* Needed for HCI and conflicts with MUSB, keep PHY0 on MUSB */
+ if (usb_phy->id != 0)
+ sun4i_usb_phy_passby(phy, true);
+
+ /* Route PHY0 to MUSB to allow USB gadget */
+ if (data->cfg->phy0_dual_route)
+ sun4i_usb_phy0_reroute(data, true);
+#else
sun4i_usb_phy_passby(phy, true);
- sun4i_usb_phy0_reroute(data, true);
+ /* Route PHY0 to HCI to allow USB host */
+ if (data->cfg->phy0_dual_route)
+ sun4i_usb_phy0_reroute(data, false);
+#endif
return 0;
}
diff --git a/drivers/phy/phy-ab8500-usb.c b/drivers/phy/phy-ab8500-usb.c
new file mode 100644
index 0000000000..0e04595717
--- /dev/null
+++ b/drivers/phy/phy-ab8500-usb.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (C) 2019 Stephan Gerhold */
+
+#include <common.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <linux/bitops.h>
+#include <power/pmic.h>
+#include <power/ab8500.h>
+
+#define AB8500_USB_PHY_CTRL_REG AB8500_USB(0x8A)
+#define AB8500_BIT_PHY_CTRL_HOST_EN BIT(0)
+#define AB8500_BIT_PHY_CTRL_DEVICE_EN BIT(1)
+#define AB8500_USB_PHY_CTRL_MASK (AB8500_BIT_PHY_CTRL_HOST_EN |\
+ AB8500_BIT_PHY_CTRL_DEVICE_EN)
+
+static int ab8500_usb_phy_power_on(struct phy *phy)
+{
+ struct udevice *dev = phy->dev;
+ uint set = AB8500_BIT_PHY_CTRL_DEVICE_EN;
+
+ if (CONFIG_IS_ENABLED(USB_MUSB_HOST))
+ set = AB8500_BIT_PHY_CTRL_HOST_EN;
+
+ return pmic_clrsetbits(dev->parent, AB8500_USB_PHY_CTRL_REG,
+ AB8500_USB_PHY_CTRL_MASK, set);
+}
+
+static int ab8500_usb_phy_power_off(struct phy *phy)
+{
+ struct udevice *dev = phy->dev;
+
+ return pmic_clrsetbits(dev->parent, AB8500_USB_PHY_CTRL_REG,
+ AB8500_USB_PHY_CTRL_MASK, 0);
+}
+
+struct phy_ops ab8500_usb_phy_ops = {
+ .power_on = ab8500_usb_phy_power_on,
+ .power_off = ab8500_usb_phy_power_off,
+};
+
+static const struct udevice_id ab8500_usb_phy_ids[] = {
+ { .compatible = "stericsson,ab8500-usb" },
+ { }
+};
+
+U_BOOT_DRIVER(ab8500_usb_phy) = {
+ .name = "ab8500_usb_phy",
+ .id = UCLASS_PHY,
+ .of_match = ab8500_usb_phy_ids,
+ .ops = &ab8500_usb_phy_ops,
+};
diff --git a/drivers/phy/socionext/Kconfig b/drivers/phy/socionext/Kconfig
new file mode 100644
index 0000000000..bcd579e98e
--- /dev/null
+++ b/drivers/phy/socionext/Kconfig
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# PHY drivers for Socionext platforms.
+#
+
+config PHY_UNIPHIER_PCIE
+ bool "UniPhier PCIe PHY driver"
+ depends on PHY && ARCH_UNIPHIER
+ imply REGMAP
+ help
+ Enable this to support PHY implemented in PCIe controller
+ on UniPhier SoCs.
diff --git a/drivers/phy/socionext/Makefile b/drivers/phy/socionext/Makefile
new file mode 100644
index 0000000000..5484360b70
--- /dev/null
+++ b/drivers/phy/socionext/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the phy drivers.
+#
+
+obj-$(CONFIG_PHY_UNIPHIER_PCIE) += phy-uniphier-pcie.o
diff --git a/drivers/phy/socionext/phy-uniphier-pcie.c b/drivers/phy/socionext/phy-uniphier-pcie.c
new file mode 100644
index 0000000000..d352c4ca3a
--- /dev/null
+++ b/drivers/phy/socionext/phy-uniphier-pcie.c
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * phy_uniphier_pcie.c - Socionext UniPhier PCIe PHY driver
+ * Copyright 2019-2021 Socionext, Inc.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <linux/bitops.h>
+#include <linux/compat.h>
+#include <regmap.h>
+#include <syscon.h>
+
+/* SG */
+#define SG_USBPCIESEL 0x590
+#define SG_USBPCIESEL_PCIE BIT(0)
+
+struct uniphier_pciephy_priv {
+ int dummy;
+};
+
+static int uniphier_pciephy_init(struct phy *phy)
+{
+ return 0;
+}
+
+static int uniphier_pciephy_probe(struct udevice *dev)
+{
+ struct regmap *regmap;
+
+ regmap = syscon_regmap_lookup_by_phandle(dev,
+ "socionext,syscon");
+ if (!IS_ERR(regmap))
+ regmap_update_bits(regmap, SG_USBPCIESEL,
+ SG_USBPCIESEL_PCIE, SG_USBPCIESEL_PCIE);
+
+ return 0;
+}
+
+static struct phy_ops uniphier_pciephy_ops = {
+ .init = uniphier_pciephy_init,
+};
+
+static const struct udevice_id uniphier_pciephy_ids[] = {
+ { .compatible = "socionext,uniphier-pro5-pcie-phy" },
+ { .compatible = "socionext,uniphier-ld20-pcie-phy" },
+ { .compatible = "socionext,uniphier-pxs3-pcie-phy" },
+ { }
+};
+
+U_BOOT_DRIVER(uniphier_pcie_phy) = {
+ .name = "uniphier-pcie-phy",
+ .id = UCLASS_PHY,
+ .of_match = uniphier_pciephy_ids,
+ .ops = &uniphier_pciephy_ops,
+ .probe = uniphier_pciephy_probe,
+ .priv_auto = sizeof(struct uniphier_pciephy_priv),
+};
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index 7af6c5f0b0..cf9ad3670f 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -471,6 +471,7 @@ static int single_probe(struct udevice *dev)
return -ENOMEM;
#endif
+ /* looks like a possible divide by 0, but data->width avoids this */
priv->npins = size / (pdata->width / BITS_PER_BYTE);
if (pdata->bits_per_mux) {
if (!pdata->mask) {
diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig
index 583fd3ddcd..fd6648b313 100644
--- a/drivers/power/pmic/Kconfig
+++ b/drivers/power/pmic/Kconfig
@@ -31,6 +31,16 @@ config SPL_PMIC_CHILDREN
to call your regulator code (e.g. see rk8xx.c for direct functions
for use in SPL).
+config PMIC_AB8500
+ bool "Enable driver for ST-Ericsson AB8500 PMIC via PRCMU"
+ depends on DM_PMIC
+ select REGMAP
+ select SYSCON
+ help
+ Enable support for the ST-Ericsson AB8500 (Analog Baseband) PMIC.
+ It connects with the ST-Ericsson DB8500 SoC via an I2C bus managed by
+ the power/reset/clock management unit (PRCMU) firmware.
+
config PMIC_ACT8846
bool "Enable support for the active-semi 8846 PMIC"
depends on DM_PMIC && DM_I2C
diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile
index 89099fde57..5d1a97e5f6 100644
--- a/drivers/power/pmic/Makefile
+++ b/drivers/power/pmic/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_$(SPL_)DM_PMIC_PFUZE100) += pfuze100.o
obj-$(CONFIG_$(SPL_)DM_PMIC_PCA9450) += pca9450.o
obj-$(CONFIG_PMIC_S2MPS11) += s2mps11.o
obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o
+obj-$(CONFIG_PMIC_AB8500) += ab8500.o
obj-$(CONFIG_PMIC_ACT8846) += act8846.o
obj-$(CONFIG_PMIC_AS3722) += as3722.o as3722_gpio.o
obj-$(CONFIG_PMIC_MAX8997) += max8997.o
diff --git a/drivers/power/pmic/ab8500.c b/drivers/power/pmic/ab8500.c
new file mode 100644
index 0000000000..1f64f217c3
--- /dev/null
+++ b/drivers/power/pmic/ab8500.c
@@ -0,0 +1,268 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Stephan Gerhold
+ *
+ * Adapted from old U-Boot and Linux kernel implementation:
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <power/ab8500.h>
+#include <power/pmic.h>
+
+/* CPU mailbox registers */
+#define PRCM_MBOX_CPU_VAL 0x0fc
+#define PRCM_MBOX_CPU_SET 0x100
+#define PRCM_MBOX_CPU_CLR 0x104
+
+#define PRCM_ARM_IT1_CLR 0x48C
+#define PRCM_ARM_IT1_VAL 0x494
+
+#define PRCM_TCDM_RANGE 2
+#define PRCM_REQ_MB5 0xE44
+#define PRCM_ACK_MB5 0xDF4
+#define _PRCM_MBOX_HEADER 0xFE8
+#define PRCM_MBOX_HEADER_REQ_MB5 (_PRCM_MBOX_HEADER + 0x5)
+#define PRCMU_I2C_MBOX_BIT BIT(5)
+
+/* Mailbox 5 Requests */
+#define PRCM_REQ_MB5_I2C_SLAVE_OP (PRCM_REQ_MB5 + 0x0)
+#define PRCM_REQ_MB5_I2C_HW_BITS (PRCM_REQ_MB5 + 0x1)
+#define PRCM_REQ_MB5_I2C_REG (PRCM_REQ_MB5 + 0x2)
+#define PRCM_REQ_MB5_I2C_VAL (PRCM_REQ_MB5 + 0x3)
+#define PRCMU_I2C(bank) (((bank) << 1) | BIT(6))
+#define PRCMU_I2C_WRITE 0
+#define PRCMU_I2C_READ 1
+#define PRCMU_I2C_STOP_EN BIT(3)
+
+/* Mailbox 5 ACKs */
+#define PRCM_ACK_MB5_I2C_STATUS (PRCM_ACK_MB5 + 0x1)
+#define PRCM_ACK_MB5_I2C_VAL (PRCM_ACK_MB5 + 0x3)
+#define PRCMU_I2C_WR_OK 0x1
+#define PRCMU_I2C_RD_OK 0x2
+
+/* AB8500 version registers */
+#define AB8500_MISC_REV_REG AB8500_MISC(0x80)
+#define AB8500_MISC_IC_NAME_REG AB8500_MISC(0x82)
+
+struct ab8500_priv {
+ struct ab8500 ab8500;
+ struct regmap *regmap;
+};
+
+static inline int prcmu_tcdm_readb(struct regmap *map, uint offset, u8 *valp)
+{
+ return regmap_raw_read_range(map, PRCM_TCDM_RANGE, offset,
+ valp, sizeof(*valp));
+}
+
+static inline int prcmu_tcdm_writeb(struct regmap *map, uint offset, u8 val)
+{
+ return regmap_raw_write_range(map, PRCM_TCDM_RANGE, offset,
+ &val, sizeof(val));
+}
+
+static int prcmu_wait_i2c_mbx_ready(struct ab8500_priv *priv)
+{
+ uint val;
+ int ret;
+
+ ret = regmap_read(priv->regmap, PRCM_ARM_IT1_VAL, &val);
+ if (ret)
+ return ret;
+
+ if (val & PRCMU_I2C_MBOX_BIT) {
+ printf("ab8500: warning: PRCMU i2c mailbox was not acked\n");
+ /* clear mailbox 5 ack irq */
+ ret = regmap_write(priv->regmap, PRCM_ARM_IT1_CLR,
+ PRCMU_I2C_MBOX_BIT);
+ if (ret)
+ return ret;
+ }
+
+ /* wait for on-going transaction, use 1s timeout */
+ return regmap_read_poll_timeout(priv->regmap, PRCM_MBOX_CPU_VAL, val,
+ !(val & PRCMU_I2C_MBOX_BIT), 0, 1000);
+}
+
+static int prcmu_wait_i2c_mbx_done(struct ab8500_priv *priv)
+{
+ uint val;
+ int ret;
+
+ /* set interrupt to XP70 */
+ ret = regmap_write(priv->regmap, PRCM_MBOX_CPU_SET, PRCMU_I2C_MBOX_BIT);
+ if (ret)
+ return ret;
+
+ /* wait for mailbox 5 (i2c) ack, use 1s timeout */
+ return regmap_read_poll_timeout(priv->regmap, PRCM_ARM_IT1_VAL, val,
+ (val & PRCMU_I2C_MBOX_BIT), 0, 1000);
+}
+
+static int ab8500_transfer(struct udevice *dev, uint bank_reg, u8 *val,
+ u8 op, u8 expected_status)
+{
+ struct ab8500_priv *priv = dev_get_priv(dev);
+ u8 reg = bank_reg & 0xff;
+ u8 bank = bank_reg >> 8;
+ u8 status;
+ int ret;
+
+ ret = prcmu_wait_i2c_mbx_ready(priv);
+ if (ret)
+ return ret;
+
+ ret = prcmu_tcdm_writeb(priv->regmap, PRCM_MBOX_HEADER_REQ_MB5, 0);
+ if (ret)
+ return ret;
+ ret = prcmu_tcdm_writeb(priv->regmap, PRCM_REQ_MB5_I2C_SLAVE_OP,
+ PRCMU_I2C(bank) | op);
+ if (ret)
+ return ret;
+ ret = prcmu_tcdm_writeb(priv->regmap, PRCM_REQ_MB5_I2C_HW_BITS,
+ PRCMU_I2C_STOP_EN);
+ if (ret)
+ return ret;
+ ret = prcmu_tcdm_writeb(priv->regmap, PRCM_REQ_MB5_I2C_REG, reg);
+ if (ret)
+ return ret;
+ ret = prcmu_tcdm_writeb(priv->regmap, PRCM_REQ_MB5_I2C_VAL, *val);
+ if (ret)
+ return ret;
+
+ ret = prcmu_wait_i2c_mbx_done(priv);
+ if (ret) {
+ printf("%s: mailbox request timed out\n", __func__);
+ return ret;
+ }
+
+ /* read transfer result */
+ ret = prcmu_tcdm_readb(priv->regmap, PRCM_ACK_MB5_I2C_STATUS, &status);
+ if (ret)
+ return ret;
+ ret = prcmu_tcdm_readb(priv->regmap, PRCM_ACK_MB5_I2C_VAL, val);
+ if (ret)
+ return ret;
+
+ /*
+ * Clear mailbox 5 ack irq. Note that the transfer is already complete
+ * here so checking for errors does not make sense. Clearing the irq
+ * will be retried in prcmu_wait_i2c_mbx_ready() on the next transfer.
+ */
+ regmap_write(priv->regmap, PRCM_ARM_IT1_CLR, PRCMU_I2C_MBOX_BIT);
+
+ if (status != expected_status) {
+ /*
+ * AB8500 does not have the AB8500_MISC_IC_NAME_REG register,
+ * but we need to try reading it to detect AB8505.
+ * In case of an error, assume that we have AB8500.
+ */
+ if (op == PRCMU_I2C_READ && bank_reg == AB8500_MISC_IC_NAME_REG) {
+ *val = AB8500_VERSION_AB8500;
+ return 0;
+ }
+
+ printf("%s: return status %d\n", __func__, status);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int ab8500_reg_count(struct udevice *dev)
+{
+ return AB8500_NUM_REGISTERS;
+}
+
+static int ab8500_read(struct udevice *dev, uint reg, uint8_t *buf, int len)
+{
+ int ret;
+
+ if (len != 1)
+ return -EINVAL;
+
+ *buf = 0;
+ ret = ab8500_transfer(dev, reg, buf, PRCMU_I2C_READ, PRCMU_I2C_RD_OK);
+ if (ret) {
+ printf("%s failed: %d\n", __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ab8500_write(struct udevice *dev, uint reg, const uint8_t *buf, int len)
+{
+ int ret;
+ u8 val;
+
+ if (len != 1)
+ return -EINVAL;
+
+ val = *buf;
+ ret = ab8500_transfer(dev, reg, &val, PRCMU_I2C_WRITE, PRCMU_I2C_WR_OK);
+ if (ret) {
+ printf("%s failed: %d\n", __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct dm_pmic_ops ab8500_ops = {
+ .reg_count = ab8500_reg_count,
+ .read = ab8500_read,
+ .write = ab8500_write,
+};
+
+static int ab8500_probe(struct udevice *dev)
+{
+ struct ab8500_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ /* get regmap from the PRCMU parent device (syscon in U-Boot) */
+ priv->regmap = syscon_get_regmap(dev->parent);
+ if (IS_ERR(priv->regmap))
+ return PTR_ERR(priv->regmap);
+
+ ret = pmic_reg_read(dev, AB8500_MISC_IC_NAME_REG);
+ if (ret < 0) {
+ printf("ab8500: failed to read chip version: %d\n", ret);
+ return ret;
+ }
+ priv->ab8500.version = ret;
+
+ ret = pmic_reg_read(dev, AB8500_MISC_REV_REG);
+ if (ret < 0) {
+ printf("ab8500: failed to read chip id: %d\n", ret);
+ return ret;
+ }
+ priv->ab8500.chip_id = ret;
+
+ debug("ab8500: version: %#x, chip id: %#x\n",
+ priv->ab8500.version, priv->ab8500.chip_id);
+
+ return 0;
+}
+
+static const struct udevice_id ab8500_ids[] = {
+ { .compatible = "stericsson,ab8500" },
+ { }
+};
+
+U_BOOT_DRIVER(pmic_ab8500) = {
+ .name = "pmic_ab8500",
+ .id = UCLASS_PMIC,
+ .of_match = ab8500_ids,
+ .bind = dm_scan_fdt_dev,
+ .probe = ab8500_probe,
+ .ops = &ab8500_ops,
+ .priv_auto = sizeof(struct ab8500_priv),
+};
diff --git a/drivers/reset/reset-uclass.c b/drivers/reset/reset-uclass.c
index 8caa616ed9..c09c009130 100644
--- a/drivers/reset/reset-uclass.c
+++ b/drivers/reset/reset-uclass.c
@@ -325,6 +325,8 @@ struct reset_ctl_bulk *devm_reset_bulk_get_by_node(struct udevice *dev,
bulk = devres_alloc(devm_reset_bulk_release,
sizeof(struct reset_ctl_bulk),
__GFP_ZERO);
+
+ /* this looks like a leak, but devres takes care of it */
if (unlikely(!bulk))
return ERR_PTR(-ENOMEM);
diff --git a/drivers/reset/reset-uniphier.c b/drivers/reset/reset-uniphier.c
index 2694d130b6..c5af995b4b 100644
--- a/drivers/reset/reset-uniphier.c
+++ b/drivers/reset/reset-uniphier.c
@@ -50,6 +50,7 @@ static const struct uniphier_reset_data uniphier_pro4_sys_reset_data[] = {
UNIPHIER_RESETX(12, 0x2000, 6), /* GIO */
UNIPHIER_RESETX(14, 0x2000, 17), /* USB30 */
UNIPHIER_RESETX(15, 0x2004, 17), /* USB31 */
+ UNIPHIER_RESETX(24, 0x2008, 2), /* PCIE */
UNIPHIER_RESET_END,
};
@@ -79,6 +80,7 @@ static const struct uniphier_reset_data uniphier_ld20_sys_reset_data[] = {
UNIPHIER_RESETX(17, 0x200c, 13), /* USB30-PHY1 */
UNIPHIER_RESETX(18, 0x200c, 14), /* USB30-PHY2 */
UNIPHIER_RESETX(19, 0x200c, 15), /* USB30-PHY3 */
+ UNIPHIER_RESETX(24, 0x200c, 4), /* PCIE */
UNIPHIER_RESET_END,
};
@@ -95,6 +97,7 @@ static const struct uniphier_reset_data uniphier_pxs3_sys_reset_data[] = {
UNIPHIER_RESETX(18, 0x200c, 20), /* USB30-PHY2 */
UNIPHIER_RESETX(20, 0x200c, 17), /* USB31-PHY0 */
UNIPHIER_RESETX(21, 0x200c, 19), /* USB31-PHY1 */
+ UNIPHIER_RESETX(24, 0x200c, 3), /* PCIE */
UNIPHIER_RESET_END,
};
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index f668cf9050..331a49ab59 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -7,7 +7,6 @@
obj-$(CONFIG_$(SPL_TPL_)DM_RTC) += rtc-uclass.o
obj-$(CONFIG_RTC_AT91SAM9_RTT) += at91sam9_rtt.o
-obj-y += rtc-lib.o
obj-$(CONFIG_RTC_ARMADA38X) += armada38x.o
obj-$(CONFIG_RTC_DAVINCI) += davinci.o
obj-$(CONFIG_RTC_DS1302) += ds1302.o
diff --git a/drivers/rtc/m41t62.c b/drivers/rtc/m41t62.c
index 0a4e12d698..8be532c3e3 100644
--- a/drivers/rtc/m41t62.c
+++ b/drivers/rtc/m41t62.c
@@ -213,13 +213,13 @@ static int m41t62_rtc_restart_osc(struct udevice *dev)
/* 1. Set stop bit */
val |= M41T62_SEC_ST;
- ret = dm_i2c_write(dev, M41T62_REG_ALARM_HOUR, &val, sizeof(val));
+ ret = dm_i2c_write(dev, M41T62_REG_SEC, &val, sizeof(val));
if (ret)
return ret;
/* 2. Clear stop bit */
val &= ~M41T62_SEC_ST;
- ret = dm_i2c_write(dev, M41T62_REG_ALARM_HOUR, &val, sizeof(val));
+ ret = dm_i2c_write(dev, M41T62_REG_SEC, &val, sizeof(val));
if (ret)
return ret;
diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c
deleted file mode 100644
index 1f7bdade29..0000000000
--- a/drivers/rtc/rtc-lib.c
+++ /dev/null
@@ -1,77 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * rtc and date/time utility functions
- *
- * Copyright (C) 2005-06 Tower Technologies
- * Author: Alessandro Zummo <a.zummo@towertech.it>
- *
- * U-Boot rtc_time differs from Linux rtc_time:
- * - The year field takes the actual value, not year - 1900.
- * - January is month 1.
- */
-
-#include <common.h>
-#include <rtc.h>
-#include <linux/math64.h>
-
-static const unsigned char rtc_days_in_month[] = {
- 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
-};
-
-#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
-
-/*
- * The number of days in the month.
- */
-int rtc_month_days(unsigned int month, unsigned int year)
-{
- return rtc_days_in_month[month] + (is_leap_year(year) && month == 1);
-}
-
-/*
- * rtc_to_tm - Converts u64 to rtc_time.
- * Convert seconds since 01-01-1970 00:00:00 to Gregorian date.
- *
- * This function is copied from rtc_time64_to_tm() in the Linux kernel.
- * But in U-Boot January is month 1 and we do not subtract 1900 from the year.
- */
-void rtc_to_tm(u64 time, struct rtc_time *tm)
-{
- unsigned int month, year, secs;
- int days;
-
- days = div_u64_rem(time, 86400, &secs);
-
- /* day of the week, 1970-01-01 was a Thursday */
- tm->tm_wday = (days + 4) % 7;
-
- year = 1970 + days / 365;
- days -= (year - 1970) * 365
- + LEAPS_THRU_END_OF(year - 1)
- - LEAPS_THRU_END_OF(1970 - 1);
- while (days < 0) {
- year -= 1;
- days += 365 + is_leap_year(year);
- }
- tm->tm_year = year; /* Not year - 1900 */
- tm->tm_yday = days + 1;
-
- for (month = 0; month < 11; month++) {
- int newdays;
-
- newdays = days - rtc_month_days(month, year);
- if (newdays < 0)
- break;
- days = newdays;
- }
- tm->tm_mon = month + 1; /* January = 1 */
- tm->tm_mday = days + 1;
-
- tm->tm_hour = secs / 3600;
- secs -= tm->tm_hour * 3600;
- tm->tm_min = secs / 60;
- tm->tm_sec = secs - tm->tm_min * 60;
-
- /* Zero unused fields */
- tm->tm_isdst = 0;
-}
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 961e3fb031..93348c0929 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -443,6 +443,7 @@ config DEBUG_UART_CLOCK
int "UART input clock"
depends on DEBUG_UART
default 0 if DEBUG_UART_SANDBOX
+ default 0 if DEBUG_MVEBU_A3700_UART
help
The UART input clock determines the speed of the internal UART
circuitry. The baud rate is derived from this by dividing the input
diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c
index 1cd410493b..3d49c22a9d 100644
--- a/drivers/spi/ich.c
+++ b/drivers/spi/ich.c
@@ -114,7 +114,7 @@ static bool ich9_can_do_33mhz(struct udevice *dev)
struct ich_spi_priv *priv = dev_get_priv(dev);
u32 fdod, speed;
- if (!CONFIG_IS_ENABLED(PCI))
+ if (!CONFIG_IS_ENABLED(PCI) || !priv->pch)
return false;
/* Observe SPI Descriptor Component Section 0 */
dm_pci_write_config32(priv->pch, 0xb0, 0x1000);
@@ -632,7 +632,7 @@ static int ich_spi_get_basics(struct udevice *bus, bool can_probe,
if (device_get_uclass_id(pch) != UCLASS_PCH) {
uclass_first_device(UCLASS_PCH, &pch);
if (!pch)
- return log_msg_ret("uclass", -EPROTOTYPE);
+ ; /* ignore this error since we don't need it */
}
}
diff --git a/drivers/timer/nomadik-mtu-timer.c b/drivers/timer/nomadik-mtu-timer.c
index 417b419d46..4d24de14ae 100644
--- a/drivers/timer/nomadik-mtu-timer.c
+++ b/drivers/timer/nomadik-mtu-timer.c
@@ -67,14 +67,11 @@ static int nomadik_mtu_probe(struct udevice *dev)
struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
struct nomadik_mtu_priv *priv = dev_get_priv(dev);
struct nomadik_mtu_regs *mtu;
- fdt_addr_t addr;
u32 prescale;
- addr = dev_read_addr(dev);
- if (addr == FDT_ADDR_T_NONE)
+ mtu = dev_read_addr_ptr(dev);
+ if (!mtu)
return -EINVAL;
-
- mtu = (struct nomadik_mtu_regs *)addr;
priv->timer = mtu->timers; /* Use first timer */
if (!uc_priv->clock_rate)
diff --git a/drivers/tpm/cr50_i2c.c b/drivers/tpm/cr50_i2c.c
index 76432bdec1..7a2b5a4faa 100644
--- a/drivers/tpm/cr50_i2c.c
+++ b/drivers/tpm/cr50_i2c.c
@@ -18,8 +18,6 @@
#include <acpi/acpi_device.h>
#include <asm/gpio.h>
#include <asm/io.h>
-#include <asm/arch/iomap.h>
-#include <asm/arch/pm.h>
#include <linux/delay.h>
#include <dm/acpi.h>
diff --git a/drivers/usb/musb-new/Kconfig b/drivers/usb/musb-new/Kconfig
index fd6f4109b0..81ceea9740 100644
--- a/drivers/usb/musb-new/Kconfig
+++ b/drivers/usb/musb-new/Kconfig
@@ -72,6 +72,15 @@ config USB_MUSB_SUNXI
Say y here to enable support for the sunxi OTG / DRC USB controller
used on almost all sunxi boards.
+config USB_MUSB_UX500
+ bool "Enable ST-Ericsson Ux500 USB controller"
+ depends on DM_USB && DM_USB_GADGET && ARCH_U8500
+ default y
+ help
+ Say y to enable support for the MUSB OTG USB controller used in
+ ST-Ericsson Ux500. The driver supports either gadget or host mode
+ based on the selection of CONFIG_USB_MUSB_HOST.
+
config USB_MUSB_DISABLE_BULK_COMBINE_SPLIT
bool "Disable MUSB bulk split/combine"
default y
@@ -85,7 +94,7 @@ endif
config USB_MUSB_PIO_ONLY
bool "Disable DMA (always use PIO)"
- default y if USB_MUSB_AM35X || USB_MUSB_PIC32 || USB_MUSB_OMAP2PLUS || USB_MUSB_DSPS || USB_MUSB_SUNXI || USB_MUSB_MT85XX
+ default y if USB_MUSB_AM35X || USB_MUSB_PIC32 || USB_MUSB_OMAP2PLUS || USB_MUSB_DSPS || USB_MUSB_SUNXI || USB_MUSB_MT85XX || USB_MUSB_UX500
help
All data is copied between memory and FIFO by the CPU.
DMA controllers are ignored.
diff --git a/drivers/usb/musb-new/Makefile b/drivers/usb/musb-new/Makefile
index 6355eb12dd..396ff02654 100644
--- a/drivers/usb/musb-new/Makefile
+++ b/drivers/usb/musb-new/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_USB_MUSB_OMAP2PLUS) += omap2430.o
obj-$(CONFIG_USB_MUSB_PIC32) += pic32.o
obj-$(CONFIG_USB_MUSB_SUNXI) += sunxi.o
obj-$(CONFIG_USB_MUSB_TI) += ti-musb.o
+obj-$(CONFIG_USB_MUSB_UX500) += ux500.o
ccflags-y := $(call cc-option,-Wno-unused-variable) \
$(call cc-option,-Wno-unused-but-set-variable) \
diff --git a/drivers/usb/musb-new/musb_core.c b/drivers/usb/musb-new/musb_core.c
index 22811a5efb..18d9bc805f 100644
--- a/drivers/usb/musb-new/musb_core.c
+++ b/drivers/usb/musb-new/musb_core.c
@@ -1526,7 +1526,7 @@ static int __devinit musb_core_init(u16 musb_type, struct musb *musb)
/*-------------------------------------------------------------------------*/
#if defined(CONFIG_SOC_OMAP2430) || defined(CONFIG_SOC_OMAP3430) || \
- defined(CONFIG_ARCH_OMAP4)
+ defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_ARCH_U8500)
static irqreturn_t generic_interrupt(int irq, void *__hci)
{
diff --git a/drivers/usb/musb-new/ux500.c b/drivers/usb/musb-new/ux500.c
new file mode 100644
index 0000000000..57c7d5630d
--- /dev/null
+++ b/drivers/usb/musb-new/ux500.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (C) 2019 Stephan Gerhold */
+
+#include <common.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <dm/device_compat.h>
+#include "musb_uboot.h"
+
+static struct musb_hdrc_config ux500_musb_hdrc_config = {
+ .multipoint = true,
+ .dyn_fifo = true,
+ .num_eps = 16,
+ .ram_bits = 16,
+};
+
+struct ux500_glue {
+ struct musb_host_data mdata;
+ struct device dev;
+ struct phy phy;
+ bool enabled;
+};
+#define to_ux500_glue(d) container_of(d, struct ux500_glue, dev)
+
+static int ux500_musb_enable(struct musb *musb)
+{
+ struct ux500_glue *glue = to_ux500_glue(musb->controller);
+ int ret;
+
+ if (glue->enabled)
+ return 0;
+
+ ret = generic_phy_power_on(&glue->phy);
+ if (ret) {
+ printf("%s: failed to power on USB PHY\n", __func__);
+ return ret;
+ }
+
+ glue->enabled = true;
+ return 0;
+}
+
+static void ux500_musb_disable(struct musb *musb)
+{
+ struct ux500_glue *glue = to_ux500_glue(musb->controller);
+ int ret;
+
+ if (!glue->enabled)
+ return;
+
+ ret = generic_phy_power_off(&glue->phy);
+ if (ret) {
+ printf("%s: failed to power off USB PHY\n", __func__);
+ return;
+ }
+
+ glue->enabled = false;
+}
+
+static int ux500_musb_init(struct musb *musb)
+{
+ struct ux500_glue *glue = to_ux500_glue(musb->controller);
+ int ret;
+
+ ret = generic_phy_init(&glue->phy);
+ if (ret) {
+ printf("%s: failed to init USB PHY\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ux500_musb_exit(struct musb *musb)
+{
+ struct ux500_glue *glue = to_ux500_glue(musb->controller);
+ int ret;
+
+ ret = generic_phy_exit(&glue->phy);
+ if (ret) {
+ printf("%s: failed to exit USB PHY\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct musb_platform_ops ux500_musb_ops = {
+ .init = ux500_musb_init,
+ .exit = ux500_musb_exit,
+ .enable = ux500_musb_enable,
+ .disable = ux500_musb_disable,
+};
+
+int dm_usb_gadget_handle_interrupts(struct udevice *dev)
+{
+ struct ux500_glue *glue = dev_get_priv(dev);
+
+ glue->mdata.host->isr(0, glue->mdata.host);
+ return 0;
+}
+
+static int ux500_musb_probe(struct udevice *dev)
+{
+#ifdef CONFIG_USB_MUSB_HOST
+ struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
+#endif
+ struct ux500_glue *glue = dev_get_priv(dev);
+ struct musb_host_data *host = &glue->mdata;
+ struct musb_hdrc_platform_data pdata;
+ void *base = dev_read_addr_ptr(dev);
+ int ret;
+
+ if (!base)
+ return -EINVAL;
+
+ ret = generic_phy_get_by_name(dev, "usb", &glue->phy);
+ if (ret) {
+ dev_err(dev, "failed to get USB PHY: %d\n", ret);
+ return ret;
+ }
+
+ memset(&pdata, 0, sizeof(pdata));
+ pdata.platform_ops = &ux500_musb_ops;
+ pdata.config = &ux500_musb_hdrc_config;
+
+#ifdef CONFIG_USB_MUSB_HOST
+ priv->desc_before_addr = true;
+ pdata.mode = MUSB_HOST;
+
+ host->host = musb_init_controller(&pdata, &glue->dev, base);
+ if (!host->host)
+ return -EIO;
+
+ return musb_lowlevel_init(host);
+#else
+ pdata.mode = MUSB_PERIPHERAL;
+ host->host = musb_init_controller(&pdata, &glue->dev, base);
+ if (!host->host)
+ return -EIO;
+
+ return usb_add_gadget_udc(&glue->dev, &host->host->g);
+#endif
+}
+
+static int ux500_musb_remove(struct udevice *dev)
+{
+ struct ux500_glue *glue = dev_get_priv(dev);
+ struct musb_host_data *host = &glue->mdata;
+
+ usb_del_gadget_udc(&host->host->g);
+ musb_stop(host->host);
+ free(host->host);
+ host->host = NULL;
+
+ return 0;
+}
+
+static const struct udevice_id ux500_musb_ids[] = {
+ { .compatible = "stericsson,db8500-musb" },
+ { }
+};
+
+U_BOOT_DRIVER(ux500_musb) = {
+ .name = "ux500-musb",
+#ifdef CONFIG_USB_MUSB_HOST
+ .id = UCLASS_USB,
+#else
+ .id = UCLASS_USB_GADGET_GENERIC,
+#endif
+ .of_match = ux500_musb_ids,
+ .probe = ux500_musb_probe,
+ .remove = ux500_musb_remove,
+#ifdef CONFIG_USB_MUSB_HOST
+ .ops = &musb_usb_ops,
+#endif
+ .plat_auto = sizeof(struct usb_plat),
+ .priv_auto = sizeof(struct ux500_glue),
+};
diff --git a/drivers/video/pwm_backlight.c b/drivers/video/pwm_backlight.c
index 4c86215bd7..d7c096923b 100644
--- a/drivers/video/pwm_backlight.c
+++ b/drivers/video/pwm_backlight.c
@@ -235,8 +235,10 @@ static int pwm_backlight_of_to_plat(struct udevice *dev)
priv->levels = malloc(len);
if (!priv->levels)
return log_ret(-ENOMEM);
- dev_read_u32_array(dev, "brightness-levels", priv->levels,
- count);
+ ret = dev_read_u32_array(dev, "brightness-levels", priv->levels,
+ count);
+ if (ret)
+ return log_msg_ret("levels", ret);
priv->num_levels = count;
priv->default_level = priv->levels[index];
priv->max_level = priv->levels[count - 1];
diff --git a/drivers/watchdog/designware_wdt.c b/drivers/watchdog/designware_wdt.c
index 9e5487168c..afed81e6c6 100644
--- a/drivers/watchdog/designware_wdt.c
+++ b/drivers/watchdog/designware_wdt.c
@@ -22,6 +22,7 @@
struct designware_wdt_priv {
void __iomem *base;
unsigned int clk_khz;
+ struct reset_ctl_bulk *resets;
};
/*
@@ -95,6 +96,18 @@ static int designware_wdt_stop(struct udevice *dev)
designware_wdt_reset(dev);
writel(0, priv->base + DW_WDT_CR);
+ if (CONFIG_IS_ENABLED(DM_RESET)) {
+ int ret;
+
+ ret = reset_assert_bulk(priv->resets);
+ if (ret)
+ return ret;
+
+ ret = reset_deassert_bulk(priv->resets);
+ if (ret)
+ return ret;
+ }
+
return 0;
}
@@ -143,13 +156,11 @@ static int designware_wdt_probe(struct udevice *dev)
#endif
if (CONFIG_IS_ENABLED(DM_RESET)) {
- struct reset_ctl_bulk resets;
-
- ret = reset_get_bulk(dev, &resets);
+ ret = reset_get_bulk(dev, priv->resets);
if (ret)
goto err;
- ret = reset_deassert_bulk(&resets);
+ ret = reset_deassert_bulk(priv->resets);
if (ret)
goto err;
}
diff --git a/drivers/watchdog/wdt-uclass.c b/drivers/watchdog/wdt-uclass.c
index a0c2429e5a..17334dbda6 100644
--- a/drivers/watchdog/wdt-uclass.c
+++ b/drivers/watchdog/wdt-uclass.c
@@ -53,7 +53,7 @@ int initr_watchdog(void)
4 * reset_period) / 4;
}
- if (!CONFIG_IS_ENABLED(WATCHDOG_AUTOSTART)) {
+ if (!IS_ENABLED(CONFIG_WATCHDOG_AUTOSTART)) {
printf("WDT: Not starting\n");
return 0;
}