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