From 29c6fbe0471afd7ffa41fcb2103eec5b53294897 Mon Sep 17 00:00:00 2001 From: Damien Dusha Date: Thu, 14 Oct 2010 15:27:06 +0200 Subject: [PATCH] MPC5121: Add USB EHCI support Signed-off-by: Francesco Rendine Signed-off-by: Damien Dusha Signed-off-by: Anatolij Gustschin Coding style cleanup; slight file restructuring. Signed-off-by: Wolfgang Denk Acked-by: Remy Bohmer --- arch/powerpc/include/asm/immap_512x.h | 4 + board/freescale/mpc5121ads/mpc5121ads.c | 4 +- drivers/usb/host/Makefile | 4 + drivers/usb/host/ehci-fsl.c | 2 +- drivers/usb/host/ehci-mpc512x.c | 159 ++++++++++++++++++++++++ drivers/usb/host/ehci.h | 5 + include/configs/mpc5121ads.h | 21 +++- include/usb/ehci-fsl.h | 148 ++++++++++++++++++---- 8 files changed, 318 insertions(+), 29 deletions(-) create mode 100644 drivers/usb/host/ehci-mpc512x.c diff --git a/arch/powerpc/include/asm/immap_512x.h b/arch/powerpc/include/asm/immap_512x.h index 7f9db8bae3..f763a5413e 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 8cc68530e6..b356a478b3 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/Makefile b/drivers/usb/host/Makefile index 399520e22e..0e7c9db9dc 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -35,7 +35,11 @@ COBJS-$(CONFIG_USB_SL811HS) += sl811-hcd.o # echi COBJS-$(CONFIG_USB_EHCI) += ehci-hcd.o +ifdef CONFIG_MPC512X +COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-mpc512x.o +else COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o +endif COBJS-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o COBJS-$(CONFIG_USB_EHCI_PPC4XX) += ehci-ppc4xx.o COBJS-$(CONFIG_USB_EHCI_IXP4XX) += ehci-ixp.o diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index c674929725..6e0043a502 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -40,7 +40,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))); diff --git a/drivers/usb/host/ehci-mpc512x.c b/drivers/usb/host/ehci-mpc512x.c new file mode 100644 index 0000000000..d36010826b --- /dev/null +++ b/drivers/usb/host/ehci-mpc512x.c @@ -0,0 +1,159 @@ +/* + * (C) Copyright 2010, Damien Dusha, + * + * (C) Copyright 2009, Value Team S.p.A. + * Francesco Rendine, + * + * (C) Copyright 2009 Freescale Semiconductor, Inc. + * + * (C) Copyright 2008, Excito Elektronik i Sk=E5ne AB + * + * Author: Tor Krill tor@excito.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include "ehci.h" +#include "ehci-core.h" + +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); + +/* + * Initialize 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) +{ + /* Configure interface for UTMI_WIDE */ + out_be32(&ehci->isiphyctrl, PHYCTRL_PHYE | PHYCTRL_PXE); + out_be32(&ehci->usbgenctrl, GC_PPP | GC_PFP ); +} diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index b3c1d5d728..6fae8baf95 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) /* Interrupt on async adavance enable */ 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 f5c2bd3a57..19006ac725 100644 --- a/include/configs/mpc5121ads.h +++ b/include/configs/mpc5121ads.h @@ -376,6 +376,20 @@ #define CONFIG_RTC_M41T62 /* use M41T62 rtc via i2 */ #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 */ @@ -444,10 +458,15 @@ "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 f48945a27a..08691a0f2a 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) /* Defined on Page 39-44 of the mpc5151 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, default is LE */ #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 (0x1<<0) +#define CTRL_VBUS_CHARGE (0x1<<1) +#define CTRL_OTG_TERMINATION (0x1<<3) +#define CTRL_DATA_PULSING (0x1<<4) +#define CTRL_ID_PULL_EN (0x1<<5) +#define HA_DATA_PULSE (0x1<<6) +#define HA_BA (0x1<<7) +#define STS_USB_ID (0x1<<8) +#define STS_A_VBUS_VALID (0x1<<9) +#define STS_A_SESSION_VALID (0x1<<10) +#define STS_B_SESSION_VALID (0x1<<11) +#define STS_B_SESSION_END (0x1<<12) +#define STS_1MS_TOGGLE (0x1<<13) +#define STS_DATA_PULSING (0x1<<14) +#define INTSTS_USB_ID (0x1<<16) +#define INTSTS_A_VBUS_VALID (0x1<<17) +#define INTSTS_A_SESSION_VALID (0x1<<18) +#define INTSTS_B_SESSION_VALID (0x1<<19) +#define INTSTS_B_SESSION_END (0x1<<20) +#define INTSTS_1MS (0x1<<21) +#define INTSTS_DATA_PULSING (0x1<<22) +#define INTR_USB_ID_EN (0x1<<24) +#define INTR_A_VBUS_VALID_EN (0x1<<25) +#define INTR_A_SESSION_VALID_EN (0x1<<26) +#define INTR_B_SESSION_VALID_EN (0x1<<27) +#define INTR_B_SESSION_END_EN (0x1<<28) +#define INTR_1MS_TIMER_EN (0x1<<29) +#define INTR_DATA_PULSING_EN (0x1<<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,85 @@ #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 */ -- 2.39.2