2 Copyright © 2010-2013, The AROS Development Team. All rights reserved.
9 #include <proto/exec.h>
10 #include <proto/dos.h> /* FIXME: Remove after removing Delay() */
12 #include <aros/debug.h>
14 #include "agp_private.h"
16 #undef HiddAGPBridgeDeviceAttrBase
17 #define HiddAGPBridgeDeviceAttrBase (SD(cl)->hiddAGPBridgeDeviceAB)
19 struct HiddAgpPciDevicesEnumeratorData
21 struct HIDDGenericBridgeDeviceData
*gbddata
;
22 OOP_AttrBase hiddPCIDeviceAB
;
26 UBYTE
readconfigbyte(OOP_Object
* pciDevice
, UBYTE where
)
28 struct pHidd_PCIDevice_ReadConfigByte rcbmsg
= {
29 mID
: OOP_GetMethodID(IID_Hidd_PCIDevice
, moHidd_PCIDevice_ReadConfigByte
),
33 return (UBYTE
)OOP_DoMethod(pciDevice
, (OOP_Msg
)msg
);
36 UWORD
readconfigword(OOP_Object
* pciDevice
, UBYTE where
)
38 struct pHidd_PCIDevice_ReadConfigWord rcwmsg
= {
39 mID
: OOP_GetMethodID(IID_Hidd_PCIDevice
, moHidd_PCIDevice_ReadConfigWord
),
43 return (UWORD
)OOP_DoMethod(pciDevice
, (OOP_Msg
)msg
);
46 ULONG
readconfiglong(OOP_Object
* pciDevice
, UBYTE where
)
48 struct pHidd_PCIDevice_ReadConfigLong rclmsg
= {
49 mID
: OOP_GetMethodID(IID_Hidd_PCIDevice
, moHidd_PCIDevice_ReadConfigLong
),
53 return (ULONG
)OOP_DoMethod(pciDevice
, (OOP_Msg
)msg
);
56 VOID
writeconfiglong(OOP_Object
* pciDevice
, UBYTE where
, ULONG val
)
58 struct pHidd_PCIDevice_WriteConfigLong wclmsg
= {
59 mID
: OOP_GetMethodID(IID_Hidd_PCIDevice
, moHidd_PCIDevice_WriteConfigLong
),
64 OOP_DoMethod(pciDevice
, (OOP_Msg
)msg
);
67 VOID
writeconfigbyte(OOP_Object
* pciDevice
, UBYTE where
, UBYTE val
)
69 struct pHidd_PCIDevice_WriteConfigByte wcbmsg
= {
70 mID
: OOP_GetMethodID(IID_Hidd_PCIDevice
, moHidd_PCIDevice_WriteConfigByte
),
75 OOP_DoMethod(pciDevice
, (OOP_Msg
)msg
);
78 VOID
writeconfigword(OOP_Object
* pciDevice
, UBYTE where
, UWORD val
)
80 struct pHidd_PCIDevice_WriteConfigWord wcwmsg
= {
81 mID
: OOP_GetMethodID(IID_Hidd_PCIDevice
, moHidd_PCIDevice_WriteConfigWord
),
86 OOP_DoMethod(pciDevice
, (OOP_Msg
)msg
);
89 AROS_UFH3(void, HiddAgpPciDevicesEnumerator
,
90 AROS_UFHA(struct Hook
*, hook
, A0
),
91 AROS_UFHA(OOP_Object
*, pciDevice
, A2
),
92 AROS_UFHA(APTR
, message
, A1
))
96 IPTR
class, agpcapptr
;
97 struct HiddAgpPciDevicesEnumeratorData
* hdata
=
98 (struct HiddAgpPciDevicesEnumeratorData
*)hook
->h_Data
;
100 #undef HiddPCIDeviceAttrBase
101 #define HiddPCIDeviceAttrBase hdata->hiddPCIDeviceAB
103 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Class
, &class);
104 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_CapabilityAGP
, (APTR
)&agpcapptr
);
106 /* Select bridges and AGP devices */
107 if ((class == 0x06) || (agpcapptr
))
110 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_INTLine
, &intline
);
112 /* If the device is not a bridge and it has not interrupt line set, skip it */
113 if ((class != 0x06) && ((intline
== 0) || (intline
>= 255)))
116 struct PciAgpDevice
* pciagpdev
=
117 (struct PciAgpDevice
*)AllocVec(sizeof(struct PciAgpDevice
), MEMF_ANY
| MEMF_CLEAR
);
119 pciagpdev
->PciDevice
= pciDevice
;
120 pciagpdev
->AgpCapability
= (UBYTE
)agpcapptr
;
121 pciagpdev
->Class
= (UBYTE
)class;
122 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_VendorID
, &temp
);
123 pciagpdev
->VendorID
= (UWORD
)temp
;
124 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_ProductID
, &temp
);
125 pciagpdev
->ProductID
= (UWORD
)temp
;
127 AddTail(&hdata
->gbddata
->devices
, (struct Node
*)pciagpdev
);
130 #undef HiddPCIDeviceAttrBase
135 static ULONG
HiddAgpGenericAgp3CalibrateModes(ULONG requestedmode
, ULONG bridgemode
, ULONG vgamode
)
137 ULONG calibratedmode
= bridgemode
;
140 /* Apply reserved mask to requestedmode */
141 requestedmode
&= ~AGP3_RESERVED_MASK
;
143 /* Select a speed for requested mode */
144 temp
= requestedmode
& 0x07;
145 requestedmode
&= ~0x07; /* Clear any speed */
146 if (temp
& AGP_STATUS_REG_AGP3_X8
)
147 requestedmode
|= AGP_STATUS_REG_AGP3_X8
;
149 requestedmode
|= AGP_STATUS_REG_AGP3_X4
;
151 /* Set ARQSZ as max value. Ignore requestedmode */
152 calibratedmode
= ((calibratedmode
& ~AGP_STATUS_REG_ARQSZ_MASK
) |
153 max(calibratedmode
& AGP_STATUS_REG_ARQSZ_MASK
, vgamode
& AGP_STATUS_REG_ARQSZ_MASK
));
155 /* Set calibration cycle. Ignore requestedmode */
156 calibratedmode
= ((calibratedmode
& ~AGP_STATUS_REG_CAL_MASK
) |
157 min(calibratedmode
& AGP_STATUS_REG_CAL_MASK
, vgamode
& AGP_STATUS_REG_CAL_MASK
));
159 /* Set SBA for AGP3 (always) */
160 calibratedmode
|= AGP_STATUS_REG_SBA
;
162 /* Select speed based on request and capabilities of bridge and vgacard */
163 calibratedmode
&= ~0x07; /* Clear any mode */
164 if ((requestedmode
& AGP_STATUS_REG_AGP3_X8
) &&
165 (bridgemode
& AGP_STATUS_REG_AGP3_X8
) &&
166 (vgamode
& AGP_STATUS_REG_AGP3_X8
))
167 calibratedmode
|= AGP_STATUS_REG_AGP3_X8
;
169 calibratedmode
|= AGP_STATUS_REG_AGP3_X4
;
171 return calibratedmode
;
174 static ULONG
HiddAgpGenericAgp2CalibrateModes(ULONG requestedmode
, ULONG bridgemode
, ULONG vgamode
)
176 ULONG calibratedmode
= bridgemode
;
179 /* Apply reserved mask to requestedmode */
180 requestedmode
&= ~AGP2_RESERVED_MASK
;
182 /* Fix for some bridges reporting only one speed instead of all */
183 if (bridgemode
& AGP_STATUS_REG_AGP2_X4
)
184 bridgemode
|= (AGP_STATUS_REG_AGP2_X2
| AGP_STATUS_REG_AGP2_X1
);
185 if (bridgemode
& AGP_STATUS_REG_AGP2_X2
)
186 bridgemode
|= AGP_STATUS_REG_AGP2_X1
;
188 /* Select speed for requested mode */
189 temp
= requestedmode
& 0x07;
190 requestedmode
&= ~0x07; /* Clear any speed */
191 if (temp
& AGP_STATUS_REG_AGP2_X4
)
192 requestedmode
|= AGP_STATUS_REG_AGP2_X4
;
195 if (temp
& AGP_STATUS_REG_AGP2_X2
)
196 requestedmode
|= AGP_STATUS_REG_AGP2_X2
;
198 requestedmode
|= AGP_STATUS_REG_AGP2_X1
;
201 /* Disable SBA if not supported/requested */
202 if (!((bridgemode
& AGP_STATUS_REG_SBA
) && (requestedmode
& AGP_STATUS_REG_SBA
)
203 && (vgamode
& AGP_STATUS_REG_SBA
)))
204 calibratedmode
&= ~AGP_STATUS_REG_SBA
;
206 /* Select speed based on request and capabilities of bridge and vgacard */
207 calibratedmode
&= ~0x07; /* Clear any mode */
208 if ((requestedmode
& AGP_STATUS_REG_AGP2_X4
) &&
209 (bridgemode
& AGP_STATUS_REG_AGP2_X4
) &&
210 (vgamode
& AGP_STATUS_REG_AGP2_X4
))
211 calibratedmode
|= AGP_STATUS_REG_AGP2_X4
;
214 if ((requestedmode
& AGP_STATUS_REG_AGP2_X2
) &&
215 (bridgemode
& AGP_STATUS_REG_AGP2_X2
) &&
216 (vgamode
& AGP_STATUS_REG_AGP2_X2
))
217 calibratedmode
|= AGP_STATUS_REG_AGP2_X2
;
219 calibratedmode
|= AGP_STATUS_REG_AGP2_X1
;
222 /* Disable fast writed if in X1 mode */
223 if (calibratedmode
& AGP_STATUS_REG_AGP2_X1
)
224 calibratedmode
&= ~AGP_STATUS_REG_FAST_WRITES
;
226 return calibratedmode
;
229 static ULONG
HiddAgpGenericSelectBestMode(struct HIDDGenericBridgeDeviceData
* gbddata
, ULONG requestedmode
, ULONG bridgemode
)
231 OOP_Object
* videodev
= gbddata
->videocard
->PciDevice
;
232 UBYTE videoagpcap
= gbddata
->videocard
->AgpCapability
;
235 /* Get VGA card capability */
236 vgamode
= readconfiglong(videodev
, videoagpcap
+ AGP_STATUS_REG
);
238 D(bug("[AGP] VGA mode 0x%x\n", vgamode
));
240 /* Set Request Queue */
241 bridgemode
= ((bridgemode
& ~AGP_STATUS_REG_RQ_DEPTH_MASK
) |
242 min(requestedmode
& AGP_STATUS_REG_RQ_DEPTH_MASK
,
243 min(bridgemode
& AGP_STATUS_REG_RQ_DEPTH_MASK
, vgamode
& AGP_STATUS_REG_RQ_DEPTH_MASK
)));
247 (bridgemode
& AGP_STATUS_REG_FAST_WRITES
) &&
248 (requestedmode
& AGP_STATUS_REG_FAST_WRITES
) &&
249 (vgamode
& AGP_STATUS_REG_FAST_WRITES
)))
251 bridgemode
&= ~AGP_STATUS_REG_FAST_WRITES
;
254 if (gbddata
->bridgemode
& AGP_STATUS_REG_AGP_3_0
)
256 bridgemode
= HiddAgpGenericAgp3CalibrateModes(requestedmode
, bridgemode
, vgamode
);
260 bridgemode
= HiddAgpGenericAgp2CalibrateModes(requestedmode
, bridgemode
, vgamode
);
266 static VOID
HiddAgpGenericSendCommand(struct HIDDGenericBridgeDeviceData
* gbddata
, ULONG status
)
268 struct PciAgpDevice
* pciagpdev
= NULL
;
270 /* Send command to all AGP capable devices */
271 ForeachNode(&gbddata
->devices
, pciagpdev
)
273 if(pciagpdev
->AgpCapability
)
278 if (status
& AGP_STATUS_REG_AGP_3_0
)
281 D(bug("[AGP] Set AGP%d device 0x%x/0x%x to speed %dx\n",
282 (status
& AGP_STATUS_REG_AGP_3_0
) ? 3 : 2,
283 pciagpdev
->VendorID
, pciagpdev
->ProductID
, mode
));
285 writeconfiglong(pciagpdev
->PciDevice
, pciagpdev
->AgpCapability
+ AGP_COMMAND_REG
, status
);
287 /* FIXME: Change this to timer.device interaction. DOS may not be up when agp.hidd is used */
288 /* Keep this delay here. Some bridges need it. */
294 /* NON-PUBLIC METHODS */
295 BOOL
METHOD(GenericBridgeDevice
, Hidd_AGPBridgeDevice
, ScanAndDetectDevices
)
297 struct HIDDGenericBridgeDeviceData
* gbddata
= OOP_INST_DATA(cl
, o
);
298 struct PciAgpDevice
* pciagpdev
= NULL
;
303 /* Scan all PCI devices */
304 struct HiddAgpPciDevicesEnumeratorData hdata
= {
306 hiddPCIDeviceAB
: SD(cl
)->hiddPCIDeviceAB
309 struct Hook FindHook
= {
310 h_Entry
: (IPTR (*)())HiddAgpPciDevicesEnumerator
,
314 struct TagItem Requirements
[] = {
318 struct pHidd_PCI_EnumDevices enummsg
= {
319 mID
: OOP_GetMethodID(IID_Hidd_PCI
, moHidd_PCI_EnumDevices
),
321 requirements
: (struct TagItem
*)&Requirements
,
324 OOP_DoMethod(SD(cl
)->pcibus
, (OOP_Msg
)&enummsg
);
326 /* Select matching devices */
327 ForeachNode(&gbddata
->devices
, pciagpdev
)
330 if ((!gbddata
->bridge
) && (pciagpdev
->Class
== 0x06) &&
331 (pciagpdev
->AgpCapability
))
333 gbddata
->bridge
= pciagpdev
;
336 /* Select video card */
337 if ((!gbddata
->videocard
) && (pciagpdev
->Class
== 0x03) &&
338 (pciagpdev
->AgpCapability
))
340 gbddata
->videocard
= pciagpdev
;
344 return (gbddata
->videocard
&& gbddata
->bridge
);
347 BOOL
METHOD(GenericBridgeDevice
, Hidd_AGPBridgeDevice
, CreateGattTable
)
349 struct HIDDGenericBridgeDeviceData
* gbddata
= OOP_INST_DATA(cl
, o
);
351 if (gbddata
->bridgeapersize
== 0)
354 /* Create a table that will hold a certain number of 32bit pointers */
355 ULONG entries
= gbddata
->bridgeapersize
* 1024 * 1024 / 4096;
356 ULONG tablesize
= entries
* 4;
359 gbddata
->scratchmembuffer
= AllocVec(4096 * 2, MEMF_PUBLIC
| MEMF_CLEAR
);
360 gbddata
->scratchmem
= (ULONG
*)(ALIGN((IPTR
)gbddata
->scratchmembuffer
, 4096));
361 D(bug("[AGP] Created scratch memory at 0x%x\n", (ULONG
)gbddata
->scratchmem
));
364 gbddata
->gatttablebuffer
= AllocVec(tablesize
+ 4096, MEMF_PUBLIC
| MEMF_CLEAR
);
365 gbddata
->gatttable
= (ULONG
*)(ALIGN((IPTR
)gbddata
->gatttablebuffer
, 4096));
367 D(bug("[AGP] Created GATT table size %d at 0x%x\n", tablesize
,
368 (ULONG
)gbddata
->gatttable
));
370 for (i
= 0; i
< entries
; i
++)
372 writel((ULONG
)(IPTR
)gbddata
->scratchmem
, gbddata
->gatttable
+ i
);
373 readl(gbddata
->gatttable
+ i
); /* PCI Posting. */
381 VOID
METHOD(GenericBridgeDevice
, Hidd_AGPBridgeDevice
, FlushGattTable
)
383 bug("[GenericBridgeDevice] abstract FlushGattTable method called\n");
387 OOP_Object
* METHOD(GenericBridgeDevice
, Root
, New
)
389 o
= (OOP_Object
*)OOP_DoSuperMethod(cl
, o
, (OOP_Msg
) msg
);
393 struct HIDDGenericBridgeDeviceData
* gbddata
= OOP_INST_DATA(cl
, o
);
394 gbddata
->bridge
= NULL
;
395 gbddata
->bridgemode
= 0;
396 gbddata
->bridgeapersize
= 0;
397 gbddata
->bridgeaperbase
= 0;
398 gbddata
->gatttable
= NULL
;
399 gbddata
->gatttablebuffer
= NULL
;
400 gbddata
->scratchmem
= NULL
;
401 gbddata
->scratchmembuffer
= NULL
;
402 gbddata
->videocard
= NULL
;
403 NEWLIST(&gbddata
->devices
);
404 gbddata
->state
= STATE_UNKNOWN
;
405 gbddata
->memmask
= 0x00000000;
406 InitSemaphore(&gbddata
->lock
);
412 VOID
GenericBridgeDevice__Root__Dispose(OOP_Class
* cl
, OOP_Object
* o
, OOP_Msg msg
)
414 struct HIDDGenericBridgeDeviceData
* gbddata
= OOP_INST_DATA(cl
, o
);
415 struct PciAgpDevice
* pciagpdev
= NULL
;
417 /* Free scanned device information */
418 while((pciagpdev
= (struct PciAgpDevice
*)RemHead(&gbddata
->devices
)) != NULL
)
421 /* Free GATT table */
422 D(bug("[AGP] Freeing GATT table 0x%x, scratch memory 0x%x\n",
423 (ULONG
)gbddata
->gatttable
, (ULONG
)gbddata
->scratchmem
));
425 FreeVec(gbddata
->scratchmembuffer
);
426 gbddata
->scratchmembuffer
= NULL
;
427 gbddata
->scratchmem
= NULL
;
429 FreeVec(gbddata
->gatttablebuffer
);
430 gbddata
->gatttablebuffer
= NULL
;
431 gbddata
->gatttable
= NULL
;
433 OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)msg
);
436 VOID
METHOD(GenericBridgeDevice
, Root
, Get
)
439 struct HIDDGenericBridgeDeviceData
* gbddata
= OOP_INST_DATA(cl
, o
);
441 if (IS_AGPBRIDGEDEV_ATTR(msg
->attrID
, idx
))
445 case aoHidd_AGPBridgeDevice_Mode
:
446 *msg
->storage
= gbddata
->bridgemode
;
449 case aoHidd_AGPBridgeDevice_ApertureBase
:
450 *msg
->storage
= gbddata
->bridgeaperbase
;
453 case aoHidd_AGPBridgeDevice_ApertureSize
:
454 *msg
->storage
= gbddata
->bridgeapersize
;
459 /* Use parent class for all other properties */
460 OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)msg
);
463 BOOL
METHOD(GenericBridgeDevice
, Hidd_AGPBridgeDevice
, Enable
)
465 struct HIDDGenericBridgeDeviceData
* gbddata
= OOP_INST_DATA(cl
, o
);
467 ObtainSemaphore(&gbddata
->lock
);
469 if (gbddata
->state
!= STATE_INITIALIZED
)
471 ReleaseSemaphore(&gbddata
->lock
);
475 OOP_Object
* bridgedev
= gbddata
->bridge
->PciDevice
;
476 UBYTE bridgeagpcap
= gbddata
->bridge
->AgpCapability
;
477 ULONG requestedmode
= msg
->requestedmode
;
478 ULONG bridgemode
= 0;
482 D(bug("[AGP] Enable AGP:\n"));
483 D(bug("[AGP] Requested mode 0x%x\n", requestedmode
));
485 bridgemode
= readconfiglong(bridgedev
, bridgeagpcap
+ AGP_STATUS_REG
);
486 D(bug("[AGP] Bridge mode 0x%x\n", requestedmode
));
488 bridgemode
= HiddAgpGenericSelectBestMode(gbddata
, requestedmode
, bridgemode
);
490 bridgemode
|= AGP_STATUS_REG_AGP_ENABLED
;
492 major
= (readconfigbyte(bridgedev
, bridgeagpcap
+ AGP_VERSION_REG
) >> 4) & 0xf;
496 /* Bridge supports version 3 or greater) */
497 if (gbddata
->bridgemode
& AGP_STATUS_REG_AGP_3_0
)
499 /* Bridge is operating in mode 3.0 */
503 /* Bridge is operating in legacy mode */
504 /* Disable calibration cycle */
506 bridgemode
&= ~(7 << 10);
507 temp
= readconfiglong(bridgedev
, bridgeagpcap
+ AGP_CTRL_REG
);
509 writeconfiglong(bridgedev
, bridgeagpcap
+ AGP_CTRL_REG
, temp
);
513 D(bug("[AGP] Mode to write: 0x%x\n", bridgemode
));
515 HiddAgpGenericSendCommand(gbddata
, bridgemode
);
516 gbddata
->state
= STATE_ENABLED
;
518 ReleaseSemaphore(&gbddata
->lock
);
523 VOID
METHOD(GenericBridgeDevice
, Hidd_AGPBridgeDevice
, BindMemory
)
526 struct HIDDGenericBridgeDeviceData
* gbddata
= OOP_INST_DATA(cl
, o
);
528 D(bug("Bind address 0x%x into offset %d, size %d\n", (ULONG
)msg
->address
, msg
->offset
, msg
->size
));
530 if (gbddata
->state
!= STATE_ENABLED
)
533 ObtainSemaphore(&gbddata
->lock
);
535 /* TODO: check if offset + size / 4096 ends before gatt_table end */
537 /* TODO: get mask type */
539 /* TODO: Check if each entry in GATT to be written is unbound */
541 /* Flush incomming memory - will be done in flush_cpu_cache below */
543 /* Insert entries into GATT table */
544 for(i
= 0; i
< msg
->size
/ 4096; i
++)
546 /* Write masked memory address into GATT */
547 writel((msg
->address
+ (4096 * i
)) | gbddata
->memmask
,
548 gbddata
->gatttable
+ msg
->offset
+ i
);
551 readl(gbddata
->gatttable
+ msg
->offset
+ i
- 1); /* PCI posting */
553 /* Flush CPU cache - make sure data in GATT is up to date */
556 /* Flush GATT table at card */
557 struct pHidd_AGPBridgeDevice_FlushGattTable fgtmsg
= {
558 mID
: OOP_GetMethodID(IID_Hidd_AGPBridgeDevice
, moHidd_AGPBridgeDevice_FlushGattTable
)
561 OOP_DoMethod(o
, (OOP_Msg
)&fgtmsg
);
563 ReleaseSemaphore(&gbddata
->lock
);
566 VOID
METHOD(GenericBridgeDevice
, Hidd_AGPBridgeDevice
, UnBindMemory
)
569 struct HIDDGenericBridgeDeviceData
* gbddata
= OOP_INST_DATA(cl
, o
);
571 D(bug("Unbind offset %d, size %d\n", msg
->offset
, msg
->size
));
573 if (gbddata
->state
!= STATE_ENABLED
)
579 ObtainSemaphore(&gbddata
->lock
);
581 /* TODO: get mask type */
583 /* Remove entries from GATT table */
584 for(i
= 0; i
< msg
->size
/ 4096; i
++)
586 writel((ULONG
)(IPTR
)gbddata
->scratchmem
, gbddata
->gatttable
+ msg
->offset
+ i
);
589 readl(gbddata
->gatttable
+ msg
->offset
+ i
- 1); /* PCI posting */
591 /* Flush CPU cache - make sure data in GATT is up to date */
594 /* Flush GATT table */
595 struct pHidd_AGPBridgeDevice_FlushGattTable fgtmsg
= {
596 mID
: OOP_GetMethodID(IID_Hidd_AGPBridgeDevice
, moHidd_AGPBridgeDevice_FlushGattTable
)
599 OOP_DoMethod(o
, (OOP_Msg
)&fgtmsg
);
601 ReleaseSemaphore(&gbddata
->lock
);
604 VOID
METHOD(GenericBridgeDevice
, Hidd_AGPBridgeDevice
, FlushChipset
)
606 /* This function is a NOOP */
609 BOOL
METHOD(GenericBridgeDevice
, Hidd_AGPBridgeDevice
, Initialize
)
611 bug("[GenericBridgeDevice] abstract Initialize method called\n");