[U-Boot] [PATCH] Add support for the MPC5121e USB Host controller.

Damien Dusha d.dusha at gmail.com
Sun Aug 22 07:41:54 CEST 2010


Add support for the USB Host controller of the MPC5121e, based on the original patch by Francesco Rendine [1].

The patch configures the USB Host controller and the on-board UTMI phy, including the Freescale-specific registers as per the Linux kernel driver.

Tested on the MPC5121ADS platform with various USB mass storage devices.

[1] http://lists.denx.de/pipermail/u-boot/2009-June/055022.html

Signed-off-by: Damien Dusha <d.dusha at gmail.com>
---
 arch/powerpc/include/asm/immap_512x.h   |    4 +
 board/freescale/mpc5121ads/mpc5121ads.c |    4 +-
 drivers/usb/host/ehci-fsl.c             |  137 ++++++++++++++++++++++++++++-
 drivers/usb/host/ehci.h                 |    5 +
 include/configs/mpc5121ads.h            |   22 +++++-
 include/usb/ehci-fsl.h                  |  149 +++++++++++++++++++++++++------
 6 files changed, 292 insertions(+), 29 deletions(-)

diff --git a/arch/powerpc/include/asm/immap_512x.h b/arch/powerpc/include/asm/immap_512x.h
index 7f9db8b..4923a17 100644
--- a/arch/powerpc/include/asm/immap_512x.h
+++ b/arch/powerpc/include/asm/immap_512x.h
@@ -1246,4 +1246,8 @@ static inline u32 get_pata_base (void)
 }
 #endif	/* __ASSEMBLY__ */
 
+#define CONFIG_SYS_MPC512x_USB_OFFSET   0x4000
+#define CONFIG_SYS_MPC512x_USB_ADDR \
+	(CONFIG_SYS_IMMR + CONFIG_SYS_MPC512x_USB_OFFSET)
+
 #endif /* __IMMAP_512x__ */
diff --git a/board/freescale/mpc5121ads/mpc5121ads.c b/board/freescale/mpc5121ads/mpc5121ads.c
index 2e13ea8..4c0caa7 100644
--- a/board/freescale/mpc5121ads/mpc5121ads.c
+++ b/board/freescale/mpc5121ads/mpc5121ads.c
@@ -53,7 +53,9 @@ DECLARE_GLOBAL_DATA_PTR;
 #define SCCR2_CLOCKS_EN	(CLOCK_SCCR2_DIU_EN |		\
 			 CLOCK_SCCR2_I2C_EN |		\
 			 CLOCK_SCCR2_MEM_EN |		\
