Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ci20 v3.18 ehci fix #29

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions arch/mips/include/asm/mach-jz4740/jz4780-cgu.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,13 @@
#define CGU_REG_MSC1CDR 0xa4
#define CGU_REG_MSC2CDR 0xa8
#define CGU_REG_BCHCDR 0xac
#define CGU_REG_SRBC 0xc4
#define CGU_REG_CLOCKSTATUS 0xd4

/* This isn't documented in the Ingenic manual but was provided in their
* kernel as a hack. */
#define EHCI_REG_UTMI_BUS 0xb34900b0

/* bits within a PLL control register */
#define PLLCTL_M_SHIFT 19
#define PLLCTL_M_MASK (0x1fff << PLLCTL_M_SHIFT)
Expand Down Expand Up @@ -96,6 +101,8 @@
#define USBPCR1_USB_SEL BIT(28)
#define USBPCR1_WORD_IF0 BIT(19)
#define USBPCR1_WORD_IF1 BIT(18)
#define USBPCR1_DPPD1 BIT(22)
#define USBPCR1_DMPD1 BIT(23)

/* bits within the USBRDT register */
#define USBRDT_VBFIL_LD_EN BIT(25)
Expand All @@ -106,6 +113,14 @@
#define USBVBFIL_IDDIGFIL_MASK (0xffff << USBVBFIL_IDDIGFIL_SHIFT)
#define USBVBFIL_USBVBFIL_MASK (0xffff)

/* Bits within the UTMI Bus register */
#define UTMIBUS_WIDTH BIT(6)
/* bits within the SRBC register */
#define SRBC_UHC_SR BIT(14)

/* bits within the SRBC register */
#define SRBC_UHC_SR BIT(14)

