revert between 56095 -> 55830 in arch
[AROS.git] / arch / m68k-amiga / hidd / pci-mediator / driverclass.c
blobededec690986c23bb7470871faebbf8fc5f548f4
1 /*
2 Copyright © 2004-2006, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: PCI direct driver for Elbox Mediator series
6 Lang: English
7 */
9 #define __OOP_NOATTRBASES__
11 #define DEBUG 1
12 #include <aros/debug.h>
14 #include <exec/types.h>
15 #include <hidd/pci.h>
16 #include <oop/oop.h>
18 #include <libraries/configvars.h>
19 #include <utility/tagitem.h>
21 #include <proto/exec.h>
22 #include <proto/utility.h>
23 #include <proto/oop.h>
24 #include <proto/expansion.h>
26 #include <aros/symbolsets.h>
28 #include "pci.h"
29 #include "pci_resource.h"
30 #include "empbreg.h"
32 #undef HiddPCIDriverAttrBase
33 #undef HiddAttrBase
35 #define HiddPCIDriverAttrBase (PSD(cl)->hiddPCIDriverAB)
36 #define HiddAttrBase (PSD(cl)->hiddAB)
38 #define pci_readl(b, d, f, r) base->cfg_readl(base, b, d, f, r)
39 #define pci_writel(b, d, f, r, v) base->cfg_writel(base, b, d, f, r, v)
41 static ULONG a12k_pci_readl(struct pcibase *base, UBYTE bus, UBYTE dev, UBYTE sub, UBYTE reg)
43 ULONG tmp;
44 UWORD offset;
46 if (bus >= 1)
47 return ~0;
49 offset = EMPB_CONF_DEV_STRIDE * dev +
50 EMPB_CONF_FUNC_STRIDE * sub +
51 reg;
52 offset >>= 2;
54 Disable();
55 base->setup[EMPB_SETUP_BRIDGE_OFF] = EMPB_BRIDGE_CONF;
56 tmp = base->config[offset];
57 base->setup[EMPB_SETUP_BRIDGE_OFF] = EMPB_BRIDGE_IO;
58 Enable();
60 return AROS_LE2LONG(tmp);
63 static VOID a12k_pci_writel(struct pcibase *base, UBYTE bus, UBYTE dev, UBYTE sub, UBYTE reg, ULONG val)
65 UWORD offset;
67 if (bus >= 1)
68 return;
70 offset = EMPB_CONF_DEV_STRIDE * dev +
71 EMPB_CONF_FUNC_STRIDE * sub +
72 reg;
73 offset >>= 2;
75 val = AROS_LONG2LE(val);
77 Disable();
78 base->setup[EMPB_SETUP_BRIDGE_OFF] = EMPB_BRIDGE_CONF;
79 base->config[offset] = val;
80 base->setup[EMPB_SETUP_BRIDGE_OFF] = EMPB_BRIDGE_IO;
81 Enable();
84 static BOOL a12k_init(struct pcibase *base)
86 D(bug("MEDIATOR: Attempting A1200 style init\n"));
88 base->setup = base->baseDev->cd_BoardAddr;
89 base->config = base->baseDev->cd_BoardAddr + EMPB_BRIDGE_OFF;
90 base->cfg_readl = a12k_pci_readl;
91 base->cfg_writel = a12k_pci_writel;
93 base->io = CreatePCIResourceList((IPTR)base->baseDev->cd_BoardAddr + EMPB_BRIDGE_OFF, EMPB_BRIDGE_SIZE + 1);
94 base->mem = CreatePCIResourceList((IPTR)base->memDev->cd_BoardAddr, base->memDev->cd_BoardSize);
96 return TRUE;
99 static ULONG a4k_pci_readl(struct pcibase *base, UBYTE bus, UBYTE dev, UBYTE sub, UBYTE reg)
101 ULONG tmp;
102 UWORD offset;
104 if (bus >= 64)
105 return ~0;
107 offset = EMZ4_CONF_BUS_STRIDE * bus +
108 EMZ4_CONF_DEV_STRIDE * dev +
109 EMZ4_CONF_FUNC_STRIDE * sub +
110 reg;
111 offset >>= 2;
113 tmp = base->config[offset];
115 return AROS_LE2LONG(tmp);
118 static VOID a4k_pci_writel(struct pcibase *base, UBYTE bus, UBYTE dev, UBYTE sub, UBYTE reg, ULONG val)
120 UWORD offset;
122 if (bus >= 64)
123 return;
125 offset = EMZ4_CONF_BUS_STRIDE * bus +
126 EMZ4_CONF_DEV_STRIDE * dev +
127 EMZ4_CONF_FUNC_STRIDE * sub +
128 reg;
129 offset >>= 2;
131 base->config[offset] = AROS_LONG2LE(val);
134 static BOOL a4k_init(struct pcibase *base)
136 D(bug("MEDIATOR: Attempting A3000/4000 style init\n"));
138 base->setup = base->baseDev->cd_BoardAddr;
139 base->config = base->baseDev->cd_BoardAddr + EMZ4_CONFIG_OFF;
141 base->setup[EMZ4_SETUP_STATUS_OFF] = 0x00;
142 base->setup[EMZ4_SETUP_CONFIG_OFF] = 0x41;
144 base->cfg_readl = a4k_pci_readl;
145 base->cfg_writel = a4k_pci_writel;
147 base->io = CreatePCIResourceList((IPTR)base->baseDev->cd_BoardAddr + EMZ4_IOPORT_OFF, EMZ4_IOPORT_SIZE + 1);
148 base->mem = CreatePCIResourceList((IPTR)base->memDev->cd_BoardAddr, base->memDev->cd_BoardSize);
150 return TRUE;
153 static void PCIInitialize(struct pcibase *base, int bus, struct MinList *io, struct MinList *mem)
155 int dev, sub;
157 int i;
158 D(bug("MEDIATOR: Dumping config area for device 0:\n"));
159 for (i = 0; i < 256/4; i++) {
160 if ((i % 4) == 0) {
161 D(bug("%p:", i));
163 D(bug("%c%08x", (i ==2) ? '-' : ' ',pci_readl(0, 0, 0, i)));
164 if ((i % 4) == 3) {
165 D(bug("\n"));
170 /* Initialize all devices attached to this PCIDriver
172 * TODO: Handle PCI bridges
174 for (dev = 0; dev < 32; dev++) {
175 for (sub = 0; sub < 8; sub++) {
176 ULONG tmp, venprod;
177 int i;
178 UBYTE cmd = PCICMF_BUSMASTER;
180 venprod = pci_readl(bus, dev, sub, 0);
181 if (venprod == 0 || venprod == ~0)
182 continue;
184 D(bug("MEDIATOR: %d:%02x.%d %04x:%04x\n", bus, dev, sub, venprod & 0xffff, (venprod >> 16) & 0xffff));
186 /* Program the 6 BARs */
187 for (i = 0; i < 6; i++) {
188 ULONG bar, start, size;
190 pci_writel(bus, dev, sub, PCICS_BAR0 + i * 4, ~0);
191 bar = pci_readl(bus, dev, sub, PCICS_BAR0 + i * 4);
192 size = bar & ((bar & PCIBAR_MASK_TYPE) ? PCIBAR_MASK_IO : PCIBAR_MASK_MEM);
193 size = (~size + 1);
194 if (size == 0)
195 continue;
197 if ((bar & PCIBAR_MASK_TYPE) == PCIBAR_TYPE_IO) {
198 start = AllocPCIResource(base->io, size);
199 cmd |= PCICMF_IODECODE;
200 } else {
201 start = AllocPCIResource(base->mem, size);
202 cmd |= PCICMF_MEMDECODE;
205 if (start == ~0) {
206 D(bug("\tBAR%d: %s - %d bytes unallocated\n", i, (bar & PCIBAR_MASK_TYPE) ? "IO" : "Mem", size));
207 cmd = 0;
209 break;
212 D(bug("\tBAR%d: %s 0x%x-0x%x\n", i, (bar & PCIBAR_MASK_TYPE) ? "IO" : "Mem", start, start + size - 1));
214 pci_writel(bus, dev, sub, PCICS_BAR0 + i*4, start);
216 if ((bar & PCIBAR_MEMTYPE_MASK) == PCIBAR_MEMTYPE_64BIT) {
217 /* Skip the 2nd part of a 64 bit BAR */
218 i++;
219 pci_writel(bus, dev, sub, PCICS_BAR0 + i*4, 0);
223 /* Set up the interrupt */
224 tmp = pci_readl(bus, dev, sub, PCICS_INT_LINE);
225 tmp &= ~0xff;
226 tmp |= EMPB_INT;
227 pci_writel(bus, dev, sub, PCICS_INT_LINE, tmp);
229 /* Enable the device */
230 tmp = pci_readl(bus, dev, sub, PCICS_COMMAND);
231 tmp &= ~0xff;
232 tmp |= cmd;
233 pci_writel(bus, dev, sub, PCICS_COMMAND, tmp);
235 /* If not multi-function, skip the rest */
236 if (sub == 0) {
237 tmp = pci_readl(bus, dev, sub, PCICS_CACHELS);
238 tmp >>= 16;
239 tmp &= 0xff;
240 if (!(tmp & PCIHT_MULTIFUNC))
241 break;
248 We overload the New method in order to introduce the Hidd Name and
249 HardwareName attributes.
251 OOP_Object *PCIMediator__Root__New(OOP_Class *cl, OOP_Object *o, struct pRoot_New *msg)
253 struct pRoot_New mymsg;
254 struct ConfigDev *baseDev, *memDev;
255 struct CurrentBinding cb;
256 struct Library *ExpansionBase;
258 struct TagItem mytags[] = {
259 { aHidd_Name, (IPTR)"PCIMediator" },
260 { aHidd_HardwareName, (IPTR)"Elbox Mediator PCI driver" },
261 { TAG_DONE, 0 }
264 if (!(ExpansionBase = OpenLibrary("expansion.library",33))) {
265 OOP_DisposeObject(o);
266 return NULL;
269 if (GetCurrentBinding(&cb, sizeof(cb)) == sizeof(cb)) {
270 baseDev = cb.cb_ConfigDev;
271 D(bug("MEDIATOR: Configuring for %d/%d @%p\n", baseDev->cd_Rom.er_Manufacturer, baseDev->cd_Rom.er_Product, baseDev->cd_BoardAddr));
272 if ((memDev = FindConfigDev(baseDev, baseDev->cd_Rom.er_Manufacturer, baseDev->cd_Rom.er_Product | 0x80))) {
273 D(bug("MEDIATOR: Found companion board\n"));
275 baseDev->cd_Flags &= ~CDF_CONFIGME;
276 baseDev->cd_Driver = BASE(cl);
278 memDev->cd_Flags &= ~CDF_CONFIGME;
279 memDev->cd_Driver = BASE(cl);
281 BASE(cl)->baseDev = baseDev;
282 BASE(cl)->memDev = memDev;
284 mymsg.mID = msg->mID;
285 mymsg.attrList = (struct TagItem *)&mytags;
287 if (msg->attrList)
289 mytags[2].ti_Tag = TAG_MORE;
290 mytags[2].ti_Data = (IPTR)msg->attrList;
293 msg = &mymsg;
295 /* Set up board, based on whether the baseDev is
296 * in Zorro III space or not.
298 if (baseDev->cd_Rom.er_Flags & ERFF_EXTENDED) {
299 a4k_init(BASE(cl));
300 } else {
301 a12k_init(BASE(cl));
304 /* Initialize bus 0 */
305 PCIInitialize(BASE(cl), 0, BASE(cl)->io, BASE(cl)->mem);
307 /* We don't need these resource lists any longer */
308 DeletePCIResourceList(BASE(cl)->io);
309 DeletePCIResourceList(BASE(cl)->mem);
311 o = (OOP_Object *)OOP_DoSuperMethod(cl, o, (OOP_Msg)msg);
312 } else {
313 OOP_DisposeObject(o);
315 } else {
316 OOP_DisposeObject(o);
319 CloseLibrary(ExpansionBase);
321 return o;
324 VOID PCIMediator__Root__Dispose(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
326 BASE(cl)->baseDev->cd_Flags |= CDF_CONFIGME;
327 BASE(cl)->baseDev->cd_Driver = NULL;
328 BASE(cl)->memDev->cd_Flags |= CDF_CONFIGME;
329 BASE(cl)->memDev->cd_Driver = NULL;
332 void PCIMediator__Hidd_PCIDriver__WriteConfigLong(OOP_Class *cl, OOP_Object *o,
333 struct pHidd_PCIDriver_WriteConfigLong *msg)
335 BASE(cl)->cfg_writel(BASE(cl), msg->bus, msg->dev, msg->sub, msg->reg, msg->val);
338 ULONG PCIMediator__Hidd_PCIDriver__ReadConfigLong(OOP_Class *cl, OOP_Object *o,
339 struct pHidd_PCIDriver_ReadConfigLong *msg)
341 return BASE(cl)->cfg_readl(BASE(cl), msg->bus, msg->dev, msg->sub, msg->reg);
344 /* Class initialization and destruction */
345 static int PCIMediator_InitClass(LIBBASETYPEPTR LIBBASE)
347 OOP_Object *pci;
349 struct pHidd_PCI_AddHardwareDriver msg,*pmsg=&msg;
351 D(bug("PCIMediator: Driver initialization\n"));
353 LIBBASE->psd.hiddPCIDriverAB = OOP_ObtainAttrBase(IID_Hidd_PCIDriver);
354 LIBBASE->psd.hiddAB = OOP_ObtainAttrBase(IID_Hidd);
355 if (LIBBASE->psd.hiddPCIDriverAB == 0 || LIBBASE->psd.hiddAB == 0)
357 D(bug("PCIMediator: ObtainAttrBases failed\n"));
358 return FALSE;
361 msg.driverClass = LIBBASE->psd.driverClass;
362 msg.mID = OOP_GetMethodID(IID_Hidd_PCI, moHidd_PCI_AddHardwareDriver);
363 D(bug("PCIMediator: Adding Driver to main the class OK\n"));
365 pci = OOP_NewObject(NULL, CLID_Hidd_PCI, NULL);
366 OOP_DoMethod(pci, (OOP_Msg)pmsg);
367 OOP_DisposeObject(pci);
369 D(bug("PCIMediator: All OK\n"));
371 return TRUE;
374 static int PCIMediator_ExpungeClass(LIBBASETYPEPTR LIBBASE)
376 D(bug("PCIMediator: Class destruction\n"));
378 OOP_ReleaseAttrBase(IID_Hidd_PCIDriver);
379 OOP_ReleaseAttrBase(IID_Hidd);
381 return TRUE;
384 ADD2INITLIB(PCIMediator_InitClass, 0)
385 ADD2EXPUNGELIB(PCIMediator_ExpungeClass, 0)