blob: 8ba67a59ddd24141412c5e5de753788ffa993595 [file] [log] [blame]
/*
* (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;
}