]>
Commit | Line | Data |
---|---|---|
29c6fbe0 DD |
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 | * | |
1a459660 | 13 | * SPDX-License-Identifier: GPL-2.0+ |
29c6fbe0 DD |
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" | |
29c6fbe0 DD |
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 | */ | |
676ae068 | 35 | int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor) |
29c6fbe0 DD |
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; | |
676ae068 LS |
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))); | |
29c6fbe0 DD |
44 | |
45 | /* configure interface for UTMI_WIDE */ | |
46 | usb_platform_dr_init(ehci); | |
47 | ||
48 | /* Init Phy USB0 to UTMI+ */ | |
676ae068 | 49 | fsl_setup_phy(*hcor); |
29c6fbe0 DD |
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 | */ | |
676ae068 | 78 | int ehci_hcd_stop(int index) |
29c6fbe0 DD |
79 | { |
80 | volatile struct usb_ehci *ehci; | |
81 | int exit_status = 0; | |
82 | ||
676ae068 LS |
83 | /* Reset the USB controller */ |
84 | ehci = (struct usb_ehci *)CONFIG_SYS_FSL_USB_ADDR; | |
85 | exit_status = reset_usb_controller(ehci); | |
29c6fbe0 DD |
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 | } |