u-boot/drivers/usb/host/ehci-mpc512x.c
Lucas Stach 676ae068d9 usb: ehci: rework to take advantage of new lowlevel interface
Kill off ehci-core.h
It was used to specify some static controller data. To support more than
one controller being active at any time we have to carry the controller
data ourselfes. Change the ehci interface accordingly.

NOTE: OMAP implemented the ehci stuff a bit backwards and should be fixed
to do the same thing as other platforms. But the change for now is at least
compile clean.

Signed-off-by: Lucas Stach <dev@lynxeye.de>
Reviewed-by: Marek Vasut <marex@denx.de>
2012-10-15 11:54:00 -07:00

152 lines
4.2 KiB
C

/*
* (C) Copyright 2010, Damien Dusha, <d.dusha@gmail.com>
*
* (C) Copyright 2009, Value Team S.p.A.
* Francesco Rendine, <francesco.rendine@valueteam.com>
*
* (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 <common.h>
#include <pci.h>
#include <usb.h>
#include <asm/io.h>
#include <usb/ehci-fsl.h>
#include "ehci.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(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
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(int index)
{
volatile struct usb_ehci *ehci;
int exit_status = 0;
/* 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 );
}