enum jz4780_usb_port {
USB_PORT_OTG = 0,
USB_PORT_HOST = 1,
Expand Down Expand Up @@ -194,4 +209,18 @@ extern void jz4780_cgu_usb_reset(void);
*/
extern int jz4780_cgu_set_usbpcr_param(u32 param, bool enable);

/**
* jz4780_cgu_start_ehci - Setup SoC registers so that EHCI mode can work.
* Returns zero on success, else -ERRNO.
*/
extern int jz4780_cgu_start_ehci(void);

/**
* jz4780_cgu_stop_ehci - Force the USB port into suspend mode, thus disabling
* EHCI.
*/
extern void jz4780_cgu_stop_ehci(void);

extern int jz4780_cgu_start_ehci(void);

#endif /* __MIPS_ASM_MACH_JZ4780_JZ4780_CGU_H__ */
154 changes: 71 additions & 83 deletions drivers/clk/jz47xx/jz4780-cgu.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,89 +27,6 @@
#include "jz47xx-cgu.h"
#include <asm/mach-jz4740/jz4780-cgu.h>

/* CGU register offsets */
#define CGU_REG_CLOCKCONTROL 0x00
#define CGU_REG_PLLCONTROL 0x0c
#define CGU_REG_APLL 0x10
#define CGU_REG_MPLL 0x14
#define CGU_REG_EPLL 0x18
#define CGU_REG_VPLL 0x1c
#define CGU_REG_OPCR 0x24
#define CGU_REG_DDRCDR 0x2c
#define CGU_REG_VPUCDR 0x30
#define CGU_REG_USBPCR 0x3c
#define CGU_REG_USBRDT 0x40
#define CGU_REG_USBVBFIL 0x44
#define CGU_REG_USBPCR1 0x48
#define CGU_REG_LP0CDR 0x54
#define CGU_REG_I2SCDR 0x60
#define CGU_REG_LP1CDR 0x64
#define CGU_REG_MSC0CDR 0x68
#define CGU_REG_UHCCDR 0x6c
#define CGU_REG_SSICDR 0x74
#define CGU_REG_CIMCDR 0x7c
#define CGU_REG_PCMCDR 0x84
#define CGU_REG_GPUCDR 0x88
#define CGU_REG_HDMICDR 0x8c
#define CGU_REG_MSC1CDR 0xa4
#define CGU_REG_MSC2CDR 0xa8
#define CGU_REG_BCHCDR 0xac
#define CGU_REG_CLOCKSTATUS 0xd4

/* bits within a PLL control register */
#define PLLCTL_M_SHIFT 19
#define PLLCTL_M_MASK (0x1fff << PLLCTL_M_SHIFT)
#define PLLCTL_N_SHIFT 13
#define PLLCTL_N_MASK (0x3f << PLLCTL_N_SHIFT)
#define PLLCTL_OD_SHIFT 9
#define PLLCTL_OD_MASK (0xf << PLLCTL_OD_SHIFT)
#define PLLCTL_ON (1 << 4)
#define PLLCTL_BYPASS (1 << 1)
#define PLLCTL_ENABLE (1 << 0)

/* bits within the OPCR register */
#define OPCR_SPENDN0 (1 << 7)
#define OPCR_SPENDN1 (1 << 6)

/* bits within the USBPCR register */
#define USBPCR_USB_MODE BIT(31)
#define USBPCR_IDPULLUP_MASK (0x3 << 28)
#define USBPCR_COMMONONN BIT(25)
#define USBPCR_VBUSVLDEXT BIT(24)
#define USBPCR_VBUSVLDEXTSEL BIT(23)
#define USBPCR_POR BIT(22)
#define USBPCR_OTG_DISABLE BIT(20)
#define USBPCR_COMPDISTUNE_MASK (0x7 << 17)
#define USBPCR_OTGTUNE_MASK (0x7 << 14)
#define USBPCR_SQRXTUNE_MASK (0x7 << 11)
#define USBPCR_TXFSLSTUNE_MASK (0xf << 7)
#define USBPCR_TXPREEMPHTUNE BIT(6)
#define USBPCR_TXHSXVTUNE_MASK (0x3 << 4)
#define USBPCR_TXVREFTUNE_MASK 0xf

/* bits within the USBPCR1 register */
#define USBPCR1_REFCLKSEL_SHIFT 26
#define USBPCR1_REFCLKSEL_MASK (0x3 << USBPCR1_REFCLKSEL_SHIFT)
#define USBPCR1_REFCLKSEL_CORE (0x2 << USBPCR1_REFCLKSEL_SHIFT)
#define USBPCR1_REFCLKDIV_SHIFT 24
#define USBPCR1_REFCLKDIV_MASK (0x3 << USBPCR1_REFCLKDIV_SHIFT)
#define USBPCR1_REFCLKDIV_19_2 (0x3 << USBPCR1_REFCLKDIV_SHIFT)
#define USBPCR1_REFCLKDIV_48 (0x2 << USBPCR1_REFCLKDIV_SHIFT)
#define USBPCR1_REFCLKDIV_24 (0x1 << USBPCR1_REFCLKDIV_SHIFT)
#define USBPCR1_REFCLKDIV_12 (0x0 << USBPCR1_REFCLKDIV_SHIFT)
#define USBPCR1_USB_SEL BIT(28)
#define USBPCR1_WORD_IF0 BIT(19)
#define USBPCR1_WORD_IF1 BIT(18)

/* bits within the USBRDT register */
#define USBRDT_VBFIL_LD_EN BIT(25)
#define USBRDT_USBRDT_MASK 0x7fffff

/* bits within the USBVBFIL register */
#define USBVBFIL_IDDIGFIL_SHIFT 16
#define USBVBFIL_IDDIGFIL_MASK (0xffff << USBVBFIL_IDDIGFIL_SHIFT)
#define USBVBFIL_USBVBFIL_MASK (0xffff)

static struct jz47xx_cgu *cgu;

static u8 jz4780_otg_phy_get_parent(struct clk_hw *hw)
Expand Down Expand Up @@ -967,3 +884,74 @@ int jz4780_cgu_set_usbpcr_param(u32 param, bool enable)
return 0;
}
EXPORT_SYMBOL_GPL(jz4780_cgu_set_usbpcr_param);

void jz4780_cgu_stop_ehci(void)
{
u32 reg;

reg = readl(cgu->base + CGU_REG_OPCR);
writel(reg & (~OPCR_SPENDN1), cgu->base + CGU_REG_OPCR);
}
EXPORT_SYMBOL_GPL(jz4780_cgu_stop_ehci);

