tizen 2.4 release
[kernel/u-boot-tm1.git] / drivers / usb / host / ehci-mpc512x.c
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  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License as
15  * published by the Free Software Foundation; either version 2 of
16  * the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
26  * MA 02111-1307 USA
27  */
28
29 #include <common.h>
30 #include <pci.h>
31 #include <usb.h>
32 #include <asm/io.h>
33 #include <usb/ehci-fsl.h>
34
35 #include "ehci.h"
36 #include "ehci-core.h"
37
38 static void fsl_setup_phy(volatile struct ehci_hcor *);
39 static void fsl_platform_set_host_mode(volatile struct usb_ehci *ehci);
40 static int reset_usb_controller(volatile struct usb_ehci *ehci);
41 static void usb_platform_dr_init(volatile struct usb_ehci *ehci);
42
43 /*
44  * Initialize SOC FSL EHCI Controller
45  *
46  * This code is derived from EHCI FSL USB Linux driver for MPC5121
47  *
48  */
49 int ehci_hcd_init(void)
50 {
51         volatile struct usb_ehci *ehci;
52
53         /* Hook the memory mapped registers for EHCI-Controller */
54         ehci = (struct usb_ehci *)CONFIG_SYS_FSL_USB_ADDR;
55         hccr = (struct ehci_hccr *)((uint32_t)&(ehci->caplength));
56         hcor = (struct ehci_hcor *)((uint32_t) hccr +
57                                 HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
58
59         /* configure interface for UTMI_WIDE */
60         usb_platform_dr_init(ehci);
61
62         /* Init Phy USB0 to UTMI+ */
63         fsl_setup_phy(hcor);
64
65         /* Set to host mode */
66         fsl_platform_set_host_mode(ehci);
67
68         /*
69          * Setting the burst size seems to be required to prevent the
70          * USB from hanging when communicating with certain USB Mass
71          * storage devices. This was determined by analysing the
72          * EHCI registers under Linux vs U-Boot and burstsize was the
73          * major non-interrupt related difference between the two
74          * implementations.
75          *
76          * Some USB sticks behave better than others. In particular,
77          * the following USB stick is especially problematic:
78          * 0930:6545 Toshiba Corp
79          *
80          * The burstsize is set here to match the Linux implementation.
81          */
82         out_be32(&ehci->burstsize, FSL_EHCI_TXPBURST(8) |
83                                    FSL_EHCI_RXPBURST(8));
84
85         return 0;
86 }
87
88 /*
89  * Destroy the appropriate control structures corresponding
90  * the the EHCI host controller.
91  */
92 int ehci_hcd_stop(void)
93 {
94         volatile struct usb_ehci *ehci;
95         int exit_status = 0;
96
97         if (hcor) {
98                 /* Unhook struct */
99                 hccr = NULL;
100                 hcor = NULL;
101
102                 /* Reset the USB controller */
103                 ehci = (struct usb_ehci *)CONFIG_SYS_FSL_USB_ADDR;
104                 exit_status = reset_usb_controller(ehci);
105         }
106
107         return exit_status;
108 }
109
110 static int reset_usb_controller(volatile struct usb_ehci *ehci)
111 {
112         unsigned int i;
113
114         /* Command a reset of the USB Controller */
115         out_be32(&(ehci->usbcmd), EHCI_FSL_USBCMD_RST);
116
117         /* Wait for the reset process to finish */
118         for (i = 65535 ; i > 0 ; i--) {
119                 /*
120                  * The host will set this bit to zero once the
121                  * reset process is complete
122                  */
123                 if ((in_be32(&(ehci->usbcmd)) & EHCI_FSL_USBCMD_RST) == 0)
124                         return 0;
125         }
126
127         /* Hub did not reset in time */
128         return -1;
129 }
130
131 static void fsl_setup_phy(volatile struct ehci_hcor *hcor)
132 {
133         uint32_t portsc;
134
135         portsc  = ehci_readl(&hcor->or_portsc[0]);
136         portsc &= ~(PORT_PTS_MSK | PORT_PTS_PTW);
137
138         /* Enable the phy mode to UTMI Wide */
139         portsc |= PORT_PTS_PTW;
140         portsc |= PORT_PTS_UTMI;
141
142         ehci_writel(&hcor->or_portsc[0], portsc);
143 }
144
145 static void fsl_platform_set_host_mode(volatile struct usb_ehci *ehci)
146 {
147         uint32_t temp;
148
149         temp  = in_le32(&ehci->usbmode);
150         temp |= CM_HOST | ES_BE;
151         out_le32(&ehci->usbmode, temp);
152 }
153
154 static void usb_platform_dr_init(volatile struct usb_ehci *ehci)
155 {
156         /* Configure interface for UTMI_WIDE */
157         out_be32(&ehci->isiphyctrl, PHYCTRL_PHYE | PHYCTRL_PXE);
158         out_be32(&ehci->usbgenctrl, GC_PPP | GC_PFP );
159 }