Merge https://source.denx.de/u-boot/custodians/u-boot-snapdragon into next

- Reworks Qualcomm support to be more generic, dropping board specific
  build targets and relying on DT as the only source of truth
- Switches all Qualcomm devices to use upstream devicetree
diff --git a/drivers/clk/qcom/clock-apq8016.c b/drivers/clk/qcom/clock-apq8016.c
index c0ce570..e6647f7 100644
--- a/drivers/clk/qcom/clock-apq8016.c
+++ b/drivers/clk/qcom/clock-apq8016.c
@@ -13,6 +13,7 @@
 #include <errno.h>
 #include <asm/io.h>
 #include <linux/bitops.h>
+#include <dt-bindings/clock/qcom,gcc-msm8916.h>
 
 #include "clock-qcom.h"
 
@@ -102,20 +103,20 @@
 };
 
 /* UART: 115200 */
-static int clk_init_uart(struct msm_clk_priv *priv)
+int apq8016_clk_init_uart(phys_addr_t base)
 {
 	/* Enable AHB clock */
-	clk_enable_vote_clk(priv->base, &gcc_blsp1_ahb_clk);
+	clk_enable_vote_clk(base, &gcc_blsp1_ahb_clk);
 
 	/* 7372800 uart block clock @ GPLL0 */
-	clk_rcg_set_rate_mnd(priv->base, &uart2_regs, 1, 144, 15625,
+	clk_rcg_set_rate_mnd(base, &uart2_regs, 1, 144, 15625,
 			     CFG_CLK_SRC_GPLL0, 16);
 
 	/* Vote for gpll0 clock */
-	clk_enable_gpll0(priv->base, &gpll0_vote_clk);
+	clk_enable_gpll0(base, &gpll0_vote_clk);
 
 	/* Enable core clk */
-	clk_enable_cbc(priv->base + BLSP1_UART2_APPS_CBCR);
+	clk_enable_cbc(base + BLSP1_UART2_APPS_CBCR);
 
 	return 0;
 }
@@ -125,14 +126,14 @@
 	struct msm_clk_priv *priv = dev_get_priv(clk->dev);
 
 	switch (clk->id) {
-	case 0: /* SDC1 */
+	case GCC_SDCC1_APPS_CLK: /* SDC1 */
 		return clk_init_sdc(priv, 0, rate);
 		break;
-	case 1: /* SDC2 */
+	case GCC_SDCC2_APPS_CLK: /* SDC2 */
 		return clk_init_sdc(priv, 1, rate);
 		break;
-	case 4: /* UART2 */
-		return clk_init_uart(priv);
+	case GCC_BLSP1_UART2_APPS_CLK: /* UART2 */
+		return apq8016_clk_init_uart(priv->base);
 		break;
 	default:
 		return 0;
@@ -145,7 +146,7 @@
 
 static const struct udevice_id gcc_apq8016_of_match[] = {
 	{
-		.compatible = "qcom,gcc-apq8016",
+		.compatible = "qcom,gcc-msm8916",
 		.data = (ulong)&apq8016_clk_data,
 	},
 	{ }
diff --git a/drivers/clk/qcom/clock-apq8096.c b/drivers/clk/qcom/clock-apq8096.c
index cf1a347..a473161 100644
--- a/drivers/clk/qcom/clock-apq8096.c
+++ b/drivers/clk/qcom/clock-apq8096.c
@@ -13,6 +13,7 @@
 #include <errno.h>
 #include <asm/io.h>
 #include <linux/bitops.h>
+#include <dt-bindings/clock/qcom,gcc-msm8996.h>
 
 #include "clock-qcom.h"
 
@@ -107,10 +108,10 @@
 	struct msm_clk_priv *priv = dev_get_priv(clk->dev);
 
 	switch (clk->id) {
-	case 0: /* SDC1 */
+	case GCC_SDCC1_APPS_CLK: /* SDC1 */
 		return clk_init_sdc(priv, rate);
 		break;
-	case 4: /*UART2*/
+	case GCC_BLSP2_UART2_APPS_CLK: /*UART2*/
 		return clk_init_uart(priv);
 	default:
 		return 0;
@@ -123,7 +124,7 @@
 
 static const struct udevice_id gcc_apq8096_of_match[] = {
 	{
-		.compatible = "qcom,gcc-apq8096",
+		.compatible = "qcom,gcc-msm8996",
 		.data = (ulong)&apq8096_clk_data,
 	},
 	{ }
diff --git a/drivers/clk/qcom/clock-qcs404.c b/drivers/clk/qcom/clock-qcs404.c
index f5b3528..958312b 100644
--- a/drivers/clk/qcom/clock-qcs404.c
+++ b/drivers/clk/qcom/clock-qcs404.c
@@ -193,24 +193,18 @@
 
 	switch (clk->id) {
 	case GCC_BLSP1_UART2_APPS_CLK:
-		/* UART: 115200 */
+		/* UART: 1843200Hz for a fixed 115200 baudrate (19200000 * (12/125)) */
 		clk_rcg_set_rate_mnd(priv->base, &uart2_regs, 0, 12, 125,
 				     CFG_CLK_SRC_CXO, 16);
 		clk_enable_cbc(priv->base + BLSP1_UART2_APPS_CBCR);
-		break;
-	case GCC_BLSP1_AHB_CLK:
-		clk_enable_vote_clk(priv->base, &gcc_blsp1_ahb_clk);
-		break;
+		return 1843200;
 	case GCC_SDCC1_APPS_CLK:
 		/* SDCC1: 200MHz */
 		clk_rcg_set_rate_mnd(priv->base, &sdc_regs, 7, 0, 0,
 				     CFG_CLK_SRC_GPLL0, 8);
 		clk_enable_gpll0(priv->base, &gpll0_vote_clk);
 		clk_enable_cbc(priv->base + SDCC_APPS_CBCR(1));
-		break;
-	case GCC_SDCC1_AHB_CLK:
-		clk_enable_cbc(priv->base + SDCC_AHB_CBCR(1));
-		break;
+		return rate;
 	case GCC_ETH_RGMII_CLK:
 		if (rate == 250000000)
 			clk_rcg_set_rate_mnd(priv->base, &emac_regs, 3, 0, 0,
@@ -224,11 +218,15 @@
 		else if (rate == 5000000)
 			clk_rcg_set_rate_mnd(priv->base, &emac_regs, 3, 1, 50,
 					     CFG_CLK_SRC_GPLL1, 8);
-		break;
-	default:
-		return 0;
+		return rate;
 	}
 
+	/* There is a bug only seeming to affect this board where the MMC driver somehow calls
+	 * clk_set_rate() on a clock with id 0 which is associated with the qcom_clk device.
+	 * The only clock with ID 0 is the xo_board clock which should not be associated with
+	 * this device...
+	 */
+	log_debug("Unknown clock id %ld\n", clk->id);
 	return 0;
 }
 
@@ -305,6 +303,9 @@
 		clk_rcg_set_rate(priv->base, &blsp1_qup4_i2c_apps_regs, 0,
 				 CFG_CLK_SRC_CXO);
 		break;
+	case GCC_SDCC1_AHB_CLK:
+		clk_enable_cbc(priv->base + SDCC_AHB_CBCR(1));
+		break;
 	default:
 		return 0;
 	}
diff --git a/drivers/gpio/msm_gpio.c b/drivers/gpio/msm_gpio.c
index 80cd28b..5e57b0c 100644
--- a/drivers/gpio/msm_gpio.c
+++ b/drivers/gpio/msm_gpio.c
@@ -39,6 +39,10 @@
 {
 	struct msm_gpio_bank *priv = dev_get_priv(dev);
 
+	/* Always NOP for special pins, assume they're in the correct state */
+	if (qcom_is_special_pin(priv->pin_data, gpio))
+		return 0;
+
 	/* Disable OE bit */
 	clrsetbits_le32(priv->base + GPIO_CONFIG_REG(dev, gpio),
 			GPIO_OE_MASK, GPIO_OE_DISABLE);
@@ -50,6 +54,10 @@
 {
 	struct msm_gpio_bank *priv = dev_get_priv(dev);
 
+	/* Always NOP for special pins, assume they're in the correct state */
+	if (qcom_is_special_pin(priv->pin_data, gpio))
+		return 0;
+
 	value = !!value;
 	/* set value */
 	writel(value << GPIO_OUT, priv->base + GPIO_IN_OUT_REG(dev, gpio));
@@ -62,6 +70,10 @@
 {
 	struct msm_gpio_bank *priv = dev_get_priv(dev);
 
+	/* Always NOP for special pins, assume they're in the correct state */
+	if (qcom_is_special_pin(priv->pin_data, gpio))
+		return 0;
+
 	value = !!value;
 	/* set value */
 	writel(value << GPIO_OUT, priv->base + GPIO_IN_OUT_REG(dev, gpio));
@@ -76,6 +88,10 @@
 {
 	struct msm_gpio_bank *priv = dev_get_priv(dev);
 
+	/* Always NOP for special pins, assume they're in the correct state */
+	if (qcom_is_special_pin(priv->pin_data, gpio))
+		return 0;
+
 	return !!(readl(priv->base + GPIO_IN_OUT_REG(dev, gpio)) >> GPIO_IN);
 }
 
@@ -83,6 +99,10 @@
 {
 	struct msm_gpio_bank *priv = dev_get_priv(dev);
 
+	/* Always NOP for special pins, assume they're in the correct state */
+	if (qcom_is_special_pin(priv->pin_data, gpio))
+		return 0;
+
 	if (readl(priv->base + GPIO_CONFIG_REG(dev, gpio)) & GPIO_OE_ENABLE)
 		return GPIOF_OUTPUT;
 
diff --git a/drivers/gpio/qcom_pmic_gpio.c b/drivers/gpio/qcom_pmic_gpio.c
index 6167c84..14a8210 100644
--- a/drivers/gpio/qcom_pmic_gpio.c
+++ b/drivers/gpio/qcom_pmic_gpio.c
@@ -7,10 +7,14 @@
 
 #include <common.h>
 #include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/pinctrl.h>
 #include <log.h>
 #include <power/pmic.h>
 #include <spmi/spmi.h>
 #include <asm/io.h>
+#include <stdlib.h>
 #include <asm/gpio.h>
 #include <linux/bitops.h>
 
@@ -64,27 +68,34 @@
 #define REG_EN_CTL             0x46
 #define REG_EN_CTL_ENABLE      (1 << 7)
 
-struct qcom_gpio_bank {
+/**
+ * pmic_gpio_match_data - platform specific configuration
+ *
+ * @PMIC_MATCH_READONLY: treat all GPIOs as readonly, don't attempt to configure them.
+ * This is a workaround for an unknown bug on some platforms where trying to write the
+ * GPIO configuration registers causes the board to hang.
+ */
+enum pmic_gpio_quirks {
+	QCOM_PMIC_QUIRK_READONLY = (1 << 0),
+};
+
+struct qcom_pmic_gpio_data {
 	uint32_t pid; /* Peripheral ID on SPMI bus */
 	bool     lv_mv_type; /* If subtype is GPIO_LV(0x10) or GPIO_MV(0x11) */
+	u32 pin_count;
+	struct udevice *pmic; /* Reference to pmic device for read/write */
 };
 
-static int qcom_gpio_set_direction(struct udevice *dev, unsigned offset,
-				   bool input, int value)
+/* dev can be the GPIO or pinctrl device */
+static int _qcom_gpio_set_direction(struct udevice *dev, u32 offset, bool input, int value)
 {
-	struct qcom_gpio_bank *priv = dev_get_priv(dev);
-	uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
-	uint32_t reg_ctl_val;
-	int ret;
-
-	/* Disable the GPIO */
-	ret = pmic_clrsetbits(dev->parent, gpio_base + REG_EN_CTL,
-			      REG_EN_CTL_ENABLE, 0);
-	if (ret < 0)
-		return ret;
+	struct qcom_pmic_gpio_data *plat = dev_get_plat(dev);
+	u32 gpio_base = plat->pid + REG_OFFSET(offset);
+	u32 reg_ctl_val;
+	int ret = 0;
 
 	/* Select the mode and output */
-	if (priv->lv_mv_type) {
+	if (plat->lv_mv_type) {
 		if (input)
 			reg_ctl_val = REG_CTL_LV_MV_MODE_INPUT;
 		else
@@ -96,20 +107,43 @@
 			reg_ctl_val = REG_CTL_MODE_INOUT | !!value;
 	}
 
-	ret = pmic_reg_write(dev->parent, gpio_base + REG_CTL, reg_ctl_val);
+	ret = pmic_reg_write(plat->pmic, gpio_base + REG_CTL, reg_ctl_val);
 	if (ret < 0)
 		return ret;
 
-	if (priv->lv_mv_type && !input) {
-		ret = pmic_reg_write(dev->parent,
+	if (plat->lv_mv_type && !input) {
+		ret = pmic_reg_write(plat->pmic,
 				     gpio_base + REG_LV_MV_OUTPUT_CTL,
 				     !!value << REG_LV_MV_OUTPUT_CTL_SHIFT);
 		if (ret < 0)
 			return ret;
 	}
 
+	return 0;
+}
+
+static int qcom_gpio_set_direction(struct udevice *dev, unsigned int offset,
+				   bool input, int value)
+{
+	struct qcom_pmic_gpio_data *plat = dev_get_plat(dev);
+	uint32_t gpio_base = plat->pid + REG_OFFSET(offset);
+	ulong quirks = dev_get_driver_data(dev);
+	int ret = 0;
+
+	/* Some PMICs don't like their GPIOs being configured */
+	if (quirks & QCOM_PMIC_QUIRK_READONLY)
+		return 0;
+
+	/* Disable the GPIO */
+	ret = pmic_clrsetbits(dev->parent, gpio_base + REG_EN_CTL,
+			      REG_EN_CTL_ENABLE, 0);
+	if (ret < 0)
+		return ret;
+
+	_qcom_gpio_set_direction(dev, offset, input, value);
+
 	/* Set the right pull (no pull) */
-	ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_PULL_CTL,
+	ret = pmic_reg_write(plat->pmic, gpio_base + REG_DIG_PULL_CTL,
 			     REG_DIG_PULL_NO_PU);
 	if (ret < 0)
 		return ret;
@@ -117,13 +151,13 @@
 	/* Configure output pin drivers if needed */
 	if (!input) {
 		/* Select the VIN - VIN0, pin is input so it doesn't matter */
-		ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_VIN_CTL,
+		ret = pmic_reg_write(plat->pmic, gpio_base + REG_DIG_VIN_CTL,
 				     REG_DIG_VIN_VIN0);
 		if (ret < 0)
 			return ret;
 
 		/* Set the right dig out control */
-		ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_OUT_CTL,
+		ret = pmic_reg_write(plat->pmic, gpio_base + REG_DIG_OUT_CTL,
 				     REG_DIG_OUT_CTL_CMOS |
 				     REG_DIG_OUT_CTL_DRIVE_L);
 		if (ret < 0)
@@ -148,15 +182,15 @@
 
 static int qcom_gpio_get_function(struct udevice *dev, unsigned offset)
 {
-	struct qcom_gpio_bank *priv = dev_get_priv(dev);
-	uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
+	struct qcom_pmic_gpio_data *plat = dev_get_plat(dev);
+	uint32_t gpio_base = plat->pid + REG_OFFSET(offset);
 	int reg;
 
-	reg = pmic_reg_read(dev->parent, gpio_base + REG_CTL);
+	reg = pmic_reg_read(plat->pmic, gpio_base + REG_CTL);
 	if (reg < 0)
 		return reg;
 
-	if (priv->lv_mv_type) {
+	if (plat->lv_mv_type) {
 		switch (reg & REG_CTL_LV_MV_MODE_MASK) {
 		case REG_CTL_LV_MV_MODE_INPUT:
 			return GPIOF_INPUT;
@@ -181,11 +215,11 @@
 
 static int qcom_gpio_get_value(struct udevice *dev, unsigned offset)
 {
-	struct qcom_gpio_bank *priv = dev_get_priv(dev);
-	uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
+	struct qcom_pmic_gpio_data *plat = dev_get_plat(dev);
+	uint32_t gpio_base = plat->pid + REG_OFFSET(offset);
 	int reg;
 
-	reg = pmic_reg_read(dev->parent, gpio_base + REG_STATUS);
+	reg = pmic_reg_read(plat->pmic, gpio_base + REG_STATUS);
 	if (reg < 0)
 		return reg;
 
@@ -195,11 +229,11 @@
 static int qcom_gpio_set_value(struct udevice *dev, unsigned offset,
 			       int value)
 {
-	struct qcom_gpio_bank *priv = dev_get_priv(dev);
-	uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
+	struct qcom_pmic_gpio_data *plat = dev_get_plat(dev);
+	uint32_t gpio_base = plat->pid + REG_OFFSET(offset);
 
 	/* Set the output value of the gpio */
-	if (priv->lv_mv_type)
+	if (plat->lv_mv_type)
 		return pmic_clrsetbits(dev->parent,
 				       gpio_base + REG_LV_MV_OUTPUT_CTL,
 				       REG_LV_MV_OUTPUT_CTL_MASK,
@@ -209,71 +243,104 @@
 				       REG_CTL_OUTPUT_MASK, !!value);
 }
 
+static int qcom_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
+			   struct ofnode_phandle_args *args)
+{
+	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+	if (args->args_count < 1)
+		return -EINVAL;
+
+	/* GPIOs in DT are 1-based */
+	desc->offset = args->args[0] - 1;
+	if (desc->offset >= uc_priv->gpio_count)
+		return -EINVAL;
+
+	if (args->args_count < 2)
+		return 0;
+
+	desc->flags = gpio_flags_xlate(args->args[1]);
+
+	return 0;
+}
+
 static const struct dm_gpio_ops qcom_gpio_ops = {
 	.direction_input	= qcom_gpio_direction_input,
 	.direction_output	= qcom_gpio_direction_output,
 	.get_value		= qcom_gpio_get_value,
 	.set_value		= qcom_gpio_set_value,
 	.get_function		= qcom_gpio_get_function,
+	.xlate			= qcom_gpio_xlate,
 };
 
+static int qcom_gpio_bind(struct udevice *dev)
+{
+
+	struct qcom_pmic_gpio_data *plat = dev_get_plat(dev);
+	ulong quirks = dev_get_driver_data(dev);
+	struct udevice *child;
+	struct driver *drv;
+	int ret;
+
+	drv = lists_driver_lookup_name("qcom_pmic_pinctrl");
+	if (!drv) {
+		log_warning("Cannot find driver '%s'\n", "qcom_pmic_pinctrl");
+		return -ENOENT;
+	}
+
+	/* Bind the GPIO driver as a child of the PMIC. */
+	ret = device_bind_with_driver_data(dev, drv,
+					   dev->name,
+					   quirks, dev_ofnode(dev), &child);
+	if (ret)
+		return log_msg_ret("bind", ret);
+
+	dev_set_plat(child, plat);
+
+	return 0;
+}
+
 static int qcom_gpio_probe(struct udevice *dev)
 {
-	struct qcom_gpio_bank *priv = dev_get_priv(dev);
-	int reg;
+	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct qcom_pmic_gpio_data *plat = dev_get_plat(dev);
+	struct ofnode_phandle_args args;
+	int val, ret;
 	u64 pid;
 
+	plat->pmic = dev->parent;
+
 	pid = dev_read_addr(dev);
 	if (pid == FDT_ADDR_T_NONE)
 		return log_msg_ret("bad address", -EINVAL);
 
-	priv->pid = pid;
+	plat->pid = pid;
 
 	/* Do a sanity check */
-	reg = pmic_reg_read(dev->parent, priv->pid + REG_TYPE);
-	if (reg != REG_TYPE_VAL)
+	val = pmic_reg_read(plat->pmic, plat->pid + REG_TYPE);
+	if (val != REG_TYPE_VAL)
 		return log_msg_ret("bad type", -ENXIO);
 
-	reg = pmic_reg_read(dev->parent, priv->pid + REG_SUBTYPE);
-	if (reg != REG_SUBTYPE_GPIO_4CH && reg != REG_SUBTYPE_GPIOC_4CH &&
-	    reg != REG_SUBTYPE_GPIO_LV && reg != REG_SUBTYPE_GPIO_MV)
+	val = pmic_reg_read(plat->pmic, plat->pid + REG_SUBTYPE);
+	if (val != REG_SUBTYPE_GPIO_4CH && val != REG_SUBTYPE_GPIOC_4CH &&
+	    val != REG_SUBTYPE_GPIO_LV && val != REG_SUBTYPE_GPIO_MV)
 		return log_msg_ret("bad subtype", -ENXIO);
 
-	priv->lv_mv_type = reg == REG_SUBTYPE_GPIO_LV ||
-			   reg == REG_SUBTYPE_GPIO_MV;
-
-	return 0;
-}
-
-/*
- * Parse basic GPIO count specified via the gpio-ranges property
- * as specified in Linux devicetrees
- * Returns < 0 on error, otherwise gpio count
- */
-static int qcom_gpio_of_parse_ranges(struct udevice *dev)
-{
-	int ret;
-	struct ofnode_phandle_args args;
+	plat->lv_mv_type = val == REG_SUBTYPE_GPIO_LV ||
+			   val == REG_SUBTYPE_GPIO_MV;
 
+	/*
+	 * Parse basic GPIO count specified via the gpio-ranges property
+	 * as specified in upstream devicetrees
+	 */
 	ret = ofnode_parse_phandle_with_args(dev_ofnode(dev), "gpio-ranges",
 					     NULL, 3, 0, &args);
 	if (ret)
 		return log_msg_ret("gpio-ranges", ret);
 
-	return args.args[2];
-}
-
-static int qcom_gpio_of_to_plat(struct udevice *dev)
-{
-	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
-	int ret;
-
-	ret = qcom_gpio_of_parse_ranges(dev);
-	if (ret > 0)
-		uc_priv->gpio_count = ret;
-	else
-		return ret;
+	plat->pin_count = args.args[2];
 
+	uc_priv->gpio_count = plat->pin_count;
 	uc_priv->bank_name = "pmic";
 
 	return 0;
@@ -282,7 +349,7 @@
 static const struct udevice_id qcom_gpio_ids[] = {
 	{ .compatible = "qcom,pm8916-gpio" },
 	{ .compatible = "qcom,pm8994-gpio" },	/* 22 GPIO's */
-	{ .compatible = "qcom,pm8998-gpio" },
+	{ .compatible = "qcom,pm8998-gpio", .data = QCOM_PMIC_QUIRK_READONLY },
 	{ .compatible = "qcom,pms405-gpio" },
 	{ }
 };
@@ -291,9 +358,75 @@
 	.name	= "qcom_pmic_gpio",
 	.id	= UCLASS_GPIO,
 	.of_match = qcom_gpio_ids,
-	.of_to_plat = qcom_gpio_of_to_plat,
-	.probe	= qcom_gpio_probe,
+	.bind	= qcom_gpio_bind,
+	.probe = qcom_gpio_probe,
 	.ops	= &qcom_gpio_ops,
-	.priv_auto	= sizeof(struct qcom_gpio_bank),
+	.plat_auto = sizeof(struct qcom_pmic_gpio_data),
+	.flags = DM_FLAG_ALLOC_PDATA,
+};
+
+static const struct pinconf_param qcom_pmic_pinctrl_conf_params[] = {
+	{ "output-high", PIN_CONFIG_OUTPUT_ENABLE, 1 },
+	{ "output-low", PIN_CONFIG_OUTPUT, 0 },
 };
 
+static int qcom_pmic_pinctrl_get_pins_count(struct udevice *dev)
+{
+	struct qcom_pmic_gpio_data *plat = dev_get_plat(dev);
+
+	return plat->pin_count;
+}
+
+static const char *qcom_pmic_pinctrl_get_pin_name(struct udevice *dev, unsigned int selector)
+{
+	static char name[8];
+
+	/* DT indexes from 1 */
+	snprintf(name, sizeof(name), "gpio%u", selector + 1);
+
+	return name;
+}
+
+static int qcom_pmic_pinctrl_pinconf_set(struct udevice *dev, unsigned int selector,
+					 unsigned int param, unsigned int arg)
+{
+	/* We only support configuring the pin as an output, either low or high */
+	return _qcom_gpio_set_direction(dev, selector, false,
+					param == PIN_CONFIG_OUTPUT_ENABLE);
+}
+
+static const char *qcom_pmic_pinctrl_get_function_name(struct udevice *dev, unsigned int selector)
+{
+	if (!selector)
+		return "normal";
+	return NULL;
+}
+
+static int qcom_pmic_pinctrl_generic_get_functions_count(struct udevice *dev)
+{
+	return 1;
+}
+
+static int qcom_pmic_pinctrl_generic_pinmux_set_mux(struct udevice *dev, unsigned int selector,
+						    unsigned int func_selector)
+{
+	return 0;
+}
+
+struct pinctrl_ops qcom_pmic_pinctrl_ops = {
+	.get_pins_count = qcom_pmic_pinctrl_get_pins_count,
+	.get_pin_name = qcom_pmic_pinctrl_get_pin_name,
+	.set_state = pinctrl_generic_set_state,
+	.pinconf_num_params = ARRAY_SIZE(qcom_pmic_pinctrl_conf_params),
+	.pinconf_params = qcom_pmic_pinctrl_conf_params,
+	.pinconf_set = qcom_pmic_pinctrl_pinconf_set,
+	.get_function_name = qcom_pmic_pinctrl_get_function_name,
+	.get_functions_count = qcom_pmic_pinctrl_generic_get_functions_count,
+	.pinmux_set = qcom_pmic_pinctrl_generic_pinmux_set_mux,
+};
+
+U_BOOT_DRIVER(qcom_pmic_pinctrl) = {
+	.name	= "qcom_pmic_pinctrl",
+	.id	= UCLASS_PINCTRL,
+	.ops	= &qcom_pmic_pinctrl_ops,
+};
diff --git a/drivers/mmc/msm_sdhci.c b/drivers/mmc/msm_sdhci.c
index fe1e754..059cb3d 100644
--- a/drivers/mmc/msm_sdhci.c
+++ b/drivers/mmc/msm_sdhci.c
@@ -44,6 +44,7 @@
 struct msm_sdhc {
 	struct sdhci_host host;
 	void *base;
+	struct clk_bulk clks;
 };
 
 struct msm_sdhc_variant_info {
@@ -54,35 +55,57 @@
 
 static int msm_sdc_clk_init(struct udevice *dev)
 {
-	int node = dev_of_offset(dev);
-	uint clk_rate = fdtdec_get_uint(gd->fdt_blob, node, "clock-frequency",
-					400000);
-	uint clkd[2]; /* clk_id and clk_no */
-	int clk_offset;
-	struct udevice *clk_dev;
-	struct clk clk;
-	int ret;
+	struct msm_sdhc *prv = dev_get_priv(dev);
+	ofnode node = dev_ofnode(dev);
+	ulong clk_rate;
+	int ret, i = 0, n_clks;
+	const char *clk_name;
 
-	ret = fdtdec_get_int_array(gd->fdt_blob, node, "clock", clkd, 2);
+	ret = ofnode_read_u32(node, "clock-frequency", (uint *)(&clk_rate));
 	if (ret)
-		return ret;
-
-	clk_offset = fdt_node_offset_by_phandle(gd->fdt_blob, clkd[0]);
-	if (clk_offset < 0)
-		return clk_offset;
+		clk_rate = 400000;
 
-	ret = uclass_get_device_by_of_offset(UCLASS_CLK, clk_offset, &clk_dev);
-	if (ret)
+	ret = clk_get_bulk(dev, &prv->clks);
+	if (ret) {
+		log_warning("Couldn't get mmc clocks: %d\n", ret);
 		return ret;
+	}
 
-	clk.id = clkd[1];
-	ret = clk_request(clk_dev, &clk);
-	if (ret < 0)
+	ret = clk_enable_bulk(&prv->clks);
+	if (ret) {
+		log_warning("Couldn't enable mmc clocks: %d\n", ret);
 		return ret;
+	}
 
-	ret = clk_set_rate(&clk, clk_rate);
-	if (ret < 0)
-		return ret;
+	/* If clock-names is unspecified, then the first clock is the core clock */
+	if (!ofnode_get_property(node, "clock-names", &n_clks)) {
+		if (!clk_set_rate(&prv->clks.clks[0], clk_rate)) {
+			log_warning("Couldn't set core clock rate: %d\n", ret);
+			return -EINVAL;
+		}
+	}
+
+	/* Find the index of the "core" clock */
+	while (i < n_clks) {
+		ofnode_read_string_index(node, "clock-names", i, &clk_name);
+		if (!strcmp(clk_name, "core"))
+			break;
+		i++;
+	}
+
+	if (i >= prv->clks.count) {
+		log_warning("Couldn't find core clock (index %d but only have %d clocks)\n", i,
+		       prv->clks.count);
+		return -EINVAL;
+	}
+
+	/* The clock is already enabled by the clk_bulk above */
+	clk_rate = clk_set_rate(&prv->clks.clks[i], clk_rate);
+	/* If we get a rate of 0 then something has probably gone wrong. */
+	if (clk_rate == 0 || IS_ERR((void *)clk_rate)) {
+		log_warning("Couldn't set MMC core clock rate: %dE\n", clk_rate ? (int)PTR_ERR((void *)clk_rate) : 0);
+		return -EINVAL;
+	}
 
 	return 0;
 }
@@ -187,6 +210,8 @@
 	if (!var_info->mci_removed)
 		writel(0, priv->base + SDCC_MCI_HC_MODE);
 
+	clk_release_bulk(&priv->clks);
+
 	return 0;
 }
 
diff --git a/drivers/phy/qcom/msm8916-usbh-phy.c b/drivers/phy/qcom/msm8916-usbh-phy.c
index 7c9d030..f52046f 100644
--- a/drivers/phy/qcom/msm8916-usbh-phy.c
+++ b/drivers/phy/qcom/msm8916-usbh-phy.c
@@ -74,7 +74,7 @@
 {
 	struct msm_phy_priv *priv = dev_get_priv(dev);
 
-	priv->regs = dev_remap_addr(dev);
+	priv->regs = dev_remap_addr(dev_get_parent(dev));
 	if (!priv->regs)
 		return -EINVAL;
 
@@ -96,7 +96,7 @@
 };
 
 static const struct udevice_id msm_phy_ids[] = {
-	{ .compatible = "qcom,apq8016-usbphy" },
+	{ .compatible = "qcom,usb-hs-phy-msm8916" },
 	{ }
 };
 
diff --git a/drivers/pinctrl/qcom/pinctrl-apq8016.c b/drivers/pinctrl/qcom/pinctrl-apq8016.c
index 8149ffd..db0e212 100644
--- a/drivers/pinctrl/qcom/pinctrl-apq8016.c
+++ b/drivers/pinctrl/qcom/pinctrl-apq8016.c
@@ -14,22 +14,22 @@
 #define MAX_PIN_NAME_LEN 32
 static char pin_name[MAX_PIN_NAME_LEN] __section(".data");
 static const char * const msm_pinctrl_pins[] = {
-	"SDC1_CLK",
-	"SDC1_CMD",
-	"SDC1_DATA",
-	"SDC2_CLK",
-	"SDC2_CMD",
-	"SDC2_DATA",
-	"QDSD_CLK",
-	"QDSD_CMD",
-	"QDSD_DATA0",
-	"QDSD_DATA1",
-	"QDSD_DATA2",
-	"QDSD_DATA3",
+	"sdc1_clk",
+	"sdc1_cmd",
+	"sdc1_data",
+	"sdc2_clk",
+	"sdc2_cmd",
+	"sdc2_data",
+	"qdsd_clk",
+	"qdsd_cmd",
+	"qdsd_data0",
+	"qdsd_data1",
+	"qdsd_data2",
+	"qdsd_data3",
 };
 
 static const struct pinctrl_function msm_pinctrl_functions[] = {
-	{"blsp1_uart", 2},
+	{"blsp_uart2", 2},
 };
 
 static const char *apq8016_get_function_name(struct udevice *dev,
@@ -42,7 +42,7 @@
 					unsigned int selector)
 {
 	if (selector < 122) {
-		snprintf(pin_name, MAX_PIN_NAME_LEN, "GPIO_%u", selector);
+		snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector);
 		return pin_name;
 	} else {
 		return msm_pinctrl_pins[selector - 122];
@@ -55,7 +55,10 @@
 }
 
 static const struct msm_pinctrl_data apq8016_data = {
-	.pin_data = { .pin_count = 133, },
+	.pin_data = {
+		.pin_count = 133,
+		.special_pins_start = 122,
+	},
 	.functions_count = ARRAY_SIZE(msm_pinctrl_functions),
 	.get_function_name = apq8016_get_function_name,
 	.get_function_mux = apq8016_get_function_mux,
@@ -73,4 +76,5 @@
 	.of_match	= msm_pinctrl_ids,
 	.ops		= &msm_pinctrl_ops,
 	.bind		= msm_pinctrl_bind,
+	.flags		= DM_FLAG_PRE_RELOC,
 };
diff --git a/drivers/pinctrl/qcom/pinctrl-apq8096.c b/drivers/pinctrl/qcom/pinctrl-apq8096.c
index d64ab1f..880df8f 100644
--- a/drivers/pinctrl/qcom/pinctrl-apq8096.c
+++ b/drivers/pinctrl/qcom/pinctrl-apq8096.c
@@ -14,13 +14,13 @@
 #define MAX_PIN_NAME_LEN 32
 static char pin_name[MAX_PIN_NAME_LEN] __section(".data");
 static const char * const msm_pinctrl_pins[] = {
-	"SDC1_CLK",
-	"SDC1_CMD",
-	"SDC1_DATA",
-	"SDC2_CLK",
-	"SDC2_CMD",
-	"SDC2_DATA",
-	"SDC1_RCLK",
+	"sdc1_clk",
+	"sdc1_cmd",
+	"sdc1_data",
+	"sdc2_clk",
+	"sdc2_cmd",
+	"sdc2_data",
+	"sdc1_rclk",
 };
 
 static const struct pinctrl_function msm_pinctrl_functions[] = {
@@ -37,7 +37,7 @@
 					unsigned int selector)
 {
 	if (selector < 150) {
-		snprintf(pin_name, MAX_PIN_NAME_LEN, "GPIO_%u", selector);
+		snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector);
 		return pin_name;
 	} else {
 		return msm_pinctrl_pins[selector - 150];
@@ -50,7 +50,10 @@
 }
 
 static const struct msm_pinctrl_data apq8096_data = {
-	.pin_data = { .pin_count = 157, },
+	.pin_data = {
+		.pin_count = 157,
+		.special_pins_start = 150,
+	},
 	.functions_count = ARRAY_SIZE(msm_pinctrl_functions),
 	.get_function_name = apq8096_get_function_name,
 	.get_function_mux = apq8096_get_function_mux,
diff --git a/drivers/pinctrl/qcom/pinctrl-ipq4019.c b/drivers/pinctrl/qcom/pinctrl-ipq4019.c
index 2d99f99..74c04ab 100644
--- a/drivers/pinctrl/qcom/pinctrl-ipq4019.c
+++ b/drivers/pinctrl/qcom/pinctrl-ipq4019.c
@@ -46,7 +46,10 @@
 }
 
 static const struct msm_pinctrl_data ipq4019_data = {
-	.pin_data = { .pin_count = 100, },
+	.pin_data = {
+		.pin_count = 100,
+		.special_pins_start = 100, /* There are no special pins */
+	},
 	.functions_count = ARRAY_SIZE(msm_pinctrl_functions),
 	.get_function_name = ipq4019_get_function_name,
 	.get_function_mux = ipq4019_get_function_mux,
diff --git a/drivers/pinctrl/qcom/pinctrl-qcom.c b/drivers/pinctrl/qcom/pinctrl-qcom.c
index dc3d8c4..ee0624d 100644
--- a/drivers/pinctrl/qcom/pinctrl-qcom.c
+++ b/drivers/pinctrl/qcom/pinctrl-qcom.c
@@ -16,6 +16,7 @@
 #include <asm/gpio.h>
 #include <dm/pinctrl.h>
 #include <linux/bitops.h>
+#include <linux/bug.h>
 #include <mach/gpio.h>
 
 #include "pinctrl-qcom.h"
@@ -83,6 +84,10 @@
 {
 	struct msm_pinctrl_priv *priv = dev_get_priv(dev);
 
+	/* Always NOP for special pins, assume they're in the correct state */
+	if (qcom_is_special_pin(&priv->data->pin_data, pin_selector))
+		return 0;
+
 	clrsetbits_le32(priv->base + GPIO_CONFIG_REG(priv, pin_selector),
 			TLMM_FUNC_SEL_MASK | TLMM_GPIO_DISABLE,
 			priv->data->get_function_mux(func_selector) << 2);
@@ -94,6 +99,10 @@
 {
 	struct msm_pinctrl_priv *priv = dev_get_priv(dev);
 
+	/* Always NOP for special pins */
+	if (qcom_is_special_pin(&priv->data->pin_data, pin_selector))
+		return 0;
+
 	switch (param) {
 	case PIN_CONFIG_DRIVE_STRENGTH:
 		argument = (argument / 2) - 1;
@@ -136,6 +145,9 @@
 	const char *name;
 	int ret;
 
+	if (!data->pin_data.special_pins_start)
+		dev_warn(dev, "Special pins start index not defined!\n");
+
 	drv = lists_driver_lookup_name("pinctrl_qcom");
 	if (!drv)
 		return -ENOENT;
diff --git a/drivers/pinctrl/qcom/pinctrl-qcs404.c b/drivers/pinctrl/qcom/pinctrl-qcs404.c
index ac00afa..3a2d468 100644
--- a/drivers/pinctrl/qcom/pinctrl-qcs404.c
+++ b/drivers/pinctrl/qcom/pinctrl-qcs404.c
@@ -10,20 +10,24 @@
 
 #include "pinctrl-qcom.h"
 
+#define NORTH	0x00300000
+#define SOUTH	0x00000000
+#define EAST	0x06b00000
+
 #define MAX_PIN_NAME_LEN 32
 static char pin_name[MAX_PIN_NAME_LEN] __section(".data");
 static const char * const msm_pinctrl_pins[] = {
-	"SDC1_RCLK",
-	"SDC1_CLK",
-	"SDC1_CMD",
-	"SDC1_DATA",
-	"SDC2_CLK",
-	"SDC2_CMD",
-	"SDC2_DATA",
+	"sdc1_rclk",
+	"sdc1_clk",
+	"sdc1_cmd",
+	"sdc1_data",
+	"sdc2_clk",
+	"sdc2_cmd",
+	"sdc2_data",
 };
 
 static const struct pinctrl_function msm_pinctrl_functions[] = {
-	{"blsp_uart2", 1},
+	{"gpio", 0},
 	{"rgmii_int", 1},
 	{"rgmii_ck", 1},
 	{"rgmii_tx", 1},
@@ -37,6 +41,40 @@
 	{"blsp_i2c_scl_a2", 3},
 	{"blsp_i2c3", 2},
 	{"blsp_i2c4", 1},
+	{"blsp_uart_tx_a2", 1},
+	{"blsp_uart_rx_a2", 1},
+};
+
+static const unsigned int qcs404_pin_offsets[] = {
+	[0] = SOUTH,    [1] = SOUTH,    [2] = SOUTH,    [3] = SOUTH,    [4] = SOUTH,
+	[5] = SOUTH,   [6] = SOUTH,   [7] = SOUTH,   [8] = SOUTH,    [9] = SOUTH,
+	[10] = SOUTH,   [11] = SOUTH,   [12] = SOUTH,  [13] = SOUTH,  [14] = SOUTH,
+	[15] = SOUTH,  [16] = SOUTH,  [17] = NORTH,  [18] = NORTH,  [19] = NORTH,
+	[20] = NORTH,  [21] = SOUTH,  [22] = NORTH,  [23] = NORTH,  [24] = NORTH,
+	[25] = NORTH,  [26] = EAST,  [27] = EAST,   [28] = EAST,   [29] = EAST,
+	[30] = NORTH,   [31] = NORTH,  [32] = NORTH,  [33] = NORTH,  [34] = SOUTH,
+	[35] = SOUTH,  [36] = NORTH,  [37] = NORTH,  [38] = NORTH,  [39] = EAST,
+	[40] = EAST,  [41] = EAST,   [42] = EAST,   [43] = EAST,   [44] = EAST,
+	[45] = EAST,   [46] = EAST,   [47] = EAST,   [48] = EAST,   [49] = EAST,
+	[50] = EAST,  [51] = EAST,  [52] = EAST,  [53] = EAST,  [54] = EAST,
+	[55] = EAST,  [56] = EAST,  [57] = EAST,  [58] = EAST,  [59] = EAST,
+	[60] = NORTH,  [61] = NORTH,  [62] = NORTH,  [63] = NORTH,  [64] = NORTH,
+	[65] = NORTH,  [66] = NORTH,  [67] = NORTH,  [68] = NORTH,  [69] = NORTH,
+	[70] = NORTH,   [71] = NORTH,   [72] = NORTH,   [73] = NORTH,   [74] = NORTH,
+	[75] = NORTH,   [76] = NORTH,   [77] = NORTH,   [78] = EAST,   [79] = EAST,
+	[80] = EAST,  [81] = EAST,  [82] = NORTH,  [83] = NORTH,  [84] = NORTH,
+	[85] = NORTH,   [86] = EAST,   [87] = EAST,   [88] = EAST,   [89] = EAST,
+	[90] = EAST,  [91] = EAST,  [92] = EAST,  [93] = EAST,  [94] = EAST,
+	[95] = EAST,  [96] = EAST,  [97] = EAST,  [98] = EAST,  [99] = EAST,
+	[100] = EAST, [101] = EAST, [102] = EAST, [103] = EAST, [104] = EAST,
+	[105] = EAST, [106] = EAST, [107] = EAST, [108] = EAST, [109] = EAST,
+	[110] = EAST, [111] = EAST, [112] = EAST, [113] = EAST, [114] = EAST,
+	[115] = EAST, [116] = EAST, [117] = NORTH, [118] = NORTH, [119] = EAST,
+	/*
+	 * There's 126 pins but the last ones are special and have non-standard registers
+	 * so we leave them out here. The pinctrl and GPIO drivers both currently ignore
+	 * these pins.
+	 */
 };
 
 static const char *qcs404_get_function_name(struct udevice *dev,
@@ -49,7 +87,7 @@
 				       unsigned int selector)
 {
 	if (selector < 120) {
-		snprintf(pin_name, MAX_PIN_NAME_LEN, "GPIO_%u", selector);
+		snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector);
 		return pin_name;
 	} else {
 		return msm_pinctrl_pins[selector - 120];
@@ -61,8 +99,12 @@
 	return msm_pinctrl_functions[selector].val;
 }
 
-static struct msm_pinctrl_data qcs404_data = {
-	.pin_data = { .pin_count = 126, },
+static const struct msm_pinctrl_data qcs404_data = {
+	.pin_data = {
+		.pin_count = 126,
+		.pin_offsets = qcs404_pin_offsets,
+		.special_pins_start = 120,
+	},
 	.functions_count = ARRAY_SIZE(msm_pinctrl_functions),
 	.get_function_name = qcs404_get_function_name,
 	.get_function_mux = qcs404_get_function_mux,
diff --git a/drivers/pinctrl/qcom/pinctrl-sdm845.c b/drivers/pinctrl/qcom/pinctrl-sdm845.c
index 9f0f408..76bd8c4 100644
--- a/drivers/pinctrl/qcom/pinctrl-sdm845.c
+++ b/drivers/pinctrl/qcom/pinctrl-sdm845.c
@@ -75,10 +75,11 @@
 	return msm_pinctrl_functions[selector].val;
 }
 
-static struct msm_pinctrl_data sdm845_data = {
+static const struct msm_pinctrl_data sdm845_data = {
 	.pin_data = {
 		.pin_offsets = sdm845_pin_offsets,
-		.pin_count = ARRAY_SIZE(sdm845_pin_offsets),
+		.pin_count = 154,
+		.special_pins_start = 150,
 	},
 	.functions_count = ARRAY_SIZE(msm_pinctrl_functions),
 	.get_function_name = sdm845_get_function_name,
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 26460c4..fbd351a 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -319,6 +319,14 @@
 	  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
+	bool "Qualcomm QUP UART debug"
+	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_MSM_GENI
 	bool "Qualcomm snapdragon"
 	depends on ARCH_SNAPDRAGON
diff --git a/drivers/serial/serial_msm.c b/drivers/serial/serial_msm.c
index f4d9631..ac4280c 100644
--- a/drivers/serial/serial_msm.c
+++ b/drivers/serial/serial_msm.c
@@ -160,29 +160,14 @@
 {
 	uint clk_rate = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
 					"clock-frequency", 115200);
-	uint clkd[2]; /* clk_id and clk_no */
-	int clk_offset;
-	struct udevice *clk_dev;
 	struct clk clk;
 	int ret;
 
-	ret = fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(dev), "clock",
-				   clkd, 2);
-	if (ret)
-		return ret;
-
-	clk_offset = fdt_node_offset_by_phandle(gd->fdt_blob, clkd[0]);
-	if (clk_offset < 0)
-		return clk_offset;
-
-	ret = uclass_get_device_by_of_offset(UCLASS_CLK, clk_offset, &clk_dev);
-	if (ret)
-		return ret;
-
-	clk.id = clkd[1];
-	ret = clk_request(clk_dev, &clk);
-	if (ret < 0)
+	ret = clk_get_by_name(dev, "core", &clk);
+	if (ret < 0) {
+		pr_warn("%s: Failed to get clock: %d\n", __func__, ret);
 		return ret;
+	}
 
 	ret = clk_set_rate(&clk, clk_rate);
 	if (ret < 0)
@@ -218,7 +203,6 @@
 	if (ret)
 		return ret;
 
-	pinctrl_select_state(dev, "uart");
 	uart_dm_init(priv);
 
 	return 0;
@@ -251,4 +235,42 @@
 	.priv_auto	= sizeof(struct msm_serial_data),
 	.probe = msm_serial_probe,
 	.ops	= &msm_serial_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+#ifdef CONFIG_DEBUG_UART_MSM
+
+static struct msm_serial_data init_serial_data = {
+	.base = CONFIG_VAL(DEBUG_UART_BASE),
+	.clk_rate = 7372800,
 };
+
+#include <debug_uart.h>
+
+/* Uncomment to turn on UART clocks when debugging U-Boot as aboot on MSM8916 */
+//int apq8016_clk_init_uart(phys_addr_t gcc_base);
+
+static inline void _debug_uart_init(void)
+{
+	/* Uncomment to turn on UART clocks when debugging U-Boot as aboot on MSM8916 */
+	//apq8016_clk_init_uart(0x1800000);
+	uart_dm_init(&init_serial_data);
+}
+
+static inline void _debug_uart_putc(int ch)
+{
+	struct msm_serial_data *priv = &init_serial_data;
+
+	while (!(readl(priv->base + UARTDM_SR) & UARTDM_SR_TX_EMPTY) &&
+	       !(readl(priv->base + UARTDM_ISR) & UARTDM_ISR_TX_READY))
+		;
+
+	writel(UARTDM_CR_CMD_RESET_TX_READY, priv->base + UARTDM_CR);
+
+	writel(1, priv->base + UARTDM_NCF_TX);
+	writel(ch, priv->base + UARTDM_TF);
+}
+
+DEBUG_UART_FUNCS
+
+#endif
diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c
index 6fb2de8..a379a00 100644
--- a/drivers/usb/dwc3/dwc3-generic.c
+++ b/drivers/usb/dwc3/dwc3-generic.c
@@ -21,6 +21,7 @@
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 #include <malloc.h>
+#include <power/regulator.h>
 #include <usb.h>
 #include "core.h"
 #include "gadget.h"
@@ -47,6 +48,7 @@
 struct dwc3_generic_host_priv {
 	struct xhci_ctrl xhci_ctrl;
 	struct dwc3_generic_priv gen_priv;
+	struct udevice *vbus_supply;
 };
 
 static int dwc3_generic_probe(struct udevice *dev,
@@ -240,11 +242,24 @@
 	if (rc)
 		return rc;
 
+	rc = device_get_supply_regulator(dev, "vbus-supply", &priv->vbus_supply);
+	if (rc)
+		debug("%s: No vbus regulator found: %d\n", dev->name, rc);
+
+	/* Only returns an error if regulator is valid and failed to enable due to a driver issue */
+	rc = regulator_set_enable_if_allowed(priv->vbus_supply, true);
+	if (rc)
+		return rc;
+
 	hccr = (struct xhci_hccr *)priv->gen_priv.base;
 	hcor = (struct xhci_hcor *)(priv->gen_priv.base +
 			HC_LENGTH(xhci_readl(&(hccr)->cr_capbase)));
 
-	return xhci_register(dev, hccr, hcor);
+	rc = xhci_register(dev, hccr, hcor);
+	if (rc)
+		regulator_set_enable_if_allowed(priv->vbus_supply, false);
+
+	return rc;
 }
 
 static int dwc3_generic_host_remove(struct udevice *dev)
@@ -252,9 +267,12 @@
 	struct dwc3_generic_host_priv *priv = dev_get_priv(dev);
 	int rc;
 
-	rc = xhci_deregister(dev);
+	/* This function always returns 0 */
+	xhci_deregister(dev);
+
+	rc = regulator_set_enable_if_allowed(priv->vbus_supply, false);
 	if (rc)
-		return rc;
+		debug("%s: Failed to disable vbus regulator: %d\n", dev->name, rc);
 
 	return dwc3_generic_remove(dev, &priv->gen_priv);
 }
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index dd0d153..98fe7bc 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -9,6 +9,7 @@
 
 #include <common.h>
 #include <dm.h>
+#include <dm/lists.h>
 #include <errno.h>
 #include <usb.h>
 #include <usb/ehci-ci.h>
@@ -119,6 +120,24 @@
 	return 0;
 }
 
+static int ehci_usb_of_bind(struct udevice *dev)
+{
+	ofnode ulpi_node = ofnode_first_subnode(dev_ofnode(dev));
+	ofnode phy_node;
+
+	if (!ofnode_valid(ulpi_node))
+		return 0;
+
+	phy_node = ofnode_first_subnode(ulpi_node);
+	if (!ofnode_valid(phy_node)) {
+		printf("%s: ulpi subnode with no phy\n", __func__);
+		return -ENOENT;
+	}
+
+	return device_bind_driver_to_node(dev, "msm8916_usbphy", "msm8916_usbphy",
+					  phy_node, NULL);
+}
+
 #if defined(CONFIG_CI_UDC)
 /* Little quirk that MSM needs with Chipidea controller
  * Must reinit phy after reset
@@ -132,7 +151,7 @@
 #endif
 
 static const struct udevice_id ehci_usb_ids[] = {
-	{ .compatible = "qcom,ehci-host", },
+	{ .compatible = "qcom,ci-hdrc", },
 	{ }
 };
 
@@ -141,6 +160,7 @@
 	.id	= UCLASS_USB,
 	.of_match = ehci_usb_ids,
 	.of_to_plat = ehci_usb_of_to_plat,
+	.bind = ehci_usb_of_bind,
 	.probe = ehci_usb_probe,
 	.remove = ehci_usb_remove,
 	.ops	= &ehci_usb_ops,