Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 230f7ede authored by Anatolij Gustschin's avatar Anatolij Gustschin Committed by Greg Kroah-Hartman
Browse files

USB: add USB EHCI support for MPC5121 SoC



Extends FSL EHCI platform driver glue layer to support
MPC5121 USB controllers. MPC5121 Rev 2.0 silicon EHCI
registers are in big endian format. The appropriate flags
are set using the information in the platform data structure.
MPC83xx system interface registers are not available on
MPC512x, so the access to these registers is isolated in
MPC512x case. Furthermore the USB controller clocks
must be enabled before 512x register accesses which is
done by providing platform specific init callback.

The MPC512x internal USB PHY doesn't provide supply voltage.
For boards using different power switches allow specifying
DRVVBUS and PWR_FAULT signal polarity of the MPC5121 internal
PHY using "fsl,invert-drvvbus" and "fsl,invert-pwr-fault"
properties in the device tree USB nodes. Adds documentation
for this new device tree bindings.

Signed-off-by: default avatarAnatolij Gustschin <agust@denx.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 126512e3
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@ and additions :
Required properties :
 - compatible : Should be "fsl-usb2-mph" for multi port host USB
   controllers, or "fsl-usb2-dr" for dual role USB controllers
   or "fsl,mpc5121-usb2-dr" for dual role USB controllers of MPC5121
 - phy_type : For multi port host USB controllers, should be one of
   "ulpi", or "serial". For dual role USB controllers, should be
   one of "ulpi", "utmi", "utmi_wide", or "serial".
@@ -33,6 +34,12 @@ Recommended properties :
 - interrupt-parent : the phandle for the interrupt controller that
   services interrupts for this device.

Optional properties :
 - fsl,invert-drvvbus : boolean; for MPC5121 USB0 only. Indicates the
   port power polarity of internal PHY signal DRVVBUS is inverted.
 - fsl,invert-pwr-fault : boolean; for MPC5121 USB0 only. Indicates
   the PWR_FAULT signal polarity is inverted.

Example multi port host USB controller device node :
	usb@22000 {
		compatible = "fsl-usb2-mph";
@@ -57,3 +64,18 @@ Example dual role USB controller device node :
		dr_mode = "otg";
		phy = "ulpi";
	};

Example dual role USB controller device node for MPC5121ADS:

	usb@4000 {
		compatible = "fsl,mpc5121-usb2-dr";
		reg = <0x4000 0x1000>;
		#address-cells = <1>;
		#size-cells = <0>;
		interrupt-parent = < &ipic >;
		interrupts = <44 0x8>;
		dr_mode = "otg";
		phy_type = "utmi_wide";
		fsl,invert-drvvbus;
		fsl,invert-pwr-fault;
	};
+1 −0
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ config USB_ARCH_HAS_OHCI
config USB_ARCH_HAS_EHCI
	boolean
	default y if PPC_83xx
	default y if PPC_MPC512x
	default y if SOC_AU1200
	default y if ARCH_IXP4XX
	default y if ARCH_W90X900
+4 −2
Original line number Diff line number Diff line
@@ -93,12 +93,14 @@ config USB_EHCI_TT_NEWSCHED

config USB_EHCI_BIG_ENDIAN_MMIO
	bool
	depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX)
	depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || ARCH_IXP4XX || \
				    XPS_USB_HCD_XILINX || PPC_MPC512x)
	default y

config USB_EHCI_BIG_ENDIAN_DESC
	bool
	depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX)
	depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX || \
				    PPC_MPC512x)
	default y

config XPS_USB_HCD_XILINX
+71 −28
Original line number Diff line number Diff line
@@ -116,13 +116,33 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
		goto err3;
	}

	/* Enable USB controller */
	temp = in_be32(hcd->regs + 0x500);
	out_be32(hcd->regs + 0x500, temp | 0x4);
	pdata->regs = hcd->regs;

	/* Set to Host mode */
	temp = in_le32(hcd->regs + 0x1a8);
	out_le32(hcd->regs + 0x1a8, temp | 0x3);
	/*
	 * do platform specific init: check the clock, grab/config pins, etc.
	 */
	if (pdata->init && pdata->init(pdev)) {
		retval = -ENODEV;
		goto err3;
	}

	/*
	 * Check if it is MPC5121 SoC, otherwise set pdata->have_sysif_regs
	 * flag for 83xx or 8536 system interface registers.
	 */
	if (pdata->big_endian_mmio)
		temp = in_be32(hcd->regs + FSL_SOC_USB_ID);
	else
		temp = in_le32(hcd->regs + FSL_SOC_USB_ID);

	if ((temp & ID_MSK) != (~((temp & NID_MSK) >> 8) & ID_MSK))
		pdata->have_sysif_regs = 1;

	/* Enable USB controller, 83xx or 8536 */
	if (pdata->have_sysif_regs)
		setbits32(hcd->regs + FSL_SOC_USB_CTRL, 0x4);

	/* Don't need to set host mode here. It will be done by tdi_reset() */

	retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
	if (retval != 0)
@@ -137,6 +157,8 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
	usb_put_hcd(hcd);
      err1:
	dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), retval);
	if (pdata->exit)
		pdata->exit(pdev);
	return retval;
}

@@ -154,17 +176,30 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
			       struct platform_device *pdev)
{
	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;

	usb_remove_hcd(hcd);

	/*
	 * do platform specific un-initialization:
	 * release iomux pins, disable clock, etc.
	 */
	if (pdata->exit)
		pdata->exit(pdev);
	iounmap(hcd->regs);
	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
	usb_put_hcd(hcd);
}

