grub2: bring back build of aros-side grub2 tools
[AROS.git] / workbench / devs / USB / drivers / EHCI / ehci_init.c
blobfce2779bda61d631f84abd96b959d504b8b0afe0
1 /*
2 Copyright (C) 2006 by Michal Schulz
3 $Id$
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with this program; if not, write to the
17 Free Software Foundation, Inc.,
18 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 #include <inttypes.h>
22 #include <aros/symbolsets.h>
24 #include <asm/io.h>
26 #include <hidd/hidd.h>
27 #include <hidd/pci.h>
29 #include <usb/usb.h>
31 #define DEBUG 1
33 #include <devices/timer.h>
35 #include <proto/exec.h>
36 #include <proto/oop.h>
37 #include <aros/debug.h>
39 #include "ehci.h"
41 #undef SD
42 #define SD(x) (&LIBBASE->sd)
44 static
45 AROS_UFH3(void, Enumerator,
46 AROS_UFHA(struct Hook *, hook, A0),
47 AROS_UFHA(OOP_Object *, pciDevice, A2),
48 AROS_UFHA(APTR, message, A1))
50 AROS_USERFUNC_INIT
52 LIBBASETYPE *LIBBASE = (LIBBASETYPE *)hook->h_Data;
53 char *base, *reg_base;
54 OOP_Object *driver;
55 uint8_t cap_length, offset;
56 int count = 64;
58 struct MsgPort *port;
59 struct timerequest *tr;
61 port = CreateMsgPort();
62 tr = CreateIORequest(port, sizeof(struct timerequest));
64 OpenDevice("timer.device", UNIT_VBLANK, (struct IORequest *)tr, 0);
66 struct pHidd_PCIDevice_WriteConfigLong wl;
67 struct pHidd_PCIDevice_ReadConfigLong rl;
68 struct pHidd_PCIDevice_WriteConfigByte wb;
70 wl.mID = OOP_GetMethodID(IID_Hidd_PCIDevice, moHidd_PCIDevice_WriteConfigLong);
71 rl.mID = OOP_GetMethodID(IID_Hidd_PCIDevice, moHidd_PCIDevice_ReadConfigLong);
72 wb.mID = OOP_GetMethodID(IID_Hidd_PCIDevice, moHidd_PCIDevice_WriteConfigByte);
74 struct TagItem attrs[] = {
75 { aHidd_PCIDevice_isMEM, TRUE },
76 { aHidd_PCIDevice_isMaster, TRUE },
77 { TAG_DONE, 0UL },
80 OOP_SetAttrs(pciDevice, (struct TagItem *)attrs);
81 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Base0, (IPTR *)&base);
82 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Driver, (void *)&driver);
84 cap_length = mmio_b(base);
85 reg_base = base + cap_length;
87 D(bug("[EHCI] EHCI device Device @ %p, cap_length: %d\n", base, cap_length));
89 uint32_t hcc_params = mmio_l(base + 0x08);
90 offset = (hcc_params >> 8) & 0xff; // Get the address of first capability
92 D(bug("[EHCI] hcc_params=%08x\n", hcc_params));
94 D(bug("[EHCI] Try to perform the BIOS handoff procedure\n"));
96 while(offset && count--)
98 uint32_t cap;
99 rl.reg = offset;
100 cap = OOP_DoMethod(driver, &rl.mID);
102 if ((cap & 0xff) == 1)
104 D(bug("[EHCI] cap=%08x\n", cap));
106 D(bug("[EHCI] LEGSUP capability found\n"));
107 uint8_t delay = 200;
109 if ((cap & 0x10000))
111 D(bug("[EHCI] BIOS was owning the EHCI. Changing it.\n"));
112 wb.reg = offset + 3;
113 wb.val = 1;
114 OOP_DoMethod(driver, &wb.mID);
117 while((cap & 0x10000) && delay > 0)
119 tr->tr_node.io_Command = TR_ADDREQUEST;
120 tr->tr_time.tv_sec = 0;
121 tr->tr_time.tv_usec = 40000;
122 DoIO((struct IORequest *)tr);
123 delay--;
124 rl.reg = offset;
125 cap = OOP_DoMethod(driver, &rl.mID);
128 if (cap & 0x10000)
130 D(bug("[EHCI] BIOS is not going to give up! Forcing it...\n"));
131 wb.val = 0;
132 wb.reg = offset + 2;
134 OOP_DoMethod(driver, &wb.mID);
137 D(bug("[EHCI] Disabling SMI\n"));
138 wl.reg = offset + 4;
139 wl.val = 0;
140 OOP_DoMethod(driver, &wl.mID);
142 else if ((cap & 0xff) == 0)
143 cap = 0;
145 offset = (cap >> 8) & 0xff;
148 D(bug("[EHCI] Performing full reset of the EHCI\n"));
150 uint32_t value = mmio_l(reg_base + 0x04); // Read the status register
151 if ((value & 0x1000) == 0) // Halted flag not cleared? Then the EHCI is still running. Stop it.
153 int nloop = 10;
155 value = mmio_l(reg_base + 0); // USBCMD reg
156 value &= ~1; // clear RUN flag
157 mmio_l(reg_base + 0) = value;
159 do {
160 mmio_l(reg_base + 0x04) = 0x3f;
161 tr->tr_node.io_Command = TR_ADDREQUEST;
162 tr->tr_time.tv_sec = 0;
163 tr->tr_time.tv_usec = 40000;
164 DoIO((struct IORequest *)tr);
165 value = mmio_l(reg_base + 0x04);
166 if ((value == ~(uint32_t)0) || value & 0x1000)
167 break;
168 } while(--nloop > 0);
171 mmio_l(reg_base + 0x08) = 0; // USBINTR = 0, no interrupts allowed
172 mmio_l(reg_base + 0x04) = 0x3f; // USBSTS flags cleared
173 mmio_l(reg_base + 0x40) = 0; // Unconfigure the chip
175 mmio_l(reg_base + 0) = 2;
176 tr->tr_node.io_Command = TR_ADDREQUEST;
177 tr->tr_time.tv_sec = 0;
178 tr->tr_time.tv_usec = 100000;
179 DoIO((struct IORequest *)tr);
180 mmio_l(reg_base + 0) = 0;
182 hcc_params &= 0xf;
184 while (hcc_params--)
186 mmio_l(reg_base + 0x44 + 4*hcc_params) = 1 << 13;
189 CloseDevice((struct IORequest *)tr);
190 DeleteIORequest(tr);
191 DeleteMsgPort(port);
193 AROS_USERFUNC_EXIT
196 static int EHCI_Init(LIBBASETYPEPTR LIBBASE)
198 D(bug("[EHCI] EHCI_Init()\n"));
200 LIBBASE->sd.usb = OOP_NewObject(NULL, (STRPTR)CLID_Hidd_USB, NULL);
202 if (!LIBBASE->sd.usb)
204 bug("[EHCI] Cannot create the instance of base USB class\n");
205 return FALSE;
208 if ((LIBBASE->sd.pci=OOP_NewObject(NULL, (STRPTR)CLID_Hidd_PCI, NULL)))
210 struct TagItem tags[] = {
211 { tHidd_PCI_Class, PCI_BASE_CLASS_SERIAL },
212 { tHidd_PCI_SubClass, PCI_SUB_CLASS_USB },
213 { tHidd_PCI_Interface, PCI_INTERFACE_EHCI },
214 { TAG_DONE, 0UL }
217 struct OOP_ABDescr attrbases[] = {
218 { (STRPTR)IID_Hidd, &HiddAttrBase },
219 { (STRPTR)IID_Hidd_PCIDevice, &HiddPCIDeviceAttrBase },
220 { (STRPTR)IID_Hidd_USBDevice, &HiddUSBDeviceAttrBase },
221 { (STRPTR)IID_Hidd_USBHub, &HiddUSBHubAttrBase },
222 { (STRPTR)IID_Hidd_USBDrv, &HiddUSBDrvAttrBase },
223 { NULL, NULL }
226 struct Hook FindHook = {
227 h_Entry: (IPTR (*)())Enumerator,
228 h_Data: LIBBASE,
231 OOP_ObtainAttrBases(attrbases);
233 D(bug("[EHCI] Searching for EHCI devices...\n"));
235 HIDD_PCI_EnumDevices(LIBBASE->sd.pci, &FindHook, (struct TagItem *)&tags);
237 D(bug("[EHCI] Done\n"));
239 OOP_DisposeObject(LIBBASE->sd.pci);
242 return FALSE;
245 static int EHCI_Expunge(LIBBASETYPEPTR LIBBASE)
247 struct OOP_ABDescr attrbases[] = {
248 { (STRPTR)IID_Hidd, &HiddAttrBase },
249 { (STRPTR)IID_Hidd_PCIDevice, &HiddPCIDeviceAttrBase },
250 { (STRPTR)IID_Hidd_USBDevice, &HiddUSBDeviceAttrBase },
251 { (STRPTR)IID_Hidd_USBHub, &HiddUSBHubAttrBase },
252 { (STRPTR)IID_Hidd_USBDrv, &HiddUSBDrvAttrBase },
253 { NULL, NULL }
256 OOP_ReleaseAttrBases(attrbases);
258 return TRUE;
261 OOP_Object *METHOD(EHCI, Root, New)
263 return NULL;
266 void METHOD(EHCI, Root, Dispose)
270 ADD2INITLIB(EHCI_Init, 0)
271 ADD2EXPUNGELIB(EHCI_Expunge, 0)
272 ADD2LIBS((STRPTR)"usb.hidd", 0, static struct Library *, __usbbase)