source: mainline/uspace/drv/bus/usb/ehci/res.c@ d967aa1

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since d967aa1 was e4d7363, checked in by Ondřej Hlavatý <aearsis@…>, 8 years ago

usbhost: refactor the initialization

Before that, drivers had to setup MMIO range multiple times, or even parse hw
resources themselves again. The former init method was split in half - init and
start. Init shall allocate and initialize inner structures, start shall start
the HC.

In the XHCI it is demonstrated how to isolate inner HC implementation from the
fact this driver is using libusbhost. It adds some boilerplate code, but
I think it leads to cleaner design.

  • Property mode set to 100644
File size: 6.3 KB
Line 
1/*
2 * Copyright (c) 2011 Jan Vesely
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/**
30 * @addtogroup drvusbehci
31 * @{
32 */
33/**
34 * @file
35 * PCI related functions needed by the EHCI driver.
36 */
37
38#include <errno.h>
39#include <str_error.h>
40#include <assert.h>
41#include <devman.h>
42#include <ddi.h>
43#include <usb/debug.h>
44#include <device/hw_res_parsed.h>
45#include <pci_dev_iface.h>
46
47#include "res.h"
48#include "ehci_regs.h"
49
50#define USBLEGSUP_OFFSET 0
51#define USBLEGSUP_BIOS_CONTROL (1 << 16)
52#define USBLEGSUP_OS_CONTROL (1 << 24)
53#define USBLEGCTLSTS_OFFSET 4
54
55#define DEFAULT_WAIT 1000
56#define WAIT_STEP 10
57
58/** Implements BIOS hands-off routine as described in EHCI spec
59 *
60 * @param device EHCI device
61 * @param eecp Value of EHCI Extended Capabilities pointer.
62 * @return Error code.
63 */
64static int disable_extended_caps(async_sess_t *parent_sess, unsigned eecp)
65{
66 /* nothing to do */
67 if (eecp == 0)
68 return EOK;
69
70 /* Read the first EEC. i.e. Legacy Support register */
71 uint32_t usblegsup;
72 int ret = pci_config_space_read_32(parent_sess,
73 eecp + USBLEGSUP_OFFSET, &usblegsup);
74 if (ret != EOK) {
75 usb_log_error("Failed to read USBLEGSUP: %s.\n", str_error(ret));
76 return ret;
77 }
78 usb_log_debug2("USBLEGSUP: %" PRIx32 ".\n", usblegsup);
79
80 /* Request control from firmware/BIOS by writing 1 to highest
81 * byte. (OS Control semaphore)*/
82 usb_log_debug("Requesting OS control.\n");
83 ret = pci_config_space_write_8(parent_sess,
84 eecp + USBLEGSUP_OFFSET + 3, 1);
85 if (ret != EOK) {
86 usb_log_error("Failed to request OS EHCI control: %s.\n",
87 str_error(ret));
88 return ret;
89 }
90
91 size_t wait = 0;
92 /* Wait for BIOS to release control. */
93 ret = pci_config_space_read_32(
94 parent_sess, eecp + USBLEGSUP_OFFSET, &usblegsup);
95 while ((ret == EOK) && (wait < DEFAULT_WAIT)
96 && (usblegsup & USBLEGSUP_BIOS_CONTROL)) {
97 async_usleep(WAIT_STEP);
98 ret = pci_config_space_read_32(parent_sess,
99 eecp + USBLEGSUP_OFFSET, &usblegsup);
100 wait += WAIT_STEP;
101 }
102
103 if ((usblegsup & USBLEGSUP_BIOS_CONTROL) == 0) {
104 usb_log_info("BIOS released control after %zu usec.\n", wait);
105 return EOK;
106 }
107
108 /* BIOS failed to hand over control, this should not happen. */
109 usb_log_warning( "BIOS failed to release control after "
110 "%zu usecs, force it.\n", wait);
111 ret = pci_config_space_write_32(parent_sess,
112 eecp + USBLEGSUP_OFFSET, USBLEGSUP_OS_CONTROL);
113 if (ret != EOK) {
114 usb_log_error("Failed to force OS control: %s.\n",
115 str_error(ret));
116 return ret;
117 }
118
119 /*
120 * Check capability type here, value of 01h identifies the capability
121 * as Legacy Support. This extended capability requires one additional
122 * 32-bit register for control/status information and this register is
123 * located at offset EECP+04h
124 */
125 if ((usblegsup & 0xff) == 1) {
126 /* Read the second EEC Legacy Support and Control register */
127 uint32_t usblegctlsts;
128 ret = pci_config_space_read_32(parent_sess,
129 eecp + USBLEGCTLSTS_OFFSET, &usblegctlsts);
130 if (ret != EOK) {
131 usb_log_error("Failed to get USBLEGCTLSTS: %s.\n",
132 str_error(ret));
133 return ret;
134 }
135 usb_log_debug2("USBLEGCTLSTS: %" PRIx32 ".\n", usblegctlsts);
136 /*
137 * Zero SMI enables in legacy control register.
138 * It should prevent pre-OS code from
139 * interfering. NOTE: Three upper bits are WC
140 */
141 ret = pci_config_space_write_32(parent_sess,
142 eecp + USBLEGCTLSTS_OFFSET, 0xe0000000);
143 if (ret != EOK) {
144 usb_log_error("Failed to zero USBLEGCTLSTS: %s\n",
145 str_error(ret));
146 return ret;
147 }
148
149 udelay(10);
150 /* read again to amke sure it's zeroed */
151 ret = pci_config_space_read_32(parent_sess,
152 eecp + USBLEGCTLSTS_OFFSET, &usblegctlsts);
153 if (ret != EOK) {
154 usb_log_error("Failed to get USBLEGCTLSTS 2: %s.\n",
155 str_error(ret));
156 return ret;
157 }
158 usb_log_debug2("Zeroed USBLEGCTLSTS: %" PRIx32 ".\n",
159 usblegctlsts);
160 }
161
162 /* Read again Legacy Support register */
163 ret = pci_config_space_read_32(parent_sess,
164 eecp + USBLEGSUP_OFFSET, &usblegsup);
165 if (ret != EOK) {
166 usb_log_error("Failed to read USBLEGSUP: %s.\n",
167 str_error(ret));
168 return ret;
169 }
170 usb_log_debug2("USBLEGSUP: %" PRIx32 ".\n", usblegsup);
171 return ret;
172}
173
174int disable_legacy(hc_t *hc, ddf_dev_t *device)
175{
176 assert(device);
177
178 async_sess_t *parent_sess = devman_parent_device_connect(
179 ddf_dev_get_handle(device), IPC_FLAG_BLOCKING);
180 if (!parent_sess)
181 return ENOMEM;
182
183 usb_log_debug("Disabling EHCI legacy support.\n");
184
185
186 const uint32_t hcc_params = EHCI_RD(hc->caps->hccparams);
187 usb_log_debug2("Value of hcc params register: %x.\n", hcc_params);
188
189 /* Read value of EHCI Extended Capabilities Pointer
190 * position of EEC registers (points to PCI config space) */
191 const uint32_t eecp =
192 (hcc_params >> EHCI_CAPS_HCC_EECP_SHIFT) & EHCI_CAPS_HCC_EECP_MASK;
193 usb_log_debug2("Value of EECP: %x.\n", eecp);
194
195 int ret = disable_extended_caps(parent_sess, eecp);
196 if (ret != EOK) {
197 usb_log_error("Failed to disable extended capabilities: %s.\n",
198 str_error(ret));
199 goto clean;
200 }
201clean:
202 async_hangup(parent_sess);
203 return ret;
204}
205
206/**
207 * @}
208 */
Note: See TracBrowser for help on using the repository browser.