static void mpc83xx_setup_phy(struct ehci_hcd *ehci,
static void ehci_fsl_setup_phy(struct ehci_hcd *ehci,
			       enum fsl_usb2_phy_modes phy_mode,
			       unsigned int port_offset)
{
	u32 portsc = 0;
	u32 portsc;

	portsc = ehci_readl(ehci, &ehci->regs->port_status[port_offset]);
	portsc &= ~(PORT_PTS_MSK | PORT_PTS_PTW);

	switch (phy_mode) {
	case FSL_USB2_PHY_ULPI:
		portsc |= PORT_PTS_ULPI;
@@ -184,20 +219,21 @@ static void mpc83xx_setup_phy(struct ehci_hcd *ehci,
	ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]);
}

static void mpc83xx_usb_setup(struct usb_hcd *hcd)
static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
{
	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
	struct usb_hcd *hcd = ehci_to_hcd(ehci);
	struct fsl_usb2_platform_data *pdata;
	void __iomem *non_ehci = hcd->regs;
	u32 temp;

	pdata =
	    (struct fsl_usb2_platform_data *)hcd->self.controller->
	    platform_data;
	pdata = hcd->self.controller->platform_data;

	/* Enable PHY interface in the control reg. */
	if (pdata->have_sysif_regs) {
		temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
		out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | 0x00000004);
		out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0000001b);
	}

#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
	/*
@@ -214,7 +250,7 @@ static void mpc83xx_usb_setup(struct usb_hcd *hcd)

	if ((pdata->operating_mode == FSL_USB2_DR_HOST) ||
			(pdata->operating_mode == FSL_USB2_DR_OTG))
		mpc83xx_setup_phy(ehci, pdata->phy_mode, 0);
		ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0);

	if (pdata->operating_mode == FSL_USB2_MPH_HOST) {
		unsigned int chip, rev, svr;
@@ -228,11 +264,12 @@ static void mpc83xx_usb_setup(struct usb_hcd *hcd)
			ehci->has_fsl_port_bug = 1;

		if (pdata->port_enables & FSL_USB2_PORT0_ENABLED)
			mpc83xx_setup_phy(ehci, pdata->phy_mode, 0);
			ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0);
		if (pdata->port_enables & FSL_USB2_PORT1_ENABLED)
			mpc83xx_setup_phy(ehci, pdata->phy_mode, 1);
			ehci_fsl_setup_phy(ehci, pdata->phy_mode, 1);
	}

	if (pdata->have_sysif_regs) {
#ifdef CONFIG_PPC_85xx
		out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x00000008);
		out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000080);
@@ -242,11 +279,12 @@ static void mpc83xx_usb_setup(struct usb_hcd *hcd)
#endif
		out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
	}
}

/* called after powerup, by probe or system-pm "wakeup" */
static int ehci_fsl_reinit(struct ehci_hcd *ehci)
{
	mpc83xx_usb_setup(ehci_to_hcd(ehci));
	ehci_fsl_usb_setup(ehci);
	ehci_port_power(ehci, 0);

	return 0;
@@ -257,6 +295,11 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
{
	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
	int retval;
	struct fsl_usb2_platform_data *pdata;

	pdata = hcd->self.controller->platform_data;
	ehci->big_endian_desc = pdata->big_endian_desc;
	ehci->big_endian_mmio = pdata->big_endian_mmio;

	/* EHCI registers start at offset 0x100 */
	ehci->caps = hcd->regs + 0x100;
@@ -370,7 +413,7 @@ static const struct hc_driver ehci_fsl_hc_driver = {
	 * generic hardware linkage
	 */
	.irq = ehci_irq,
	.flags = HCD_USB2,
	.flags = HCD_USB2 | HCD_MEMORY,

	/*
	 * basic lifecycle operations
+12 −1
Original line number Diff line number Diff line
/* Copyright (c) 2005 freescale semiconductor
/* Copyright (C) 2005-2010 Freescale Semiconductor, Inc.
 * Copyright (c) 2005 MontaVista Software
 *
 * This program is free software; you can redistribute  it and/or modify it
@@ -19,6 +19,9 @@
#define _EHCI_FSL_H

/* offsets for the non-ehci registers in the FSL SOC USB controller */
#define FSL_SOC_USB_ID		0x0
#define ID_MSK			0x3f
#define NID_MSK			0x3f00
#define FSL_SOC_USB_ULPIVP	0x170
#define FSL_SOC_USB_PORTSC1	0x184
#define PORT_PTS_MSK		(3<<30)
@@ -27,6 +30,14 @@
#define	PORT_PTS_SERIAL		(3<<30)
#define PORT_PTS_PTW		(1<<28)
#define FSL_SOC_USB_PORTSC2	0x188

#define FSL_SOC_USB_USBGENCTRL	0x200
#define USBGENCTRL_PPP		(1 << 3)
#define USBGENCTRL_PFP		(1 << 2)
#define FSL_SOC_USB_ISIPHYCTRL	0x204
#define ISIPHYCTRL_PXE		(1)
#define ISIPHYCTRL_PHYE		(1 << 4)

#define FSL_SOC_USB_SNOOP1	0x400	/* NOTE: big-endian */
#define FSL_SOC_USB_SNOOP2	0x404	/* NOTE: big-endian */
#define FSL_SOC_USB_AGECNTTHRSH	0x408	/* NOTE: big-endian */
Loading