Message ID | 1437639980-16286-9-git-send-email-sr@denx.de |
---|---|
State | Superseded |
Delegated to: | Prafulla Wadaskar |
Headers | show |
On Thursday, July 23, 2015 at 10:26:19 AM, Stefan Roese wrote: > This patch enables the USB EHCI support for the Marvell Armada XP (AXP) > SoCs. In compatism to the Armada 38x (A38x), the AXP needs to configure > the USB PLL and the USB PHY's specifically in U-Boot. The A38x has done > this already in the bin_hdr (SPL U-Boot). Without this, accessing the > controller registers in U-Boot or Linux will hang the CPU. > > Additionally, the AXP uses a different USB EHCI base address. This > patch also takes care of this by runtime SoC detection in the Marvell > EHCI driver. > > Signed-off-by: Stefan Roese <sr@denx.de> > Signed-off-by: Anton Schubert <anton.schubert@gmx.de> > Cc: Marek Vasut <marex@denx.de> > Cc: Luka Perkov <luka.perkov@sartura.hr> > --- > arch/arm/mach-mvebu/cpu.c | 58 > ++++++++++++++++++++++++++++++++++ arch/arm/mach-mvebu/include/mach/soc.h > | 1 + > drivers/usb/host/ehci-marvell.c | 9 +++++- > 3 files changed, 67 insertions(+), 1 deletion(-) > > diff --git a/arch/arm/mach-mvebu/cpu.c b/arch/arm/mach-mvebu/cpu.c > index bde3990..0a31b85 100644 > --- a/arch/arm/mach-mvebu/cpu.c > +++ b/arch/arm/mach-mvebu/cpu.c > @@ -179,6 +179,61 @@ static void set_cbar(u32 addr) > asm("mcr p15, 4, %0, c15, c0" : : "r" (addr)); > } > > +#define MV_USB_PHY_BASE (MVEBU_AXP_USB_BASE + 0x800) > +#define MV_USB_PHY_PLL_REG(reg) (MV_USB_PHY_BASE | ((reg & 0xF) << 2)) (reg) in the macro please. > +#define MV_USB_X3_BASE(addr) (MVEBU_AXP_USB_BASE | BIT(11) | \ > + (((addr) & 0xF) << 6)) > +#define MV_USB_X3_PHY_CHANNEL(dev, reg) (MV_USB_X3_BASE(dev + 1) | \ > + ((reg & 0xF) << 2)) Same here. > + > +static void setup_usb_phys(void) > +{ > + u32 val; > + int dev; > + > + /* > + * USB PLL init > + */ > + > + /* Setup PLL frequency */ > + val = readl(MV_USB_PHY_PLL_REG(1)); > + val &= ~(0x3FF); > + val |= 0x605; /* USB REF frequency = 25 MHz */ > + writel(val, MV_USB_PHY_PLL_REG(1)); Please use clrsetbits_le32() and friends :) > + /* Power up PLL and PHY channel */ > + val = readl(MV_USB_PHY_PLL_REG(2)); > + val |= BIT(9); > + writel(val, MV_USB_PHY_PLL_REG(2)); > + > + /* Assert VCOCAL_START */ > + val = readl(MV_USB_PHY_PLL_REG(1)); > + val |= BIT(21); > + writel(val, MV_USB_PHY_PLL_REG(1)); > + > + mdelay(1); > + > + /* > + * USB PHY init (change from defaults) specific for 40nm (78X30 78X60) > + */ > + > + for (dev = 0; dev < 3; dev++) { > + val = readl(MV_USB_X3_PHY_CHANNEL(dev, 3)); > + val |= BIT(15); > + writel(val, MV_USB_X3_PHY_CHANNEL(dev, 3)); > + > + /* Assert REG_RCAL_START in Channel REG 1 */ > + val = readl(MV_USB_X3_PHY_CHANNEL(dev, 1)); > + val |= BIT(12); > + writel(val, MV_USB_X3_PHY_CHANNEL(dev, 1)); > + > + udelay(40); > + > + val = readl(MV_USB_X3_PHY_CHANNEL(dev, 1)); > + val &= ~BIT(12); > + writel(val, MV_USB_X3_PHY_CHANNEL(dev, 1)); > + } > +} > > int arch_cpu_init(void) > { > @@ -249,6 +304,9 @@ int arch_cpu_init(void) > reg |= GE0_PUP_EN | GE1_PUP_EN | LCD_PUP_EN | > NAND_PUP_EN | SPI_PUP_EN; > writel(reg, ARMADA_XP_PUP_ENABLE); > + > + /* Configure USB PLL and PHYs on AXP */ > + setup_usb_phys(); > } > > /* Enable NAND and NAND arbiter */ > diff --git a/arch/arm/mach-mvebu/include/mach/soc.h > b/arch/arm/mach-mvebu/include/mach/soc.h index 6115d6e..a8a6b27 100644 > --- a/arch/arm/mach-mvebu/include/mach/soc.h > +++ b/arch/arm/mach-mvebu/include/mach/soc.h > @@ -65,6 +65,7 @@ > #define MVEBU_EGIGA2_BASE (MVEBU_REGISTER(0x30000)) > #define MVEBU_EGIGA3_BASE (MVEBU_REGISTER(0x34000)) > #define MVEBU_REG_PCIE_BASE (MVEBU_REGISTER(0x40000)) > +#define MVEBU_AXP_USB_BASE (MVEBU_REGISTER(0x50000)) > #define MVEBU_USB20_BASE (MVEBU_REGISTER(0x58000)) > #define MVEBU_EGIGA0_BASE (MVEBU_REGISTER(0x70000)) > #define MVEBU_EGIGA1_BASE (MVEBU_REGISTER(0x74000)) The () around MVEBU_REGISTER() shouldn't be needed btw ;-)
diff --git a/arch/arm/mach-mvebu/cpu.c b/arch/arm/mach-mvebu/cpu.c index bde3990..0a31b85 100644 --- a/arch/arm/mach-mvebu/cpu.c +++ b/arch/arm/mach-mvebu/cpu.c @@ -179,6 +179,61 @@ static void set_cbar(u32 addr) asm("mcr p15, 4, %0, c15, c0" : : "r" (addr)); } +#define MV_USB_PHY_BASE (MVEBU_AXP_USB_BASE + 0x800) +#define MV_USB_PHY_PLL_REG(reg) (MV_USB_PHY_BASE | ((reg & 0xF) << 2)) +#define MV_USB_X3_BASE(addr) (MVEBU_AXP_USB_BASE | BIT(11) | \ + (((addr) & 0xF) << 6)) +#define MV_USB_X3_PHY_CHANNEL(dev, reg) (MV_USB_X3_BASE(dev + 1) | \ + ((reg & 0xF) << 2)) + +static void setup_usb_phys(void) +{ + u32 val; + int dev; + + /* + * USB PLL init + */ + + /* Setup PLL frequency */ + val = readl(MV_USB_PHY_PLL_REG(1)); + val &= ~(0x3FF); + val |= 0x605; /* USB REF frequency = 25 MHz */ + writel(val, MV_USB_PHY_PLL_REG(1)); + + /* Power up PLL and PHY channel */ + val = readl(MV_USB_PHY_PLL_REG(2)); + val |= BIT(9); + writel(val, MV_USB_PHY_PLL_REG(2)); + + /* Assert VCOCAL_START */ + val = readl(MV_USB_PHY_PLL_REG(1)); + val |= BIT(21); + writel(val, MV_USB_PHY_PLL_REG(1)); + + mdelay(1); + + /* + * USB PHY init (change from defaults) specific for 40nm (78X30 78X60) + */ + + for (dev = 0; dev < 3; dev++) { + val = readl(MV_USB_X3_PHY_CHANNEL(dev, 3)); + val |= BIT(15); + writel(val, MV_USB_X3_PHY_CHANNEL(dev, 3)); + + /* Assert REG_RCAL_START in Channel REG 1 */ + val = readl(MV_USB_X3_PHY_CHANNEL(dev, 1)); + val |= BIT(12); + writel(val, MV_USB_X3_PHY_CHANNEL(dev, 1)); + + udelay(40); + + val = readl(MV_USB_X3_PHY_CHANNEL(dev, 1)); + val &= ~BIT(12); + writel(val, MV_USB_X3_PHY_CHANNEL(dev, 1)); + } +} int arch_cpu_init(void) { @@ -249,6 +304,9 @@ int arch_cpu_init(void) reg |= GE0_PUP_EN | GE1_PUP_EN | LCD_PUP_EN | NAND_PUP_EN | SPI_PUP_EN; writel(reg, ARMADA_XP_PUP_ENABLE); + + /* Configure USB PLL and PHYs on AXP */ + setup_usb_phys(); } /* Enable NAND and NAND arbiter */ diff --git a/arch/arm/mach-mvebu/include/mach/soc.h b/arch/arm/mach-mvebu/include/mach/soc.h index 6115d6e..a8a6b27 100644 --- a/arch/arm/mach-mvebu/include/mach/soc.h +++ b/arch/arm/mach-mvebu/include/mach/soc.h @@ -65,6 +65,7 @@ #define MVEBU_EGIGA2_BASE (MVEBU_REGISTER(0x30000)) #define MVEBU_EGIGA3_BASE (MVEBU_REGISTER(0x34000)) #define MVEBU_REG_PCIE_BASE (MVEBU_REGISTER(0x40000)) +#define MVEBU_AXP_USB_BASE (MVEBU_REGISTER(0x50000)) #define MVEBU_USB20_BASE (MVEBU_REGISTER(0x58000)) #define MVEBU_EGIGA0_BASE (MVEBU_REGISTER(0x70000)) #define MVEBU_EGIGA1_BASE (MVEBU_REGISTER(0x74000)) diff --git a/drivers/usb/host/ehci-marvell.c b/drivers/usb/host/ehci-marvell.c index 03c489c..826e7f7 100644 --- a/drivers/usb/host/ehci-marvell.c +++ b/drivers/usb/host/ehci-marvell.c @@ -33,7 +33,14 @@ DECLARE_GLOBAL_DATA_PTR; */ #ifdef CONFIG_ARMADA_XP -#define MVUSB0_BASE MVEBU_USB20_BASE +/* + * Armada XP and Armada 38x have different base addresses for + * the USB 2.0 EHCI host controller. So we need to provide + * a mechnism to support both here. + */ +#define MVUSB0_BASE \ + (mvebu_soc_family() == MVEBU_SOC_A38X ? \ + MVEBU_USB20_BASE : MVEBU_AXP_USB_BASE) /* * Once all the older Marvell SoC's (Orion, Kirkwood) are converted