mirror of
https://github.com/Ysurac/openmptcprouter.git
synced 2025-03-09 15:40:20 +00:00
508 lines
17 KiB
C
508 lines
17 KiB
C
/*
|
|
* Copyright (c) 2014 The Linux Foundation. All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 and
|
|
* only version 2 as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <usb.h>
|
|
#include <asm-generic/errno.h>
|
|
|
|
#include <linux/compat.h>
|
|
#include <linux/usb/dwc3.h>
|
|
#include <linux/usb/msm_usb30.h>
|
|
|
|
#include "xhci.h"
|
|
|
|
#define IPQ_XHCI_BASE_1 0x11000000
|
|
#define IPQ_XHCI_BASE_2 0x10000000
|
|
#define USB30_RESET 0x00903B50
|
|
#define USB30_1_RESET 0x00903B58
|
|
#define DWC3_SSUSB_REG_GCTL 0xC110
|
|
#define DWC3_SSUSB_REG_GUSB2PHYCFG_PHYSOFTRST (1 << 31)
|
|
#define DWC3_SSUSB_REG_GUSB2PHYCFG(n) (0xC200 + ((n) * 0x16))
|
|
#define DWC3_SSUSB_REG_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
|
|
#define DWC3_SSUSB_REG_GUSB3PIPECTL(n) (0xC2C0 + ((n) * 0x16))
|
|
#define DWC3_SSUSB_PHY_RTUNE_RTUNE_CTRL_REG 0x34
|
|
#define DWC3_SSUSB_PHY_RTUNE_DEBUG_REG 0x3
|
|
#define RX_TERM_VALUE 0
|
|
#define RX_EQ_VALUE 4
|
|
#define DWC3_SSUSB_PHY_RX_OVRD_IN_HI_REG 0x1006
|
|
#define DWC3_SSUSB_PHY_RX_OVRD_IN_HI_RX_EQ_EN 6
|
|
#define DWC3_SSUSB_PHY_RX_OVRD_IN_HI_RX_EQ_EN_OVRD 7
|
|
#define DWC3_SSUSB_PHY_RX_OVRD_IN_HI_RX_EQ_MASK 0x7
|
|
#define DWC3_SSUSB_PHY_RX_OVRD_IN_HI_RX_EQ 8
|
|
#define DWC3_SSUSB_PHY_RX_OVRD_IN_HI_RX_EQ_OVRD 11
|
|
#define AMPLITUDE_VALUE 110
|
|
#define TX_DEEMPH_3_5DB 23
|
|
#define DWC3_SSUSB_PHY_TX_OVRD_DRV_LO_REG 0x1002
|
|
#define DWC3_SSUSB_PHY_TX_DEEMPH_MASK 0x3F80
|
|
#define DWC3_SSUSB_PHY_AMP_MASK 0x7F
|
|
#define DWC3_SSUSB_PHY_AMP_EN (1 << 14)
|
|
#define DWC3_SSUSB_REG_GUCTL 0xC12C
|
|
#define DWC3_SSUSB_PHY_TX_ALT_BLOCK_REG 0x102D
|
|
#define DWC3_SSUSB_PHY_TX_ALT_BLOCK_EN_ALT_BUS (1 << 7)
|
|
#define DWC3_GCTL_U2EXIT_LFPS (1 << 2)
|
|
#define DWC3_GCTL_SOFITPSYNC (1 << 10)
|
|
#define DWC3_GCTL 0xc110
|
|
#define DWC3_SSUSB_REG_GUSB2PHYCFG_SUSPENDUSB20 (1 << 6)
|
|
#define DWC3_SSUSB_REG_GUSB2PHYCFG_ENBLSLPM (1 << 8)
|
|
#define DWC3_SSUSB_REG_GUSB2PHYCFG_USBTRDTIM(n) ((n) << 10)
|
|
#define DWC3_SSUSB_REG_GUSB3PIPECTL_ELASTIC_BUFFER_MODE (1 << 0)
|
|
#define DWC3_SSUSB_REG_GUSB3PIPECTL_TX_DE_EPPHASIS(n) ((n) << 1)
|
|
#define DWC3_SSUSB_REG_GUSB3PIPECTL_TX_MARGIN(n) ((n) << 3)
|
|
#define DWC3_SSUSB_REG_GUSB3PIPECTL_DELAYP1TRANS (1 << 18)
|
|
#define DWC3_SSUSB_REG_GUSB3PIPECTL_DELAYP1P2P3(n) ((n) << 19)
|
|
#define DWC3_SSUSB_REG_GUSB3PIPECTL_U1U2EXITFAIL_TO_RECOV (1 << 25)
|
|
#define DWC3_SSUSB_REG_GUSB3PIPECTL_REQUEST_P1P2P3 (1 << 24)
|
|
#define DWC3_SSUSB_PHY_TX_DEEMPH_SHIFT 7
|
|
#define DWC3_SSUSB_XHCI_REV_10 1
|
|
|
|
extern board_ipq806x_params_t board_params[];
|
|
extern board_ipq806x_params_t *gboard_param;
|
|
|
|
/* Declare global data pointer */
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
struct ipq_xhci {
|
|
struct xhci_hccr *hcd;
|
|
struct dwc3 *dwc3_reg;
|
|
};
|
|
static struct ipq_xhci ipq;
|
|
|
|
int __board_usb_init(int index, enum usb_init_type init)
|
|
{
|
|
return 0;
|
|
}
|
|
int board_usb_init(int index, enum usb_init_type init)
|
|
__attribute__((weak, alias("__board_usb_init")));
|
|
|
|
static void dwc3_set_mode(struct dwc3 *dwc3_reg, u32 mode)
|
|
{
|
|
clrsetbits_le32(&dwc3_reg->g_ctl,
|
|
DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG),
|
|
DWC3_GCTL_PRTCAPDIR(mode));
|
|
}
|
|
|
|
void ipq_reset_usb_phy(struct dwc3 *dwc3_reg)
|
|
{
|
|
/* Assert USB3 PHY reset */
|
|
setbits_le32(&dwc3_reg->g_usb3pipectl[0], DWC3_GUSB3PIPECTL_PHYSOFTRST);
|
|
|
|
/* Assert USB2 PHY reset */
|
|
setbits_le32(&dwc3_reg->g_usb2phycfg, DWC3_GUSB2PHYCFG_PHYSOFTRST);
|
|
|
|
mdelay(100);
|
|
|
|
/* Clear USB3 PHY reset */
|
|
clrbits_le32(&dwc3_reg->g_usb3pipectl[0], DWC3_GUSB3PIPECTL_PHYSOFTRST);
|
|
|
|
/* Clear USB2 PHY reset */
|
|
clrbits_le32(&dwc3_reg->g_usb2phycfg, DWC3_GUSB2PHYCFG_PHYSOFTRST);
|
|
|
|
}
|
|
static void dwc3_core_soft_reset(struct dwc3 *dwc3_reg)
|
|
{
|
|
/* Before Resetting PHY, put Core in Reset */
|
|
setbits_le32(&dwc3_reg->g_ctl, DWC3_GCTL_CORESOFTRESET);
|
|
|
|
ipq_reset_usb_phy(dwc3_reg);
|
|
|
|
/* After PHYs are stable we can take Core out of reset state */
|
|
clrbits_le32(&dwc3_reg->g_ctl, DWC3_GCTL_CORESOFTRESET);
|
|
}
|
|
|
|
static int dwc3_core_init(struct dwc3 *dwc3_reg)
|
|
{
|
|
u32 reg;
|
|
u32 revision;
|
|
unsigned int dwc3_hwparams1;
|
|
|
|
revision = readl(&dwc3_reg->g_snpsid);
|
|
/* This should read as U3 followed by revision number */
|
|
if ((revision & DWC3_GSNPSID_MASK) != 0x55330000) {
|
|
puts("this is not a DesignWare USB3 DRD Core\n");
|
|
return -1;
|
|
}
|
|
|
|
dwc3_core_soft_reset(dwc3_reg);
|
|
|
|
dwc3_hwparams1 = readl(&dwc3_reg->g_hwparams1);
|
|
|
|
reg = readl(&dwc3_reg->g_ctl);
|
|
reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
|
|
reg &= ~DWC3_GCTL_DISSCRAMBLE;
|
|
switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc3_hwparams1)) {
|
|
case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
|
|
reg &= ~DWC3_GCTL_DSBLCLKGTNG;
|
|
break;
|
|
default:
|
|
debug("No power optimization available\n");
|
|
}
|
|
|
|
/*
|
|
* WORKAROUND: DWC3 revisions <1.90a have a bug
|
|
* where the device can fail to connect at SuperSpeed
|
|
* and falls back to high-speed mode which causes
|
|
* the device to enter a Connect/Disconnect loop
|
|
*/
|
|
if ((revision & DWC3_REVISION_MASK) < 0x190a)
|
|
reg |= DWC3_GCTL_U2RSTECN;
|
|
|
|
writel(reg, &dwc3_reg->g_ctl);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static u16 dwc3_ipq_ssusb_read_phy_reg(unsigned int addr, unsigned int ipq_base)
|
|
{
|
|
u16 tmp_phy[3], i;
|
|
do {
|
|
for (i = 0; i < 3; i++) {
|
|
writel(addr, ipq_base +
|
|
IPQ_SSUSB_REG_QSCRATCH_SS_CR_PROTOCOL_DATA_IN);
|
|
writel(0x1, ipq_base +
|
|
IPQ_SSUSB_REG_QSCRATCH_SS_CR_PROTOCOL_CAP_ADDR);
|
|
while (0 != readl(ipq_base +
|
|
IPQ_SSUSB_REG_QSCRATCH_SS_CR_PROTOCOL_CAP_ADDR));
|
|
writel(0x1, ipq_base +
|
|
IPQ_SSUSB_REG_QSCRATCH_SS_CR_PROTOCOL_READ);
|
|
while (0 != readl(ipq_base +
|
|
IPQ_SSUSB_REG_QSCRATCH_SS_CR_PROTOCOL_READ));
|
|
tmp_phy[i] = (u16)readl(ipq_base +
|
|
IPQ_SSUSB_REG_QSCRATCH_SS_CR_PROTOCOL_DATA_OUT);
|
|
}
|
|
} while (tmp_phy[1] != tmp_phy[2]);
|
|
return tmp_phy[2];
|
|
}
|
|
|
|
static void dwc3_ipq_ssusb_write_phy_reg(u32 addr, u16 data, unsigned int ipq_base)
|
|
{
|
|
writel(addr, ipq_base + IPQ_SSUSB_REG_QSCRATCH_SS_CR_PROTOCOL_DATA_IN);
|
|
writel(0x1, ipq_base + IPQ_SSUSB_REG_QSCRATCH_SS_CR_PROTOCOL_CAP_ADDR);
|
|
while (0 != readl(ipq_base +
|
|
IPQ_SSUSB_REG_QSCRATCH_SS_CR_PROTOCOL_CAP_ADDR));
|
|
writel(data, ipq_base + IPQ_SSUSB_REG_QSCRATCH_SS_CR_PROTOCOL_DATA_IN);
|
|
writel(0x1, ipq_base + IPQ_SSUSB_REG_QSCRATCH_SS_CR_PROTOCOL_CAP_DATA);
|
|
while (0 != readl(ipq_base +
|
|
IPQ_SSUSB_REG_QSCRATCH_SS_CR_PROTOCOL_CAP_DATA));
|
|
writel(0x1, ipq_base + IPQ_SSUSB_REG_QSCRATCH_SS_CR_PROTOCOL_WRITE);
|
|
while (0 != readl(ipq_base +
|
|
IPQ_SSUSB_REG_QSCRATCH_SS_CR_PROTOCOL_WRITE));
|
|
}
|
|
|
|
static void ipq_ssusb_clear_bits32(u32 offset, u32 bits, unsigned int ipq_base)
|
|
{
|
|
u32 data;
|
|
data = readl(ipq_base+offset);
|
|
data = data & ~bits;
|
|
writel(data, ipq_base + offset);
|
|
}
|
|
|
|
static void ipq_ssusb_clear_and_set_bits32(u32 offset, u32 clear_bits, u32 set_bits, unsigned int ipq_base)
|
|
{
|
|
u32 data;
|
|
data = readl(ipq_base + offset);
|
|
data = (data & ~clear_bits) | set_bits;
|
|
writel(data, ipq_base + offset);
|
|
}
|
|
|
|
static void partial_rx_reset_init(unsigned int ipq_base)
|
|
{
|
|
u32 addr = DWC3_SSUSB_PHY_TX_ALT_BLOCK_REG;
|
|
u16 data = dwc3_ipq_ssusb_read_phy_reg(addr, ipq_base);
|
|
data |= DWC3_SSUSB_PHY_TX_ALT_BLOCK_EN_ALT_BUS;
|
|
dwc3_ipq_ssusb_write_phy_reg(addr, data, ipq_base);
|
|
return;
|
|
}
|
|
|
|
static void uw_ssusb_pre_init(unsigned int ipq_base)
|
|
{
|
|
u32 set_bits, tmp;
|
|
|
|
/* GCTL Reset ON */
|
|
writel(0x800, ipq_base + DWC3_SSUSB_REG_GCTL);
|
|
/* Config SS PHY CTRL */
|
|
set_bits = 0;
|
|
writel(0x80, ipq_base + IPQ_SS_PHY_CTRL_REG);
|
|
udelay(5);
|
|
ipq_ssusb_clear_bits32(IPQ_SS_PHY_CTRL_REG, 0x80, ipq_base);
|
|
udelay(5);
|
|
/* REF_USE_PAD */
|
|
set_bits = 0x0000000; /* USE Internal clock */
|
|
set_bits |= IPQ_SSUSB_QSCRATCH_SS_PHY_CTRL_LANE0_PWR_PRESENT;
|
|
set_bits |= IPQ_SSUSB_QSCRATCH_SS_PHY_CTRL_REF_SS_PHY_EN;
|
|
writel(set_bits, ipq_base + IPQ_SS_PHY_CTRL_REG);
|
|
/* Config HS PHY CTRL */
|
|
set_bits = IPQ_SSUSB_REG_QSCRATCH_HS_PHY_CTRL_UTMI_OTG_VBUS_VALID;
|
|
/*
|
|
* COMMONONN forces xo, bias and pll to stay on during suspend;
|
|
* Allowing suspend (writing 1) kills Aragorn V1
|
|
*/
|
|
set_bits |= IPQ_SSUSB_REG_QSCRATCH_HS_PHY_CTRL_COMMONONN;
|
|
set_bits |= IPQ_SSUSB_REG_QSCRATCH_HS_PHY_CTRL_USE_CLKCORE;
|
|
set_bits |= IPQ_SSUSB_REG_QSCRATCH_HS_PHY_CTRL_FSEL_VAL;
|
|
/*
|
|
* If the configuration of clocks is not bypassed in Host mode,
|
|
* HS PHY suspend needs to be prohibited, otherwise - SS connection fails
|
|
*/
|
|
ipq_ssusb_clear_and_set_bits32(IPQ_SSUSB_REG_QSCRATCH_HS_PHY_CTRL, 0,
|
|
set_bits, ipq_base);
|
|
/* USB2 PHY Reset ON */
|
|
writel(DWC3_SSUSB_REG_GUSB2PHYCFG_PHYSOFTRST, ipq_base +
|
|
DWC3_SSUSB_REG_GUSB2PHYCFG(0));
|
|
/* USB3 PHY Reset ON */
|
|
writel(DWC3_SSUSB_REG_GUSB3PIPECTL_PHYSOFTRST, ipq_base +
|
|
DWC3_SSUSB_REG_GUSB3PIPECTL(0));
|
|
udelay(5);
|
|
/* USB3 PHY Reset OFF */
|
|
ipq_ssusb_clear_bits32(DWC3_SSUSB_REG_GUSB3PIPECTL(0),
|
|
DWC3_SSUSB_REG_GUSB3PIPECTL_PHYSOFTRST, ipq_base);
|
|
ipq_ssusb_clear_bits32(DWC3_SSUSB_REG_GUSB2PHYCFG(0),
|
|
DWC3_GUSB2PHYCFG_PHYSOFTRST, ipq_base);
|
|
udelay(5);
|
|
/* GCTL Reset OFF */
|
|
ipq_ssusb_clear_bits32(DWC3_SSUSB_REG_GCTL, DWC3_GCTL_CORESOFTRESET,
|
|
ipq_base);
|
|
udelay(5);
|
|
if (RX_TERM_VALUE) {
|
|
dwc3_ipq_ssusb_write_phy_reg(DWC3_SSUSB_PHY_RTUNE_RTUNE_CTRL_REG,
|
|
0, ipq_base);
|
|
dwc3_ipq_ssusb_write_phy_reg(DWC3_SSUSB_PHY_RTUNE_DEBUG_REG,
|
|
0x0448, ipq_base);
|
|
dwc3_ipq_ssusb_write_phy_reg(DWC3_SSUSB_PHY_RTUNE_DEBUG_REG,
|
|
RX_TERM_VALUE, ipq_base);
|
|
}
|
|
if (0 != RX_EQ_VALUE) { /* Values from 1 to 7 */
|
|
tmp =0;
|
|
/*
|
|
* 1. Fixed EQ setting. This can be achieved as follows:
|
|
* LANE0.RX_OVRD_IN_HI. RX_EQ_EN set to 0 - address 1006 bit 6
|
|
* LANE0.RX_OVRD_IN_HI.RX_EQ_EN_OVRD set to 1 0- address 1006 bit 7
|
|
* LANE0.RX_OVRD_IN_HI.RX_EQ set to 4 (also try setting 3 if possible) -
|
|
* address 1006 bits 10:8 - please make this a variable, if unchanged the section is not executed
|
|
* LANE0.RX_OVRD_IN_HI.RX_EQ_OVRD set to 1 - address 1006 bit 11
|
|
*/
|
|
tmp = dwc3_ipq_ssusb_read_phy_reg(DWC3_SSUSB_PHY_RX_OVRD_IN_HI_REG,
|
|
ipq_base);
|
|
tmp &= ~((u16)1 << DWC3_SSUSB_PHY_RX_OVRD_IN_HI_RX_EQ_EN);
|
|
tmp |= ((u16)1 << DWC3_SSUSB_PHY_RX_OVRD_IN_HI_RX_EQ_EN_OVRD);
|
|
tmp &= ~((u16) DWC3_SSUSB_PHY_RX_OVRD_IN_HI_RX_EQ_MASK <<
|
|
DWC3_SSUSB_PHY_RX_OVRD_IN_HI_RX_EQ);
|
|
tmp |= RX_EQ_VALUE << DWC3_SSUSB_PHY_RX_OVRD_IN_HI_RX_EQ;
|
|
tmp |= 1 << DWC3_SSUSB_PHY_RX_OVRD_IN_HI_RX_EQ_OVRD;
|
|
dwc3_ipq_ssusb_write_phy_reg(DWC3_SSUSB_PHY_RX_OVRD_IN_HI_REG,
|
|
tmp, ipq_base);
|
|
}
|
|
if ((113 != AMPLITUDE_VALUE) || (21 != TX_DEEMPH_3_5DB)) {
|
|
tmp = dwc3_ipq_ssusb_read_phy_reg(DWC3_SSUSB_PHY_TX_OVRD_DRV_LO_REG,
|
|
ipq_base);
|
|
tmp &= ~DWC3_SSUSB_PHY_TX_DEEMPH_MASK;
|
|
tmp |= (TX_DEEMPH_3_5DB << DWC3_SSUSB_PHY_TX_DEEMPH_SHIFT);
|
|
tmp &= ~DWC3_SSUSB_PHY_AMP_MASK;
|
|
tmp |= AMPLITUDE_VALUE;
|
|
tmp |= DWC3_SSUSB_PHY_AMP_EN;
|
|
dwc3_ipq_ssusb_write_phy_reg(DWC3_SSUSB_PHY_TX_OVRD_DRV_LO_REG,
|
|
tmp, ipq_base);
|
|
}
|
|
ipq_ssusb_clear_and_set_bits32(IPQ_SS_PHY_PARAM_CTRL_1_REG,
|
|
0x7, 0x5, ipq_base);
|
|
/* XHCI REV */
|
|
writel((1 << 2), ipq_base + IPQ_QSCRATCH_GENERAL_CFG);
|
|
writel(0x0c80c010, ipq_base + DWC3_SSUSB_REG_GUCTL);
|
|
partial_rx_reset_init(ipq_base);
|
|
set_bits = 0;
|
|
/* Test U2EXIT_LFPS */
|
|
set_bits |= IPQ_SSUSB_REG_GCTL_U2EXIT_LFPS;
|
|
ipq_ssusb_clear_and_set_bits32(DWC3_SSUSB_REG_GCTL, 0,
|
|
set_bits, ipq_base);
|
|
set_bits = 0;
|
|
set_bits |= IPQ_SSUSB_REG_GCTL_U2RSTECN;
|
|
set_bits |= IPQ_SSUSB_REG_GCTL_U2EXIT_LFPS;
|
|
ipq_ssusb_clear_and_set_bits32(DWC3_SSUSB_REG_GCTL, 0,
|
|
set_bits, ipq_base);
|
|
writel(DWC3_GCTL_U2EXIT_LFPS | DWC3_GCTL_SOFITPSYNC |
|
|
DWC3_GCTL_PRTCAPDIR(1) |
|
|
DWC3_GCTL_U2RSTECN | DWC3_GCTL_PWRDNSCALE(2),
|
|
ipq_base + DWC3_GCTL);
|
|
writel((IPQ_SSUSB_QSCRATCH_SS_PHY_CTRL_MPLL_MULTI(0x19) |
|
|
IPQ_SSUSB_QSCRATCH_SS_PHY_CTRL_REF_SS_PHY_EN |
|
|
IPQ_SSUSB_QSCRATCH_SS_PHY_CTRL_LANE0_PWR_PRESENT),
|
|
ipq_base + IPQ_SS_PHY_CTRL_REG);
|
|
writel((DWC3_SSUSB_REG_GUSB2PHYCFG_SUSPENDUSB20 |
|
|
DWC3_SSUSB_REG_GUSB2PHYCFG_ENBLSLPM |
|
|
DWC3_SSUSB_REG_GUSB2PHYCFG_USBTRDTIM(9)),
|
|
ipq_base + DWC3_SSUSB_REG_GUSB2PHYCFG(0));
|
|
writel(DWC3_SSUSB_REG_GUSB3PIPECTL_ELASTIC_BUFFER_MODE |
|
|
DWC3_SSUSB_REG_GUSB3PIPECTL_TX_DE_EPPHASIS(1) |
|
|
DWC3_SSUSB_REG_GUSB3PIPECTL_TX_MARGIN(0)|
|
|
DWC3_SSUSB_REG_GUSB3PIPECTL_DELAYP1TRANS |
|
|
DWC3_SSUSB_REG_GUSB3PIPECTL_DELAYP1P2P3(1) |
|
|
DWC3_SSUSB_REG_GUSB3PIPECTL_U1U2EXITFAIL_TO_RECOV |
|
|
DWC3_SSUSB_REG_GUSB3PIPECTL_REQUEST_P1P2P3,
|
|
ipq_base + DWC3_SSUSB_REG_GUSB3PIPECTL(0));
|
|
writel(IPQ_SSUSB_REG_QSCRATCH_SS_PHY_PARAM_CTRL_1_LOS_LEVEL(0x9) |
|
|
IPQ_SSUSB_REG_QSCRATCH_SS_PHY_PARAM_CTRL_1_TX_DEEMPH_3_5DB(0x17) |
|
|
IPQ_SSUSB_REG_QSCRATCH_SS_PHY_PARAM_CTRL_1_TX_DEEMPH_6DB(0x20) |
|
|
IPQ_SSUSB_REG_QSCRATCH_SS_PHY_PARAM_CTRL_1_TX_SWING_FULL(0x6E),
|
|
ipq_base + IPQ_SS_PHY_PARAM_CTRL_1_REG);
|
|
writel(IPQ_SSUSB_REG_QSCRATCH_GENERAL_CFG_XHCI_REV(DWC3_SSUSB_XHCI_REV_10),
|
|
ipq_base + IPQ_QSCRATCH_GENERAL_CFG);
|
|
}
|
|
|
|
static void usb30_common_pre_init(int id, unsigned int ipq_base)
|
|
{
|
|
unsigned int reg;
|
|
if (id == 0)
|
|
reg = USB30_RESET;
|
|
else
|
|
reg = USB30_1_RESET;
|
|
|
|
writel(IPQ_USB30_RESET_PHY_ASYNC_RESET, reg);
|
|
writel(IPQ_USB30_RESET_POWERON_ASYNC_RESET |
|
|
IPQ_USB30_RESET_PHY_ASYNC_RESET, reg);
|
|
writel(IPQ_USB30_RESET_MOC_UTMI_ASYNC_RESET |
|
|
IPQ_USB30_RESET_POWERON_ASYNC_RESET |
|
|
IPQ_USB30_RESET_PHY_ASYNC_RESET, reg);
|
|
writel(IPQ_USB30_RESET_SLEEP_ASYNC_RESET |
|
|
IPQ_USB30_RESET_MOC_UTMI_ASYNC_RESET |
|
|
IPQ_USB30_RESET_POWERON_ASYNC_RESET |
|
|
IPQ_USB30_RESET_PHY_ASYNC_RESET, reg);
|
|
writel(IPQ_USB30_RESET_MASTER_ASYNC_RESET |
|
|
IPQ_USB30_RESET_SLEEP_ASYNC_RESET |
|
|
IPQ_USB30_RESET_MOC_UTMI_ASYNC_RESET |
|
|
IPQ_USB30_RESET_POWERON_ASYNC_RESET |
|
|
IPQ_USB30_RESET_PHY_ASYNC_RESET, reg);
|
|
if (id == 0) {
|
|
writel(IPQ_USB30_RESET_PORT2_HS_PHY_ASYNC_RESET |
|
|
IPQ_USB30_RESET_MASTER_ASYNC_RESET |
|
|
IPQ_USB30_RESET_SLEEP_ASYNC_RESET |
|
|
IPQ_USB30_RESET_MOC_UTMI_ASYNC_RESET |
|
|
IPQ_USB30_RESET_POWERON_ASYNC_RESET |
|
|
IPQ_USB30_RESET_PHY_ASYNC_RESET, reg);
|
|
}
|
|
udelay(5);
|
|
writel(IPQ_USB30_RESET_MASK & ~(IPQ_USB30_RESET_PHY_ASYNC_RESET), reg);
|
|
writel(IPQ_USB30_RESET_MASK & ~(IPQ_USB30_RESET_POWERON_ASYNC_RESET |
|
|
IPQ_USB30_RESET_PHY_ASYNC_RESET), reg);
|
|
writel(IPQ_USB30_RESET_MASK & ~(IPQ_USB30_RESET_MOC_UTMI_ASYNC_RESET |
|
|
IPQ_USB30_RESET_POWERON_ASYNC_RESET |
|
|
IPQ_USB30_RESET_PHY_ASYNC_RESET), reg);
|
|
writel(IPQ_USB30_RESET_MASK & ~(IPQ_USB30_RESET_SLEEP_ASYNC_RESET |
|
|
IPQ_USB30_RESET_MOC_UTMI_ASYNC_RESET |
|
|
IPQ_USB30_RESET_POWERON_ASYNC_RESET |
|
|
IPQ_USB30_RESET_PHY_ASYNC_RESET), reg);
|
|
writel(IPQ_USB30_RESET_MASK & ~(IPQ_USB30_RESET_MASTER_ASYNC_RESET |
|
|
IPQ_USB30_RESET_SLEEP_ASYNC_RESET|
|
|
IPQ_USB30_RESET_MOC_UTMI_ASYNC_RESET |
|
|
IPQ_USB30_RESET_POWERON_ASYNC_RESET |
|
|
IPQ_USB30_RESET_PHY_ASYNC_RESET), reg);
|
|
if (id == 0) {
|
|
writel(IPQ_USB30_RESET_MASK &
|
|
~(IPQ_USB30_RESET_PORT2_HS_PHY_ASYNC_RESET |
|
|
IPQ_USB30_RESET_MASTER_ASYNC_RESET |
|
|
IPQ_USB30_RESET_SLEEP_ASYNC_RESET |
|
|
IPQ_USB30_RESET_MOC_UTMI_ASYNC_RESET |
|
|
IPQ_USB30_RESET_POWERON_ASYNC_RESET |
|
|
IPQ_USB30_RESET_PHY_ASYNC_RESET), reg);
|
|
reg = IPQ_TCSR_USB_CONTROLLER_TYPE_SEL;
|
|
if (reg) {
|
|
writel(0x3, reg);
|
|
}
|
|
}
|
|
writel((IPQ_SSUSB_REG_QSCRATCH_CGCTL_RAM1112_EN |
|
|
IPQ_SSUSB_REG_QSCRATCH_CGCTL_RAM13_EN),
|
|
ipq_base + IPQ_SSUSB_REG_QSCRATCH_CGCTL);
|
|
writel((IPQ_SSUSB_REG_QSCRATCH_RAM1_RAM13_EN |
|
|
IPQ_SSUSB_REG_QSCRATCH_RAM1RAM12_EN |
|
|
IPQ_SSUSB_REG_QSCRATCH_RAM1_RAM11_EN),
|
|
ipq_base + IPQ_SSUSB_REG_QSCRATCH_RAM1);
|
|
}
|
|
|
|
|
|
static int ipq_xhci_core_init(struct ipq_xhci *ipq, unsigned int ipq_base)
|
|
{
|
|
int ret = 0;
|
|
|
|
/* Configure the usb core clock */
|
|
usb_ss_core_clock_config(0,
|
|
gboard_param->usb_core_mnd_value.m_value,
|
|
gboard_param->usb_core_mnd_value.n_value,
|
|
gboard_param->usb_core_mnd_value.d_value,
|
|
gboard_param->clk_dummy);
|
|
/* Configure the usb core clock */
|
|
usb_ss_utmi_clock_config(0,
|
|
gboard_param->usb_utmi_mnd_value.m_value,
|
|
gboard_param->usb_utmi_mnd_value.n_value,
|
|
gboard_param->usb_utmi_mnd_value.d_value,
|
|
gboard_param->clk_dummy);
|
|
|
|
usb30_common_pre_init(0, ipq_base);
|
|
uw_ssusb_pre_init(ipq_base);
|
|
ret = dwc3_core_init(ipq->dwc3_reg);
|
|
if (ret) {
|
|
debug("%s:failed to initialize core\n", __func__);
|
|
return ret;
|
|
}
|
|
|
|
/* We are hard-coding DWC3 core to Host Mode */
|
|
dwc3_set_mode(ipq->dwc3_reg, DWC3_GCTL_PRTCAP_HOST);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void ipq_xhci_core_exit(struct ipq_xhci *ipq)
|
|
{
|
|
|
|
}
|
|
|
|
int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
|
|
{
|
|
struct ipq_xhci *ctx = &ipq;
|
|
unsigned int ipq_base;
|
|
int ret = 0;
|
|
|
|
if ( index == 0 )
|
|
ipq_base = IPQ_XHCI_BASE_1;
|
|
else
|
|
ipq_base = IPQ_XHCI_BASE_2;
|
|
|
|
ctx->hcd = (struct xhci_hccr *)ipq_base;
|
|
ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET);
|
|
|
|
ret = board_usb_init(index, USB_INIT_HOST);
|
|
if (ret != 0) {
|
|
puts("Failed to initialize board for USB\n");
|
|
return ret;
|
|
}
|
|
|
|
ret = ipq_xhci_core_init(ctx, ipq_base);
|
|
if (ret < 0) {
|
|
puts("Failed to initialize xhci\n");
|
|
return ret;
|
|
}
|
|
|
|
*hccr = (struct xhci_hccr *)(ipq_base);
|
|
*hcor = (struct xhci_hcor *)((uint32_t) *hccr
|
|
+ HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
|
|
|
|
debug("omap-xhci: init hccr %x and hcor %x hc_length %d\n",
|
|
(uint32_t)*hccr, (uint32_t)*hcor,
|
|
(uint32_t)HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
|
|
|
|
return ret;
|
|
}
|
|
|
|
void xhci_hcd_stop(int index)
|
|
{
|
|
struct ipq_xhci *ctx = &ipq;
|
|
|
|
ipq_xhci_core_exit(ctx);
|
|
}
|