aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2021-07-14 16:48:23 -0400
committerTom Rini <trini@konsulko.com>2021-07-14 16:48:23 -0400
commiteae8c7c33829c3bd25a792600c1fe6ed842a1ddc (patch)
tree48ac04976fdc068a5f6aea009a153feb9dde34ff
parenta7bdd2dd8e7685166767c5fecfdce7e5dc8a40be (diff)
parent845d9cf61c3a319fed0069c36f402e74a61ceb8c (diff)
downloadu-boot-eae8c7c33829c3bd25a792600c1fe6ed842a1ddc.zip
u-boot-eae8c7c33829c3bd25a792600c1fe6ed842a1ddc.tar.gz
u-boot-eae8c7c33829c3bd25a792600c1fe6ed842a1ddc.tar.bz2
Merge branch '2021-07-14-platform-updates'
- Assorted platform updates
-rw-r--r--MAINTAINERS4
-rw-r--r--arch/arm/dts/Makefile1
-rw-r--r--arch/arm/dts/uniphier-ld20-akebi96.dts189
-rw-r--r--arch/arm/mach-snapdragon/pinctrl-apq8016.c3
-rw-r--r--arch/arm/mach-snapdragon/pinctrl-apq8096.c2
-rw-r--r--arch/arm/mach-u8500/Kconfig2
-rw-r--r--board/ste/stemmy/README1
-rw-r--r--board/ste/stemmy/stemmy.c149
-rw-r--r--common/board_info.c10
-rw-r--r--configs/stemmy_defconfig2
-rw-r--r--configs/total_compute_defconfig3
-rw-r--r--doc/git-mailrc3
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/clk/uniphier/clk-uniphier-sys.c3
-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/i2c_eeprom.c1
-rw-r--r--drivers/pci/Kconfig10
-rw-r--r--drivers/pci/Makefile1
-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/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/power/pmic/Kconfig10
-rw-r--r--drivers/power/pmic/Makefile1
-rw-r--r--drivers/power/pmic/ab8500.c268
-rw-r--r--drivers/reset/reset-uniphier.c3
-rw-r--r--drivers/timer/nomadik-mtu-timer.c7
-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--include/configs/stemmy.h24
-rw-r--r--include/configs/uniphier.h2
-rw-r--r--include/power/ab8500.h125
41 files changed, 1682 insertions, 254 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 79d356d..34ed880 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -118,8 +118,8 @@ F: cmd/arm/
ARM ALTERA SOCFPGA
M: Marek Vasut <marex@denx.de>
M: Simon Goldschmidt <simon.k.r.goldschmidt@gmail.com>
-M: Ley Foon Tan <lftan.linux@gmail.com>
-S: Maintainted
+M: Tien Fong Chee <tien.fong.chee@intel.com>
+S: Maintained
T: git https://source.denx.de/u-boot/custodians/u-boot-socfpga.git
F: arch/arm/mach-socfpga/
F: drivers/sysreset/sysreset_socfpga*
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index 7ce3ae6..708ce2d 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -254,6 +254,7 @@ dtb-$(CONFIG_ARCH_UNIPHIER_LD11) += \
uniphier-ld11-global.dtb \
uniphier-ld11-ref.dtb
dtb-$(CONFIG_ARCH_UNIPHIER_LD20) += \
+ uniphier-ld20-akebi96.dtb \
uniphier-ld20-global.dtb \
uniphier-ld20-ref.dtb
dtb-$(CONFIG_ARCH_UNIPHIER_LD4) += \
diff --git a/arch/arm/dts/uniphier-ld20-akebi96.dts b/arch/arm/dts/uniphier-ld20-akebi96.dts
new file mode 100644
index 0000000..aa159a1
--- /dev/null
+++ b/arch/arm/dts/uniphier-ld20-akebi96.dts
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+//
+// Device Tree Source for Akebi96 Development Board
+//
+// Derived from uniphier-ld20-global.dts.
+//
+// Copyright (C) 2015-2017 Socionext Inc.
+// Copyright (C) 2019-2020 Linaro Ltd.
+
+/dts-v1/;
+#include <dt-bindings/gpio/uniphier-gpio.h>
+#include "uniphier-ld20.dtsi"
+
+/ {
+ model = "Akebi96";
+ compatible = "socionext,uniphier-ld20-akebi96",
+ "socionext,uniphier-ld20";
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ aliases {
+ serial0 = &serial0;
+ serial1 = &serial1;
+ serial2 = &serial2;
+ serial3 = &serial3;
+ i2c0 = &i2c0;
+ i2c1 = &i2c1;
+ i2c2 = &i2c2;
+ i2c3 = &i2c3;
+ i2c4 = &i2c4;
+ i2c5 = &i2c5;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ spi2 = &spi2;
+ spi3 = &spi3;
+ ethernet0 = &eth;
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ reg = <0 0x80000000 0 0xc0000000>;
+ };
+
+ framebuffer@c0000000 {
+ compatible = "simple-framebuffer";
+ reg = <0 0xc0000000 0 0x02000000>;
+ width = <1920>;
+ height = <1080>;
+ stride = <7680>;
+ format = "a8r8g8b8";
+ };
+
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ memory@c0000000 {
+ reg = <0 0xc0000000 0 0x02000000>;
+ no-map;
+ };
+ };
+
+ sound {
+ compatible = "audio-graph-card";
+ label = "UniPhier LD20";
+ dais = <&spdif_port0
+ &comp_spdif_port0>;
+ };
+
+ spdif-out {
+ compatible = "linux,spdif-dit";
+ #sound-dai-cells = <0>;
+
+ port@0 {
+ spdif_tx: endpoint {
+ remote-endpoint = <&spdif_hiecout1>;
+ };
+ };
+ };
+
+ comp-spdif-out {
+ compatible = "linux,spdif-dit";
+ #sound-dai-cells = <0>;
+
+ port@0 {
+ comp_spdif_tx: endpoint {
+ remote-endpoint = <&comp_spdif_hiecout1>;
+ };
+ };
+ };
+
+ firmware {
+ optee {
+ compatible = "linaro,optee-tz";
+ method = "smc";
+ };
+ };
+};
+
+&spi3 {
+ status = "okay";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ usb-over-spi@0 {
+ compatible = "maxim,max3421-udc";
+ reg = <0>;
+ spi-max-frequency = <12500000>;
+ interrupt-parent = <&gpio>;
+ interrupt-names = "udc";
+ interrupts = <0 2>;
+ };
+};
+
+&serial0 {
+ /* Onboard USB-UART */
+ status = "okay";
+};
+
+&serial2 {
+ /* LS connector UART1 */
+ status = "okay";
+};
+
+&serial3 {
+ /* LS connector UART0 */
+ status = "okay";
+};
+
+&spdif_hiecout1 {
+ remote-endpoint = <&spdif_tx>;
+};
+
+&comp_spdif_hiecout1 {
+ remote-endpoint = <&comp_spdif_tx>;
+};
+
+&i2c0 {
+ /* LS connector I2C0 */
+ status = "okay";
+};
+
+&i2c1 {
+ /* LS connector I2C1 */
+ status = "okay";
+};
+
+&eth {
+ status = "okay";
+ phy-handle = <&ethphy>;
+};
+
+&mdio {
+ ethphy: ethernet-phy@0 {
+ reg = <0>;
+ };
+};
+
+&usb {
+ status = "okay";
+};
+
+&pcie {
+ status = "okay";
+};
+
+&gpio {
+ /* IRQs for Max3421 */
+ xirq0 {
+ gpio-hog;
+ gpios = <UNIPHIER_GPIO_IRQ(0) 1>;
+ input;
+ };
+ xirq10 {
+ gpio-hog;
+ gpios = <UNIPHIER_GPIO_IRQ(10) 1>;
+ input;
+ };
+};
+
+&pinctrl_aout1 {
+ groups = "aout1b";
+};
+
+&pinctrl_uart3 {
+ groups = "uart3", "uart3_ctsrts";
+};
diff --git a/arch/arm/mach-snapdragon/pinctrl-apq8016.c b/arch/arm/mach-snapdragon/pinctrl-apq8016.c
index 1042b56..70c0be0 100644
--- a/arch/arm/mach-snapdragon/pinctrl-apq8016.c
+++ b/arch/arm/mach-snapdragon/pinctrl-apq8016.c
@@ -10,7 +10,7 @@
#include <common.h>
#define MAX_PIN_NAME_LEN 32
-static char pin_name[MAX_PIN_NAME_LEN];
+static char pin_name[MAX_PIN_NAME_LEN] __section(".data");
static const char * const msm_pinctrl_pins[] = {
"SDC1_CLK",
"SDC1_CMD",
@@ -59,4 +59,3 @@ struct msm_pinctrl_data apq8016_data = {
.get_function_mux = apq8016_get_function_mux,
.get_pin_name = apq8016_get_pin_name,
};
-
diff --git a/arch/arm/mach-snapdragon/pinctrl-apq8096.c b/arch/arm/mach-snapdragon/pinctrl-apq8096.c
index 20a71c3..45462f0 100644
--- a/arch/arm/mach-snapdragon/pinctrl-apq8096.c
+++ b/arch/arm/mach-snapdragon/pinctrl-apq8096.c
@@ -10,7 +10,7 @@
#include <common.h>
#define MAX_PIN_NAME_LEN 32
-static char pin_name[MAX_PIN_NAME_LEN];
+static char pin_name[MAX_PIN_NAME_LEN] __section(".data");
static const char * const msm_pinctrl_pins[] = {
"SDC1_CLK",
"SDC1_CMD",
diff --git a/arch/arm/mach-u8500/Kconfig b/arch/arm/mach-u8500/Kconfig
index 7478deb..db7a29a 100644
--- a/arch/arm/mach-u8500/Kconfig
+++ b/arch/arm/mach-u8500/Kconfig
@@ -8,6 +8,7 @@ choice
config TARGET_STEMMY
bool "Samsung (stemmy) board"
+ select MISC_INIT_R
help
The Samsung "stemmy" board supports Samsung smartphones released with
the ST-Ericsson NovaThor U8500 SoC, e.g.
@@ -15,6 +16,7 @@ config TARGET_STEMMY
- Samsung Galaxy S III mini (GT-I8190) "golden"
- Samsung Galaxy S Advance (GT-I9070) "janice"
- Samsung Galaxy Xcover 2 (GT-S7710) "skomer"
+ - Samsung Galaxy Ace 2 (GT-I8160) "codina"
and likely others as well (untested).
diff --git a/board/ste/stemmy/README b/board/ste/stemmy/README
index 81f7242..1b83b83 100644
--- a/board/ste/stemmy/README
+++ b/board/ste/stemmy/README
@@ -7,6 +7,7 @@ the ST-Ericsson NovaThor U8500 SoC, e.g.
- Samsung Galaxy S III mini (GT-I8190) "golden"
- Samsung Galaxy S Advance (GT-I9070) "janice"
- Samsung Galaxy Xcover 2 (GT-S7710) "skomer"
+ - Samsung Galaxy Ace 2 (GT-I8160) "codina"
and likely others as well (untested).
diff --git a/board/ste/stemmy/stemmy.c b/board/ste/stemmy/stemmy.c
index b9b2a6f..5f1150c 100644
--- a/board/ste/stemmy/stemmy.c
+++ b/board/ste/stemmy/stemmy.c
@@ -3,18 +3,165 @@
* Copyright (C) 2019 Stephan Gerhold <stephan@gerhold.net>
*/
#include <common.h>
+#include <env.h>
#include <init.h>
+#include <log.h>
+#include <stdlib.h>
#include <asm/global_data.h>
+#include <asm/setup.h>
+#include <asm/system.h>
DECLARE_GLOBAL_DATA_PTR;
+/* Parse atags provided by Samsung bootloader to get available memory */
+static ulong fw_mach __section(".data");
+static ulong fw_atags __section(".data");
+
+static const struct tag *fw_atags_copy;
+static uint fw_atags_size;
+
+void save_boot_params(ulong r0, ulong r1, ulong r2, ulong r3)
+{
+ fw_mach = r1;
+ fw_atags = r2;
+ save_boot_params_ret();
+}
+
+static const struct tag *fw_atags_get(void)
+{
+ const struct tag *tags = (const struct tag *)fw_atags;
+
+ if (tags->hdr.tag != ATAG_CORE) {
+ log_err("Invalid atags: tag 0x%x at %p\n", tags->hdr.tag, tags);
+ return NULL;
+ }
+
+ return tags;
+}
+
int dram_init(void)
{
- gd->ram_size = get_ram_size(CONFIG_SYS_SDRAM_BASE, CONFIG_SYS_SDRAM_SIZE);
+ const struct tag *t, *tags = fw_atags_get();
+
+ if (!tags)
+ return -EINVAL;
+
+ for_each_tag(t, tags) {
+ if (t->hdr.tag != ATAG_MEM)
+ continue;
+
+ debug("Memory: %#x-%#x (size %#x)\n", t->u.mem.start,
+ t->u.mem.start + t->u.mem.size, t->u.mem.size);
+ gd->ram_size += t->u.mem.size;
+ }
+ return 0;
+}
+
+int dram_init_banksize(void)
+{
+ const struct tag *t, *tags = fw_atags_get();
+ unsigned int bank = 0;
+
+ if (!tags)
+ return -EINVAL;
+
+ for_each_tag(t, tags) {
+ if (t->hdr.tag != ATAG_MEM)
+ continue;
+
+ gd->bd->bi_dram[bank].start = t->u.mem.start;
+ gd->bd->bi_dram[bank].size = t->u.mem.size;
+ if (++bank == CONFIG_NR_DRAM_BANKS)
+ break;
+ }
return 0;
}
int board_init(void)
{
+ gd->bd->bi_arch_number = fw_mach;
+ gd->bd->bi_boot_params = fw_atags;
return 0;
}
+
+static void parse_serial(const struct tag_serialnr *serialnr)
+{
+ char serial[17];
+
+ if (env_get("serial#"))
+ return;
+
+ sprintf(serial, "%08x%08x", serialnr->high, serialnr->low);
+ env_set("serial#", serial);
+}
+
+/*
+ * The downstream/vendor kernel (provided by Samsung) uses ATAGS for booting.
+ * It also requires an extremely long cmdline provided by the primary bootloader
+ * that is not suitable for booting mainline.
+ *
+ * Since downstream is the only user of ATAGS, we emulate the behavior of the
+ * Samsung bootloader by generating only the initrd atag in U-Boot, and copying
+ * all other ATAGS as-is from the primary bootloader.
+ */
+static inline bool skip_atag(u32 tag)
+{
+ return (tag == ATAG_NONE || tag == ATAG_CORE ||
+ tag == ATAG_INITRD || tag == ATAG_INITRD2);
+}
+
+static void copy_atags(const struct tag *tags)
+{
+ const struct tag *t;
+ struct tag *copy;
+
+ if (!tags)
+ return;
+
+ /* Calculate necessary size for tags we want to copy */
+ for_each_tag(t, tags) {
+ if (skip_atag(t->hdr.tag))
+ continue;
+
+ if (t->hdr.tag == ATAG_SERIAL)
+ parse_serial(&t->u.serialnr);
+
+ fw_atags_size += t->hdr.size * sizeof(u32);
+ }
+
+ if (!fw_atags_size)
+ return; /* No tags to copy */
+
+ copy = malloc(fw_atags_size);
+ if (!copy)
+ return;
+ fw_atags_copy = copy;
+
+ /* Copy tags */
+ for_each_tag(t, tags) {
+ if (skip_atag(t->hdr.tag))
+ continue;
+
+ memcpy(copy, t, t->hdr.size * sizeof(u32));
+ copy = tag_next(copy);
+ }
+}
+
+int misc_init_r(void)
+{
+ copy_atags(fw_atags_get());
+ return 0;
+}
+
+void setup_board_tags(struct tag **in_params)
+{
+ if (!fw_atags_copy)
+ return;
+
+ /*
+ * fw_atags_copy contains only full "struct tag" (plus data)
+ * so copying it bytewise here should be fine.
+ */
+ memcpy(*in_params, fw_atags_copy, fw_atags_size);
+ *(u8 **)in_params += fw_atags_size;
+}
diff --git a/common/board_info.c b/common/board_info.c
index 1cfe34f..e0f2d93 100644
--- a/common/board_info.c
+++ b/common/board_info.c
@@ -31,11 +31,15 @@ int __weak show_board_info(void)
if (IS_ENABLED(CONFIG_SYSINFO)) {
/* This might provide more detail */
- ret = uclass_first_device_err(UCLASS_SYSINFO, &dev);
- if (!ret)
- ret = sysinfo_get_str(dev,
+ ret = sysinfo_get(&dev);
+ if (!ret) {
+ ret = sysinfo_detect(dev);
+ if (!ret) {
+ ret = sysinfo_get_str(dev,
SYSINFO_ID_BOARD_MODEL,
sizeof(str), str);
+ }
+ }
}
/* Fail back to the main 'model' if available */
diff --git a/configs/stemmy_defconfig b/configs/stemmy_defconfig
index 79c05ac..f31960b 100644
--- a/configs/stemmy_defconfig
+++ b/configs/stemmy_defconfig
@@ -1,7 +1,7 @@
CONFIG_ARM=y
CONFIG_ARCH_U8500=y
CONFIG_SYS_TEXT_BASE=0x100000
-CONFIG_NR_DRAM_BANKS=1
+CONFIG_NR_DRAM_BANKS=2
CONFIG_DEFAULT_DEVICE_TREE="ste-ux500-samsung-stemmy"
CONFIG_SYS_CONSOLE_INFO_QUIET=y
CONFIG_HUSH_PARSER=y
diff --git a/configs/total_compute_defconfig b/configs/total_compute_defconfig
index 418f94b..63f2e9c 100644
--- a/configs/total_compute_defconfig
+++ b/configs/total_compute_defconfig
@@ -13,8 +13,7 @@ CONFIG_FIT=y
CONFIG_FIT_SIGNATURE=y
CONFIG_LEGACY_IMAGE_FORMAT=y
CONFIG_BOOTDELAY=5
-CONFIG_USE_BOOTARGS=y
-CONFIG_BOOTARGS="console=ttyAMA0 debug user_debug=31 earlycon=pl011,0x7ff80000 loglevel=9 androidboot.hardware=total_compute video=640x480-32@60 androidboot.boot_devices=1c050000.mmci ip=dhcp androidboot.selinux=permissive"
+# CONFIG_USE_BOOTARGS is not set
# CONFIG_USE_BOOTCOMMAND is not set
# CONFIG_DISPLAY_CPUINFO is not set
# CONFIG_DISPLAY_BOARDINFO is not set
diff --git a/doc/git-mailrc b/doc/git-mailrc
index 3ed3802..001681c 100644
--- a/doc/git-mailrc
+++ b/doc/git-mailrc
@@ -46,6 +46,7 @@ alias simongoldschmidt Simon Goldschmidt <simon.k.r.goldschmidt@gmail.com>
alias sjg Simon Glass <sjg@chromium.org>
alias smcnutt Scott McNutt <smcnutt@psyent.com>
alias stroese Stefan Roese <sr@denx.de>
+alias tienfong Tien Fong Chee <tien.fong.chee@intel.com>
alias trini Tom Rini <trini@konsulko.com>
alias wd Wolfgang Denk <wd@denx.de>
alias priyankajain Priyanka Jain <priyanka.jain@nxp.com>
@@ -69,7 +70,7 @@ alias s3c samsung
alias s5pc samsung
alias samsung uboot, prom
alias snapdragon uboot, mateusz
-alias socfpga uboot, marex, dinh, simongoldschmidt, leyfoon
+alias socfpga uboot, marex, dinh, simongoldschmidt, tienfong
alias sunxi uboot, jagan, apritzel
alias tegra uboot, sjg, Tom Warren <twarren@nvidia.com>, Stephen Warren <swarren@nvidia.com>
alias tegra2 tegra
diff --git a/drivers/Kconfig b/drivers/Kconfig
index b1ada1c..c9c812b 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 3510dab..4081289 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/uniphier/clk-uniphier-sys.c b/drivers/clk/uniphier/clk-uniphier-sys.c
index c627a4b..ff5d364 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/gpio/Kconfig b/drivers/gpio/Kconfig
index de4dc51..0817b12 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 06dfc32..16b09fb 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 eefb56d..0000000
--- 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 0000000..e1bb41b
--- /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/i2c_eeprom.c b/drivers/misc/i2c_eeprom.c
index 3b24984..89a450d 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/pci/Kconfig b/drivers/pci/Kconfig
index 782179e..517cf95 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 6568dc9..ec8ee9d 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/pcie_uniphier.c b/drivers/pci/pcie_uniphier.c
new file mode 100644
index 0000000..f2edea9
--- /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 008186a..92c74b9 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 3c4a673..bf03d05 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/phy-ab8500-usb.c b/drivers/phy/phy-ab8500-usb.c
new file mode 100644
index 0000000..0e04595
--- /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 0000000..bcd579e
--- /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 0000000..5484360
--- /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 0000000..d352c4c
--- /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/power/pmic/Kconfig b/drivers/power/pmic/Kconfig
index 583fd3d..fd6648b 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 89099fd..5d1a97e 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 0000000..1f64f21
--- /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-uniphier.c b/drivers/reset/reset-uniphier.c
index 2694d13..c5af995 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/timer/nomadik-mtu-timer.c b/drivers/timer/nomadik-mtu-timer.c
index 417b419..4d24de1 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/usb/musb-new/Kconfig b/drivers/usb/musb-new/Kconfig
index fd6f410..81ceea9 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 6355eb1..396ff02 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 22811a5..18d9bc8 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 0000000..57c7d56
--- /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/include/configs/stemmy.h b/include/configs/stemmy.h
index 922eec4..b94ef91 100644
--- a/include/configs/stemmy.h
+++ b/include/configs/stemmy.h
@@ -7,23 +7,23 @@
#include <linux/sizes.h>
-#define CONFIG_SKIP_LOWLEVEL_INIT /* Loaded by another bootloader */
-#define CONFIG_SYS_MALLOC_LEN SZ_2M
+/*
+ * The "stemmy" U-Boot port is designed to be chainloaded by the Samsung
+ * bootloader on devices based on ST-Ericsson Ux500. Therefore, we skip most
+ * low-level initialization and rely on configuration provided by the Samsung
+ * bootloader. New images are loaded at the same address for compatibility.
+ */
+#define CONFIG_SKIP_LOWLEVEL_INIT
+#define CONFIG_SYS_INIT_SP_ADDR CONFIG_SYS_TEXT_BASE
+#define CONFIG_SYS_LOAD_ADDR CONFIG_SYS_TEXT_BASE
-/* Physical Memory Map */
-#define PHYS_SDRAM_1 0x00000000 /* DDR-SDRAM Bank #1 */
-#define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1
-#define CONFIG_SYS_SDRAM_SIZE SZ_1G
-#define CONFIG_SYS_INIT_RAM_SIZE 0x00100000
-#define CONFIG_SYS_GBL_DATA_OFFSET (CONFIG_SYS_SDRAM_BASE + \
- CONFIG_SYS_INIT_RAM_SIZE - \
- GENERATED_GBL_DATA_SIZE)
-#define CONFIG_SYS_INIT_SP_ADDR CONFIG_SYS_GBL_DATA_OFFSET
+#define CONFIG_SYS_MALLOC_LEN SZ_2M
/* FIXME: This should be loaded from device tree... */
#define CONFIG_SYS_L2_PL310
#define CONFIG_SYS_PL310_BASE 0xa0412000
-#define CONFIG_SYS_LOAD_ADDR 0x00100000
+/* Generate initrd atag for downstream kernel (others are copied in stemmy.c) */
+#define CONFIG_INITRD_TAG
#endif
diff --git a/include/configs/uniphier.h b/include/configs/uniphier.h
index bad4e41..12028e5 100644
--- a/include/configs/uniphier.h
+++ b/include/configs/uniphier.h
@@ -210,4 +210,6 @@
#define CONFIG_SPL_PAD_TO 0x20000
+#define CONFIG_SYS_PCI_64BIT
+
#endif /* __CONFIG_UNIPHIER_H__ */
diff --git a/include/power/ab8500.h b/include/power/ab8500.h
new file mode 100644
index 0000000..157eb4a
--- /dev/null
+++ b/include/power/ab8500.h
@@ -0,0 +1,125 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Based on include/linux/mfd/abx500/ab8500.h from Linux
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
+ */
+
+#ifndef _PMIC_AB8500_H_
+#define _PMIC_AB8500_H_
+
+/*
+ * AB IC versions
+ *
+ * AB8500_VERSION_AB8500 should be 0xFF but will never be read as need a
+ * non-supported multi-byte I2C access via PRCMU. Set to 0x00 to ease the
+ * print of version string.
+ */
+enum ab8500_version {
+ AB8500_VERSION_AB8500 = 0x0,
+ AB8500_VERSION_AB8505 = 0x1,
+ AB8500_VERSION_AB9540 = 0x2,
+ AB8500_VERSION_AB8540 = 0x4,
+ AB8500_VERSION_UNDEFINED,
+};
+
+/* AB8500 CIDs*/
+#define AB8500_CUTEARLY 0x00
+#define AB8500_CUT1P0 0x10
+#define AB8500_CUT1P1 0x11
+#define AB8500_CUT1P2 0x12 /* Only valid for AB8540 */
+#define AB8500_CUT2P0 0x20
+#define AB8500_CUT3P0 0x30
+#define AB8500_CUT3P3 0x33
+
+/*
+ * AB8500 bank addresses
+ */
+#define AB8500_BANK(bank, reg) (((bank) << 8) | (reg))
+#define AB8500_M_FSM_RANK(reg) AB8500_BANK(0x0, reg)
+#define AB8500_SYS_CTRL1_BLOCK(reg) AB8500_BANK(0x1, reg)
+#define AB8500_SYS_CTRL2_BLOCK(reg) AB8500_BANK(0x2, reg)
+#define AB8500_REGU_CTRL1(reg) AB8500_BANK(0x3, reg)
+#define AB8500_REGU_CTRL2(reg) AB8500_BANK(0x4, reg)
+#define AB8500_USB(reg) AB8500_BANK(0x5, reg)
+#define AB8500_TVOUT(reg) AB8500_BANK(0x6, reg)
+#define AB8500_DBI(reg) AB8500_BANK(0x7, reg)
+#define AB8500_ECI_AV_ACC(reg) AB8500_BANK(0x8, reg)
+#define AB8500_RESERVED(reg) AB8500_BANK(0x9, reg)
+#define AB8500_GPADC(reg) AB8500_BANK(0xA, reg)
+#define AB8500_CHARGER(reg) AB8500_BANK(0xB, reg)
+#define AB8500_GAS_GAUGE(reg) AB8500_BANK(0xC, reg)
+#define AB8500_AUDIO(reg) AB8500_BANK(0xD, reg)
+#define AB8500_INTERRUPT(reg) AB8500_BANK(0xE, reg)
+#define AB8500_RTC(reg) AB8500_BANK(0xF, reg)
+#define AB8500_GPIO(reg) AB8500_BANK(0x10, reg)
+#define AB8500_MISC(reg) AB8500_BANK(0x10, reg)
+#define AB8500_DEVELOPMENT(reg) AB8500_BANK(0x11, reg)
+#define AB8500_DEBUG(reg) AB8500_BANK(0x12, reg)
+#define AB8500_PROD_TEST(reg) AB8500_BANK(0x13, reg)
+#define AB8500_STE_TEST(reg) AB8500_BANK(0x14, reg)
+#define AB8500_OTP_EMUL(reg) AB8500_BANK(0x15, reg)
+
+#define AB8500_NUM_BANKS 0x16
+#define AB8500_NUM_REGISTERS AB8500_BANK(AB8500_NUM_BANKS, 0)
+
+struct ab8500 {
+ enum ab8500_version version;
+ u8 chip_id;
+};
+
+static inline int is_ab8500(struct ab8500 *ab)
+{
+ return ab->version == AB8500_VERSION_AB8500;
+}
+
+static inline int is_ab8505(struct ab8500 *ab)
+{
+ return ab->version == AB8500_VERSION_AB8505;
+}
+
+/* exclude also ab8505, ab9540... */
+static inline int is_ab8500_1p0_or_earlier(struct ab8500 *ab)
+{
+ return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT1P0));
+}
+
+/* exclude also ab8505, ab9540... */
+static inline int is_ab8500_1p1_or_earlier(struct ab8500 *ab)
+{
+ return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT1P1));
+}
+
+/* exclude also ab8505, ab9540... */
+static inline int is_ab8500_2p0_or_earlier(struct ab8500 *ab)
+{
+ return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT2P0));
+}
+
+static inline int is_ab8500_3p3_or_earlier(struct ab8500 *ab)
+{
+ return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT3P3));
+}
+
+/* exclude also ab8505, ab9540... */
+static inline int is_ab8500_2p0(struct ab8500 *ab)
+{
+ return (is_ab8500(ab) && (ab->chip_id == AB8500_CUT2P0));
+}
+
+static inline int is_ab8505_1p0_or_earlier(struct ab8500 *ab)
+{
+ return (is_ab8505(ab) && (ab->chip_id <= AB8500_CUT1P0));
+}
+
+static inline int is_ab8505_2p0(struct ab8500 *ab)
+{
+ return (is_ab8505(ab) && (ab->chip_id == AB8500_CUT2P0));
+}
+
+static inline int is_ab8505_2p0_earlier(struct ab8500 *ab)
+{
+ return (is_ab8505(ab) && (ab->chip_id < AB8500_CUT2P0));
+}
+
+#endif