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;
+}