int jz4780_cgu_start_ehci(void)
{
static int has_reset;
int ret = 0;
unsigned long flags;
u32 reg;

spin_lock_irqsave(&cgu->power_lock, flags);
reg = readl(cgu->base + CGU_REG_USBPCR);
writel(reg & (~USBPCR_OTG_DISABLE), cgu->base + CGU_REG_USBPCR);

/* The PLL uses CLKCORE as reference */
reg = readl(cgu->base + CGU_REG_USBPCR1);
writel(reg | USBPCR1_REFCLKSEL_MASK, cgu->base + CGU_REG_USBPCR1);
spin_unlock_irqrestore(&cgu->power_lock, flags);

/* NOTE: hw and parent_rate aren't used, so we can set them to
* whatever. They are only there for compatibility with clk_ops.*/
jz4780_otg_phy_set_rate(NULL,
clk_get_rate(cgu->clocks.clks[JZ4780_CLK_EXCLK]), 0);

spin_lock_irqsave(&cgu->power_lock, flags);
/* Don't force port1(uhc) into suspend mode. */
reg = readl(cgu->base + CGU_REG_OPCR);
writel(reg | OPCR_SPENDN1, cgu->base + CGU_REG_OPCR);

/* port1's pulldown resistance on D- */
reg = readl(cgu->base + CGU_REG_USBPCR1);
writel(reg | USBPCR1_DMPD1, cgu->base + CGU_REG_USBPCR1);

/* port1's pulldown resistance on D+ */
reg = readl(cgu->base + CGU_REG_USBPCR1);
writel(reg | USBPCR1_DPPD1, cgu->base + CGU_REG_USBPCR1);
spin_unlock_irqrestore(&cgu->power_lock, flags);

ret = jz4780_cgu_set_usb_utmi_bus_width(USB_PORT_HOST,
USB_PORT_UTMI_BUS_WIDTH_16);
if (ret)
return ret;

/* Set utmi data bus width of controller to 16bit */
reg = readl((volatile int *)EHCI_REG_UTMI_BUS);
writel(reg | UTMIBUS_WIDTH, (volatile int *)EHCI_REG_UTMI_BUS);

jz4780_cgu_usb_reset();

if (!has_reset) {
/* UHC soft reset */
/* TODO: Check if these delays are correct */
reg = readl(cgu->base + CGU_REG_SRBC);
writel(reg | SRBC_UHC_SR, cgu->base + CGU_REG_SRBC);
udelay(300);
reg = readl(cgu->base + CGU_REG_SRBC);
writel(reg & ~(SRBC_UHC_SR), cgu->base + CGU_REG_SRBC);
udelay(300);
has_reset = 1;
}

return ret;
}
EXPORT_SYMBOL_GPL(jz4780_cgu_start_ehci);
9 changes: 9 additions & 0 deletions drivers/usb/host/ehci-jz4780.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ static int jz4780_ehci_probe(struct platform_device *pdev)
struct ehci_hcd *ehci;
struct jz4780_ehci_hcd *jz_ehci;
int irq, gpio_vbus, err = 0;
u32 temp;

/* Right now device-tree probed devices don't get dma_mask set.
* Since shared usb code relies on it, set it here for now.
Expand Down Expand Up @@ -139,12 +140,18 @@ static int jz4780_ehci_probe(struct platform_device *pdev)
goto cleanup_clk_en;
}

jz4780_cgu_start_ehci();

err = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (err) {
dev_err(&pdev->dev, "failed to add USB HCD\n");
goto cleanup_clk_en;
}

/* Set utmi data bus width of controller to 16bit */
temp = readl((volatile int *)EHCI_REG_UTMI_BUS);
writel(temp | UTMIBUS_WIDTH, (volatile int *)EHCI_REG_UTMI_BUS);

return err;

cleanup_clk_en:
Expand All @@ -167,6 +174,8 @@ static int jz4780_ehci_remove(struct platform_device *pdev)
usb_remove_hcd(hcd);
usb_put_hcd(hcd);

jz4780_cgu_stop_ehci();

clk_disable_unprepare(jz_ehci->clk);

return 0;
Expand Down