blob: 3254a8a1c2e118a3d5bfb076c37cf289098f1014 [file] [log] [blame]
Kyösti Mälkki83fe6d72014-02-25 20:11:52 +02001/*
2 * This file is part of the coreboot project.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
Kyösti Mälkki83fe6d72014-02-25 20:11:52 +020012 */
13
14#include <stddef.h>
15#include <console/console.h>
Kyösti Mälkki46249be22014-10-27 14:07:28 +020016#include <string.h>
Kyösti Mälkki83fe6d72014-02-25 20:11:52 +020017
18#include "ehci_debug.h"
19#include "usb_ch9.h"
20#include "ehci.h"
21
Kyösti Mälkki46249be22014-10-27 14:07:28 +020022#define dprintk printk
Kyösti Mälkki83fe6d72014-02-25 20:11:52 +020023
24#define USB_HUB_PORT_CONNECTION 0
25#define USB_HUB_PORT_ENABLED 1
26#define USB_HUB_PORT_RESET 4
27#define USB_HUB_PORT_POWER 8
28#define USB_HUB_C_PORT_CONNECTION 16
29#define USB_HUB_C_PORT_RESET 20
30
31
Elyes HAOUASb0b0c8c2018-07-08 12:33:47 +020032static int hub_port_status(const char *buf, int feature)
Kyösti Mälkki83fe6d72014-02-25 20:11:52 +020033{
34 return !!(buf[feature>>3] & (1<<(feature&0x7)));
35}
36
37/* After USB port reset, treat device number 0 as an USB hub. Assign it with
38 * a device number hub_addr. Then apply enable and reset on downstream port.
39 */
Martin Rothb9810a42017-07-23 20:00:04 -060040static int dbgp_hub_enable(struct ehci_dbg_port *ehci_debug, unsigned char hub_addr,
Kyösti Mälkki83fe6d72014-02-25 20:11:52 +020041 unsigned char port)
42{
43 char status[8];
44 int ret, loop;
45
46 /* Assign a devicenumber for the hub. */
47 ret = dbgp_control_msg(ehci_debug, 0,
48 USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
49 USB_REQ_SET_ADDRESS, hub_addr, 0, NULL, 0);
50 if (ret < 0)
51 goto err;
52
53 /* Enter configured state on hub. */
54 ret = dbgp_control_msg(ehci_debug, hub_addr,
55 USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
56 USB_REQ_SET_CONFIGURATION, 1, 0, NULL, 0);
57 if (ret < 0)
58 goto err;
59
60 /* Set PORT_POWER, poll for PORT_CONNECTION. */
61 ret = dbgp_control_msg(ehci_debug, hub_addr,
62 USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER,
63 USB_REQ_SET_FEATURE, USB_HUB_PORT_POWER, port, NULL, 0);
64 if (ret < 0)
65 goto err;
66
67 loop = 100;
68 do {
69 dbgp_mdelay(10);
70 ret = dbgp_control_msg(ehci_debug, hub_addr,
71 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_OTHER,
72 USB_REQ_GET_STATUS, 0, port, status, 4);
73 if (ret < 0)
74 goto err;
75 if (hub_port_status(status, USB_HUB_PORT_CONNECTION))
76 break;
77 } while (--loop);
78 if (! loop)
79 goto err;
80
81 ret = dbgp_control_msg(ehci_debug, hub_addr,
82 USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER,
83 USB_REQ_CLEAR_FEATURE, USB_HUB_C_PORT_CONNECTION, port, NULL, 0);
84 if (ret < 0)
85 goto err;
86
87
88 /* Set PORT_RESET, poll for C_PORT_RESET. */
89 ret = dbgp_control_msg(ehci_debug, hub_addr,
90 USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER,
91 USB_REQ_SET_FEATURE, USB_HUB_PORT_RESET, port, NULL, 0);
92 if (ret < 0)
93 goto err;
94
95 loop = 100;
96 do {
97 dbgp_mdelay(10);
98 ret = dbgp_control_msg(ehci_debug, hub_addr,
99 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_OTHER,
100 USB_REQ_GET_STATUS, 0, port, status, 4);
101 if (ret < 0)
102 goto err;
103 if (hub_port_status(status, USB_HUB_C_PORT_RESET))
104 break;
105 } while (--loop);
106 if (! loop)
107 goto err;
108
109 ret = dbgp_control_msg(ehci_debug, hub_addr,
110 USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER,
111 USB_REQ_CLEAR_FEATURE, USB_HUB_C_PORT_RESET, port, NULL, 0);
112 if (ret < 0)
113 goto err;
114
115 if (hub_port_status(status, USB_HUB_PORT_ENABLED))
116 return 0;
117err:
118 return -1;
119}
120
Kyösti Mälkki46249be22014-10-27 14:07:28 +0200121static void ack_set_configuration(struct dbgp_pipe *pipe, u8 devnum, int timeout)
122{
123 int i = DBGP_SETUP_EP0;
124 while (++i < DBGP_MAX_ENDPOINTS) {
125 if (pipe[i].endpoint != 0) {
126 pipe[i].devnum = devnum;
127 pipe[i].pid = USB_PID_DATA0;
128 pipe[i].timeout = timeout;
129 }
130 }
131}
132
133static void activate_endpoints(struct dbgp_pipe *pipe)
134{
135 int i = DBGP_SETUP_EP0;
136 pipe[i].status |= DBGP_EP_ENABLED | DBGP_EP_VALID;
137 while (++i < DBGP_MAX_ENDPOINTS) {
138 if (pipe[i].endpoint != 0)
139 pipe[i].status |= DBGP_EP_ENABLED | DBGP_EP_VALID;
140 }
141}
142
143static int probe_for_debug_descriptor(struct ehci_dbg_port *ehci_debug, struct dbgp_pipe *pipe)
144{
145 struct usb_debug_descriptor dbgp_desc;
146 int configured = 0, ret;
147 u8 devnum = 0;
148
149 /* Find the debug device and make it device number 127 */
150debug_dev_retry:
151 memset(&dbgp_desc, 0, sizeof(dbgp_desc));
152 ret = dbgp_control_msg(ehci_debug, devnum,
153 USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
154 USB_REQ_GET_DESCRIPTOR, (USB_DT_DEBUG << 8), 0,
155 &dbgp_desc, sizeof(dbgp_desc));
156 if (ret == sizeof(dbgp_desc)) {
Elyes HAOUAS9b41bae2018-04-26 10:29:10 +0200157 if (dbgp_desc.bLength == sizeof(dbgp_desc) && dbgp_desc.bDescriptorType == USB_DT_DEBUG)
Kyösti Mälkki46249be22014-10-27 14:07:28 +0200158 goto debug_dev_found;
159 else
160 dprintk(BIOS_INFO, "Invalid debug device descriptor.\n");
161 }
162 if (devnum == 0) {
163 devnum = USB_DEBUG_DEVNUM;
164 goto debug_dev_retry;
165 } else {
166 dprintk(BIOS_INFO, "Could not find attached debug device.\n");
167 return -1;
168 }
169debug_dev_found:
170
171 /* Move the device to 127 if it isn't already there */
172 if (devnum != USB_DEBUG_DEVNUM) {
173 ret = dbgp_control_msg(ehci_debug, devnum,
174 USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
175 USB_REQ_SET_ADDRESS, USB_DEBUG_DEVNUM, 0, NULL, 0);
176 if (ret < 0) {
177 dprintk(BIOS_INFO, "Could not move attached device to %d.\n",
178 USB_DEBUG_DEVNUM);
179 return -2;
180 }
181 devnum = USB_DEBUG_DEVNUM;
182 dprintk(BIOS_INFO, "EHCI debug device renamed to 127.\n");
183 }
184
185 /* Enable the debug interface */
186 ret = dbgp_control_msg(ehci_debug, USB_DEBUG_DEVNUM,
187 USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
188 USB_REQ_SET_FEATURE, USB_DEVICE_DEBUG_MODE, 0, NULL, 0);
189 if (ret < 0) {
190 dprintk(BIOS_INFO, "Could not enable EHCI debug device.\n");
191 return -3;
192 }
193 dprintk(BIOS_INFO, "EHCI debug interface enabled.\n");
194
195 pipe[DBGP_CONSOLE_EPOUT].endpoint = dbgp_desc.bDebugOutEndpoint;
196 pipe[DBGP_CONSOLE_EPIN].endpoint = dbgp_desc.bDebugInEndpoint;
197
198 ack_set_configuration(pipe, devnum, 1000);
199
200 /* Perform a small write. */
201 configured = 0;
202small_write:
203 ret = dbgp_bulk_write_x(&pipe[DBGP_CONSOLE_EPOUT], "USB\r\n",5);
204 if (ret < 0) {
205 dprintk(BIOS_INFO, "dbgp_bulk_write failed: %d\n", ret);
206 if (!configured) {
207 /* Send Set Configure request to device. This is required for FX2
208 (CY7C68013) to transfer from USB state Addressed to Configured,
209 only then endpoints other than 0 are enabled. */
210 if (dbgp_control_msg(ehci_debug, USB_DEBUG_DEVNUM,
211 USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
212 USB_REQ_SET_CONFIGURATION, 1, 0, NULL, 0) >= 0) {
213 configured = 1;
214 goto small_write;
215 }
216 }
217 return -4;
218 }
219 dprintk(BIOS_INFO, "Test write done\n");
220 return 0;
221}
222
Kyösti Mälkkicc4d3092015-05-03 06:27:11 +0300223/* FTDI FT232H UART programming. */
224#define FTDI_SIO_SET_FLOW_CTRL_REQUEST 0x02
225#define FTDI_SIO_SET_BAUDRATE_REQUEST 0x03
226#define FTDI_SIO_SET_DATA_REQUEST 0x04
227#define FTDI_SIO_SET_BITMODE_REQUEST 0x0b
228
Nico Huberc868fd12016-11-18 20:11:43 +0100229/* Simplified divisor selection for 12MHz base clock only */
230static void ft232h_baud(u16 *const value, u16 *const index, u32 baud)
231{
232 static const u32 fraction_map[8] = { 0, 3, 2, 4, 1, 5, 6, 7 };
233
234 /* divisor must fit into 14 bits */
235 if (baud < 733)
236 baud = 733;
237
238 /* divisor is given as a fraction of 8 */
239 const u32 div8 = ((12 * 1000 * 1000) * 8) / baud;
240 /* upper 3 bits fractional part, lower 14 bits integer */
241 u32 div = fraction_map[div8 & 7] << 14 | div8 / 8;
242
243 /* special case for 12MHz */
244 if (div == 1)
245 div = 0;
246 /* special case for 8MHz */
247 else if (div == (fraction_map[4] << 14 | 1))
248 div = 1;
249
250 *value = div; /* divisor lower 16 bits */
251 *index = (div >> 8) & 0x0100; /* divisor bit 16 */
252 *index |= 0x0200; /* select 120MHz / 10 */
253}
254
Kyösti Mälkkicc4d3092015-05-03 06:27:11 +0300255static int probe_for_ftdi(struct ehci_dbg_port *ehci_debug, struct dbgp_pipe *pipe)
256{
257 int ret;
258 u8 devnum = 0;
259 u8 uart_if = 1; /* FTDI_INTERFACE_A 1 */
Nico Huberc868fd12016-11-18 20:11:43 +0100260 u16 baud_value, baud_index;
Kyösti Mälkkicc4d3092015-05-03 06:27:11 +0300261
262 /* Move the device to 127 if it isn't already there */
263 ret = dbgp_control_msg(ehci_debug, devnum,
264 USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
265 USB_REQ_SET_ADDRESS, USB_DEBUG_DEVNUM, 0, NULL, 0);
266 if (ret < 0) {
267 dprintk(BIOS_INFO, "Could not move attached device to %d.\n",
268 USB_DEBUG_DEVNUM);
269 return -2;
270 }
271 devnum = USB_DEBUG_DEVNUM;
272 dprintk(BIOS_INFO, "EHCI debug device renamed to %d.\n", devnum);
273
274 /* Send Set Configure request to device. */
275 ret = dbgp_control_msg(ehci_debug, devnum,
276 USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
277 USB_REQ_SET_CONFIGURATION, 1, 0, NULL, 0);
278 if (ret < 0) {
279 dprintk(BIOS_INFO, "FTDI set configuration failed.\n");
280 return -2;
281 }
282
283 ret = dbgp_control_msg(ehci_debug, devnum,
284 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
285 FTDI_SIO_SET_BITMODE_REQUEST, 0, uart_if, NULL, 0);
286 if (ret < 0) {
287 dprintk(BIOS_INFO, "FTDI SET_BITMODE failed.\n");
288 return -3;
289 }
Nico Huberc868fd12016-11-18 20:11:43 +0100290 ft232h_baud(&baud_value, &baud_index,
291 CONFIG_USBDEBUG_DONGLE_FTDI_FT232H_BAUD);
Kyösti Mälkkicc4d3092015-05-03 06:27:11 +0300292 ret = dbgp_control_msg(ehci_debug, devnum,
293 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
294 FTDI_SIO_SET_BAUDRATE_REQUEST,
Nico Huberc868fd12016-11-18 20:11:43 +0100295 baud_value, baud_index | uart_if, NULL, 0);
Kyösti Mälkkicc4d3092015-05-03 06:27:11 +0300296 if (ret < 0) {
297 dprintk(BIOS_INFO, "FTDI SET_BAUDRATE failed.\n");
298 return -3;
299 }
300 ret = dbgp_control_msg(ehci_debug, devnum,
301 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
302 FTDI_SIO_SET_DATA_REQUEST,
303 0x0008, uart_if, NULL, 0);
304 if (ret < 0) {
305 dprintk(BIOS_INFO, "FTDI SET_DATA failed.\n");
306 return -3;
307 }
308 ret = dbgp_control_msg(ehci_debug, devnum,
309 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
310 FTDI_SIO_SET_FLOW_CTRL_REQUEST,
311 0x0000, uart_if, NULL, 0);
312 if (ret < 0) {
313 dprintk(BIOS_INFO, "FTDI SET_FLOW_CTRL failed.\n");
314 return -3;
315 }
316
317 pipe[DBGP_CONSOLE_EPOUT].endpoint = 0x02;
318 pipe[DBGP_CONSOLE_EPIN].endpoint = 0x81;
319
320 ack_set_configuration(pipe, devnum, 1000);
321
322 /* Perform a small write. */
323 ret = dbgp_bulk_write_x(&pipe[DBGP_CONSOLE_EPOUT], "USB\r\n", 5);
324 if (ret < 0) {
325 dprintk(BIOS_INFO, "dbgp_bulk_write failed: %d\n", ret);
326 return -4;
327 }
328 dprintk(BIOS_INFO, "Test write done\n");
329 return 0;
330}
Kyösti Mälkki83fe6d72014-02-25 20:11:52 +0200331
332int dbgp_probe_gadget(struct ehci_dbg_port *ehci_debug, struct dbgp_pipe *pipe)
333{
334 int ret;
335
336 if (CONFIG_USBDEBUG_OPTIONAL_HUB_PORT != 0) {
337 ret = dbgp_hub_enable(ehci_debug, USB_DEBUG_DEVNUM-1,
338 CONFIG_USBDEBUG_OPTIONAL_HUB_PORT);
339 if (ret < 0) {
340 printk(BIOS_INFO, "Could not enable USB hub on debug port.\n");
341 return ret;
342 }
343 }
344
Kyösti Mälkkicc4d3092015-05-03 06:27:11 +0300345 if (IS_ENABLED(CONFIG_USBDEBUG_DONGLE_FTDI_FT232H)) {
346 ret = probe_for_ftdi(ehci_debug, pipe);
347 } else {
348 ret = probe_for_debug_descriptor(ehci_debug, pipe);
349 }
Kyösti Mälkki46249be22014-10-27 14:07:28 +0200350 if (ret < 0) {
Kyösti Mälkkicc4d3092015-05-03 06:27:11 +0300351 dprintk(BIOS_INFO, "Could not enable debug dongle.\n");
Kyösti Mälkki46249be22014-10-27 14:07:28 +0200352 return ret;
353 }
354
355 activate_endpoints(pipe);
Kyösti Mälkki83fe6d72014-02-25 20:11:52 +0200356 return 0;
357}