]> git.sur5r.net Git - u-boot/blob - drivers/usb/host/ehci-mpc512x.c
Merge branch 'agust@denx.de-next' of git://git.denx.de/u-boot-staging
[u-boot] / 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
37 static void fsl_setup_phy(volatile struct ehci_hcor *);
38 static void fsl_platform_set_host_mode(volatile struct usb_ehci *ehci);
39 static int reset_usb_controller(volatile struct usb_ehci *ehci);
40 static void usb_platform_dr_init(volatile struct usb_ehci *ehci);
41
42 /*
43  * Initialize SOC FSL EHCI Controller
44  *
45  * This code is derived from EHCI FSL USB Linux driver for MPC5121
46  *
47  */
48 int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
49 {
50         volatile struct usb_ehci *ehci;
51
52         /* Hook the memory mapped registers for EHCI-Controller */
53         ehci = (struct usb_ehci *)CONFIG_SYS_FSL_USB_ADDR;
54         *hccr = (struct ehci_hccr *)((uint32_t)&(ehci->caplength));
55         *hcor = (struct ehci_hcor *)((uint32_t) *hccr +
56                                 HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
57
58         /* configure interface for UTMI_WIDE */
59         usb_platform_dr_init(ehci);
60
61         /* Init Phy USB0 to UTMI+ */
62         fsl_setup_phy(*hcor);
63
64         /* Set to host mode */
65         fsl_platform_set_host_mode(ehci);
66
67         /*
68          * Setting the burst size seems to be required to prevent the
69          * USB from hanging when communicating with certain USB Mass
70          * storage devices. This was determined by analysing the
71          * EHCI registers under Linux vs U-Boot and burstsize was the
72          * major non-interrupt related difference between the two
73          * implementations.
74          *
75          * Some USB sticks behave better than others. In particular,
76          * the following USB stick is especially problematic:
77          * 0930:6545 Toshiba Corp
78          *
79          * The burstsize is set here to match the Linux implementation.
80          */
81         out_be32(&ehci->burstsize, FSL_EHCI_TXPBURST(8) |
82                                    FSL_EHCI_RXPBURST(8));
83
84         return 0;
85 }
86
87 /*
88  * Destroy the appropriate control structures corresponding
89  * the the EHCI host controller.
90  */
91 int ehci_hcd_stop(int index)
92 {
93         volatile struct usb_ehci *ehci;
94         int exit_status = 0;
95
96         /* Reset the USB controller */
97         ehci = (struct usb_ehci *)CONFIG_SYS_FSL_USB_ADDR;
98         exit_status = reset_usb_controller(ehci);
99
100         return exit_status;
101 }
102
103 static int reset_usb_controller(volatile struct usb_ehci *ehci)
104 {
105         unsigned int i;
106
107         /* Command a reset of the USB Controller */
108         out_be32(&(ehci->usbcmd), EHCI_FSL_USBCMD_RST);
109
110         /* Wait for the reset process to finish */
111         for (i = 65535 ; i > 0 ; i--) {
112                 /*
113                  * The host will set this bit to zero once the
114                  * reset process is complete
115                  */
116                 if ((in_be32(&(ehci->usbcmd)) & EHCI_FSL_USBCMD_RST) == 0)
117                         return 0;
118         }
119
120         /* Hub did not reset in time */
121         return -1;
122 }
123
124 static void fsl_setup_phy(volatile struct ehci_hcor *hcor)
125 {
126         uint32_t portsc;
127
128         portsc  = ehci_readl(&hcor->or_portsc[0]);
129         portsc &= ~(PORT_PTS_MSK | PORT_PTS_PTW);
130
131         /* Enable the phy mode to UTMI Wide */
132         portsc |= PORT_PTS_PTW;
133         portsc |= PORT_PTS_UTMI;
134
135         ehci_writel(&hcor->or_portsc[0], portsc);
136 }
137
138 static void fsl_platform_set_host_mode(volatile struct usb_ehci *ehci)
139 {
140         uint32_t temp;
141
142         temp  = in_le32(&ehci->usbmode);
143         temp |= CM_HOST | ES_BE;
144         out_le32(&ehci->usbmode, temp);
145 }
146
147 static void usb_platform_dr_init(volatile struct usb_ehci *ehci)
148 {
149         /* Configure interface for UTMI_WIDE */
150         out_be32(&ehci->isiphyctrl, PHYCTRL_PHYE | PHYCTRL_PXE);
151         out_be32(&ehci->usbgenctrl, GC_PPP | GC_PFP );
152 }