-			 CLOCK_SCCR2_SPDIF_EN)
+			 CLOCK_SCCR2_SPDIF_EN |  	\
+			 CLOCK_SCCR2_USB1_EN | 		\
+			 CLOCK_SCCR2_USB2_EN)
 
 void __mpc5121_nfc_select_chip(struct mtd_info *mtd, int chip);
 
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index c674929..d7b07ca 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -1,4 +1,9 @@
 /*
+ * (C) Copyright 2010, Damien Dusha, <d.dusha at gmail.com>
+ *
+ * (C) Copyright 2009, Value Team S.p.A.
+ * Francesco Rendine, <francesco.rendine at ...>
+ *
  * (C) Copyright 2009 Freescale Semiconductor, Inc.
  *
  * (C) Copyright 2008, Excito Elektronik i Sk=E5ne AB
@@ -30,6 +35,7 @@
 #include "ehci.h"
 #include "ehci-core.h"
 
+#ifndef  CONFIG_MPC512X
 /*
  * Create the appropriate control structures to manage
  * a new EHCI host controller.
@@ -40,7 +46,7 @@ int ehci_hcd_init(void)
 {
 	struct usb_ehci *ehci;
 
-	ehci = (struct usb_ehci *)CONFIG_SYS_MPC8xxx_USB_ADDR;
+	ehci = (struct usb_ehci *)CONFIG_SYS_FSL_USB_ADDR;
 	hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength);
 	hcor = (struct ehci_hcor *)((uint32_t) hccr +
 			HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
@@ -77,3 +83,132 @@ int ehci_hcd_stop(void)
 {
 	return 0;
 }
+
+#else
+
+static void fsl_setup_phy(volatile struct ehci_hcor *);
+static void fsl_platform_set_host_mode(volatile struct usb_ehci *ehci);
+static int reset_usb_controller(volatile struct usb_ehci *ehci);
+static void usb_platform_dr_init(volatile struct usb_ehci *ehci);
+
+/*
+ * Initialise SOC FSL EHCI Controller
+ *
+ * This code is derived from EHCI FSL USB Linux driver for MPC5121
+ *
+ */
+int ehci_hcd_init(void)
+{
+	volatile struct usb_ehci *ehci;
+
+	/* Hook the memory mapped registers for EHCI-Controller */
+	ehci = (struct usb_ehci *)CONFIG_SYS_FSL_USB_ADDR;
+	hccr = (struct ehci_hccr *)((uint32_t)&(ehci->caplength));
+	hcor = (struct ehci_hcor *)((uint32_t) hccr +
+			HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+	/* configure interface for UTMI_WIDE */
+	usb_platform_dr_init(ehci);
+
+	/* Init Phy USB0 to UTMI+ */
+	fsl_setup_phy(hcor);
+
+	/* Set to host mode */
+	fsl_platform_set_host_mode(ehci);
+
+	/*
+	 * Setting the burst size seems to be required to prevent the
+	 * USB from hanging when communicating with certain USB Mass
+	 * storage devices. This was determined by analysing the
+	 * EHCI registers under Linux vs U-Boot and burstsize was the
+	 * major non-interrupt related difference between the two
+	 * implementations.
+	 *
+	 * Some USB sticks behave better than others. In particular,
+	 * the following USB stick is especially problematic:
+	 * 0930:6545 Toshiba Corp
+	 *
+	 * The burstsize is set here to match the Linux implementation.
+	 */
+	out_be32(&ehci->burstsize, FSL_EHCI_TXPBURST(8) | FSL_EHCI_RXPBURST(8));
+
+	return 0;
+}
+
+/*
+ * Destroy the appropriate control structures corresponding
+ * the the EHCI host controller.
+ */
+int ehci_hcd_stop(void)
+{
+	volatile struct usb_ehci *ehci;
+	int exit_status = 0;
+
+	if (hcor) {
+		/* Unhook struct */
+		hccr = NULL;
+		hcor = NULL;
+
+		/* Reset the USB controller */
+		ehci = (struct usb_ehci *)CONFIG_SYS_FSL_USB_ADDR;
+		exit_status = reset_usb_controller(ehci);
+	}
+
+	return exit_status;
+}
+
+static int reset_usb_controller(volatile struct usb_ehci *ehci)
+{
+	unsigned int i;
+
+	/* Command a reset of the USB Controller */
+	out_be32(&(ehci->usbcmd), EHCI_FSL_USBCMD_RST);
+
+	/* Wait for the reset process to finish */
+	for (i = 65535 ; i > 0 ; i--) {
+		/*
+		 * The host will set this bit to zero once the
+		 * reset process is complete
+		 */
+		if ((in_be32(&(ehci->usbcmd)) & EHCI_FSL_USBCMD_RST) == 0)
+			return 0;
+	}
+
+	/* Hub did not reset in time */
+	return -1;
+}
+
+static void fsl_setup_phy(volatile struct ehci_hcor *hcor)
+{
+	uint32_t portsc;
+
+	portsc  = ehci_readl(&hcor->or_portsc[0]);
+	portsc &= ~(PORT_PTS_MSK | PORT_PTS_PTW);
+
+	/* Enable the phy mode to UTMI Wide */
+	portsc |= PORT_PTS_PTW;
+	portsc |= PORT_PTS_UTMI;
+
+	ehci_writel(&hcor->or_portsc[0], portsc);
+}
+
+static void fsl_platform_set_host_mode(volatile struct usb_ehci *ehci)
+{
+	uint32_t temp;
+
+	temp  = in_le32(&ehci->usbmode);
+	temp |= CM_HOST | ES_BE;
+	out_le32(&ehci->usbmode, temp);
+}
+
+static void usb_platform_dr_init(volatile struct usb_ehci *ehci)
+{
+	/* Confgure interface for UTMI_WIDE */
+	out_be32(&ehci->isiphyctrl, PHYCTRL_PHYE | PHYCTRL_PXE);
+	out_be32(&ehci->usbgenctrl, GC_PPP | GC_PFP );
+}
+
+#endif
+
+
+
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index b3c1d5d..5ba612d 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -71,6 +71,11 @@ struct ehci_hcor {
 #define	STD_ASS		(1 << 15)
 #define STS_HALT	(1 << 12)
 	uint32_t or_usbintr;
+#define INTR_UE		(1 << 0)		/* USB interrupt enable */
+#define INTR_UEE	(1 << 1)		/* USB error interrupt enable */
+#define INTR_PCE	(1 << 2)		/* Port change detect enable */
+#define INTR_SEE	(1 << 4)		/* system error enable */
+#define INTR_AAE	(1 << 5)		/* Int on async adavance */
 	uint32_t or_frindex;
 	uint32_t or_ctrldssegment;
 	uint32_t or_periodiclistbase;
diff --git a/include/configs/mpc5121ads.h b/include/configs/mpc5121ads.h
index 5281042..ce0df57 100644
--- a/include/configs/mpc5121ads.h
+++ b/include/configs/mpc5121ads.h
@@ -374,6 +374,20 @@
 #define CONFIG_SYS_I2C_RTC_ADDR		0x68	/* at address 0x68		*/
 
 /*
+ * USB  Support
+ */
+#define CONFIG_CMD_USB
+
+#if defined(CONFIG_CMD_USB)
+#define CONFIG_USB_EHCI				/* Enable EHCI Support	*/
+#define CONFIG_USB_EHCI_FSL			/* On a FSL platform	*/
+#define CONFIG_EHCI_MMIO_BIG_ENDIAN		/* With big-endian regs	*/
+#define CONFIG_EHCI_DESC_BIG_ENDIAN
+#define CONFIG_EHCI_IS_TDI
+#define CONFIG_USB_STORAGE
+#endif
+
+/*
  * Environment
  */
 #define CONFIG_ENV_IS_IN_FLASH	1
@@ -441,10 +455,16 @@
 					"mpc5121.nand:-(data)"
 
 
-#if defined(CONFIG_CMD_IDE) || defined(CONFIG_CMD_EXT2)
+#if defined(CONFIG_CMD_IDE) || defined(CONFIG_CMD_EXT2) || \
+	defined(CONFIG_CMD_USB)
+
 #define CONFIG_DOS_PARTITION
 #define CONFIG_MAC_PARTITION
 #define CONFIG_ISO_PARTITION
+
+#define CONFIG_CMD_FAT
+#define CONFIG_SUPPORT_VFAT
+
 #endif /* defined(CONFIG_CMD_IDE) */
 
 /*
diff --git a/include/usb/ehci-fsl.h b/include/usb/ehci-fsl.h
index f48945a..559a96a 100644
--- a/include/usb/ehci-fsl.h
+++ b/include/usb/ehci-fsl.h
@@ -35,12 +35,17 @@
 #define PORT_PTS_ULPI		(2 << 30)
 #define PORT_PTS_SERIAL		(3 << 30)
 #define PORT_PTS_PTW		(1 << 28)
+#define PORT_PFSC		(1 << 24)	/* See p39 of MPC5121e ERM */
+#define PORT_PTS_PHCD		(1 << 23)
+#define PORT_PP			(1 << 12)
+#define PORT_PR			(1 << 8)
 
 /* USBMODE Register bits */
 #define CM_IDLE			(0 << 0)
 #define CM_RESERVED		(1 << 0)
 #define CM_DEVICE		(2 << 0)
 #define CM_HOST			(3 << 0)
+#define ES_BE			(1 << 2)	/* Big Endian Select MPC5121e */
 #define USBMODE_RESERVED_2	(0 << 2)
 #define SLOM			(1 << 3)
 #define SDIS			(1 << 4)
@@ -70,7 +75,78 @@
 #define PHY_CLK_VALID		(1 << 17)
 
 #define FSL_SOC_USB_PORTSC2	0x188
+
+/* OTG Status Control Register bits */
+#define FSL_SOC_USB_OTGSC	0x1a4
+#define CTRL_VBUS_DISCHARGE	(1 << 0)
+#define CTRL_VBUS_CHARGE	(1 << 1)
+#define CTRL_OTG_TERMINATION	(1 << 3)
+#define CTRL_DATA_PULSING	(1 << 4)
+#define CTRL_ID_PULL_EN		(1 << 5)
+#define HA_DATA_PULSE		(1 << 6)
+#define HA_BA			(1 << 7)
+#define STS_USB_ID		(1 << 8)
+#define STS_A_VBUS_VALID	(1 << 9)
+#define STS_A_SESSION_VALID	(1 << 10)
+#define STS_B_SESSION_VALID	(1 << 11)
+#define STS_B_SESSION_END	(1 << 12)
+#define STS_1MS_TOGGLE		(1 << 13)
+#define STS_DATA_PULSING	(1 << 14)
+#define INTSTS_USB_ID		(1 << 16)
+#define INTSTS_A_VBUS_VALID	(1 << 17)
+#define INTSTS_A_SESSION_VALID	(1 << 18)
+#define INTSTS_B_SESSION_VALID	(1 << 19)
+#define INTSTS_B_SESSION_END	(1 << 20)
+#define INTSTS_1MS		(1 << 21)
+#define INTSTS_DATA_PULSING	(1 << 22)
+#define INTR_USB_ID_EN		(1 << 24)
+#define INTR_A_VBUS_VALID_EN	(1 << 25)
+#define INTR_A_SESSION_VALID_EN	(1 << 26)
+#define INTR_B_SESSION_VALID_EN	(1 << 27)
+#define INTR_B_SESSION_END_EN	(1 << 28)
+#define INTR_1MS_TIMER_EN	(1 << 29)
+#define INTR_DATA_PULSING_EN	(1 << 30)
+#define INTSTS_MASK		0x00ff0000
+
+/* USBCMD Bits of interest */
+#define EHCI_FSL_USBCMD_RST	(1 << 1)
+#define EHCI_FSL_USBCMD_RS	(1 << 0)
+
+#define  INTERRUPT_ENABLE_BITS_MASK	\
+		(INTR_USB_ID_EN		| \
+		INTR_1MS_TIMER_EN	| \
+		INTR_A_VBUS_VALID_EN	| \
+		INTR_A_SESSION_VALID_EN	| \
+		INTR_B_SESSION_VALID_EN	| \
+		INTR_B_SESSION_END_EN	| \
+		INTR_DATA_PULSING_EN)
+
+#define  INTERRUPT_STATUS_BITS_MASK	\
+		(INTSTS_USB_ID		| \
+		INTR_1MS_TIMER_EN	| \
+		INTSTS_A_VBUS_VALID	| \
+		INTSTS_A_SESSION_VALID	| \
+		INTSTS_B_SESSION_VALID	| \
+		INTSTS_B_SESSION_END	| \
+		INTSTS_DATA_PULSING)
+
 #define FSL_SOC_USB_USBMODE	0x1a8
+
+#define USBGENCTRL		0x200		/* NOTE: big endian */
+#define GC_WU_INT_CLR		(1 << 5)	/* Wakeup int clear */
+#define GC_ULPI_SEL		(1 << 4)	/* ULPI i/f select (usb0 only)*/
+#define GC_PPP			(1 << 3)	/* Port Power Polarity */
+#define GC_PFP			(1 << 2)	/* Power Fault Polarity */
+#define GC_WU_ULPI_EN		(1 << 1)	/* Wakeup on ULPI event */
+#define GC_WU_IE		(1 << 1)	/* Wakeup interrupt enable */
+
+#define ISIPHYCTRL		0x204		/* NOTE: big endian */
+#define PHYCTRL_PHYE		(1 << 4)	/* On-chip UTMI PHY enable */
+#define PHYCTRL_BSENH		(1 << 3)	/* Bit Stuff Enable High */
+#define PHYCTRL_BSEN		(1 << 2)	/* Bit Stuff Enable */
+#define PHYCTRL_LSFE		(1 << 1)	/* Line State Filter Enable */
+#define PHYCTRL_PXE		(1 << 0)	/* PHY oscillator enable */
+
 #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 */
@@ -85,65 +161,86 @@
 #define MPC83XX_SCCR_USB_DRCM_01	0x00100000
 #define MPC83XX_SCCR_USB_DRCM_10	0x00200000
 
-#if defined(CONFIG_MPC83xx)
-#define CONFIG_SYS_MPC8xxx_USB_ADDR CONFIG_SYS_MPC83xx_USB_ADDR
+#if defined(CONFIG_MPC83XX)
+#define CONFIG_SYS_FSL_USB_ADDR CONFIG_SYS_MPC83xx_USB_ADDR
 #elif defined(CONFIG_MPC85xx)
-#define CONFIG_SYS_MPC8xxx_USB_ADDR CONFIG_SYS_MPC85xx_USB_ADDR
+#define CONFIG_SYS_FSL_USB_ADDR CONFIG_SYS_MPC85xx_USB_ADDR
+#elif defined(CONFIG_MPC512X)
+#define CONFIG_SYS_FSL_USB_ADDR CONFIG_SYS_MPC512x_USB_ADDR
 #endif
 
 /*
  * USB Registers
  */
 struct usb_ehci {
-	u8	res1[0x100];
+	u32	id;		/* 0x000 - Identification register */
+	u32	hwgeneral;	/* 0x004 - General hardware parameters */
+	u32	hwhost;		/* 0x008 - Host hardware parameters */
+	u32	hwdevice;	/* 0x00C - Device hardware parameters  */
+	u32	hwtxbuf;	/* 0x010 - TX buffer hardware parameters */
+	u32	hwrxbuf;	/* 0x014 - RX buffer hardware parameters */
+	u8	res1[0x68];
+	u32	gptimer0_ld;	/* 0x080 - General Purpose Timer 0 load value */
+	u32	gptimer0_ctrl;	/* 0x084 - General Purpose Timer 0 control */
+	u32	gptimer1_ld;	/* 0x088 - General Purpose Timer 1 load value */
+	u32	gptimer1_ctrl;	/* 0x08C - General Purpose Timer 1 control */
+	u32	sbuscfg;	/* 0x090 - System Bus Interface Control */
+	u8	res2[0x6C];
 	u16	caplength;	/* 0x100 - Capability Register Length */
 	u16	hciversion;	/* 0x102 - Host Interface Version */
 	u32	hcsparams;	/* 0x104 - Host Structural Parameters */
 	u32	hccparams;	/* 0x108 - Host Capability Parameters */
-	u8	res2[0x14];
+	u8	res3[0x14];
 	u32	dciversion;	/* 0x120 - Device Interface Version */
 	u32	dciparams;	/* 0x124 - Device Controller Params */
-	u8	res3[0x18];
+	u8	res4[0x18];
 	u32	usbcmd;		/* 0x140 - USB Command */
 	u32	usbsts;		/* 0x144 - USB Status */
 	u32	usbintr;	/* 0x148 - USB Interrupt Enable */
 	u32	frindex;	/* 0x14C - USB Frame Index */
-	u8	res4[0x4];
+	u8	res5[0x4];
 	u32	perlistbase;	/* 0x154 - Periodic List Base
 					 - USB Device Address */
 	u32	ep_list_addr;	/* 0x158 - Next Asynchronous List
-					 - Endpoint Address */
-	u8	res5[0x4];
+					 - End Point Address */
+	u8 res6[0x4];
 	u32	burstsize;	/* 0x160 - Programmable Burst Size */
+#define FSL_EHCI_TXPBURST(X)	((X) << 8)
+#define FSL_EHCI_RXPBURST(X)	(X)
 	u32	txfilltuning;	/* 0x164 - Host TT Transmit
 					   pre-buffer packet tuning */
-	u8	res6[0x8];
+	u8	res7[0x8];
 	u32	ulpi_viewpoint;	/* 0x170 - ULPI Reister Access */
-	u8	res7[0xc];
+	u8	res8[0xc];
 	u32	config_flag;	/* 0x180 - Configured Flag Register */
 	u32	portsc;		/* 0x184 - Port status/control */
-	u8	res8[0x20];
+	u8	res9[0x1C];
+	u32	otgsc;		/* 0x1a4 - Oo-The-Go status and control */
 	u32	usbmode;	/* 0x1a8 - USB Device Mode */
-	u32	epsetupstat;	/* 0x1ac - Endpoint Setup Status */
-	u32	epprime;	/* 0x1b0 - Endpoint Init Status */
-	u32	epflush;	/* 0x1b4 - Endpoint De-initlialize */
-	u32	epstatus;	/* 0x1b8 - Endpoint Status */
-	u32	epcomplete;	/* 0x1bc - Endpoint Complete */
-	u32	epctrl0;	/* 0x1c0 - Endpoint Control 0 */
-	u32	epctrl1;	/* 0x1c4 - Endpoint Control 1 */
-	u32	epctrl2;	/* 0x1c8 - Endpoint Control 2 */
-	u32	epctrl3;	/* 0x1cc - Endpoint Control 3 */
-	u32	epctrl4;	/* 0x1d0 - Endpoint Control 4 */
-	u32	epctrl5;	/* 0x1d4 - Endpoint Control 5 */
-	u8	res9[0x228];
+	u32	epsetupstat;	/* 0x1ac - End Point Setup Status */
+	u32	epprime;	/* 0x1b0 - End Point Init Status */
+	u32	epflush;	/* 0x1b4 - End Point De-initlialize */
+	u32	epstatus;	/* 0x1b8 - End Point Status */
+	u32	epcomplete;	/* 0x1bc - End Point Complete */
+	u32	epctrl0;	/* 0x1c0 - End Point Control 0 */
+	u32	epctrl1;	/* 0x1c4 - End Point Control 1 */
+	u32	epctrl2;	/* 0x1c8 - End Point Control 2 */
+	u32	epctrl3;	/* 0x1cc - End Point Control 3 */
+	u32	epctrl4;	/* 0x1d0 - End Point Control 4 */
+	u32	epctrl5;	/* 0x1d4 - End Point Control 5 */
+	u8	res10[0x28];
+	u32	usbgenctrl;	/* 0x200 - USB General Control */
+	u32	isiphyctrl;	/* 0x204 - On-Chip PHY Control */
+	u8	res11[0x1F8];
 	u32	snoop1;		/* 0x400 - Snoop 1 */
 	u32	snoop2;		/* 0x404 - Snoop 2 */
 	u32	age_cnt_limit;	/* 0x408 - Age Count Threshold */
 	u32	prictrl;	/* 0x40c - Priority Control */
 	u32	sictrl;		/* 0x410 - System Interface Control */
-	u8	res10[0xEC];
+	u8	res12[0xEC];
 	u32	control;	/* 0x500 - Control */
-	u8	res11[0xafc];
+	u8	res13[0xafc];
 };
 
 #endif /* _EHCI_FSL_H */
+
-- 
1.7.0.4



More information about the U-Boot mailing list