/* * (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 * * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include #include #include #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 ); }