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/core/device.c8
-rw-r--r--drivers/gpio/msm_gpio.c1
-rw-r--r--drivers/gpio/pm8916_gpio.c8
-rw-r--r--drivers/gpio/s5p_gpio.c1
-rw-r--r--drivers/iommu/Kconfig27
-rw-r--r--drivers/iommu/Makefile6
-rw-r--r--drivers/iommu/apple_dart.c59
-rw-r--r--drivers/iommu/iommu-uclass.c45
-rw-r--r--drivers/iommu/sandbox_iommu.c18
-rw-r--r--drivers/mmc/arm_pl180_mmci.c14
-rw-r--r--drivers/mmc/arm_pl180_mmci.h1
-rw-r--r--drivers/mmc/fsl_esdhc.c16
-rw-r--r--drivers/mmc/mmc.c4
-rw-r--r--drivers/mmc/sdhci.c20
-rw-r--r--drivers/pinctrl/exynos/Kconfig8
-rw-r--r--drivers/pinctrl/exynos/Makefile1
-rw-r--r--drivers/pinctrl/exynos/pinctrl-exynos.c28
-rw-r--r--drivers/pinctrl/exynos/pinctrl-exynos78x0.c119
-rw-r--r--drivers/serial/Kconfig22
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/serial_msm_geni.c613
-rw-r--r--drivers/serial/serial_s5p.c107
-rw-r--r--drivers/spmi/spmi-msm.c154
-rw-r--r--drivers/usb/host/xhci-brcm.c1
26 files changed, 1200 insertions, 85 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 417d6f88c2..b26ca8cf70 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -50,6 +50,8 @@ source "drivers/i2c/Kconfig"
source "drivers/input/Kconfig"
+source "drivers/iommu/Kconfig"
+
source "drivers/led/Kconfig"
source "drivers/mailbox/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 4cbc40787d..4e7cf28440 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -102,6 +102,7 @@ obj-y += mtd/
obj-y += pwm/
obj-y += reset/
obj-y += input/
+obj-y += iommu/
# SOC specific infrastructure drivers.
obj-y += smem/
obj-y += thermal/
diff --git a/drivers/core/device.c b/drivers/core/device.c
index d7a778a241..efd07176e3 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -28,6 +28,7 @@
#include <dm/uclass.h>
#include <dm/uclass-internal.h>
#include <dm/util.h>
+#include <iommu.h>
#include <linux/err.h>
#include <linux/list.h>
#include <power-domain.h>
@@ -543,6 +544,13 @@ int device_probe(struct udevice *dev)
goto fail;
}
+ if (CONFIG_IS_ENABLED(IOMMU) && dev->parent &&
+ (device_get_uclass_id(dev) != UCLASS_IOMMU)) {
+ ret = dev_iommu_enable(dev);
+ if (ret)
+ goto fail;
+ }
+
ret = device_get_dma_constraints(dev);
if (ret)
goto fail;
diff --git a/drivers/gpio/msm_gpio.c b/drivers/gpio/msm_gpio.c
index e1ff84c1c0..a3c3cd7824 100644
--- a/drivers/gpio/msm_gpio.c
+++ b/drivers/gpio/msm_gpio.c
@@ -120,6 +120,7 @@ static const struct udevice_id msm_gpio_ids[] = {
{ .compatible = "qcom,msm8916-pinctrl" },
{ .compatible = "qcom,apq8016-pinctrl" },
{ .compatible = "qcom,ipq4019-pinctrl" },
+ { .compatible = "qcom,sdm845-pinctrl" },
{ }
};
diff --git a/drivers/gpio/pm8916_gpio.c b/drivers/gpio/pm8916_gpio.c
index 40b0f2578b..7ad95784a8 100644
--- a/drivers/gpio/pm8916_gpio.c
+++ b/drivers/gpio/pm8916_gpio.c
@@ -202,6 +202,7 @@ static int pm8916_gpio_of_to_plat(struct udevice *dev)
static const struct udevice_id pm8916_gpio_ids[] = {
{ .compatible = "qcom,pm8916-gpio" },
{ .compatible = "qcom,pm8994-gpio" }, /* 22 GPIO's */
+ { .compatible = "qcom,pm8998-gpio" },
{ }
};
@@ -266,7 +267,7 @@ static int pm8941_pwrkey_probe(struct udevice *dev)
return log_msg_ret("bad type", -ENXIO);
reg = pmic_reg_read(dev->parent, priv->pid + REG_SUBTYPE);
- if (reg != 0x1)
+ if ((reg & 0x5) == 0)
return log_msg_ret("bad subtype", -ENXIO);
return 0;
@@ -287,11 +288,12 @@ static int pm8941_pwrkey_of_to_plat(struct udevice *dev)
static const struct udevice_id pm8941_pwrkey_ids[] = {
{ .compatible = "qcom,pm8916-pwrkey" },
{ .compatible = "qcom,pm8994-pwrkey" },
+ { .compatible = "qcom,pm8998-pwrkey" },
{ }
};
-U_BOOT_DRIVER(pwrkey_pm8941) = {
- .name = "pwrkey_pm8916",
+U_BOOT_DRIVER(pwrkey_pm89xx) = {
+ .name = "pwrkey_pm89xx",
.id = UCLASS_GPIO,
.of_match = pm8941_pwrkey_ids,
.of_to_plat = pm8941_pwrkey_of_to_plat,
diff --git a/drivers/gpio/s5p_gpio.c b/drivers/gpio/s5p_gpio.c
index 76f35ac5d9..06ed585f3d 100644
--- a/drivers/gpio/s5p_gpio.c
+++ b/drivers/gpio/s5p_gpio.c
@@ -357,6 +357,7 @@ static const struct udevice_id exynos_gpio_ids[] = {
{ .compatible = "samsung,exynos4x12-pinctrl" },
{ .compatible = "samsung,exynos5250-pinctrl" },
{ .compatible = "samsung,exynos5420-pinctrl" },
+ { .compatible = "samsung,exynos78x0-gpio" },
{ }
};
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
new file mode 100644
index 0000000000..dabc1f900d
--- /dev/null
+++ b/drivers/iommu/Kconfig
@@ -0,0 +1,27 @@
+#
+# IOMMU devices
+#
+
+menu "IOMMU device drivers"
+
+config IOMMU
+ bool "Enable Driver Model for IOMMU drivers"
+ depends on DM
+ help
+ Enable driver model for IOMMU devices. An IOMMU maps device
+ virtiual memory addresses to physical addresses. Devices
+ that sit behind an IOMMU can typically only access physical
+ memory if the IOMMU has been programmed to allow access to
+ that memory.
+
+config APPLE_DART
+ bool "Apple DART support"
+ depends on IOMMU && ARCH_APPLE
+ default y
+ help
+ Enable support for the DART on Apple SoCs. The DART is Apple's
+ IOMMU implementation. The driver performs the necessary
+ configuration to put the DART into bypass mode such that it can
+ be used transparently by U-Boot.
+
+endmenu
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
new file mode 100644
index 0000000000..e3e0900e17
--- /dev/null
+++ b/drivers/iommu/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+obj-$(CONFIG_IOMMU) += iommu-uclass.o
+
+obj-$(CONFIG_APPLE_DART) += apple_dart.o
+obj-$(CONFIG_SANDBOX) += sandbox_iommu.o
diff --git a/drivers/iommu/apple_dart.c b/drivers/iommu/apple_dart.c
new file mode 100644
index 0000000000..ff8c5fa62c
--- /dev/null
+++ b/drivers/iommu/apple_dart.c
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2021 Mark Kettenis <kettenis@openbsd.org>
+ */
+
+#include <common.h>
+#include <cpu_func.h>
+#include <dm.h>
+#include <asm/io.h>
+
+#define DART_PARAMS2 0x0004
+#define DART_PARAMS2_BYPASS_SUPPORT BIT(0)
+#define DART_TLB_OP 0x0020
+#define DART_TLB_OP_OPMASK (0xfff << 20)
+#define DART_TLB_OP_FLUSH (0x001 << 20)
+#define DART_TLB_OP_BUSY BIT(2)
+#define DART_TLB_OP_SIDMASK 0x0034
+#define DART_ERROR_STATUS 0x0040
+#define DART_TCR(sid) (0x0100 + 4 * (sid))
+#define DART_TCR_TRANSLATE_ENABLE BIT(7)
+#define DART_TCR_BYPASS_DART BIT(8)
+#define DART_TCR_BYPASS_DAPF BIT(12)
+#define DART_TTBR(sid, idx) (0x0200 + 16 * (sid) + 4 * (idx))
+#define DART_TTBR_VALID BIT(31)
+#define DART_TTBR_SHIFT 12
+
+static int apple_dart_probe(struct udevice *dev)
+{
+ void *base;
+ int sid, i;
+
+ base = dev_read_addr_ptr(dev);
+ if (!base)
+ return -EINVAL;
+
+ u32 params2 = readl(base + DART_PARAMS2);
+ if (params2 & DART_PARAMS2_BYPASS_SUPPORT) {
+ for (sid = 0; sid < 16; sid++) {
+ writel(DART_TCR_BYPASS_DART | DART_TCR_BYPASS_DAPF,
+ base + DART_TCR(sid));
+ for (i = 0; i < 4; i++)
+ writel(0, base + DART_TTBR(sid, i));
+ }
+ }
+
+ return 0;
+}
+
+static const struct udevice_id apple_dart_ids[] = {
+ { .compatible = "apple,t8103-dart" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(apple_dart) = {
+ .name = "apple_dart",
+ .id = UCLASS_IOMMU,
+ .of_match = apple_dart_ids,
+ .probe = apple_dart_probe
+};
diff --git a/drivers/iommu/iommu-uclass.c b/drivers/iommu/iommu-uclass.c
new file mode 100644
index 0000000000..ed917b3c3e
--- /dev/null
+++ b/drivers/iommu/iommu-uclass.c
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2021 Mark Kettenis <kettenis@openbsd.org>
+ */
+
+#define LOG_CATEGORY UCLASS_IOMMU
+
+#include <common.h>
+#include <dm.h>
+
+#if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA))
+int dev_iommu_enable(struct udevice *dev)
+{
+ struct ofnode_phandle_args args;
+ struct udevice *dev_iommu;
+ int i, count, ret = 0;
+
+ count = dev_count_phandle_with_args(dev, "iommus",
+ "#iommu-cells", 0);
+ for (i = 0; i < count; i++) {
+ ret = dev_read_phandle_with_args(dev, "iommus",
+ "#iommu-cells", 0, i, &args);
+ if (ret) {
+ debug("%s: dev_read_phandle_with_args failed: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = uclass_get_device_by_ofnode(UCLASS_IOMMU, args.node,
+ &dev_iommu);
+ if (ret) {
+ debug("%s: uclass_get_device_by_ofnode failed: %d\n",
+ __func__, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+UCLASS_DRIVER(iommu) = {
+ .id = UCLASS_IOMMU,
+ .name = "iommu",
+};
diff --git a/drivers/iommu/sandbox_iommu.c b/drivers/iommu/sandbox_iommu.c
new file mode 100644
index 0000000000..c8161a40ae
--- /dev/null
+++ b/drivers/iommu/sandbox_iommu.c
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2021 Mark Kettenis <kettenis@openbsd.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+
+static const struct udevice_id sandbox_iommu_ids[] = {
+ { .compatible = "sandbox,iommu" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(sandbox_iommu) = {
+ .name = "sandbox_iommu",
+ .id = UCLASS_IOMMU,
+ .of_match = sandbox_iommu_ids,
+};
diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c
index f99b5f997e..9c5d48e90c 100644
--- a/drivers/mmc/arm_pl180_mmci.c
+++ b/drivers/mmc/arm_pl180_mmci.c
@@ -282,6 +282,14 @@ static int host_request(struct mmc *dev,
return result;
}
+static int check_peripheral_id(struct pl180_mmc_host *host, u32 periph_id)
+{
+ return readl(&host->base->periph_id0) == (periph_id & 0xFF) &&
+ readl(&host->base->periph_id1) == ((periph_id >> 8) & 0xFF) &&
+ readl(&host->base->periph_id2) == ((periph_id >> 16) & 0xFF) &&
+ readl(&host->base->periph_id3) == ((periph_id >> 24) & 0xFF);
+}
+
static int host_set_ios(struct mmc *dev)
{
struct pl180_mmc_host *host = dev->priv;
@@ -337,6 +345,12 @@ static int host_set_ios(struct mmc *dev)
sdi_clkcr &= ~(SDI_CLKCR_WIDBUS_MASK);
sdi_clkcr |= buswidth;
}
+ /* For MMCs' with peripheral id 0x02041180 and 0x03041180, H/W flow control
+ * needs to be enabled for multi block writes (MMC CMD 18).
+ */
+ if (check_peripheral_id(host, 0x02041180) ||
+ check_peripheral_id(host, 0x03041180))
+ sdi_clkcr |= SDI_CLKCR_HWFCEN;
writel(sdi_clkcr, &host->base->clock);
udelay(CLK_CHANGE_DELAY);
diff --git a/drivers/mmc/arm_pl180_mmci.h b/drivers/mmc/arm_pl180_mmci.h
index 15c29beadb..fca15910a8 100644
--- a/drivers/mmc/arm_pl180_mmci.h
+++ b/drivers/mmc/arm_pl180_mmci.h
@@ -43,6 +43,7 @@
#define SDI_CLKCR_CLKEN 0x00000100
#define SDI_CLKCR_PWRSAV 0x00000200
#define SDI_CLKCR_BYPASS 0x00000400
+#define SDI_CLKCR_HWFCEN 0x00001000
#define SDI_CLKCR_WIDBUS_MASK 0x00001800
#define SDI_CLKCR_WIDBUS_1 0x00000000
#define SDI_CLKCR_WIDBUS_4 0x00000800
diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c
index ebb307e950..05a6d0ce15 100644
--- a/drivers/mmc/fsl_esdhc.c
+++ b/drivers/mmc/fsl_esdhc.c
@@ -27,6 +27,7 @@
#include <dm/device_compat.h>
#include <linux/bitops.h>
#include <linux/delay.h>
+#include <linux/iopoll.h>
#include <linux/dma-mapping.h>
#include <sdhci.h>
@@ -1138,6 +1139,20 @@ int fsl_esdhc_hs400_prepare_ddr(struct udevice *dev)
return 0;
}
+static int fsl_esdhc_wait_dat0(struct udevice *dev, int state,
+ int timeout_us)
+{
+ int ret;
+ u32 tmp;
+ struct fsl_esdhc_priv *priv = dev_get_priv(dev);
+ struct fsl_esdhc *regs = priv->esdhc_regs;
+
+ ret = readx_poll_timeout(esdhc_read32, &regs->prsstat, tmp,
+ !!(tmp & PRSSTAT_DAT0) == !!state,
+ timeout_us);
+ return ret;
+}
+
static const struct dm_mmc_ops fsl_esdhc_ops = {
.get_cd = fsl_esdhc_get_cd,
.send_cmd = fsl_esdhc_send_cmd,
@@ -1147,6 +1162,7 @@ static const struct dm_mmc_ops fsl_esdhc_ops = {
#endif
.reinit = fsl_esdhc_reinit,
.hs400_prepare_ddr = fsl_esdhc_hs400_prepare_ddr,
+ .wait_dat0 = fsl_esdhc_wait_dat0,
};
static const struct udevice_id fsl_esdhc_ids[] = {
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index ba54b19c14..4d9871d69f 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -819,11 +819,11 @@ static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value,
return ret;
/*
- * In cases when not allowed to poll by using CMD13 or because we aren't
+ * In cases when neiter allowed to poll by using CMD13 nor we are
* capable of polling by using mmc_wait_dat0, then rely on waiting the
* stated timeout to be sufficient.
*/
- if (ret == -ENOSYS || !send_status) {
+ if (ret == -ENOSYS && !send_status) {
mdelay(timeout_ms);
return 0;
}
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index 03bfd9d18a..766e4a6b0c 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -780,6 +780,25 @@ static int sdhci_get_cd(struct udevice *dev)
return value;
}
+static int sdhci_wait_dat0(struct udevice *dev, int state,
+ int timeout_us)
+{
+ int tmp;
+ struct mmc *mmc = mmc_get_mmc_dev(dev);
+ struct sdhci_host *host = mmc->priv;
+ unsigned long timeout = timer_get_us() + timeout_us;
+
+ // readx_poll_timeout is unsuitable because sdhci_readl accepts
+ // two arguments
+ do {
+ tmp = sdhci_readl(host, SDHCI_PRESENT_STATE);
+ if (!!(tmp & SDHCI_DATA_0_LVL_MASK) == !!state)
+ return 0;
+ } while (!timeout_us || !time_after(timer_get_us(), timeout));
+
+ return -ETIMEDOUT;
+}
+
const struct dm_mmc_ops sdhci_ops = {
.send_cmd = sdhci_send_command,
.set_ios = sdhci_set_ios,
@@ -788,6 +807,7 @@ const struct dm_mmc_ops sdhci_ops = {
#ifdef MMC_SUPPORTS_TUNING
.execute_tuning = sdhci_execute_tuning,
#endif
+ .wait_dat0 = sdhci_wait_dat0,
};
#else
static const struct mmc_ops sdhci_ops = {
diff --git a/drivers/pinctrl/exynos/Kconfig b/drivers/pinctrl/exynos/Kconfig
index 84b6aaae09..a60f49869b 100644
--- a/drivers/pinctrl/exynos/Kconfig
+++ b/drivers/pinctrl/exynos/Kconfig
@@ -8,3 +8,11 @@ config PINCTRL_EXYNOS7420
help
Support pin multiplexing and pin configuration control on
Samsung's Exynos7420 SoC.
+
+config PINCTRL_EXYNOS78x0
+ bool "Samsung Exynos78x0 pinctrl driver"
+ depends on ARCH_EXYNOS && PINCTRL_FULL
+ select PINCTRL_EXYNOS
+ help
+ Support pin multiplexing and pin configuration control on
+ Samsung's Exynos78x0 SoC.
diff --git a/drivers/pinctrl/exynos/Makefile b/drivers/pinctrl/exynos/Makefile
index 6a14a474bf..07db970ca9 100644
--- a/drivers/pinctrl/exynos/Makefile
+++ b/drivers/pinctrl/exynos/Makefile
@@ -5,3 +5,4 @@
obj-$(CONFIG_PINCTRL_EXYNOS) += pinctrl-exynos.o
obj-$(CONFIG_PINCTRL_EXYNOS7420) += pinctrl-exynos7420.o
+obj-$(CONFIG_PINCTRL_EXYNOS78x0) += pinctrl-exynos78x0.o
diff --git a/drivers/pinctrl/exynos/pinctrl-exynos.c b/drivers/pinctrl/exynos/pinctrl-exynos.c
index 2640c8fcef..898185479b 100644
--- a/drivers/pinctrl/exynos/pinctrl-exynos.c
+++ b/drivers/pinctrl/exynos/pinctrl-exynos.c
@@ -5,6 +5,7 @@
* Thomas Abraham <thomas.ab@samsung.com>
*/
+#include <log.h>
#include <common.h>
#include <dm.h>
#include <errno.h>
@@ -38,9 +39,9 @@ static unsigned long pin_to_bank_base(struct udevice *dev, const char *pin_name,
u32 *pin)
{
struct exynos_pinctrl_priv *priv = dev_get_priv(dev);
- const struct samsung_pin_ctrl *pin_ctrl = priv->pin_ctrl;
- const struct samsung_pin_bank_data *bank_data = pin_ctrl->pin_banks;
- u32 nr_banks = pin_ctrl->nr_banks, idx = 0;
+ const struct samsung_pin_ctrl *pin_ctrl_array = priv->pin_ctrl;
+ const struct samsung_pin_bank_data *bank_data;
+ u32 nr_banks, pin_ctrl_idx = 0, idx = 0, bank_base;
char bank[10];
/*
@@ -55,11 +56,26 @@ static unsigned long pin_to_bank_base(struct udevice *dev, const char *pin_name,
*pin = pin_name[++idx] - '0';
/* lookup the pin bank data using the pin bank name */
- for (idx = 0; idx < nr_banks; idx++)
- if (!strcmp(bank, bank_data[idx].name))
+ while (true) {
+ const struct samsung_pin_ctrl *pin_ctrl = &pin_ctrl_array[pin_ctrl_idx];
+
+ nr_banks = pin_ctrl->nr_banks;
+ if (!nr_banks)
break;
- return priv->base + bank_data[idx].offset;
+ bank_data = pin_ctrl->pin_banks;
+ for (idx = 0; idx < nr_banks; idx++) {
+ debug("pinctrl[%d] bank_data[%d] name is: %s\n",
+ pin_ctrl_idx, idx, bank_data[idx].name);
+ if (!strcmp(bank, bank_data[idx].name)) {
+ bank_base = priv->base + bank_data[idx].offset;
+ break;
+ }
+ }
+ pin_ctrl_idx++;
+ }
+
+ return bank_base;
}
/**
diff --git a/drivers/pinctrl/exynos/pinctrl-exynos78x0.c b/drivers/pinctrl/exynos/pinctrl-exynos78x0.c
new file mode 100644
index 0000000000..01e9a4fede
--- /dev/null
+++ b/drivers/pinctrl/exynos/pinctrl-exynos78x0.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Exynos78x0 pinctrl driver.
+ *
+ * Copyright (c) 2020 Dzmitry Sankouski (dsankouski@gmail.com)
+ *
+ * based on drivers/pinctrl/exynos/pinctrl-exynos7420.c :
+ * Copyright (C) 2016 Samsung Electronics
+ * Thomas Abraham <thomas.ab@samsung.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <dm/pinctrl.h>
+#include <dm/root.h>
+#include <fdtdec.h>
+#include <asm/arch/pinmux.h>
+#include "pinctrl-exynos.h"
+
+static struct pinctrl_ops exynos78x0_pinctrl_ops = {
+ .set_state = exynos_pinctrl_set_state
+};
+
+/* pin banks of exynos78x0 pin-controller 0 (ALIVE) */
+static struct samsung_pin_bank_data exynos78x0_pin_banks0[] = {
+ EXYNOS_PIN_BANK(6, 0x000, "etc0"),
+ EXYNOS_PIN_BANK(3, 0x020, "etc1"),
+ EXYNOS_PIN_BANK(8, 0x040, "gpa0"),
+ EXYNOS_PIN_BANK(8, 0x060, "gpa1"),
+ EXYNOS_PIN_BANK(8, 0x080, "gpa2"),
+ EXYNOS_PIN_BANK(5, 0x0a0, "gpa3"),
+ EXYNOS_PIN_BANK(2, 0x0c0, "gpq0"),
+};
+
+/* pin banks of exynos78x0 pin-controller 1 (CCORE) */
+static struct samsung_pin_bank_data exynos78x0_pin_banks1[] = {
+ EXYNOS_PIN_BANK(2, 0x000, "gpm0"),
+};
+
+/* pin banks of exynos78x0 pin-controller 2 (DISPAUD) */
+static struct samsung_pin_bank_data exynos78x0_pin_banks2[] = {
+ EXYNOS_PIN_BANK(4, 0x000, "gpz0"),
+ EXYNOS_PIN_BANK(6, 0x020, "gpz1"),
+ EXYNOS_PIN_BANK(4, 0x040, "gpz2"),
+};
+
+/* pin banks of exynos78x0 pin-controller 4 (FSYS) */
+static struct samsung_pin_bank_data exynos78x0_pin_banks4[] = {
+ EXYNOS_PIN_BANK(3, 0x000, "gpr0"),
+ EXYNOS_PIN_BANK(8, 0x020, "gpr1"),
+ EXYNOS_PIN_BANK(2, 0x040, "gpr2"),
+ EXYNOS_PIN_BANK(4, 0x060, "gpr3"),
+ EXYNOS_PIN_BANK(6, 0x080, "gpr4"),
+};
+
+/* pin banks of exynos78x0 pin-controller 6 (TOP) */
+static struct samsung_pin_bank_data exynos78x0_pin_banks6[] = {
+ EXYNOS_PIN_BANK(4, 0x000, "gpb0"),
+ EXYNOS_PIN_BANK(3, 0x020, "gpc0"),
+ EXYNOS_PIN_BANK(4, 0x040, "gpc1"),
+ EXYNOS_PIN_BANK(4, 0x060, "gpc4"),
+ EXYNOS_PIN_BANK(2, 0x080, "gpc5"),
+ EXYNOS_PIN_BANK(4, 0x0a0, "gpc6"),
+ EXYNOS_PIN_BANK(2, 0x0c0, "gpc8"),
+ EXYNOS_PIN_BANK(2, 0x0e0, "gpc9"),
+ EXYNOS_PIN_BANK(7, 0x100, "gpd1"),
+ EXYNOS_PIN_BANK(6, 0x120, "gpd2"),
+ EXYNOS_PIN_BANK(8, 0x140, "gpd3"),
+ EXYNOS_PIN_BANK(7, 0x160, "gpd4"),
+ EXYNOS_PIN_BANK(5, 0x180, "gpd5"),
+ EXYNOS_PIN_BANK(3, 0x1a0, "gpe0"),
+ EXYNOS_PIN_BANK(4, 0x1c0, "gpf0"),
+ EXYNOS_PIN_BANK(2, 0x1e0, "gpf1"),
+ EXYNOS_PIN_BANK(2, 0x200, "gpf2"),
+ EXYNOS_PIN_BANK(4, 0x220, "gpf3"),
+ EXYNOS_PIN_BANK(5, 0x240, "gpf4"),
+};
+
+struct samsung_pin_ctrl exynos78x0_pin_ctrl[] = {
+ {
+ /* pin-controller instance 0 Alive data */
+ .pin_banks = exynos78x0_pin_banks0,
+ .nr_banks = ARRAY_SIZE(exynos78x0_pin_banks0),
+ }, {
+ /* pin-controller instance 1 CCORE data */
+ .pin_banks = exynos78x0_pin_banks1,
+ .nr_banks = ARRAY_SIZE(exynos78x0_pin_banks1),
+ }, {
+ /* pin-controller instance 2 DISPAUD data */
+ .pin_banks = exynos78x0_pin_banks2,
+ .nr_banks = ARRAY_SIZE(exynos78x0_pin_banks2),
+ }, {
+ /* pin-controller instance 4 FSYS data */
+ .pin_banks = exynos78x0_pin_banks4,
+ .nr_banks = ARRAY_SIZE(exynos78x0_pin_banks4),
+ }, {
+ /* pin-controller instance 6 TOP data */
+ .pin_banks = exynos78x0_pin_banks6,
+ .nr_banks = ARRAY_SIZE(exynos78x0_pin_banks6),
+ },
+ {/* list terminator */}
+};
+
+static const struct udevice_id exynos78x0_pinctrl_ids[] = {
+ { .compatible = "samsung,exynos78x0-pinctrl",
+ .data = (ulong)exynos78x0_pin_ctrl },
+ { }
+};
+
+U_BOOT_DRIVER(pinctrl_exynos78x0) = {
+ .name = "pinctrl_exynos78x0",
+ .id = UCLASS_PINCTRL,
+ .of_match = exynos78x0_pinctrl_ids,
+ .priv_auto = sizeof(struct exynos_pinctrl_priv),
+ .ops = &exynos78x0_pinctrl_ops,
+ .probe = exynos_pinctrl_probe,
+};
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 122a39789c..6c8fdda9a0 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -290,12 +290,20 @@ config DEBUG_SBI_CONSOLE
config DEBUG_UART_S5P
bool "Samsung S5P"
- depends on ARCH_EXYNOS || ARCH_S5PC1XX
+ depends on ARCH_APPLE || ARCH_EXYNOS || ARCH_S5PC1XX
help
Select this to enable a debug UART using the serial_s5p driver. You
will need to provide parameters to make this work. The driver will
be available until the real driver-model serial is running.
+config DEBUG_UART_MSM_GENI
+ bool "Qualcomm snapdragon"
+ depends on ARCH_SNAPDRAGON
+ help
+ Select this to enable a debug UART using the serial_msm driver. You
+ will need to provide parameters to make this work. The driver will
+ be available until the real driver-model serial is running.
+
config DEBUG_UART_MESON
bool "Amlogic Meson"
depends on MESON_SERIAL
@@ -737,7 +745,7 @@ config ROCKCHIP_SERIAL
config S5P_SERIAL
bool "Support for Samsung S5P UART"
- depends on ARCH_EXYNOS || ARCH_S5PC1XX
+ depends on ARCH_APPLE || ARCH_EXYNOS || ARCH_S5PC1XX
default y
help
Select this to enable Samsung S5P UART support.
@@ -801,6 +809,16 @@ config MSM_SERIAL
for example APQ8016 and MSM8916.
Single baudrate is supported in current implementation (115200).
+config MSM_GENI_SERIAL
+ bool "Qualcomm on-chip GENI UART"
+ help
+ Support UART based on Generic Interface (GENI) Serial Engine (SE),
+ used on Qualcomm Snapdragon SoCs. Should support all qualcomm SOCs
+ with Qualcomm Universal Peripheral (QUP) Wrapper cores,
+ i.e. newer ones, starting from SDM845.
+ Driver works in FIFO mode.
+ Multiple baudrates supported.
+
config OCTEON_SERIAL_BOOTCMD
bool "MIPS Octeon PCI remote bootcmd input"
depends on ARCH_OCTEON
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 4edd2aa945..8168af640f 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -63,6 +63,7 @@ obj-$(CONFIG_PIC32_SERIAL) += serial_pic32.o
obj-$(CONFIG_BCM283X_MU_SERIAL) += serial_bcm283x_mu.o
obj-$(CONFIG_BCM283X_PL011_SERIAL) += serial_bcm283x_pl011.o
obj-$(CONFIG_MSM_SERIAL) += serial_msm.o
+obj-$(CONFIG_MSM_GENI_SERIAL) += serial_msm_geni.o
obj-$(CONFIG_MVEBU_A3700_UART) += serial_mvebu_a3700.o
obj-$(CONFIG_MPC8XX_CONS) += serial_mpc8xx.o
obj-$(CONFIG_NULLDEV_SERIAL) += serial_nulldev.o
diff --git a/drivers/serial/serial_msm_geni.c b/drivers/serial/serial_msm_geni.c
new file mode 100644
index 0000000000..3e255a99dc
--- /dev/null
+++ b/drivers/serial/serial_msm_geni.c
@@ -0,0 +1,613 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Qualcomm GENI serial engine UART driver
+ *
+ * (C) Copyright 2021 Dzmitry Sankouski <dsankouski@gmail.com>
+ *
+ * Based on Linux driver.
+ */
+
+#include <asm/io.h>
+#include <clk.h>
+#include <common.h>
+#include <dm.h>
+#include <dm/pinctrl.h>
+#include <errno.h>
+#include <linux/compiler.h>
+#include <log.h>
+#include <linux/delay.h>
+#include <malloc.h>
+#include <serial.h>
+#include <watchdog.h>
+#include <linux/bug.h>
+
+#define UART_OVERSAMPLING 32
+#define STALE_TIMEOUT 160
+
+#define USEC_PER_SEC 1000000L
+
+/* Registers*/
+#define GENI_FORCE_DEFAULT_REG 0x20
+#define GENI_SER_M_CLK_CFG 0x48
+#define GENI_SER_S_CLK_CFG 0x4C
+#define SE_HW_PARAM_0 0xE24
+#define SE_GENI_STATUS 0x40
+#define SE_GENI_S_CMD0 0x630
+#define SE_GENI_S_CMD_CTRL_REG 0x634
+#define SE_GENI_S_IRQ_CLEAR 0x648
+#define SE_GENI_S_IRQ_STATUS 0x640
+#define SE_GENI_S_IRQ_EN 0x644
+#define SE_GENI_M_CMD0 0x600
+#define SE_GENI_M_CMD_CTRL_REG 0x604
+#define SE_GENI_M_IRQ_CLEAR 0x618
+#define SE_GENI_M_IRQ_STATUS 0x610
+#define SE_GENI_M_IRQ_EN 0x614
+#define SE_GENI_TX_FIFOn 0x700
+#define SE_GENI_RX_FIFOn 0x780
+#define SE_GENI_TX_FIFO_STATUS 0x800
+#define SE_GENI_RX_FIFO_STATUS 0x804
+#define SE_GENI_TX_WATERMARK_REG 0x80C
+#define SE_GENI_TX_PACKING_CFG0 0x260
+#define SE_GENI_TX_PACKING_CFG1 0x264
+#define SE_GENI_RX_PACKING_CFG0 0x284
+#define SE_GENI_RX_PACKING_CFG1 0x288
+#define SE_UART_RX_STALE_CNT 0x294
+#define SE_UART_TX_TRANS_LEN 0x270
+#define SE_UART_TX_STOP_BIT_LEN 0x26c
+#define SE_UART_TX_WORD_LEN 0x268
+#define SE_UART_RX_WORD_LEN 0x28c
+#define SE_UART_TX_TRANS_CFG 0x25c
+#define SE_UART_TX_PARITY_CFG 0x2a4
+#define SE_UART_RX_TRANS_CFG 0x280
+#define SE_UART_RX_PARITY_CFG 0x2a8
+
+#define M_TX_FIFO_WATERMARK_EN (BIT(30))
+#define DEF_TX_WM 2
+/* GENI_FORCE_DEFAULT_REG fields */
+#define FORCE_DEFAULT (BIT(0))
+
+#define S_CMD_ABORT_EN (BIT(5))
+
+#define UART_START_READ 0x1
+
+/* GENI_M_CMD_CTRL_REG */
+#define M_GENI_CMD_CANCEL (BIT(2))
+#define M_GENI_CMD_ABORT (BIT(1))
+#define M_GENI_DISABLE (BIT(0))
+
+#define M_CMD_ABORT_EN (BIT(5))
+#define M_CMD_DONE_EN (BIT(0))
+#define M_CMD_DONE_DISABLE_MASK (~M_CMD_DONE_EN)
+
+#define S_GENI_CMD_ABORT (BIT(1))
+
+/* GENI_S_CMD0 fields */
+#define S_OPCODE_MSK (GENMASK(31, 27))
+#define S_PARAMS_MSK (GENMASK(26, 0))
+
+/* GENI_STATUS fields */
+#define M_GENI_CMD_ACTIVE (BIT(0))
+#define S_GENI_CMD_ACTIVE (BIT(12))
+#define M_CMD_DONE_EN (BIT(0))
+#define S_CMD_DONE_EN (BIT(0))
+
+#define M_OPCODE_SHIFT 27
+#define S_OPCODE_SHIFT 27
+#define M_TX_FIFO_WATERMARK_EN (BIT(30))
+#define UART_START_TX 0x1
+#define UART_CTS_MASK (BIT(1))
+#define M_SEC_IRQ_EN (BIT(31))
+#define TX_FIFO_WC_MSK (GENMASK(27, 0))
+#define RX_FIFO_WC_MSK (GENMASK(24, 0))
+
+#define S_RX_FIFO_WATERMARK_EN (BIT(26))
+#define S_RX_FIFO_LAST_EN (BIT(27))
+#define M_RX_FIFO_WATERMARK_EN (BIT(26))
+#define M_RX_FIFO_LAST_EN (BIT(27))
+
+/* GENI_SER_M_CLK_CFG/GENI_SER_S_CLK_CFG */
+#define SER_CLK_EN (BIT(0))
+#define CLK_DIV_MSK (GENMASK(15, 4))
+#define CLK_DIV_SHFT 4
+
+/* SE_HW_PARAM_0 fields */
+#define TX_FIFO_WIDTH_MSK (GENMASK(29, 24))
+#define TX_FIFO_WIDTH_SHFT 24
+#define TX_FIFO_DEPTH_MSK (GENMASK(21, 16))
+#define TX_FIFO_DEPTH_SHFT 16
+
+/*
+ * Predefined packing configuration of the serial engine (CFG0, CFG1 regs)
+ * for uart mode.
+ *
+ * Defines following configuration:
+ * - Bits of data per transfer word 8
+ * - Number of words per fifo element 4
+ * - Transfer from MSB to LSB or vice-versa false
+ */
+#define UART_PACKING_CFG0 0xf
+#define UART_PACKING_CFG1 0x0
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct msm_serial_data {
+ phys_addr_t base;
+ u32 baud;
+};
+
+unsigned long root_freq[] = {7372800, 14745600, 19200000, 29491200,
+ 32000000, 48000000, 64000000, 80000000,
+ 96000000, 100000000};
+
+/**
+ * get_clk_cfg() - Get clock rate to apply on clock supplier.
+ * @clk_freq: Desired clock frequency after build-in divider.
+ *
+ * Return: frequency, supported by clock supplier, multiple of clk_freq.
+ */
+static int get_clk_cfg(unsigned long clk_freq)
+{
+ for (int i = 0; i < ARRAY_SIZE(root_freq); i++) {
+ if (!(root_freq[i] % clk_freq))
+ return root_freq[i];
+ }
+ return 0;
+}
+
+/**
+ * get_clk_div_rate() - Find clock supplier frequency, and calculate divisor.
+ * @baud: Baudrate.
+ * @sampling_rate: Clock ticks per character.
+ * @clk_div: Pointer to calculated divisor.
+ *
+ * This function searches for suitable frequency for clock supplier,
+ * calculates divisor for internal divider, based on found frequency,
+ * and stores divisor under clk_div pointer.
+ *
+ * Return: frequency, supported by clock supplier, multiple of clk_freq.
+ */
+static int get_clk_div_rate(u32 baud,
+ u64 sampling_rate, u32 *clk_div)
+{
+ unsigned long ser_clk;
+ unsigned long desired_clk;
+
+ desired_clk = baud * sampling_rate;
+ ser_clk = get_clk_cfg(desired_clk);
+ if (!ser_clk) {
+ pr_err("%s: Can't find matching DFS entry for baud %d\n",
+ __func__, baud);
+ return ser_clk;
+ }
+
+ *clk_div = ser_clk / desired_clk;
+ return ser_clk;
+}
+
+static int geni_serial_set_clock_rate(struct udevice *dev, u64 rate)
+{
+ struct clk *clk;
+ int ret;
+
+ clk = devm_clk_get(dev, "se-clk");
+ if (!clk)
+ return -EINVAL;
+
+ ret = clk_set_rate(clk, rate);
+ return ret;
+}
+
+/**
+ * geni_se_get_tx_fifo_depth() - Get the TX fifo depth of the serial engine
+ * @base: Pointer to the concerned serial engine.
+ *
+ * This function is used to get the depth i.e. number of elements in the
+ * TX fifo of the serial engine.
+ *
+ * Return: TX fifo depth in units of FIFO words.
+ */
+static inline u32 geni_se_get_tx_fifo_depth(long base)
+{
+ u32 tx_fifo_depth;
+
+ tx_fifo_depth = ((readl(base + SE_HW_PARAM_0) & TX_FIFO_DEPTH_MSK) >>
+ TX_FIFO_DEPTH_SHFT);
+ return tx_fifo_depth;
+}
+
+/**
+ * geni_se_get_tx_fifo_width() - Get the TX fifo width of the serial engine
+ * @base: Pointer to the concerned serial engine.
+ *
+ * This function is used to get the width i.e. word size per element in the
+ * TX fifo of the serial engine.
+ *
+ * Return: TX fifo width in bits
+ */
+static inline u32 geni_se_get_tx_fifo_width(long base)
+{
+ u32 tx_fifo_width;
+
+ tx_fifo_width = ((readl(base + SE_HW_PARAM_0) & TX_FIFO_WIDTH_MSK) >>
+ TX_FIFO_WIDTH_SHFT);
+ return tx_fifo_width;
+}
+
+static inline void geni_serial_baud(phys_addr_t base_address, u32 clk_div,
+ int baud)
+{
+ u32 s_clk_cfg = 0;
+
+ s_clk_cfg |= SER_CLK_EN;
+ s_clk_cfg |= (clk_div << CLK_DIV_SHFT);
+
+ writel(s_clk_cfg, base_address + GENI_SER_M_CLK_CFG);
+ writel(s_clk_cfg, base_address + GENI_SER_S_CLK_CFG);
+}
+
+int msm_serial_setbrg(struct udevice *dev, int baud)
+{
+ struct msm_serial_data *priv = dev_get_priv(dev);
+
+ priv->baud = baud;
+ u32 clk_div;
+ u64 clk_rate;
+
+ clk_rate = get_clk_div_rate(baud, UART_OVERSAMPLING, &clk_div);
+ geni_serial_set_clock_rate(dev, clk_rate);
+ geni_serial_baud(priv->base, clk_div, baud);
+
+ return 0;
+}
+
+/**
+ * qcom_geni_serial_poll_bit() - Poll reg bit until desired value or timeout.
+ * @base: Pointer to the concerned serial engine.
+ * @offset: Offset to register address.
+ * @field: AND bitmask for desired bit.
+ * @set: Desired bit value.
+ *
+ * This function is used to get the width i.e. word size per element in the
+ * TX fifo of the serial engine.
+ *
+ * Return: true, when register bit equals desired value, false, when timeout
+ * reached.
+ */
+static bool qcom_geni_serial_poll_bit(const struct udevice *dev, int offset,
+ int field, bool set)
+{
+ u32 reg;
+ struct msm_serial_data *priv = dev_get_priv(dev);
+ unsigned int baud;
+ unsigned int tx_fifo_depth;
+ unsigned int tx_fifo_width;
+ unsigned int fifo_bits;
+ unsigned long timeout_us = 10000;
+
+ baud = 115200;
+
+ if (priv) {
+ baud = priv->baud;
+ if (!baud)
+ baud = 115200;
+ tx_fifo_depth = geni_se_get_tx_fifo_depth(priv->base);
+ tx_fifo_width = geni_se_get_tx_fifo_width(priv->base);
+ fifo_bits = tx_fifo_depth * tx_fifo_width;
+ /*
+ * Total polling iterations based on FIFO worth of bytes to be
+ * sent at current baud. Add a little fluff to the wait.
+ */
+ timeout_us = ((fifo_bits * USEC_PER_SEC) / baud) + 500;
+ }
+
+ timeout_us = DIV_ROUND_UP(timeout_us, 10) * 10;
+ while (timeout_us) {
+ reg = readl(priv->base + offset);
+ if ((bool)(reg & field) == set)
+ return true;
+ udelay(10);
+ timeout_us -= 10;
+ }
+ return false;
+}
+
+static void qcom_geni_serial_setup_tx(u64 base, u32 xmit_size)
+{
+ u32 m_cmd;
+
+ writel(xmit_size, base + SE_UART_TX_TRANS_LEN);
+ m_cmd = UART_START_TX << M_OPCODE_SHIFT;
+ writel(m_cmd, base + SE_GENI_M_CMD0);
+}
+
+static inline void qcom_geni_serial_poll_tx_done(const struct udevice *dev)
+{
+ struct msm_serial_data *priv = dev_get_priv(dev);
+ int done = 0;
+ u32 irq_clear = M_CMD_DONE_EN;
+
+ done = qcom_geni_serial_poll_bit(dev, SE_GENI_M_IRQ_STATUS,
+ M_CMD_DONE_EN, true);
+ if (!done) {
+ writel(M_GENI_CMD_ABORT, priv->base + SE_GENI_M_CMD_CTRL_REG);
+ irq_clear |= M_CMD_ABORT_EN;
+ qcom_geni_serial_poll_bit(dev, SE_GENI_M_IRQ_STATUS,
+ M_CMD_ABORT_EN, true);
+ }
+ writel(irq_clear, priv->base + SE_GENI_M_IRQ_CLEAR);
+}
+
+static u32 qcom_geni_serial_tx_empty(u64 base)
+{
+ return !readl(base + SE_GENI_TX_FIFO_STATUS);
+}
+
+/**
+ * geni_se_setup_s_cmd() - Setup the secondary sequencer
+ * @se: Pointer to the concerned serial engine.
+ * @cmd: Command/Operation to setup in the secondary sequencer.
+ * @params: Parameter for the sequencer command.
+ *
+ * This function is used to configure the secondary sequencer with the
+ * command and its associated parameters.
+ */
+static inline void geni_se_setup_s_cmd(u64 base, u32 cmd, u32 params)
+{
+ u32 s_cmd;
+
+ s_cmd = readl(base + SE_GENI_S_CMD0);
+ s_cmd &= ~(S_OPCODE_MSK | S_PARAMS_MSK);
+ s_cmd |= (cmd << S_OPCODE_SHIFT);
+ s_cmd |= (params & S_PARAMS_MSK);
+ writel(s_cmd, base + SE_GENI_S_CMD0);
+}
+
+static void qcom_geni_serial_start_tx(u64 base)
+{
+ u32 irq_en;
+ u32 status;
+
+ status = readl(base + SE_GENI_STATUS);
+ if (status & M_GENI_CMD_ACTIVE)
+ return;
+
+ if (!qcom_geni_serial_tx_empty(base))
+ return;
+
+ irq_en = readl(base + SE_GENI_M_IRQ_EN);
+ irq_en |= M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN;
+
+ writel(DEF_TX_WM, base + SE_GENI_TX_WATERMARK_REG);
+ writel(irq_en, base + SE_GENI_M_IRQ_EN);
+}
+
+static void qcom_geni_serial_start_rx(struct udevice *dev)
+{
+ u32 status;
+ struct msm_serial_data *priv = dev_get_priv(dev);
+
+ status = readl(priv->base + SE_GENI_STATUS);
+
+ geni_se_setup_s_cmd(priv->base, UART_START_READ, 0);
+
+ setbits_le32(priv->base + SE_GENI_S_IRQ_EN, S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN);
+ setbits_le32(priv->base + SE_GENI_M_IRQ_EN, M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN);
+}
+
+static void qcom_geni_serial_abort_rx(struct udevice *dev)
+{
+ struct msm_serial_data *priv = dev_get_priv(dev);
+
+ u32 irq_clear = S_CMD_DONE_EN | S_CMD_ABORT_EN;
+
+ writel(S_GENI_CMD_ABORT, priv->base + SE_GENI_S_CMD_CTRL_REG);
+ qcom_geni_serial_poll_bit(dev, SE_GENI_S_CMD_CTRL_REG,
+ S_GENI_CMD_ABORT, false);
+ writel(irq_clear, priv->base + SE_GENI_S_IRQ_CLEAR);
+ writel(FORCE_DEFAULT, priv->base + GENI_FORCE_DEFAULT_REG);
+}
+
+static void msm_geni_serial_setup_rx(struct udevice *dev)
+{
+ struct msm_serial_data *priv = dev_get_priv(dev);
+
+ qcom_geni_serial_abort_rx(dev);
+
+ writel(UART_PACKING_CFG0, priv->base + SE_GENI_RX_PACKING_CFG0);
+ writel(UART_PACKING_CFG1, priv->base + SE_GENI_RX_PACKING_CFG1);
+
+ geni_se_setup_s_cmd(priv->base, UART_START_READ, 0);
+
+ setbits_le32(priv->base + SE_GENI_S_IRQ_EN, S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN);
+ setbits_le32(priv->base + SE_GENI_M_IRQ_EN, M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN);
+}
+
+static int msm_serial_putc(struct udevice *dev, const char ch)
+{
+ struct msm_serial_data *priv = dev_get_priv(dev);
+
+ writel(DEF_TX_WM, priv->base + SE_GENI_TX_WATERMARK_REG);
+ qcom_geni_serial_setup_tx(priv->base, 1);
+
+ qcom_geni_serial_poll_bit(dev, SE_GENI_M_IRQ_STATUS,
+ M_TX_FIFO_WATERMARK_EN, true);
+
+ writel(ch, priv->base + SE_GENI_TX_FIFOn);
+ writel(M_TX_FIFO_WATERMARK_EN, priv->base + SE_GENI_M_IRQ_CLEAR);
+
+ qcom_geni_serial_poll_tx_done(dev);
+
+ return 0;
+}
+
+static int msm_serial_getc(struct udevice *dev)
+{
+ struct msm_serial_data *priv = dev_get_priv(dev);
+ u32 rx_fifo;
+ u32 m_irq_status;
+ u32 s_irq_status;
+
+ writel(1 << S_OPCODE_SHIFT, priv->base + SE_GENI_S_CMD0);
+
+ qcom_geni_serial_poll_bit(dev, SE_GENI_M_IRQ_STATUS, M_SEC_IRQ_EN,
+ true);
+
+ m_irq_status = readl(priv->base + SE_GENI_M_IRQ_STATUS);
+ s_irq_status = readl(priv->base + SE_GENI_S_IRQ_STATUS);
+ writel(m_irq_status, priv->base + SE_GENI_M_IRQ_CLEAR);
+ writel(s_irq_status, priv->base + SE_GENI_S_IRQ_CLEAR);
+ qcom_geni_serial_poll_bit(dev, SE_GENI_RX_FIFO_STATUS, RX_FIFO_WC_MSK,
+ true);
+
+ if (!readl(priv->base + SE_GENI_RX_FIFO_STATUS))
+ return 0;
+
+ rx_fifo = readl(priv->base + SE_GENI_RX_FIFOn);
+ return rx_fifo & 0xff;
+}
+
+static int msm_serial_pending(struct udevice *dev, bool input)
+{
+ struct msm_serial_data *priv = dev_get_priv(dev);
+
+ if (input)
+ return readl(priv->base + SE_GENI_RX_FIFO_STATUS) &
+ RX_FIFO_WC_MSK;
+ else
+ return readl(priv->base + SE_GENI_TX_FIFO_STATUS) &
+ TX_FIFO_WC_MSK;
+
+ return 0;
+}
+
+static const struct dm_serial_ops msm_serial_ops = {
+ .putc = msm_serial_putc,
+ .pending = msm_serial_pending,
+ .getc = msm_serial_getc,
+ .setbrg = msm_serial_setbrg,
+};
+
+static inline void geni_serial_init(struct udevice *dev)
+{
+ struct msm_serial_data *priv = dev_get_priv(dev);
+ phys_addr_t base_address = priv->base;
+ u32 tx_trans_cfg;
+ u32 tx_parity_cfg = 0; /* Disable Tx Parity */
+ u32 rx_trans_cfg = 0;
+ u32 rx_parity_cfg = 0; /* Disable Rx Parity */
+ u32 stop_bit_len = 0; /* Default stop bit length - 1 bit */
+ u32 bits_per_char;
+
+ /*
+ * Ignore Flow control.
+ * n = 8.
+ */
+ tx_trans_cfg = UART_CTS_MASK;
+ bits_per_char = BITS_PER_BYTE;
+
+ /*
+ * Make an unconditional cancel on the main sequencer to reset
+ * it else we could end up in data loss scenarios.
+ */
+ qcom_geni_serial_poll_tx_done(dev);
+ qcom_geni_serial_abort_rx(dev);
+
+ writel(UART_PACKING_CFG0, base_address + SE_GENI_TX_PACKING_CFG0);
+ writel(UART_PACKING_CFG1, base_address + SE_GENI_TX_PACKING_CFG1);
+ writel(UART_PACKING_CFG0, base_address + SE_GENI_RX_PACKING_CFG0);
+ writel(UART_PACKING_CFG1, base_address + SE_GENI_RX_PACKING_CFG1);
+
+ writel(tx_trans_cfg, base_address + SE_UART_TX_TRANS_CFG);
+ writel(tx_parity_cfg, base_address + SE_UART_TX_PARITY_CFG);
+ writel(rx_trans_cfg, base_address + SE_UART_RX_TRANS_CFG);
+ writel(rx_parity_cfg, base_address + SE_UART_RX_PARITY_CFG);
+ writel(bits_per_char, base_address + SE_UART_TX_WORD_LEN);
+ writel(bits_per_char, base_address + SE_UART_RX_WORD_LEN);
+ writel(stop_bit_len, base_address + SE_UART_TX_STOP_BIT_LEN);
+}
+
+static int msm_serial_probe(struct udevice *dev)
+{
+ struct msm_serial_data *priv = dev_get_priv(dev);
+
+ /* No need to reinitialize the UART after relocation */
+ if (gd->flags & GD_FLG_RELOC)
+ return 0;
+
+ geni_serial_init(dev);
+ msm_geni_serial_setup_rx(dev);
+ qcom_geni_serial_start_rx(dev);
+ qcom_geni_serial_start_tx(priv->base);
+
+ return 0;
+}
+
+static int msm_serial_ofdata_to_platdata(struct udevice *dev)
+{
+ struct msm_serial_data *priv = dev_get_priv(dev);
+
+ priv->base = dev_read_addr(dev);
+ if (priv->base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct udevice_id msm_serial_ids[] = {
+ {.compatible = "qcom,msm-geni-uart"}, {}};
+
+U_BOOT_DRIVER(serial_msm_geni) = {
+ .name = "serial_msm_geni",
+ .id = UCLASS_SERIAL,
+ .of_match = msm_serial_ids,
+ .of_to_plat = msm_serial_ofdata_to_platdata,
+ .priv_auto = sizeof(struct msm_serial_data),
+ .probe = msm_serial_probe,
+ .ops = &msm_serial_ops,
+};
+
+#ifdef CONFIG_DEBUG_UART_MSM_GENI
+
+static struct msm_serial_data init_serial_data = {
+ .base = CONFIG_DEBUG_UART_BASE
+};
+
+/* Serial dumb device, to reuse driver code */
+static struct udevice init_dev = {
+ .priv_ = &init_serial_data,
+};
+
+#include <debug_uart.h>
+
+#define CLK_DIV (CONFIG_DEBUG_UART_CLOCK / \
+ (CONFIG_BAUDRATE * UART_OVERSAMPLING))
+#if (CONFIG_DEBUG_UART_CLOCK % (CONFIG_BAUDRATE * UART_OVERSAMPLING) > 0)
+#error Clocks cannot be set at early debug. Change CONFIG_BAUDRATE
+#endif
+
+static inline void _debug_uart_init(void)
+{
+ phys_addr_t base = CONFIG_DEBUG_UART_BASE;
+
+ geni_serial_init(&init_dev);
+ geni_serial_baud(base, CLK_DIV, CONFIG_BAUDRATE);
+ qcom_geni_serial_start_tx(base);
+}
+
+static inline void _debug_uart_putc(int ch)
+{
+ phys_addr_t base = CONFIG_DEBUG_UART_BASE;
+
+ writel(DEF_TX_WM, base + SE_GENI_TX_WATERMARK_REG);
+ qcom_geni_serial_setup_tx(base, 1);
+ qcom_geni_serial_poll_bit(&init_dev, SE_GENI_M_IRQ_STATUS,
+ M_TX_FIFO_WATERMARK_EN, true);
+
+ writel(ch, base + SE_GENI_TX_FIFOn);
+ writel(M_TX_FIFO_WATERMARK_EN, base + SE_GENI_M_IRQ_CLEAR);
+ qcom_geni_serial_poll_tx_done(&init_dev);
+}
+
+DEBUG_UART_FUNCS
+
+#endif
diff --git a/drivers/serial/serial_s5p.c b/drivers/serial/serial_s5p.c
index 6d09952a5d..de420d2d94 100644
--- a/drivers/serial/serial_s5p.c
+++ b/drivers/serial/serial_s5p.c
@@ -14,24 +14,45 @@
#include <asm/global_data.h>
#include <linux/compiler.h>
#include <asm/io.h>
+#if !CONFIG_IS_ENABLED(ARCH_APPLE)
#include <asm/arch/clk.h>
+#endif
#include <asm/arch/uart.h>
#include <serial.h>
#include <clk.h>
DECLARE_GLOBAL_DATA_PTR;
-#define RX_FIFO_COUNT_SHIFT 0
-#define RX_FIFO_COUNT_MASK (0xff << RX_FIFO_COUNT_SHIFT)
-#define RX_FIFO_FULL (1 << 8)
-#define TX_FIFO_COUNT_SHIFT 16
-#define TX_FIFO_COUNT_MASK (0xff << TX_FIFO_COUNT_SHIFT)
-#define TX_FIFO_FULL (1 << 24)
+enum {
+ PORT_S5P = 0,
+ PORT_S5L
+};
+
+#define S5L_RX_FIFO_COUNT_SHIFT 0
+#define S5L_RX_FIFO_COUNT_MASK (0xf << S5L_RX_FIFO_COUNT_SHIFT)
+#define S5L_RX_FIFO_FULL (1 << 8)
+#define S5L_TX_FIFO_COUNT_SHIFT 4
+#define S5L_TX_FIFO_COUNT_MASK (0xf << S5L_TX_FIFO_COUNT_SHIFT)
+#define S5L_TX_FIFO_FULL (1 << 9)
+
+#define S5P_RX_FIFO_COUNT_SHIFT 0
+#define S5P_RX_FIFO_COUNT_MASK (0xff << S5P_RX_FIFO_COUNT_SHIFT)
+#define S5P_RX_FIFO_FULL (1 << 8)
+#define S5P_TX_FIFO_COUNT_SHIFT 16
+#define S5P_TX_FIFO_COUNT_MASK (0xff << S5P_TX_FIFO_COUNT_SHIFT)
+#define S5P_TX_FIFO_FULL (1 << 24)
/* Information about a serial port */
struct s5p_serial_plat {
struct s5p_uart *reg; /* address of registers in physical memory */
+ u8 reg_width; /* register width */
u8 port_id; /* uart port number */
+ u8 rx_fifo_count_shift;
+ u8 tx_fifo_count_shift;
+ u32 rx_fifo_count_mask;
+ u32 tx_fifo_count_mask;
+ u32 rx_fifo_full;
+ u32 tx_fifo_full;
};
/*
@@ -71,8 +92,8 @@ static void __maybe_unused s5p_serial_init(struct s5p_uart *uart)
writel(0x245, &uart->ucon);
}
-static void __maybe_unused s5p_serial_baud(struct s5p_uart *uart, uint uclk,
- int baudrate)
+static void __maybe_unused s5p_serial_baud(struct s5p_uart *uart, u8 reg_width,
+ uint uclk, int baudrate)
{
u32 val;
@@ -82,6 +103,8 @@ static void __maybe_unused s5p_serial_baud(struct s5p_uart *uart, uint uclk,
if (s5p_uart_divslot())
writew(udivslot[val % 16], &uart->rest.slot);
+ else if (reg_width == 4)
+ writel(val % 16, &uart->rest.value);
else
writeb(val % 16, &uart->rest.value);
}
@@ -93,7 +116,7 @@ int s5p_serial_setbrg(struct udevice *dev, int baudrate)
struct s5p_uart *const uart = plat->reg;
u32 uclk;
-#ifdef CONFIG_CLK_EXYNOS
+#if CONFIG_IS_ENABLED(CLK_EXYNOS) || CONFIG_IS_ENABLED(ARCH_APPLE)
struct clk clk;
u32 ret;
@@ -105,7 +128,7 @@ int s5p_serial_setbrg(struct udevice *dev, int baudrate)
uclk = get_uart_clk(plat->port_id);
#endif
- s5p_serial_baud(uart, uclk, baudrate);
+ s5p_serial_baud(uart, plat->reg_width, uclk, baudrate);
return 0;
}
@@ -144,11 +167,14 @@ static int s5p_serial_getc(struct udevice *dev)
struct s5p_serial_plat *plat = dev_get_plat(dev);
struct s5p_uart *const uart = plat->reg;
- if (!(readl(&uart->ufstat) & RX_FIFO_COUNT_MASK))
+ if (!(readl(&uart->ufstat) & plat->rx_fifo_count_mask))
return -EAGAIN;
serial_err_check(uart, 0);
- return (int)(readb(&uart->urxh) & 0xff);
+ if (plat->reg_width == 4)
+ return (int)(readl(&uart->urxh) & 0xff);
+ else
+ return (int)(readb(&uart->urxh) & 0xff);
}
static int s5p_serial_putc(struct udevice *dev, const char ch)
@@ -156,10 +182,13 @@ static int s5p_serial_putc(struct udevice *dev, const char ch)
struct s5p_serial_plat *plat = dev_get_plat(dev);
struct s5p_uart *const uart = plat->reg;
- if (readl(&uart->ufstat) & TX_FIFO_FULL)
+ if (readl(&uart->ufstat) & plat->tx_fifo_full)
return -EAGAIN;
- writeb(ch, &uart->utxh);
+ if (plat->reg_width == 4)
+ writel(ch, &uart->utxh);
+ else
+ writeb(ch, &uart->utxh);
serial_err_check(uart, 1);
return 0;
@@ -171,15 +200,19 @@ static int s5p_serial_pending(struct udevice *dev, bool input)
struct s5p_uart *const uart = plat->reg;
uint32_t ufstat = readl(&uart->ufstat);
- if (input)
- return (ufstat & RX_FIFO_COUNT_MASK) >> RX_FIFO_COUNT_SHIFT;
- else
- return (ufstat & TX_FIFO_COUNT_MASK) >> TX_FIFO_COUNT_SHIFT;
+ if (input) {
+ return (ufstat & plat->rx_fifo_count_mask) >>
+ plat->rx_fifo_count_shift;
+ } else {
+ return (ufstat & plat->tx_fifo_count_mask) >>
+ plat->tx_fifo_count_shift;
+ }
}
static int s5p_serial_of_to_plat(struct udevice *dev)
{
struct s5p_serial_plat *plat = dev_get_plat(dev);
+ const ulong port_type = dev_get_driver_data(dev);
fdt_addr_t addr;
addr = dev_read_addr(dev);
@@ -187,8 +220,26 @@ static int s5p_serial_of_to_plat(struct udevice *dev)
return -EINVAL;
plat->reg = (struct s5p_uart *)addr;
+ plat->reg_width = dev_read_u32_default(dev, "reg-io-width", 1);
plat->port_id = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
"id", dev_seq(dev));
+
+ if (port_type == PORT_S5L) {
+ plat->rx_fifo_count_shift = S5L_RX_FIFO_COUNT_SHIFT;
+ plat->rx_fifo_count_mask = S5L_RX_FIFO_COUNT_MASK;
+ plat->rx_fifo_full = S5L_RX_FIFO_FULL;
+ plat->tx_fifo_count_shift = S5L_TX_FIFO_COUNT_SHIFT;
+ plat->tx_fifo_count_mask = S5L_TX_FIFO_COUNT_MASK;
+ plat->tx_fifo_full = S5L_TX_FIFO_FULL;
+ } else {
+ plat->rx_fifo_count_shift = S5P_RX_FIFO_COUNT_SHIFT;
+ plat->rx_fifo_count_mask = S5P_RX_FIFO_COUNT_MASK;
+ plat->rx_fifo_full = S5P_RX_FIFO_FULL;
+ plat->tx_fifo_count_shift = S5P_TX_FIFO_COUNT_SHIFT;
+ plat->tx_fifo_count_mask = S5P_TX_FIFO_COUNT_MASK;
+ plat->tx_fifo_full = S5P_TX_FIFO_FULL;
+ }
+
return 0;
}
@@ -200,7 +251,8 @@ static const struct dm_serial_ops s5p_serial_ops = {
};
static const struct udevice_id s5p_serial_ids[] = {
- { .compatible = "samsung,exynos4210-uart" },
+ { .compatible = "samsung,exynos4210-uart", .data = PORT_S5P },
+ { .compatible = "apple,s5l-uart", .data = PORT_S5L },
{ }
};
@@ -221,19 +273,30 @@ U_BOOT_DRIVER(serial_s5p) = {
static inline void _debug_uart_init(void)
{
+ if (IS_ENABLED(CONFIG_DEBUG_UART_SKIP_INIT))
+ return;
+
struct s5p_uart *uart = (struct s5p_uart *)CONFIG_DEBUG_UART_BASE;
s5p_serial_init(uart);
- s5p_serial_baud(uart, CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE);
+#if CONFIG_IS_ENABLED(ARCH_APPLE)
+ s5p_serial_baud(uart, 4, CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE);
+#else
+ s5p_serial_baud(uart, 1, CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE);
+#endif
}
static inline void _debug_uart_putc(int ch)
{
struct s5p_uart *uart = (struct s5p_uart *)CONFIG_DEBUG_UART_BASE;
- while (readl(&uart->ufstat) & TX_FIFO_FULL);
-
+#if CONFIG_IS_ENABLED(ARCH_APPLE)
+ while (readl(&uart->ufstat) & S5L_TX_FIFO_FULL);
+ writel(ch, &uart->utxh);
+#else
+ while (readl(&uart->ufstat) & S5P_TX_FIFO_FULL);
writeb(ch, &uart->utxh);
+#endif
}
DEBUG_UART_FUNCS
diff --git a/drivers/spmi/spmi-msm.c b/drivers/spmi/spmi-msm.c
index 5a335e50aa..27a035c0a5 100644
--- a/drivers/spmi/spmi-msm.c
+++ b/drivers/spmi/spmi-msm.c
@@ -19,39 +19,63 @@
DECLARE_GLOBAL_DATA_PTR;
/* PMIC Arbiter configuration registers */
-#define PMIC_ARB_VERSION 0x0000
-#define PMIC_ARB_VERSION_V2_MIN 0x20010000
-
-#define ARB_CHANNEL_OFFSET(n) (0x4 * (n))
-#define SPMI_CH_OFFSET(chnl) ((chnl) * 0x8000)
-
-#define SPMI_REG_CMD0 0x0
-#define SPMI_REG_CONFIG 0x4
-#define SPMI_REG_STATUS 0x8
-#define SPMI_REG_WDATA 0x10
-#define SPMI_REG_RDATA 0x18
-
-#define SPMI_CMD_OPCODE_SHIFT 27
-#define SPMI_CMD_SLAVE_ID_SHIFT 20
-#define SPMI_CMD_ADDR_SHIFT 12
-#define SPMI_CMD_ADDR_OFFSET_SHIFT 4
-#define SPMI_CMD_BYTE_CNT_SHIFT 0
-
-#define SPMI_CMD_EXT_REG_WRITE_LONG 0x00
-#define SPMI_CMD_EXT_REG_READ_LONG 0x01
-
-#define SPMI_STATUS_DONE 0x1
+#define PMIC_ARB_VERSION 0x0000
+#define PMIC_ARB_VERSION_V2_MIN 0x20010000
+#define PMIC_ARB_VERSION_V3_MIN 0x30000000
+#define PMIC_ARB_VERSION_V5_MIN 0x50000000
+
+#define APID_MAP_OFFSET_V1_V2_V3 (0x800)
+#define APID_MAP_OFFSET_V5 (0x900)
+#define ARB_CHANNEL_OFFSET(n) (0x4 * (n))
+#define SPMI_CH_OFFSET(chnl) ((chnl) * 0x8000)
+#define SPMI_V5_OBS_CH_OFFSET(chnl) ((chnl) * 0x80)
+#define SPMI_V5_RW_CH_OFFSET(chnl) ((chnl) * 0x10000)
+
+#define SPMI_REG_CMD0 0x0
+#define SPMI_REG_CONFIG 0x4
+#define SPMI_REG_STATUS 0x8
+#define SPMI_REG_WDATA 0x10
+#define SPMI_REG_RDATA 0x18
+
+#define SPMI_CMD_OPCODE_SHIFT 27
+#define SPMI_CMD_SLAVE_ID_SHIFT 20
+#define SPMI_CMD_ADDR_SHIFT 12
+#define SPMI_CMD_ADDR_OFFSET_SHIFT 4
+#define SPMI_CMD_BYTE_CNT_SHIFT 0
+
+#define SPMI_CMD_EXT_REG_WRITE_LONG 0x00
+#define SPMI_CMD_EXT_REG_READ_LONG 0x01
+
+#define SPMI_STATUS_DONE 0x1
+
+#define SPMI_MAX_CHANNELS 128
+#define SPMI_MAX_SLAVES 16
+#define SPMI_MAX_PERIPH 256
+
+enum arb_ver {
+ V1 = 1,
+ V2,
+ V3,
+ V5 = 5
+};
-#define SPMI_MAX_CHANNELS 128
-#define SPMI_MAX_SLAVES 16
-#define SPMI_MAX_PERIPH 256
+/*
+ * PMIC arbiter version 5 uses different register offsets for read/write vs
+ * observer channels.
+ */
+enum pmic_arb_channel {
+ PMIC_ARB_CHANNEL_RW,
+ PMIC_ARB_CHANNEL_OBS,
+};
struct msm_spmi_priv {
- phys_addr_t arb_chnl; /* ARB channel mapping base */
+ phys_addr_t arb_chnl; /* ARB channel mapping base */
phys_addr_t spmi_core; /* SPMI core */
- phys_addr_t spmi_obs; /* SPMI observer */
+ phys_addr_t spmi_obs; /* SPMI observer */
/* SPMI channel map */
uint8_t channel_map[SPMI_MAX_SLAVES][SPMI_MAX_PERIPH];
+ /* SPMI bus arbiter version */
+ u32 arb_ver;
};
static int msm_spmi_write(struct udevice *dev, int usid, int pid, int off,
@@ -59,6 +83,7 @@ static int msm_spmi_write(struct udevice *dev, int usid, int pid, int off,
{
struct msm_spmi_priv *priv = dev_get_priv(dev);
unsigned channel;
+ unsigned int ch_offset;
uint32_t reg = 0;
if (usid >= SPMI_MAX_SLAVES)
@@ -69,8 +94,8 @@ static int msm_spmi_write(struct udevice *dev, int usid, int pid, int off,
channel = priv->channel_map[usid][pid];
/* Disable IRQ mode for the current channel*/
- writel(0x0, priv->spmi_core + SPMI_CH_OFFSET(channel) +
- SPMI_REG_CONFIG);
+ writel(0x0,
+ priv->spmi_core + SPMI_CH_OFFSET(channel) + SPMI_REG_CONFIG);
/* Write single byte */
writel(val, priv->spmi_core + SPMI_CH_OFFSET(channel) + SPMI_REG_WDATA);
@@ -82,6 +107,11 @@ static int msm_spmi_write(struct udevice *dev, int usid, int pid, int off,
reg |= (off << SPMI_CMD_ADDR_OFFSET_SHIFT);
reg |= 1; /* byte count */
+ if (priv->arb_ver == V5)
+ ch_offset = SPMI_V5_RW_CH_OFFSET(channel);
+ else
+ ch_offset = SPMI_CH_OFFSET(channel);
+
/* Send write command */
writel(reg, priv->spmi_core + SPMI_CH_OFFSET(channel) + SPMI_REG_CMD0);
@@ -104,6 +134,7 @@ static int msm_spmi_read(struct udevice *dev, int usid, int pid, int off)
{
struct msm_spmi_priv *priv = dev_get_priv(dev);
unsigned channel;
+ unsigned int ch_offset;
uint32_t reg = 0;
if (usid >= SPMI_MAX_SLAVES)
@@ -113,8 +144,13 @@ static int msm_spmi_read(struct udevice *dev, int usid, int pid, int off)
channel = priv->channel_map[usid][pid];
+ if (priv->arb_ver == V5)
+ ch_offset = SPMI_V5_OBS_CH_OFFSET(channel);
+ else
+ ch_offset = SPMI_CH_OFFSET(channel);
+
/* Disable IRQ mode for the current channel*/
- writel(0x0, priv->spmi_obs + SPMI_CH_OFFSET(channel) + SPMI_REG_CONFIG);
+ writel(0x0, priv->spmi_obs + ch_offset + SPMI_REG_CONFIG);
/* Prepare read command */
reg |= SPMI_CMD_EXT_REG_READ_LONG << SPMI_CMD_OPCODE_SHIFT;
@@ -124,13 +160,12 @@ static int msm_spmi_read(struct udevice *dev, int usid, int pid, int off)
reg |= 1; /* byte count */
/* Request read */
- writel(reg, priv->spmi_obs + SPMI_CH_OFFSET(channel) + SPMI_REG_CMD0);
+ writel(reg, priv->spmi_obs + ch_offset + SPMI_REG_CMD0);
/* Wait till CMD DONE status */
reg = 0;
while (!reg) {
- reg = readl(priv->spmi_obs + SPMI_CH_OFFSET(channel) +
- SPMI_REG_STATUS);
+ reg = readl(priv->spmi_obs + ch_offset + SPMI_REG_STATUS);
}
if (reg ^ SPMI_STATUS_DONE) {
@@ -139,8 +174,8 @@ static int msm_spmi_read(struct udevice *dev, int usid, int pid, int off)
}
/* Read the data */
- return readl(priv->spmi_obs + SPMI_CH_OFFSET(channel) +
- SPMI_REG_RDATA) & 0xFF;
+ return readl(priv->spmi_obs + ch_offset +
+ SPMI_REG_RDATA) & 0xFF;
}
static struct dm_spmi_ops msm_spmi_ops = {
@@ -150,31 +185,50 @@ static struct dm_spmi_ops msm_spmi_ops = {
static int msm_spmi_probe(struct udevice *dev)
{
- struct udevice *parent = dev->parent;
struct msm_spmi_priv *priv = dev_get_priv(dev);
- int node = dev_of_offset(dev);
+ phys_addr_t config_addr;
u32 hw_ver;
- bool is_v1;
+ u32 version;
int i;
+ int err;
+
+ config_addr = dev_read_addr_index(dev, 0);
+ priv->spmi_core = dev_read_addr_index(dev, 1);
+ priv->spmi_obs = dev_read_addr_index(dev, 2);
+
+ hw_ver = readl(config_addr + PMIC_ARB_VERSION);
+
+ if (hw_ver < PMIC_ARB_VERSION_V3_MIN) {
+ priv->arb_ver = V2;
+ version = 2;
+ priv->arb_chnl = config_addr + APID_MAP_OFFSET_V1_V2_V3;
+ } else if (hw_ver < PMIC_ARB_VERSION_V5_MIN) {
+ priv->arb_ver = V3;
+ version = 3;
+ priv->arb_chnl = config_addr + APID_MAP_OFFSET_V1_V2_V3;
+ } else {
+ priv->arb_ver = V5;
+ version = 5;
+ priv->arb_chnl = config_addr + APID_MAP_OFFSET_V5;
+
+ if (err) {
+ dev_err(dev, "could not read APID->PPID mapping table, rc= %d\n", err);
+ return -1;
+ }
+ }
- priv->arb_chnl = dev_read_addr(dev);
- priv->spmi_core = fdtdec_get_addr_size_auto_parent(gd->fdt_blob,
- dev_of_offset(parent), node, "reg", 1, NULL, false);
- priv->spmi_obs = fdtdec_get_addr_size_auto_parent(gd->fdt_blob,
- dev_of_offset(parent), node, "reg", 2, NULL, false);
-
- hw_ver = readl(priv->arb_chnl + PMIC_ARB_VERSION - 0x800);
- is_v1 = (hw_ver < PMIC_ARB_VERSION_V2_MIN);
-
- dev_dbg(dev, "PMIC Arb Version-%d (0x%x)\n", (is_v1 ? 1 : 2), hw_ver);
+ dev_dbg(dev, "PMIC Arb Version-%d (0x%x)\n", version, hw_ver);
if (priv->arb_chnl == FDT_ADDR_T_NONE ||
priv->spmi_core == FDT_ADDR_T_NONE ||
priv->spmi_obs == FDT_ADDR_T_NONE)
return -EINVAL;
+ dev_dbg(dev, "priv->arb_chnl address (%llu)\n", priv->arb_chnl);
+ dev_dbg(dev, "priv->spmi_core address (%llu)\n", priv->spmi_core);
+ dev_dbg(dev, "priv->spmi_obs address (%llu)\n", priv->spmi_obs);
/* Scan peripherals connected to each SPMI channel */
- for (i = 0; i < SPMI_MAX_PERIPH ; i++) {
+ for (i = 0; i < SPMI_MAX_PERIPH; i++) {
uint32_t periph = readl(priv->arb_chnl + ARB_CHANNEL_OFFSET(i));
uint8_t slave_id = (periph & 0xf0000) >> 16;
uint8_t pid = (periph & 0xff00) >> 8;
@@ -195,5 +249,5 @@ U_BOOT_DRIVER(msm_spmi) = {
.of_match = msm_spmi_ids,
.ops = &msm_spmi_ops,
.probe = msm_spmi_probe,
- .priv_auto = sizeof(struct msm_spmi_priv),
+ .priv_auto = sizeof(struct msm_spmi_priv),
};
diff --git a/drivers/usb/host/xhci-brcm.c b/drivers/usb/host/xhci-brcm.c
index 27c4bbfcba..fe17924028 100644
--- a/drivers/usb/host/xhci-brcm.c
+++ b/drivers/usb/host/xhci-brcm.c
@@ -8,6 +8,7 @@
#include <fdtdec.h>
#include <usb.h>
#include <asm/io.h>
+#include <dm/device_compat.h>
#include <usb/xhci.h>
#define DRD2U3H_XHC_REGS_AXIWRA 0xC08