1/* 2 * (C) Copyright 2010, Damien Dusha, <d.dusha@gmail.com> 3 * 4 * (C) Copyright 2009, Value Team S.p.A. 5 * Francesco Rendine, <francesco.rendine@valueteam.com> 6 * 7 * (C) Copyright 2009 Freescale Semiconductor, Inc. 8 * 9 * (C) Copyright 2008, Excito Elektronik i Sk=E5ne AB 10 * 11 * Author: Tor Krill tor@excito.com 12 * 13 * SPDX-License-Identifier: GPL-2.0+ 14 */ 15 16#include <common.h> 17#include <pci.h> 18#include <usb.h> 19#include <asm/io.h> 20#include <usb/ehci-ci.h> 21 22#include "ehci.h" 23 24static void fsl_setup_phy(volatile struct ehci_hcor *); 25static void fsl_platform_set_host_mode(volatile struct usb_ehci *ehci); 26static int reset_usb_controller(volatile struct usb_ehci *ehci); 27static void usb_platform_dr_init(volatile struct usb_ehci *ehci); 28 29/* 30 * Initialize SOC FSL EHCI Controller 31 * 32 * This code is derived from EHCI FSL USB Linux driver for MPC5121 33 * 34 */ 35int ehci_hcd_init(int index, enum usb_init_type init, 36 struct ehci_hccr **hccr, struct ehci_hcor **hcor) 37{ 38 volatile struct usb_ehci *ehci; 39 40 /* Hook the memory mapped registers for EHCI-Controller */ 41 ehci = (struct usb_ehci *)CONFIG_SYS_FSL_USB1_ADDR; 42 *hccr = (struct ehci_hccr *)((uint32_t)&(ehci->caplength)); 43 *hcor = (struct ehci_hcor *)((uint32_t) *hccr + 44 HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); 45 46 /* configure interface for UTMI_WIDE */ 47 usb_platform_dr_init(ehci); 48 49 /* Init Phy USB0 to UTMI+ */ 50 fsl_setup_phy(*hcor); 51 52 /* Set to host mode */ 53 fsl_platform_set_host_mode(ehci); 54 55 /* 56 * Setting the burst size seems to be required to prevent the 57 * USB from hanging when communicating with certain USB Mass 58 * storage devices. This was determined by analysing the 59 * EHCI registers under Linux vs U-Boot and burstsize was the 60 * major non-interrupt related difference between the two 61 * implementations. 62 * 63 * Some USB sticks behave better than others. In particular, 64 * the following USB stick is especially problematic: 65 * 0930:6545 Toshiba Corp 66 * 67 * The burstsize is set here to match the Linux implementation. 68 */ 69 out_be32(&ehci->burstsize, FSL_EHCI_TXPBURST(8) | 70 FSL_EHCI_RXPBURST(8)); 71 72 return 0; 73} 74 75/* 76 * Destroy the appropriate control structures corresponding 77 * the the EHCI host controller. 78 */ 79int ehci_hcd_stop(int index) 80{ 81 volatile struct usb_ehci *ehci; 82 int exit_status = 0; 83 84 /* Reset the USB controller */ 85 ehci = (struct usb_ehci *)CONFIG_SYS_FSL_USB1_ADDR; 86 exit_status = reset_usb_controller(ehci); 87 88 return exit_status; 89} 90 91static int reset_usb_controller(volatile struct usb_ehci *ehci) 92{ 93 unsigned int i; 94 95 /* Command a reset of the USB Controller */ 96 out_be32(&(ehci->usbcmd), CMD_RESET); 97 98 /* Wait for the reset process to finish */ 99 for (i = 65535 ; i > 0 ; i--) { 100 /* 101 * The host will set this bit to zero once the 102 * reset process is complete 103 */ 104 if ((in_be32(&(ehci->usbcmd)) & CMD_RESET) == 0) 105 return 0; 106 } 107 108 /* Hub did not reset in time */ 109 return -1; 110} 111 112static void fsl_setup_phy(volatile struct ehci_hcor *hcor) 113{ 114 uint32_t portsc; 115 116 portsc = ehci_readl(&hcor->or_portsc[0]); 117 portsc &= ~(PORT_PTS_MSK | PORT_PTS_PTW); 118 119 /* Enable the phy mode to UTMI Wide */ 120 portsc |= PORT_PTS_PTW; 121 portsc |= PORT_PTS_UTMI; 122 123 ehci_writel(&hcor->or_portsc[0], portsc); 124} 125 126static void fsl_platform_set_host_mode(volatile struct usb_ehci *ehci) 127{ 128 uint32_t temp; 129 130 temp = in_le32(&ehci->usbmode); 131 temp |= CM_HOST | ES_BE; 132 out_le32(&ehci->usbmode, temp); 133} 134 135static void usb_platform_dr_init(volatile struct usb_ehci *ehci) 136{ 137 /* Configure interface for UTMI_WIDE */ 138 out_be32(&ehci->isiphyctrl, PHYCTRL_PHYE | PHYCTRL_PXE); 139 out_be32(&ehci->usbgenctrl, GC_PPP | GC_PFP ); 140} 141