mirror of
				https://source.denx.de/u-boot/u-boot.git
				synced 2025-10-31 08:21:36 +01:00 
			
		
		
		
	Introduce different macros for storing addresses of multiple USB controllers. This is required for successful initialization and usage of multiple USB controllers inside u-boot Signed-off-by: Ramneek Mehresh <ramneek.mehresh@freescale.com>
		
			
				
	
	
		
			141 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			141 lines
		
	
	
		
			3.5 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
 | |
|  *
 | |
|  * SPDX-License-Identifier:	GPL-2.0+
 | |
|  */
 | |
| 
 | |
| #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, enum usb_init_type init,
 | |
| 		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_USB1_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_USB1_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 );
 | |
| }
 |