ASR_BASE

Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/marvell/uboot/drivers/usb/phy/mv_usb_phy.c b/marvell/uboot/drivers/usb/phy/mv_usb_phy.c
new file mode 100644
index 0000000..8ba67a5
--- /dev/null
+++ b/marvell/uboot/drivers/usb/phy/mv_usb_phy.c
@@ -0,0 +1,1381 @@
+/*
+ * (C) Copyright 2013
+ * Marvell Semiconductor <www.marvell.com>
+ * Leo Song <liangs@marvell.com>
+ * Yi Zhang <yizhang@marvell.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/config.h>
+#include <usb.h>
+#include <linux/usb/mv-phy.h>
+#include <asm/arch/cpu.h>
+#include <errno.h>
+
+#ifdef CONFIG_ASR_USB3_PHY
+#include "dwc3_regs.h"
+
+#define APMU_REG_BASE		(0xd4282800)
+#define APBSPARE_REG_BASE	(0xd4090000)
+#define EVENT_BUFF_SIZE (128)
+#define DWC3_LOCAL_REG_OFFSET	(0x10000)
+#define DWC3_USB2_DEBUG_REG		(0x4C)
+#define APMU_SD_ROT_WAKE_CLR	(0xd4282800 + 0x7c)
+#define ASR190X_APMU_LINE_STAT	(0xd4282800 + 0x118)
+#define PMUA_RTERM_CAL_REG	(0x3f8)
+#define APB_SPARE_REG24		(0x15c)
+#define USB_VBUS_STS  		(0x1 << 2)
+
+__weak void dwc3_force_usb2_mode(void) {}
+
+#ifdef CONFIG_ASR1901
+static int dwc3_charger_get_vbus(unsigned int *level) 
+{
+	if (readl(ASR190X_APMU_LINE_STAT) & USB_VBUS_STS)
+		*level = 1;
+	else
+		*level = 0;
+	return 0;
+}
+#else
+static int dwc3_charger_get_vbus(unsigned int *level) 
+{
+	if (readl(APMU_SD_ROT_WAKE_CLR) & (0x1 << 15))
+		*level = 1;
+	else
+		*level = 0;
+	return 0;
+}
+#endif
+
+static void dump_phy_regs(u32 base)
+{
+	int i;
+	u32 tmp32;
+	for (i = 0; i < 0x450; i++) {
+		tmp32 = readl((uintptr_t)base + i * 4);
+		printf("[0x%x] = 0x%x\t", (base + i * 4), tmp32);
+		if (i % 5 == 0)
+			printf("\n");
+	}
+}
+
+static int asr_usbphy_dpdm_pulldown(u32 base, bool enable)
+{
+
+	u32 reg32;
+
+	if (enable) {
+		reg32 = readl(base + USB2_PHY0_REG25);
+		reg32 &= ~(PHY_28NMHP_DRV_PULLDOWN_OVERRIDE_MASK);
+		reg32 |= PHY_28NMHP_DRV_PULLDOWN_OVERRIDE_VAL2;
+		writel(reg32, base + USB2_PHY0_REG25);
+
+		/* pullup dp and pulldown dm */
+		reg32 = readl(base + USB2_PHY0_REG29);
+		reg32 |= PHY_28NMHP_DRV_PULLDOWN_OVERRIDE_EN;
+		writel(reg32, base + USB2_PHY0_REG29);
+	} else {
+		/* disable pullup dp and pulldown dm */
+		reg32 = readl(base + USB2_PHY0_REG29);
+		reg32 &= (~PHY_28NMHP_DRV_PULLDOWN_OVERRIDE_EN);
+		writel(reg32, base + USB2_PHY0_REG29);
+	}
+}
+#ifdef CONFIG_ASR1901
+static void asr1901_a0_rterm_cal_porta(u32 base)
+{
+	u32 regval, regval2;
+	u32 apmu_base = APMU_REG_BASE;
+
+	printf("RTERM Test for ASR1901 a0+\n");
+	if (!(readl(base + PUPHY_REG20) & (0x1 << 24))) {
+		printf("skip lane0 rterm calibration: 0x%x\n", readl(base + PUPHY_REG20));
+		return;
+	}
+
+	/* pll_reg2 set to 0xC0 */
+	writel(((readl(base + PUPHY_REG16) & 0xFFFF00FF) | 0xC000), base + PUPHY_REG16);
+
+	/* pll_reg7[5] of lane0, disable select refclk_100_n/p 100Mhz input */
+	writel((readl(base + PUPHY_REG17) & (~(0x1<<21))), base + PUPHY_REG17);
+
+	regval = readl(base + PUPHY_REG11);
+	writel((regval & 0xFFFF0000) | (0x13CB), base + PUPHY_REG11);
+
+	regval = readl(apmu_base + PMUA_RTERM_CAL_REG);
+	if ((regval & (0x1 << 24)) != 0) {
+		printf("USB31 RTERM Done: 0x%x\n", regval);
+	} else {
+		regval = 0xCB00;	/* default manu rterm value */
+		printf("!!!set manu reterm: 0x%x\n", regval);
+	}
+
+	regval2 = readl(base + PUPHY_REG11);
+	writel(((regval2 & 0xFFFFFF00) | ((regval & 0xFF00) >> 8)), base + PUPHY_REG11);
+
+	/* set force_rc_calib */
+	writel(readl(base + PUPHY_REG1E) | (0x1 << 1), base + PUPHY_REG1E);
+}
+
+static void asr1906_rterm_cal_porta(u32 base)
+{
+	u32 regval;
+	int timeout;
+	bool rc_restared = false;
+	u32 apbs_base = APBSPARE_REG_BASE;
+
+do_reterm_cal:
+	printf("RTERM Test for ASR1906\n");
+	if (!(readl(base + PUPHY_REG20) & (0x1 << 24))) {
+		printf("skip lane0 rterm calibration: 0x%x\n", readl(base + PUPHY_REG20));
+		return;
+	}
+
+	timeout = 100;
+	while (timeout--) {
+		regval = readl(base + PUPHY_REG21);
+		if ((regval & (0x3 << 16)) == (0x3 << 16))
+			goto latch_out;
+
+		udelay(1);
+	}
+	if (timeout <= 0) {
+		printf("usbphy rterm cal failed\n");
+		if (!rc_restared) {
+			regval = readl(apbs_base + APB_SPARE_REG24);
+			regval &= ~0x1;
+			writel(regval, apbs_base + APB_SPARE_REG24);
+
+			regval = readl(apbs_base + APB_SPARE_REG24);
+			regval |= 0x1;
+			writel(regval, apbs_base + APB_SPARE_REG24);
+			udelay(100);
+			printf("apbs-reg24: 0x%x\n", readl(apbs_base + APB_SPARE_REG24));
+			rc_restared = true;
+			goto do_reterm_cal;
+		} else {
+			BUG();
+		}
+	}
+
+latch_out:
+	/* latch rterm value */
+	writel((0x1 << 20), base + PUPHY_REG11);
+	printf("PUPHY21: 0x%x PUPHY11: 0x%x\n",
+		readl(base + PUPHY_REG21), readl(base + PUPHY_REG11));
+}
+
+static void asr190x_rterm_calibration(u32 base)
+{
+	if (cpu_is_asr1901())
+		asr1901_a0_rterm_cal_porta(base);
+	else
+		asr1906_rterm_cal_porta(base);
+}
+
+static void usb31_phy_init(u32 base)
+{
+	u32 val;
+	u32 pll_wait_us = 400;
+
+	/*
+	* CONFIG PLL, default puphy clk is 100M clk for pcie
+	* should be config to usb 38.4M
+	*/
+	val = readl(base + PUPHY_REG16);
+	val &= 0xFFFF0FFF;
+	val |= (0x6 << 13); /* 38.4M */
+	writel(val, base + PUPHY_REG16);
+
+	val = readl(base + PUPHY_REG17);
+	val &= (~(0x1 << 21));
+	writel(val, base + PUPHY_REG17);
+
+	val = readl(base + PUPHY_REG03);
+	val |= (0x3 << 8);
+	writel(val, base + PUPHY_REG03);
+
+	if (cpu_is_asr1901())
+		val = 0x18B;
+	else
+		val = 0x18C;
+	writel(val, base + PUPHY_REG1B);
+
+	writel(0x8014, base + PUPHY_REG07);
+#if 0
+	val = readl(base + PUPHY_REG07);
+	val &= ~(0x3ff<<2);
+	val |= ((512 & 0x3ff) << 2);
+	writel(val, base + PUPHY_REG07);
+#endif
+
+	val = readl(base + PUPHY_REG03);
+	val |= (0x1 << 2);
+	writel(val, base + PUPHY_REG03);
+
+	val = 0x97dfdf30;
+	writel(val, base + PUPHY_REG18);
+
+	val = readl(base + PUPHY_REG19);
+	val &= ~(0x1 << 5 | 0x1 << 6);
+	writel(val, base + PUPHY_REG19);
+
+
+	/* USB PHY config
+	* step.1
+	* config phphy, sw init done, ref clk cfg=2
+	* open allclk en bits
+	*/
+	writel(0xB7C, base + PUPHY_REG02);
+
+	/* step.2 wait for PUPHY PLL READY */
+	while((readl(base + PUPHY_REG02) & 0x1) != 0x1)
+	{
+		udelay(1);
+		pll_wait_us--;
+		if (pll_wait_us == 0)
+			break;
+	}
+
+	/* step.3 override pipe_phystatus to 0 if puphy pll not ready */
+	if (pll_wait_us == 0) {
+		dwc3_force_usb2_mode();
+		writel((readl(base + PUPHY_REG10) | (0x1 << 10)), base + PUPHY_REG10);
+	}
+	
+	/* settings for u1/u2/u3 */
+	if (!cpu_is_asr1901_z1()) {
+		val = readl(base + PUPHY_REG15);
+		val &= ~(0xF << 16);
+		val |= (0x3 << 16); /*  */
+		writel(val, base + PUPHY_REG15);
+
+		val = readl(base + PUPHY_REG07);
+		val &= ~(0x3ff << 2);
+		val |= (200 << 2); /*  */
+		writel(val, base + PUPHY_REG07);
+			
+		if (cpu_is_asr1901_z2()) {		
+			val = readl(base + PUPHY_REG2D);
+			val &= ~(0x7 << 22);
+			val |= (0X7 << 22); /* tx swing */
+			writel(val, base + PUPHY_REG2D);
+		} else if (cpu_is_asr1901_a0_plus()) {
+			val = readl(base + PUPHY_REG2D);
+			val &= ~(0x1ff << 16);
+			val |= (0X1C0 << 16); /* old rxeq value */
+			writel(val, base + PUPHY_REG2D);
+		} else if (cpu_is_asr1906()) {
+			val = readl(base + PUPHY_REG2D);
+			val &= ~(0x1ff << 16);
+			val |= (0X1f6 << 16); /* rxeq */
+			writel(val, base + PUPHY_REG2D);
+		} else {
+			val = readl(base + PUPHY_REG2D);
+			val &= ~(0x1ff << 16);
+			val |= (0X1f6 << 16); /* rxeq */
+			writel(val, base + PUPHY_REG2D);
+		}
+	}
+	/* Write 1s to clear phy err status */
+	writel(0xFFFFFFFF, base + PUPHY_REG04);
+
+	/* step.4 wait for USB2 PHY PLL READY */
+	pll_wait_us = 400;
+	while (((readl(base + USB2_PHY0_REG01) & USB2_PLL_BIT_RDY) != USB2_PLL_BIT_RDY)
+		&& (pll_wait_us--))
+	{
+		udelay(1);
+	}
+
+	/*
+	* Step 5&6
+	* Release usb2 phy internal reset and enable clock gating
+	*/
+	writel(0x60ef, base + USB2_PHY0_REG01);
+	writel(0x1C, base + USB2_PHY0_REG0D);
+
+	/* STEP.7
+	* 0x1: serial mode, 0x0: parallel mode
+	* USB2_PHY0_REG06	(USB2_BASE+0x18)
+	*
+	* serial mode
+	* writel((readl(base + USB2_PHY0_REG06) | 0x1), base + USB2_PHY0_REG06);
+	* parallel mode
+	*/
+	writel((readl(base + USB2_PHY0_REG06) & (~0x1)), base + USB2_PHY0_REG06);
+
+	/* Write 1s to clear phy err status */
+	writel(0xFFFFFFFF, base + USB2_PHY0_REG0E);
+	
+	asr190x_rterm_calibration(base);
+}
+
+#endif
+static int asr_usb3_phy_init(u32 base)
+{
+	u32 pll_wait_us = 400;
+
+#ifdef CONFIG_ASR1901
+	usb31_phy_init(base);
+	return;
+#endif
+
+	/*
+	* step.0 clear drv_pulldown_override_en
+	*/
+	writel(readl(base + USB2_PHY0_REG29) & (~PHY_28NMHP_DRV_PULLDOWN_OVERRIDE_EN), base + USB2_PHY0_REG29);
+
+	if (cpu_is_asr1903())
+		goto usb2_phy_init;
+
+	/* USB PHY config
+	* step.1
+	* config phphy, sw init done, ref clk cfg=2
+	* open allclk en bits
+	*/
+	writel(0x97C, base + PUPHY_REG02);
+
+	/* step.2 wait for PUPHY PLL READY */
+	while((readl(base + PUPHY_REG02) & 0x1) != 0x1)
+	{
+		udelay(1);
+		pll_wait_us--;
+		if (pll_wait_us == 0)
+			break;
+	}
+
+	/* step.3 override pipe_phystatus to 0 if puphy pll not ready */
+	if (pll_wait_us == 0) {
+		dwc3_force_usb2_mode();
+		writel((readl(base + PUPHY_REG10) | (0x1 << 10)), base + PUPHY_REG10);
+	}
+
+usb2_phy_init:
+	/* step.4 wait for USB2 PHY PLL READY */
+	pll_wait_us = 400;
+	while (((readl(base + USB2_PHY0_REG01) & USB2_PLL_BIT_RDY) != USB2_PLL_BIT_RDY)
+		&& (pll_wait_us--))
+	{
+		udelay(1);
+	}
+
+	/* 
+	* Step 5&6
+	* Release usb2 phy internal reset and enable clock gating
+	*/
+	writel(0x60ef, base + USB2_PHY0_REG01);
+	writel(0x1C, base + USB2_PHY0_REG0D);
+
+	/*
+	* STEP.7
+	* 0x1: serial mode, 0x0: parallel mode
+	* USB2_PHY0_REG06	(USB2_BASE+0x18)
+	*
+	* serial mode
+	* writel((readl(base + USB2_PHY0_REG06) | 0x1), base + USB2_PHY0_REG06);
+	* parallel mode
+	*
+	* set to serial mode for stability
+	*/
+	writel(readl(base + USB2_PHY0_REG06) | (0x1), base + USB2_PHY0_REG06);
+
+	printf("usb phy inited!\n");
+	return 0;
+}
+static const char *charger_type(unsigned int type)
+{
+	switch (type) {
+	case NULL_CHARGER: return "NULL_CHARGER";
+	case DEFAULT_CHARGER: return "DEFAULT_CHARGER";
+	case DCP_CHARGER: return "DCP_CHARGER";
+	case CDP_CHARGER: return "CDP_CHARGER";
+	case SDP_CHARGER: return "SDP_CHARGER";
+	default: return "NONE_STANDARD_CHARGER";
+	}
+}
+
+static int _mv_usb2_phy_28nmhp_charger_detect(u32 base)
+{
+	int charger_type_bc12 = NULL_CHARGER;
+	u32 reg32;
+
+	reg32 = readl(base + PHY_28NMHP_PHY_REG25);
+	reg32 &= ~(PHY_28NMHP_DRV_PULLDOWN_OVERRIDE_MASK);
+	reg32 |= PHY_28NMHP_DRV_PULLDOWN_OVERRIDE_VAL;
+	writel(reg32, base + PHY_28NMHP_PHY_REG25);
+
+	reg32 = readl(base + PHY_28NMHP_PHY_REG25);
+	reg32 &= ~PHY_28NMHP_DCP_DET_PULL_MASK;
+	reg32 |= PHY_28NMHP_DCP_DET_PULL_UP_DOWN;
+	writel(reg32, base + PHY_28NMHP_PHY_REG25);
+
+	reg32 = readl(base + PHY_28NMHP_PHY_REG29);
+	reg32 |= PHY_28NMHP_DRV_PULLDOWN_OVERRIDE_EN;
+	writel(reg32, base + PHY_28NMHP_PHY_REG29);
+
+	udelay(10);
+	reg32 = readl(base + PHY_28NMHP_PHY_REG04);
+	reg32 &= ~(0xff << 8);
+	reg32 |= (0x12 << 8);
+	writel(reg32, base + PHY_28NMHP_PHY_REG04);
+
+	if (cpu_is_asr1903()) {
+		if ((readl(APMU_SD_ROT_WAKE_CLR) & (0x3 << 26)) == (0x1 << 26))
+			charger_type_bc12 = NONE_STANDARD_CHARGER;
+		else
+			charger_type_bc12 = DCP_CHARGER;
+#ifdef CONFIG_ASR1901
+	} else if (cpu_is_asr1901() || cpu_is_asr1906()) {
+			if ((readl(ASR190X_APMU_LINE_STAT) & (0x3 << 0)) == (0x1 << 0))
+				charger_type_bc12 = NONE_STANDARD_CHARGER;
+			else
+				charger_type_bc12 = DCP_CHARGER;
+#endif
+	} else {
+		if ((readl(CONFIG_USB_REG_BASE + DWC3_LOCAL_REG_OFFSET + DWC3_USB2_DEBUG_REG) 
+			& (0x3 << 8)) == (0x1 << 8))
+			charger_type_bc12 = NONE_STANDARD_CHARGER;
+		else
+			charger_type_bc12 = DCP_CHARGER;
+	}
+
+	reg32 = readl(base + PHY_28NMHP_PHY_REG29);
+	reg32 &= ~PHY_28NMHP_DRV_PULLDOWN_OVERRIDE_EN;
+	writel(reg32, base + PHY_28NMHP_PHY_REG29);
+
+	return charger_type_bc12;
+}
+
+static int has_rst_event(u32 *buff, int size)
+{
+	int i;
+
+	for (i = 0; i < size; i++) {
+		if (buff[i] == 0x101)
+			return 1;
+	}
+	return 0;
+}
+static int dwc3_controller_stop(u32 base)
+{
+	u32 regval;
+
+	regval = 0x0;
+	writel(regval, base + DWC3_DEVTEN);
+
+	writel(readl(base + DWC3_GEVNTCOUNT(0)), DWC3_GEVNTCOUNT(0));
+	regval = readl(base + DWC3_DCTL);
+	regval &= (~DWC3_DCTL_RUN_STOP);
+	writel(regval, base + DWC3_DCTL);
+
+	writel(readl(base + DWC3_GEVNTCOUNT(0)), DWC3_GEVNTCOUNT(0));
+	regval = readl(base + DWC3_DCTL);
+	regval &= (~DWC3_DCTL_RUN_STOP);
+	writel(regval, base + DWC3_DCTL);
+	udelay(50);
+
+	return 0;
+}
+
+static int dwc3_sdp_charger_init(u32 base, int *charger_type)
+{
+	u32 regval, event_count, level;
+	u32 timeout;
+	static u32 event_buff = 0;
+
+	if (event_buff == 0) {
+		event_buff = memalign(64, EVENT_BUFF_SIZE);
+		if (!event_buff) {
+			printf("%s: malloc failure\n", __func__);
+			return 0;
+		}
+	}
+	memset(event_buff, 0x00, EVENT_BUFF_SIZE);
+	flush_dcache_range(event_buff, event_buff + EVENT_BUFF_SIZE);
+
+	/* SOFT RESET CONTROLLER */
+	regval = readl(base + DWC3_DCTL);
+	regval |= DWC3_DCTL_CSFTRST;
+	writel(regval, base + DWC3_DCTL);
+	/* worst case: delay 200ms to align with code in linux */
+	timeout = 50000;
+	do {
+		regval = readl(base + DWC3_DCTL);
+		if (!(regval & DWC3_DCTL_CSFTRST))
+			break;
+		udelay(4);
+	} while (--timeout);
+	/* make sure 3 phy clk delay before accessing phy */
+	udelay(5);
+
+	/* disable dpdm pull down */
+	asr_usbphy_dpdm_pulldown(CONFIG_USB_PHY_BASE, 0);
+
+	/* use mac2_clk as mac3_clk */
+	regval = readl(base + DWC3_GUCTL1);
+	regval |= (0x1 << 26);
+	writel(regval, base + DWC3_GUCTL1);
+
+	regval = 0x40002407;
+	writel(regval, base + DWC3_GUSB2PHYCFG(0));
+
+	/* dwc3_core_setup_global_control */
+	/* BIT[13:12]-10: SET AS DEVICE MODE */
+	regval = (1625<<19)|(0x2204);
+	writel(regval, base + DWC3_GCTL);
+
+	regval = 0x480800;		/* HS mode */
+	writel(regval, base + DWC3_DCFG);
+
+	writel(event_buff, base + DWC3_GEVNTADRLO(0));
+	writel(0x0, base + DWC3_GEVNTADRHI(0));
+	writel(EVENT_BUFF_SIZE, base + DWC3_GEVNTSIZ(0));
+	writel(0x0, base + DWC3_GEVNTCOUNT(0));
+	printf("event buffer: 0x%x\n\r", event_buff);
+
+	regval = readl(base + DWC3_DEVTEN);
+	regval |= 0x1f;
+	writel(regval, base + DWC3_DEVTEN);
+
+	regval = readl(base + DWC3_DCTL);
+	regval |= DWC3_DCTL_RUN_STOP;
+	writel(regval, base + DWC3_DCTL);
+
+	timeout = 800 / 10; /* leave sometime for dcp charger handling */
+	while(timeout--) {
+		dwc3_charger_get_vbus(&level);
+		if (level == 0) {
+			printf("usb plugout\r\n");
+			*charger_type = NULL_CHARGER;
+			dwc3_controller_stop(base);
+			return 0;
+		}
+		mdelay(10);
+		regval = readl(base + DWC3_DSTS);
+		debug("DWC3_DSTS: 0x%x\n", regval);
+		regval = regval & DWC3_DSTS_CONNECTSPD;
+
+		event_count = readl(base + DWC3_GEVNTCOUNT(0)) & DWC3_GEVNTCOUNT_MASK;
+		debug("DWC3_GEVNTCOUNT(0): 0x%x\n", event_count);
+		if (regval == DWC3_DSTS_HIGHSPEED) {
+			*charger_type = SDP_CHARGER;
+			dwc3_controller_stop(base);
+			return 0;
+		}
+
+		if (event_count >= 0x10) {
+			invalidate_dcache_range(event_buff, event_buff + EVENT_BUFF_SIZE);
+			if (has_rst_event((u32 *)event_buff, (event_count >> 2))) {
+				*charger_type = SDP_CHARGER;
+				dwc3_controller_stop(base);
+				return 0;
+			}
+		}
+	}
+	/* quick charger */
+	if (event_count >= 0xc) {
+		*charger_type = DCP_CHARGER;
+		dwc3_controller_stop(base);
+		return 0;
+	}
+
+	dwc3_controller_stop(base);
+	return -EIO;
+}
+
+int get_usb_charger_type(void)
+{
+	unsigned int level = 0;
+	static int usb_charger_type = NULL_CHARGER;
+	u32 regval, base = CONFIG_USB_REG_BASE;
+	static bool usb_phy_inited = false;
+
+	dwc3_charger_get_vbus(&level);
+	if (level == 0) {
+		printf("usb_charger_type is NULL_CHARGER\n");
+		usb_charger_type = NULL_CHARGER;
+		goto out;
+	}
+
+	if (usb_charger_type != NULL_CHARGER) {
+		printf("noplugout: ");
+		goto out;
+	}
+
+	if (!usb_phy_inited) {
+		regval = readl(base + DWC3_GUSB3PIPECTL(0));
+		regval &= ~DWC3_GUSB3PIPECTL_SUSPHY;
+		writel(regval, base + DWC3_GUSB3PIPECTL(0));
+		asr_usb3_phy_init(CONFIG_USB_PHY_BASE);
+		usb_phy_inited = true;
+	}
+
+	if (!dwc3_sdp_charger_init(CONFIG_USB_REG_BASE, &usb_charger_type)) {
+		goto out;
+	} else {
+		usb_charger_type = _mv_usb2_phy_28nmhp_charger_detect(
+				CONFIG_USB_PHY_BASE);
+	}
+
+out:
+	/* enable dpdm pull down */
+	asr_usbphy_dpdm_pulldown(CONFIG_USB_PHY_BASE, 1);
+	printf("charger: %s\r\n",
+			charger_type(usb_charger_type));
+	return usb_charger_type;
+}
+
+int usb_vbus_is_online(void) 
+{
+	u32 level = 0;
+
+	dwc3_charger_get_vbus(&level);
+	return level;
+}
+#endif
+
+#ifdef CONFIG_MRVL_USB_PHY_28HP
+#define APMU_SD_ROT_WAKE_CLR	(0xd4282800 + 0x7c)
+#define APMU_USB_CLK_RES_CTRL	(0xd4282800 + 0x5c)
+
+#define DWC2_USB_REG_BASE CONFIG_USB_REG_BASE
+#define DWC2_USB_GOTGCTL                     (DWC2_USB_REG_BASE + 0x0000)
+#define DWC2_USB_GOTGINT                     (DWC2_USB_REG_BASE + 0x0004)
+#define DWC2_USB_GAHBCFG                     (DWC2_USB_REG_BASE + 0x0008)
+#define DWC2_USB_GUSBCFG                     (DWC2_USB_REG_BASE + 0x000c)
+#define DWC2_USB_GRSTCTL                     (DWC2_USB_REG_BASE + 0x0010)
+#define DWC2_USB_GINTSTS                     (DWC2_USB_REG_BASE + 0x0014)
+#define DWC2_USB_GINTMSK                     (DWC2_USB_REG_BASE + 0x0018)
+#define DWC2_USB_GRXSTSR                     (DWC2_USB_REG_BASE + 0x001c)
+#define DWC2_USB_GRXSTSP                     (DWC2_USB_REG_BASE + 0x0020)
+#define DWC2_USB_GRXFSIZ                     (DWC2_USB_REG_BASE + 0x0024)
+#define DWC2_USB_GNPTXFSIZ                   (DWC2_USB_REG_BASE + 0x0028)
+#define DWC2_USB_GNPTXSTS                    (DWC2_USB_REG_BASE + 0x002c)
+#define DWC2_USB_GI2CCTL                     (DWC2_USB_REG_BASE + 0x0030)
+#define DWC2_USB_GPVNDCTL                    (DWC2_USB_REG_BASE + 0x0034)
+#define DWC2_USB_GGPIO                       (DWC2_USB_REG_BASE + 0x0038)
+#define DWC2_USB_GUID                        (DWC2_USB_REG_BASE + 0x003c)
+#define DWC2_USB_GSNPSID                     (DWC2_USB_REG_BASE + 0x0040)
+#define DWC2_USB_GHWCFG1                     (DWC2_USB_REG_BASE + 0x0044)
+#define DWC2_USB_GHWCFG2                     (DWC2_USB_REG_BASE + 0x0048)
+#define DWC2_USB_GHWCFG3                     (DWC2_USB_REG_BASE + 0x004c)
+#define DWC2_USB_GHWCFG4                     (DWC2_USB_REG_BASE + 0x0050)
+#define DWC2_USB_GLPMCFG                     (DWC2_USB_REG_BASE + 0x0054)
+#define DWC2_USB_HPTXFSIZ                    (DWC2_USB_REG_BASE + 0x0100)
+#define DWC2_USB_DPTXFSIZ(n)                 (DWC2_USB_REG_BASE + 0x0104+(n-1)*0x04)
+#define DWC2_USB_DIEPTXF(n)                  (DWC2_USB_REG_BASE + 0x0104+(n-1)*0x04)
+#define DWC2_USB_DCFG                        (DWC2_USB_REG_BASE + 0x0800)
+#define DWC2_USB_DCTL                        (DWC2_USB_REG_BASE + 0x0804)
+#define DWC2_USB_DSTS                        (DWC2_USB_REG_BASE + 0x0808)
+#define DWC2_USB_DIEPMSK                     (DWC2_USB_REG_BASE + 0x0810)
+#define DWC2_USB_DOEPMSK                     (DWC2_USB_REG_BASE + 0x0814)
+#define DWC2_USB_DAINT                       (DWC2_USB_REG_BASE + 0x0818)
+#define DWC2_USB_DAINTMSK                    (DWC2_USB_REG_BASE + 0x081c)
+
+__weak int charger_get_vbus(unsigned int *level)
+{
+	if (readl(APMU_SD_ROT_WAKE_CLR) & (0x1 << 15))
+		*level = 1;
+	else
+		*level = 0;
+
+	return 0;
+}
+
+static void dump_phy_regs(u32 base)
+{
+	int i;
+	u32 tmp32;
+	for (i = 0; i < 0x3f; i++) {
+		tmp32 = readl((uintptr_t)base + i * 4);
+		printf("[0x%x] = 0x%x\t", (base + i * 4), tmp32);
+		if (i % 5 == 0)
+			printf("\n");
+	}
+}
+
+static int asr_usb_phy_28nmhp_dpdm_pulldown(u32 base)
+{
+
+	u32 reg32;
+
+	reg32 = readl(base + PHY_28NMHP_PHY_REG25);
+	reg32 &= ~(PHY_28NMHP_DRV_PULLDOWN_OVERRIDE_MASK);
+	reg32 |= PHY_28NMHP_DRV_PULLDOWN_OVERRIDE_VAL2;
+	writel(reg32, base + PHY_28NMHP_PHY_REG25);
+
+	if (cpu_is_asr1802s()) {
+		reg32 = readl(base + PHY_28NMHP_PHY_REG28);
+		reg32 |= PHY_28NMHP_DRV_PULLDOWN_OVERRIDE_EN;
+		writel(reg32, base + PHY_28NMHP_PHY_REG28);
+	} else {
+		/* pullup dp and pulldown dm */
+		reg32 = readl(base + PHY_28NMHP_PHY_REG29);
+		reg32 |= PHY_28NMHP_DRV_PULLDOWN_OVERRIDE_EN;
+		writel(reg32, base + PHY_28NMHP_PHY_REG29);
+	}
+	return 0;
+}
+
+static int mrvl_usb_phy_28nmhp_init(u32 base)
+{
+	unsigned int loops = 200;
+	unsigned int val;
+
+	/* WAIT FOR PHY PLL RDY */
+	while (((readl(base + PHY_28NMHP_PHY_REG01) & PHY_28NMHP_PLL_BIT_RDY) !=
+			PHY_28NMHP_PLL_BIT_RDY)
+			&& (loops--))
+		udelay(1);
+	if (loops == 0)
+		printf("!!!!!!!!!!phy pll not ready after 200us\n");
+
+	/* Release usb2 phy internal reset and enable clock gating */
+	writel(0x60ef, base + PHY_28NMHP_PHY_REG01);
+	writel(0x1C, base + PHY_28NMHP_PHY_REG0D);
+	/*
+	* This is 1802s only 
+	* 1803 has new reg -> threshold map table
+	* HS RX sequelch threshold: 4 -> 7 for yield rate
+	*/
+	if (cpu_is_asr1802s()) {
+		writel(readl(base + PHY_28NMHP_PHY_REG28) & (~PHY_28NMHP_DRV_PULLDOWN_OVERRIDE_EN), base + PHY_28NMHP_PHY_REG28);
+		writel(0x7468, base + PHY_28NMHP_PHY_REG23);
+	} else if (cpu_is_asr1803() || cpu_is_asr1806()) {
+		writel(readl(base + PHY_28NMHP_PHY_REG29) & (~PHY_28NMHP_DRV_PULLDOWN_OVERRIDE_EN), base + PHY_28NMHP_PHY_REG29);
+		/* set to serial mode for stability */
+		writel(readl(base + PHY_28NMHP_PHY_REG06) | (0x1), base + PHY_28NMHP_PHY_REG06);
+
+		/* increase tx dac by 10%, will add back for some special cases */
+		/* writel((readl(base + PHY_28NMHP_PHY_REG29) & (~0x1F)) | (0x1B), base + PHY_28NMHP_PHY_REG29); */
+	}
+
+	val = readl(base + PHY_28NMHP_PHY_REG0A);
+	val &= ~(PHY_28NMHP_SUSPEND_PLL | PHY_28NMHP_SUSPEND_PHY);
+	writel(val, base + PHY_28NMHP_PHY_REG0A);
+
+	if (cpu_is_asr1806()) {
+		val = readl(APMU_USB_CLK_RES_CTRL);
+		val |= (0x1 << 2);
+		writel(val, APMU_USB_CLK_RES_CTRL);
+	}
+	printf("usb phy inited!\n");
+	return 0;
+}
+static const char *charger_type(unsigned int type)
+{
+	switch (type) {
+	case NULL_CHARGER: return "NULL_CHARGER";
+	case DEFAULT_CHARGER: return "DEFAULT_CHARGER";
+	case DCP_CHARGER: return "DCP_CHARGER";
+	case CDP_CHARGER: return "CDP_CHARGER";
+	case SDP_CHARGER: return "SDP_CHARGER";
+	default: return "NONE_STANDARD_CHARGER";
+	}
+}
+
+static int _mv_usb2_phy_28nmhp_charger_detect(u32 base)
+{
+	int charger_type_bc12 = NONE_STANDARD_CHARGER;
+	u32 reg32;
+
+	reg32 = readl(base + PHY_28NMHP_PHY_REG25);
+	reg32 &= ~(PHY_28NMHP_DRV_PULLDOWN_OVERRIDE_MASK);
+	reg32 |= PHY_28NMHP_DRV_PULLDOWN_OVERRIDE_VAL;
+	writel(reg32, base + PHY_28NMHP_PHY_REG25);
+
+	if (cpu_is_asr1802s()) {
+		reg32 = readl(base + PHY_28NMHP_PHY_REG28);
+		reg32 |= PHY_28NMHP_DRV_PULLDOWN_OVERRIDE_EN;
+		writel(reg32, base + PHY_28NMHP_PHY_REG28);
+	} else {
+		/* pullup dp and pulldown dm */
+		reg32 = readl(base + PHY_28NMHP_PHY_REG25);
+		reg32 &= ~PHY_28NMHP_DCP_DET_PULL_MASK;
+		reg32 |= PHY_28NMHP_DCP_DET_PULL_UP_DOWN;
+		writel(reg32, base + PHY_28NMHP_PHY_REG25);
+
+		reg32 = readl(base + PHY_28NMHP_PHY_REG29);
+		reg32 |= PHY_28NMHP_DRV_PULLDOWN_OVERRIDE_EN;
+		writel(reg32, base + PHY_28NMHP_PHY_REG29);
+	}
+
+	udelay(10);
+	if ((readl(CONFIG_USB_REG_BASE + 0x184) & (0x3 << 10)) == (0x2 << 10))
+		charger_type_bc12 = NONE_STANDARD_CHARGER;
+	else
+		charger_type_bc12 = DCP_CHARGER;
+
+	if (cpu_is_asr1802s()) {
+		reg32 = readl(base + PHY_28NMHP_PHY_REG28);
+		reg32 &= ~PHY_28NMHP_DRV_PULLDOWN_OVERRIDE_EN;
+		writel(reg32, base + PHY_28NMHP_PHY_REG28);
+	} else {
+		reg32 = readl(base + PHY_28NMHP_PHY_REG29);
+		reg32 &= ~PHY_28NMHP_DRV_PULLDOWN_OVERRIDE_EN;
+		writel(reg32, base + PHY_28NMHP_PHY_REG29);
+	}
+
+	return charger_type_bc12;
+}
+
+static inline dwc2_writel(u32 reg, u32 value)
+{
+	writel(value, reg);
+}
+
+static int dwc2_get_charger_type(void)
+{
+	static int asr18xx_usb_charger_type = NULL_CHARGER;
+	int timeout = 8000;
+	u32 value;
+
+	timeout = 0;
+	do {
+		value = readl(DWC2_USB_GRSTCTL);
+		if (++timeout > 100000) {
+			printf("DWC2_USB_GRSTCTL timeout\n");
+			break;
+		}
+		udelay(1); /* 1us */
+	} while ((value & (0x1 << 31)) == 0);
+
+	timeout = 0;
+	dwc2_writel(DWC2_USB_GRSTCTL, 0x80000001);
+	do {
+		value = readl(DWC2_USB_GRSTCTL);
+		if (++timeout > 100000) {
+			printf("DWC2_USB_GRSTCTL RST timeout\n");
+			break;
+		}
+		udelay(1); /* 1us */
+	} while (value & 0x1);
+
+	dwc2_writel(DWC2_USB_GUSBCFG, 0x40001400);
+	dwc2_writel(DWC2_USB_GOTGCTL, 0x900c0);
+	dwc2_writel(DWC2_USB_GAHBCFG, 0x27);
+	dwc2_writel(DWC2_USB_GUSBCFG, 0x40002400);
+	dwc2_writel(DWC2_USB_DCFG, 0x8100000);
+	dwc2_writel(DWC2_USB_GRXFSIZ, 0x200);
+	dwc2_writel(DWC2_USB_GNPTXFSIZ, 0x200200);
+	dwc2_writel(DWC2_USB_DPTXFSIZ(1), 0x2000220);
+	dwc2_writel(DWC2_USB_DPTXFSIZ(2), 0x2000420);
+	dwc2_writel(DWC2_USB_DPTXFSIZ(3), 0x2000620);
+	dwc2_writel(DWC2_USB_DPTXFSIZ(4), 0x2000820);
+	dwc2_writel(DWC2_USB_DPTXFSIZ(5), 0x2000a20);
+	dwc2_writel(DWC2_USB_DPTXFSIZ(6), 0x2000c20);
+	dwc2_writel(DWC2_USB_DPTXFSIZ(7), 0x1000e20);
+	dwc2_writel(DWC2_USB_DPTXFSIZ(8), 0x1000f20);
+	dwc2_writel(DWC2_USB_DPTXFSIZ(9), 0x1001020);
+	dwc2_writel(DWC2_USB_DPTXFSIZ(10), 0x1001120);
+	dwc2_writel(DWC2_USB_DPTXFSIZ(11), 0x1001220);
+	dwc2_writel(DWC2_USB_DPTXFSIZ(12), 0x1001320);
+	dwc2_writel(DWC2_USB_DPTXFSIZ(13), 0x1001420);
+	dwc2_writel(DWC2_USB_DPTXFSIZ(14), 0x1001520);
+	dwc2_writel(DWC2_USB_DPTXFSIZ(15), 0x1001620);
+	dwc2_writel(DWC2_USB_GINTMSK, 0x0);
+	dwc2_writel(DWC2_USB_GINTSTS, 0xffffffff);
+	dwc2_writel(DWC2_USB_GINTMSK, 0xc3000);
+	dwc2_writel(DWC2_USB_DCTL, 0x0);
+
+	timeout = 9000;
+	while(timeout --) {
+		if (readl(DWC2_USB_GINTSTS) & (0x3 << 10)) {
+			asr18xx_usb_charger_type = SDP_CHARGER;
+			printf("gintsts: 0x%x\n", readl(DWC2_USB_GINTSTS));
+			goto out;		
+		}
+
+		udelay(100);
+	}
+	asr18xx_usb_charger_type = DCP_CHARGER;
+
+out:
+	dwc2_writel(DWC2_USB_DCTL, 0x2);
+	asr_usb_phy_28nmhp_dpdm_pulldown(CONFIG_USB_PHY_BASE);
+	printf("usb_charger_type is %s\r\n",
+			charger_type(asr18xx_usb_charger_type));
+	return asr18xx_usb_charger_type;
+}
+
+int get_usb_charger_type(void)
+{
+	unsigned int level = 0;
+	static int asr18xx_usb_charger_type = NULL_CHARGER;
+	int timeout = 8000;
+
+	charger_get_vbus(&level);
+	if (level == 0) {
+		printf("usb_charger_type is NULL_CHARGER\n");
+		return NULL_CHARGER;
+	}
+
+	if (asr18xx_usb_charger_type != NULL_CHARGER)
+		return asr18xx_usb_charger_type;
+
+	mrvl_usb_phy_28nmhp_init(CONFIG_USB_PHY_BASE);
+	if (cpu_is_asr1806())
+		return dwc2_get_charger_type();
+
+	writel(readl(CONFIG_USB_REG_BASE + 0x140) | (0x1 << 1),
+			CONFIG_USB_REG_BASE + 0x140);
+	udelay(200);
+
+	writel(readl(CONFIG_USB_REG_BASE + 0x144) | (0x1 << 6),
+		CONFIG_USB_REG_BASE + 0x144);
+	udelay(10);
+
+	writel((readl(CONFIG_USB_REG_BASE + 0x1A8) & (~0x3)) | 0x2,
+		CONFIG_USB_REG_BASE + 0x1A8);
+
+	writel(readl(CONFIG_USB_REG_BASE + 0x140) | (0x1 << 0),
+			CONFIG_USB_REG_BASE + 0x140);
+
+	while(timeout --) {
+		if (readl(CONFIG_USB_REG_BASE + 0x144) & (0x1 << 6)) {
+			asr18xx_usb_charger_type = SDP_CHARGER;
+			goto out;		
+		}
+
+		udelay(100);
+	}
+
+	writel(readl(CONFIG_USB_REG_BASE + 0x140) & (~0x1),
+				CONFIG_USB_REG_BASE + 0x140);
+	asr18xx_usb_charger_type = _mv_usb2_phy_28nmhp_charger_detect(
+		CONFIG_USB_PHY_BASE);
+
+out:
+	writel(readl(CONFIG_USB_REG_BASE + 0x140) & (~0x1),
+				CONFIG_USB_REG_BASE + 0x140);
+	asr_usb_phy_28nmhp_dpdm_pulldown(CONFIG_USB_PHY_BASE);
+	printf("usb_charger_type is %s\r\n",
+			charger_type(asr18xx_usb_charger_type));
+	return asr18xx_usb_charger_type;
+}
+
+int usb_vbus_is_online(void) 
+{
+	if (readl(APMU_SD_ROT_WAKE_CLR) & (0x1 << 15))
+		return 1;
+	else
+		return 0;
+}
+#endif
+
+#ifdef CONFIG_MRVL_USB_PHY_28LP
+#define APMU_SD_ROT_WAKE_CLR	(0xd4282800 + 0x7c)
+__weak int charger_get_vbus(unsigned int *level)
+{
+	if (readl(APMU_SD_ROT_WAKE_CLR) & (0x1 << 15))
+		*level = 1;
+	else
+		*level = 0;
+
+	return 0;
+}
+
+static void dump_phy_regs(u32 base)
+{
+	int i;
+	u32 tmp32;
+	for (i = 0; i < 0x3f; i++) {
+		tmp32 = readl((uintptr_t)base + i * 4);
+		printf("[0x%x] = 0x%x\t", (base + i * 4), tmp32);
+		if (i % 5 == 0)
+			printf("\n");
+	}
+}
+
+static int wait_for_phy_ready(struct usb_file *file)
+{
+	u32 tmp, done_mask;
+	int count = 0;
+	/*
+	 * polling calibration done?
+	 * 0xd420_7018[31] = 0x1;
+	 * 0xd420_7008[31] = 0x1;
+	 * 0xd420_7008[23] = 0x1;
+	 */
+
+	/* IMP Calibrate */
+	writel(readl(&file->cal_reg) |
+		IMPCAL_START, &file->cal_reg);
+	/* Wait For Calibrate PHY */
+	udelay(400);
+	/* Make sure PHY Calibration is ready */
+	do {
+		tmp = readl(&file->cal_reg);
+		done_mask = IMPCAL_DONE_MASK;
+		tmp &= done_mask;
+		if (tmp == IMPCAL_DONE(1))
+			break;
+		udelay(1000);
+	} while ((count++) && (count < 100));
+        if (count >= 100)
+                printf("USB PHY Calibrate not done after 100mS.");
+        writel(readl(&file->cal_reg) &
+                (~IMPCAL_START), &file->cal_reg);
+
+        /* PLL Calibrate */
+	writel(readl(&file->cal_reg) |
+		PLLCAL_START, &file->cal_reg);
+	udelay(400);
+	count = 0;
+	do {
+		tmp = readl(&file->cal_reg);
+		done_mask = PLLCAL_DONE_MASK;
+		tmp &= done_mask;
+		if (tmp == PLLCAL_DONE(1))
+			break;
+		udelay(1000);
+	} while ((count++) && (count < 100));
+	if (count >= 100)
+		printf("USB PHY Calibrate not done after 100mS.");
+	writel(readl(&file->cal_reg) &
+		(~PLLCAL_START), &file->cal_reg);
+
+	/* SQ Calibrate */
+	writel(readl(&file->rx_reg1) |
+		SQCAL_START, &file->rx_reg1);
+	/* Wait For Calibrate PHY */
+	udelay(400);
+	/* Make sure PHY Calibration is ready */
+	count = 0;
+	do {
+		tmp = readl(&file->rx_reg1);
+		done_mask = SQCAL_DONE_MASK;
+		tmp &= done_mask;
+		if (tmp == SQCAL_DONE(1))
+			break;
+		udelay(1000);
+	} while ((count++) && (count < 100));
+	if (count >= 100)
+		printf("USB PHY Calibrate not done after 100mS.");
+	writel(readl(&file->rx_reg1) &
+		(~SQCAL_START), &file->rx_reg1);
+
+	/*
+	 * phy is ready?
+	 * 0xd420_7000[31] = 0x1;
+	 */
+	count = 100;
+	while (((readl(&file->pll_reg0) & PLL_READY_MASK) == 0) && count--)
+		udelay(1000);
+	if (count <= 0) {
+		printf("%s %d: wait for ready timeout, UTMI_PLL 0x%x\n",
+		       __func__, __LINE__, readl(&file->pll_reg1));
+		return -1;
+	}
+	return 0;
+}
+
+static int mrvl_usb_phy_28nm_init(u32 base)
+{
+	struct usb_file *file = (struct usb_file *)(uintptr_t)base;
+	u32 tmp32;
+	int ret;
+
+	/*
+	 * pll control 0:
+	 * 0xd420_7000[6:0] = 0xd, b'000_1101	  --->  REFDIV
+	 * 0xd420_7000[24:16] = 0xf0, b'1111_0000 --->  FBDIV
+	 * 0xd420_7000[11:8] = 0x3, b'0011        --->  ICP
+	 * 0xd420_7000[29:28] = 0x1,  b'01	  --->  SEL_LPFR
+	 */
+	tmp32 = readl(&file->pll_reg0);
+	tmp32 &= ~(REFDIV_MASK | FB_DIV_MASK | ICP_MASK | SEL_LPFR_MASK);
+	if (cpu_is_pxa1826())
+		tmp32 |= REFDIV(0xd) | FB_DIV(0xf0) | SEL_LPFR(0x1);
+	else
+		tmp32 |= REFDIV(0xd) | FB_DIV(0xf0) | ICP(0x3) | SEL_LPFR(0x1);
+	writel(tmp32, &file->pll_reg0); 
+	/*
+	 * pll control 1:
+	 * 0xd420_7004[1:0] = 0x3, b'11	   ---> [PU_PLL_BY_REG:PU_PLL]
+	 */
+	tmp32 = readl(&file->pll_reg1);
+	tmp32 &= ~(PLL_PU_MASK | PU_BY_MASK);
+	tmp32 |= PLL_PU(0x1) | PU_BY(0x1);
+	writel(tmp32, &file->pll_reg1);
+	/*
+	 * tx reg 0:
+	 * 0xd420_700c[22:20] = 0x3, b'11  ---> AMP
+	 */
+	tmp32 = readl(&file->tx_reg0);
+	tmp32 &= ~(AMP_MASK);
+	tmp32 |= AMP(0x3);
+	writel(tmp32, &file->tx_reg0);
+	/*
+	 * rx reg 0:
+	 * 0xd420_7018[3:0] = 0xa, b'1010 ---> SQ_THRESH
+	 */
+	tmp32 = readl(&file->rx_reg0);
+	tmp32 &= ~(SQ_THRESH_MASK);
+	tmp32 |= SQ_THRESH(0xa);
+	writel(tmp32, &file->rx_reg0);
+	/*
+	 * dig reg 0:
+	 * 0xd420_701c[31] = 0, b'0 ---> BITSTAFFING_ERROR
+	 * 0xd420_701c[30] = 0, b'0 ---> LOSS_OF_SYNC_ERROR
+	 * 0xd420_701c[18:16] = 0x7, b'111 ---> SQ_FILT
+	 * 0xd420_701c[14:12] = 0x4, b'100 ---> SQ_BLK
+	 * 0xd420_701c[1:0] = 0x2, b'10 ---> SYNC_NUM
+	 */
+	tmp32 = readl(&file->dig_reg0);
+	tmp32 &= ~(BITSTAFFING_ERR_MASK | SYNC_ERR_MASK | SQ_FILT_MASK | SQ_BLK_MASK | SYNC_NUM_MASK);
+	tmp32 |= (SQ_FILT(0x0) | SQ_BLK(0x0) | SYNC_NUM(0x1));
+	writel(tmp32, &file->dig_reg0);
+
+	/*
+	 * otg reg:
+	 * 0xd420_7034[5:4] = 0x1,  b'01   ---> [OTG_CONTROL_BY_PIN:PU_OTG]
+	 */
+	tmp32 = readl(&file->otg_reg);
+	tmp32 &= ~(OTG_CTRL_BY_MASK | PU_OTG_MASK);
+	tmp32 |= OTG_CTRL_BY(0x0) | PU_OTG(0x1);
+	writel(tmp32, &file->otg_reg);
+	/*
+	 * tx reg 0:
+	 * 0xd420_700c[25:24] = 0x3, b'11  --->  [PU_ANA:PU_BY_REG]
+	 */
+	tmp32 = readl(&file->tx_reg0);
+	tmp32 &= ~(ANA_PU_MASK | TX_PU_BY_MASK);
+	tmp32 |= ANA_PU(0x1) | TX_PU_BY(0x1);
+	writel(tmp32, &file->tx_reg0);
+
+	tmp32 = readl(MV_USB2_PHY_CTRL0);
+	tmp32 &= ~(VBUS_VALID_MASK);
+	tmp32 |= VBUS_VALID_CTRL(0x3);
+	writel(tmp32, MV_USB2_PHY_CTRL0);
+
+	udelay(400);
+	ret = wait_for_phy_ready(file);
+	if (ret < 0) {
+		printf("initialize usb phy failed, dump usb registers:\n");
+		dump_phy_regs(base);
+	}
+
+	printf("usb phy inited 0x%x!\n", readl(&file->usb_ctrl0));
+	return 0;
+}
+static const char *charger_type(unsigned int type)
+{
+	switch (type) {
+	case NULL_CHARGER: return "NULL_CHARGER";
+	case DEFAULT_CHARGER: return "DEFAULT_CHARGER";
+	case DCP_CHARGER: return "DCP_CHARGER";
+	case CDP_CHARGER: return "CDP_CHARGER";
+	case SDP_CHARGER: return "SDP_CHARGER";
+	default: return "NONE_STANDARD_CHARGER";
+	}
+}
+
+
+static int _mv_usb2_phy_28nm_charger_detect(u32 base)
+{
+	struct usb_file *file = (struct usb_file *)(uintptr_t)base;
+	int charger_type_bc12 = NULL_CHARGER;
+	u32 reg32;
+
+	/* Power up Analog */
+	reg32 = readl(&file->tx_reg0);
+	reg32 |= (1 << PHY_28NM_TX_PU_BY_REG_SHIFT |
+			1 << PHY_28NM_TX_PU_ANA_SHIFT);
+	writel(reg32, &file->tx_reg0);
+
+	/* Power up Charger Detector */
+	reg32 = readl(&file->chrg_reg);
+	reg32 |= (1 << PHY_28NM_CHGDTC_PU_CHRG_DTC_SHIFT_28);
+	writel(reg32, &file->chrg_reg);
+
+	udelay(100);
+
+	/* Primary detection */
+	reg32 = readl(&file->chrg_reg);
+	reg32 &= ~(1  <<  PHY_28NM_CHGDTC_DP_DM_SWAP_SHIFT_28 |
+			3 << PHY_28NM_CHGDTC_VSRC_CHARGE_SHIFT_28 |
+			3 << PHY_28NM_CHGDTC_VDAT_CHARGE_SHIFT_28 |
+			1 << PHY_28NM_CHGDTC_CDP_DM_AUTO_SWITCH_SHIFT_28 |
+			1 << PHY_28NM_CHGDTC_DCP_EN_SHIFT_28 |
+			1 << PHY_28NM_CHGDTC_CDP_EN_SHIFT_28);
+	writel(reg32, &file->chrg_reg);
+
+	reg32 = readl(&file->chrg_reg);
+	reg32 |= (1 << PHY_28NM_CHGDTC_VSRC_CHARGE_SHIFT_28 |
+			1 << PHY_28NM_CHGDTC_VDAT_CHARGE_SHIFT_28 |
+			1 << PHY_28NM_CHGDTC_PD_EN_SHIFT_28);
+	writel(reg32, &file->chrg_reg);
+
+	/* Enable swtich DM/DP */
+	reg32 = readl(&file->chrg_reg);
+	reg32 |= (1 << PHY_28NM_CHGDTC_ENABLE_SWITCH_DM_SHIFT_28 |
+			1 << PHY_28NM_CHGDTC_ENABLE_SWITCH_DP_SHIFT_28);
+	writel(reg32, &file->chrg_reg);
+
+	if ((readl(&file->usb_ctrl1)) &
+		(1 << PHY_28NM_CTRL1_CHRG_DTC_OUT_SHIFT_28)) {
+		/* We have CHRG_DTC_OUT set.
+		 * Now proceed with Secondary Detection
+		 */
+
+		mdelay(10);
+
+		reg32 = readl(&file->chrg_reg);
+		reg32 |= (1 << PHY_28NM_CHGDTC_DP_DM_SWAP_SHIFT_28);
+		writel(reg32, &file->chrg_reg);
+
+		mdelay(10);
+
+		if ((readl(&file->usb_ctrl1)) &
+			(1 << PHY_28NM_CTRL1_CHRG_DTC_OUT_SHIFT_28))
+			charger_type_bc12 = DCP_CHARGER;
+		else
+			charger_type_bc12 = CDP_CHARGER;
+	} else {
+		charger_type_bc12 = SDP_CHARGER;
+	}
+
+	/* Disable swtich DM/DP */
+	reg32 = readl(&file->chrg_reg);
+	reg32 &= ~(1<<PHY_28NM_CHGDTC_ENABLE_SWITCH_DM_SHIFT_28 |
+			1 << PHY_28NM_CHGDTC_ENABLE_SWITCH_DP_SHIFT_28);
+	writel(reg32, &file->chrg_reg);
+
+	/* Power down Charger Detector */
+	reg32 = readl(&file->chrg_reg);
+	reg32 &= ~(1 << PHY_28NM_CHGDTC_PU_CHRG_DTC_SHIFT_28);
+	writel(reg32, &file->chrg_reg);
+
+	return charger_type_bc12;
+}
+
+int get_usb_charger_type(void)
+{
+	unsigned int level = 0;
+	int usb_charger_type = NULL_CHARGER;
+
+	charger_get_vbus(&level);
+	if (level == 0) {
+		printf("usb_charger_type is NULL_CHARGER\n");
+		return NULL_CHARGER;
+	}
+	usb_charger_type = _mv_usb2_phy_28nm_charger_detect(
+						CONFIG_USB_PHY_BASE);
+	printf("usb_charger_type is %s\r\n",
+			charger_type(usb_charger_type));
+	return usb_charger_type;
+}
+
+int usb_vbus_is_online(void) 
+{
+	if (readl(APMU_SD_ROT_WAKE_CLR) & (0x1 << 15))
+		return 1;
+	else
+		return 0;
+}
+#endif
+
+#ifdef CONFIG_MRVL_USB_PHY_40LP
+static int mrvl_usb_phy_40nm_init(u32 base)
+{
+	u16 tmp16;
+	u32 tmp32;
+
+	/* Program 0xd4207004[8:0]= 0xF0 */
+	/* Program 0xd4207004[13:9]=0xD */
+	writew((MV_USB2_PHY_PLL0_DEFAULT
+		& (~MV_USB2_PHY_PLL0_FBDIV(~0))
+		& (~MV_USB2_PHY_PLL0_REFDIV(~0)))
+		| MV_USB2_PHY_PLL0_FBDIV(0xF0)
+		| MV_USB2_PHY_PLL0_REFDIV(0xD), base + MV_USB2_PHY_PLL0);
+
+	/* Program 0xd4207008[11:8]=0x1 */
+	/* Program 0xd4207008[14:13]=0x1 */
+	writew((MV_USB2_PHY_PLL1_DEFAULT
+		& (~MV_USB2_PHY_PLL1_ICP(~0))
+		& (~MV_USB2_PHY_PLL1_PLL_CONTROL_BY_PIN))
+		| MV_USB2_PHY_PLL1_ICP(0x1)
+		| MV_USB2_PHY_PLL1_PU_PLL, base + MV_USB2_PHY_PLL1);
+
+	/* Program 0xd4207034[14]=0x1 */
+	writew(MV_USB2_PHY_ANA1_DEFAULT
+		| MV_USB2_PHY_ANA1_PU_ANA, base + MV_USB2_PHY_ANA1);
+
+	/* Program 0xd420705c[3]=0x1 */
+	writew(MV_USB2_PHY_OTG_DEFAULT
+		| MV_USB2_PHY_OTG_PU, base + MV_USB2_PHY_OTG);
+
+	/* Program 0xD4207104[1] = 0x1 */
+	/* Program 0xD4207104[0] = 0x1 */
+	tmp32 = readl(base + MV_USB2_PHY_CTRL);
+	writel(tmp32 | MV_USB2_PHY_CTRL_PU_PLL
+		     | MV_USB2_PHY_CTRL_PU, base + MV_USB2_PHY_CTRL);
+
+	/* Wait for 200us */
+	udelay(200);
+
+	/* Program 0xd4207008[2]=0x1 */
+	tmp16 = readw(base + MV_USB2_PHY_PLL1);
+	writew(tmp16
+		| MV_USB2_PHY_PLL1_VCOCAL_START, base + MV_USB2_PHY_PLL1);
+
+	/* Wait for 400us */
+	udelay(400);
+
+	/* Polling 0xd4207008[15]=0x1 */
+	while ((readw(base + MV_USB2_PHY_PLL1)
+		& MV_USB2_PHY_PLL1_PLL_READY) == 0)
+		printf("polling usb phy\n");
+
+	/* Program 0xd4207010[13]=0x1 */
+	writew(MV_USB2_PHY_TX0_DEFAULT
+		| MV_USB2_PHY_TX0_RCAL_START, base + MV_USB2_PHY_TX0);
+
+	/* Wait for 40us */
+	udelay(40);
+
+	/* Program 0xd4207010[13]=0x0 */
+	tmp16 = readw(base + MV_USB2_PHY_TX0);
+	writew(tmp16
+		& (~MV_USB2_PHY_TX0_RCAL_START), base + MV_USB2_PHY_TX0);
+
+	/* Wait for 400us */
+	udelay(400);
+
+	printf("usb phy inited %x!\n", readl(base + MV_USB2_PHY_CTRL));
+
+	return 0;
+}
+#endif
+
+int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
+{
+#ifdef CONFIG_MRVL_USB_PHY_28LP
+	mrvl_usb_phy_28nm_init(CONFIG_USB_PHY_BASE);
+#endif
+
+#ifdef CONFIG_MRVL_USB_PHY_28HP
+	mrvl_usb_phy_28nmhp_init(CONFIG_USB_PHY_BASE);
+#endif
+
+#ifdef CONFIG_MRVL_USB_PHY_40LP /* CONFIG_MRVL_USB_PHY_40LP */
+	mrvl_usb_phy_40nm_init(CONFIG_USB_PHY_BASE);
+#endif
+
+#ifdef CONFIG_ASR_USB3_PHY /* CONFIG_ASR_USB3_PHY */
+	u32 regval;
+
+	regval = readl(CONFIG_USB_REG_BASE + DWC3_GUSB3PIPECTL(0));
+	regval &= ~DWC3_GUSB3PIPECTL_SUSPHY;
+	writel(regval, CONFIG_USB_REG_BASE + DWC3_GUSB3PIPECTL(0));
+	asr_usb3_phy_init(CONFIG_USB_PHY_BASE);
+#endif
+
+	return 0;
+}