5 #include <aros/debug.h>
6 #include <exec/types.h>
8 #include <proto/exec.h>
9 #include <proto/cardres.h>
10 #include <graphics/gfxbase.h>
11 #include <hardware/custom.h>
12 #include <hardware/intbits.h>
13 #include <resources/card.h>
14 #include <libraries/pccard.h>
15 #include <aros/symbolsets.h>
20 #define GAYLE_BASE_4000 0xdd2022 /* 0xdd2020.W, 0xdd2026.B, 0xdd202a.B ... (argh!) */
21 #define GAYLE_IRQ_4000 0xdd3020
23 #define GAYLE_BASE_1200 0xda0000 /* 0xda0000.W, 0xda0004.B, 0xda0008.B ... */
24 #define GAYLE_IRQ_1200 0xda9000
25 #define GAYLE_INT_1200 0xdaa000
27 #define GAYLE_IRQ_IDE 0x80
28 #define GAYLE_INT_IDE 0x80
30 struct amiga_driverdata
32 struct amiga_busdata
*bus
[2];
33 struct Interrupt ideint
;
41 struct amiga_pcmcia_driverdata
43 struct amiga_busdata
*bus
[1];
44 struct CardHandle cardhandle
;
45 struct Interrupt statusint
;
46 struct Interrupt insertint
;
47 struct Interrupt removalint
;
48 struct CardResource
*CardResource
;
51 ULONG configbase
, configmask
;
52 struct DeviceTData dtd
;
53 struct CardMemoryMap
*cmm
;
65 static void ata_insw(APTR address
, UWORD port
, ULONG count
, void *data
)
67 struct amiga_busdata
*bdata
= data
;
68 volatile UWORD
*addr
= (UWORD
*)(bdata
->port
+ (port
& ~3));
76 static void ata_outsw(APTR address
, UWORD port
, ULONG count
, APTR data
)
78 struct amiga_busdata
*bdata
= data
;
79 volatile UWORD
*addr
= (UWORD
*)(bdata
->port
+ (port
& ~3));
87 static void ata_pcmcia_insw(APTR address
, UWORD port
, ULONG count
, void *data
)
89 struct amiga_busdata
*bdata
= data
;
90 volatile UWORD
*addr
= (UWORD
*)(bdata
->port
+ 8);
98 static void ata_pcmcia_outsw(APTR address
, UWORD port
, ULONG count
, APTR data
)
100 struct amiga_busdata
*bdata
= data
;
101 volatile UWORD
*addr
= (UWORD
*)(bdata
->port
+ 8);
102 UWORD
*dst
= address
;
110 static void ata_outl(ULONG val
, UWORD offset
, IPTR port
, APTR data
)
114 static void ata_out(UBYTE val
, UWORD offset
, IPTR port
, APTR data
)
116 struct amiga_busdata
*bdata
= data
;
117 volatile UBYTE
*addr
;
120 bug("ata_out(%x,%x)=%x:%x\n", offset
, port
, (UBYTE
*)(bdata
->port
+ port
) + offset
* 4, val
);
122 /* IDE doubler hides Alternate Status/Device Control register */
124 if (bdata
->reset
== 0 && (val
& 4)) {
125 ata_out(0x40, ata_DevHead
, 0, bdata
);
126 D(bug("[ATA] Emulating reset\n"));
127 ata_out(ATA_EXECUTE_DIAG
, ata_Command
, 0, bdata
);
129 bdata
->reset
= (val
& 4) != 0;
132 addr
= (UBYTE
*)(bdata
->port
+ port
);
133 addr
[offset
* 4] = val
;
136 static UBYTE
ata_in(UWORD offset
, IPTR port
, APTR data
)
138 struct amiga_busdata
*bdata
= data
;
139 volatile UBYTE
*addr
;
143 bug("ata_in(%x,%x)=%x\n", offset
, port
, (UBYTE
*)(bdata
->port
+ port
) + offset
* 4);
149 addr
= (UBYTE
*)(bdata
->port
+ port
);
150 v
= addr
[offset
* 4];
157 static void ata_pcmcia_out(UBYTE val
, UWORD offset
, IPTR port
, APTR data
)
159 volatile UBYTE
*addr
;
161 if (offset
== ata_Feature
)
168 static UBYTE
ata_pcmcia_in(UWORD offset
, IPTR port
, APTR data
)
170 volatile UBYTE
*addr
;
172 if (offset
== ata_Feature
)
180 static BOOL
custom_check(APTR addr
)
182 volatile struct Custom
*custom
= (struct Custom
*)0xdff000;
183 volatile struct Custom
*maybe_custom
= (struct Custom
*)addr
;
185 BOOL iscustom
= TRUE
;
187 intena
= custom
->intenar
;
188 custom
->intena
= 0x7fff;
189 custom
->intena
= 0xc000;
190 maybe_custom
->intena
= 0x7fff;
191 if (custom
->intenar
== 0x4000) {
192 maybe_custom
->intena
= 0x7fff;
193 if (custom
->intenar
== 0x4000)
196 custom
->intena
= 0x7fff;
197 custom
->intena
= intena
| 0x8000;
201 static UBYTE
*getport(struct amiga_driverdata
*ddata
)
203 UBYTE id
, status1
, status2
;
204 volatile UBYTE
*port
, *altport
;
208 gfx
= (struct GfxBase
*)TaggedOpenLibrary(TAGGEDOPEN_GRAPHICS
);
212 port
= (UBYTE
*)GAYLE_BASE_1200
;
213 ddata
->gayleirqbase
= (UBYTE
*)GAYLE_IRQ_1200
;
215 // in AGA this area is never custom mirror but lets make sure..
216 if (!custom_check((APTR
)0xdd4000) && (gfx
->ChipRevBits0
& GFXF_AA_ALICE
)) {
217 port
= (UBYTE
*)GAYLE_BASE_4000
;
219 ddata
->gayleirqbase
= (UBYTE
*)GAYLE_IRQ_4000
;
223 CloseLibrary((struct Library
*)gfx
);
225 D(bug("[ATA] Gayle ID=%02x. Possible IDE port=%08x.\n", id
, (ULONG
)port
& ~3));
229 altport
= port
+ 0x1010;
231 port
[atapi_DevSel
* 4] = ATAF_ERROR
;
232 /* If nothing connected, we get back what we wrote, ATAF_ERROR set */
233 status1
= port
[ata_Status
* 4];
234 port
[atapi_DevSel
* 4] = ATAF_DATAREQ
;
235 status2
= port
[ata_Status
* 4];
236 port
[atapi_DevSel
* 4] = 0;
238 D(bug("[ATA] Status=%02x,%02x\n", status1
, status2
));
239 // BUSY and DRDY both active or ERROR/DATAREQ = no drive(s) = do not install driver
240 if ( (((status1
| status2
) & (ATAF_BUSY
| ATAF_DRDY
)) == (ATAF_BUSY
| ATAF_DRDY
))
241 || ((status1
| status2
) & (ATAF_ERROR
| ATAF_DATAREQ
)))
243 D(bug("[ATA] Drives not detected\n"));
246 if (ddata
->doubler
) {
248 /* check if AltControl is both readable and writable
249 * It is either floating or DevHead if IDE doubler is connected.
250 * AltControl = DevHead (R)
251 * Device Control = DevHead (W)
254 altport
[ata_AltControl
* 4] = 0;
255 port
[atapi_DevSel
* 4] = 1;
256 v1
= altport
[ata_AltControl
* 4];
257 altport
[ata_AltControl
* 4] = 2;
258 port
[atapi_DevSel
* 4] = 4;
259 v2
= altport
[ata_AltControl
* 4];
260 altport
[ata_AltControl
* 4] = 0;
261 port
[atapi_DevSel
* 4] = 0;
263 if ((v1
== 0 && v2
== 2) || (v1
== 1 && v2
== 4) || (v1
== 0xff && v2
== 0xff)) {
268 D(bug("[ATA] IDE doubler check (%02X, %02X) = %d\n", v1
, v2
, ddata
->doubler
));
270 /* we may have connected drives */
274 static void callbusirq(struct amiga_driverdata
*ddata
)
276 volatile UBYTE
*port
;
277 UBYTE status1
, status2
;
278 BOOL handled
= FALSE
;
281 handled
|= ata_HandleIRQ(ddata
->bus
[0]->bus
);
283 handled
|= ata_HandleIRQ(ddata
->bus
[1]->bus
);
287 /* Handle spurious interrupt */
288 port
= ddata
->gaylebase
;
289 status1
= port
[ata_Status
* 4];
291 if (ddata
->doubler
== 2)
292 status2
= port
[0x1000 + ata_Status
* 4];
293 bug("[ATA] Spurious interrupt: %02X %02X\n", status1
, status2
);
296 AROS_UFH4(APTR
, IDE_Handler_A1200
,
297 AROS_UFHA(ULONG
, dummy
, A0
),
298 AROS_UFHA(void *, data
, A1
),
299 AROS_UFHA(ULONG
, dummy2
, A5
),
300 AROS_UFHA(struct ExecBase
*, mySysBase
, A6
))
304 struct amiga_driverdata
*ddata
= data
;
305 UBYTE irqmask
= *ddata
->gayleirqbase
;
306 if (irqmask
& GAYLE_IRQ_IDE
) {
307 /* Clear interrupt */
308 *ddata
->gayleirqbase
= 0x7c | (*ddata
->gayleirqbase
& 3);
316 AROS_UFH4(APTR
, IDE_Handler_A4000
,
317 AROS_UFHA(ULONG
, dummy
, A0
),
318 AROS_UFHA(void *, data
, A1
),
319 AROS_UFHA(ULONG
, dummy2
, A5
),
320 AROS_UFHA(struct ExecBase
*, mySysBase
, A6
))
324 struct amiga_driverdata
*ddata
= data
;
325 /* A4000 interrupt clears when register is read */
326 UWORD irqmask
= *((UWORD
*)ddata
->gayleirqbase
);
327 if (irqmask
& (GAYLE_IRQ_IDE
<< 8)) {
335 AROS_UFH4(UBYTE
, IDE_PCMCIA_Handler
,
336 AROS_UFHA(UBYTE
, status
, D0
),
337 AROS_UFHA(void *, data
, A1
),
338 AROS_UFHA(ULONG
, dummy2
, A5
),
339 AROS_UFHA(struct ExecBase
*, mySysBase
, A6
))
343 struct amiga_pcmcia_driverdata
*ddata
= data
;
344 if (ddata
->poststatus
) {
346 ata_HandleIRQ(ddata
->bus
[0]->bus
);
347 } else if (status
& CARD_INTF_IRQ
) {
348 ddata
->poststatus
= TRUE
;
356 static APTR
ata_CreateInterrupt(struct ata_Bus
*bus
, UBYTE num
)
358 struct amiga_busdata
*bdata
= bus
->ab_DriverData
;
359 struct amiga_driverdata
*ddata
= bdata
->ddata
;
360 struct Interrupt
*irq
= &ddata
->ideint
;
361 volatile UBYTE
*gayleintbase
= NULL
;
364 ddata
->bus
[num
] = bdata
;
366 if (ddata
->ideintdone
)
368 ddata
->ideintdone
= TRUE
;
371 irq
->is_Code
= (APTR
)IDE_Handler_A4000
;
373 gayleintbase
= (UBYTE
*)GAYLE_INT_1200
;
374 irq
->is_Code
= (APTR
)IDE_Handler_A1200
;
377 irq
->is_Node
.ln_Pri
= 20;
378 irq
->is_Node
.ln_Type
= NT_INTERRUPT
;
379 irq
->is_Node
.ln_Name
= "AT-IDE";
380 irq
->is_Data
= ddata
;
381 AddIntServer(INTB_PORTS
, irq
);
384 *gayleintbase
|= GAYLE_INT_IDE
;
388 static APTR
ata_CreateInterrupt0(struct ata_Bus
*bus
)
390 return ata_CreateInterrupt(bus
, 0);
392 static APTR
ata_CreateInterrupt1(struct ata_Bus
*bus
)
394 return ata_CreateInterrupt(bus
, 1);
396 static APTR
ata_CreateInterrupt_pcmcia(struct ata_Bus
*bus
)
398 struct amiga_busdata
*bdata
= bus
->ab_DriverData
;
399 struct amiga_pcmcia_driverdata
*ddata
= bdata
->ddata
;
402 ddata
->bus
[0] = bdata
;
408 static const struct ata_BusDriver amiga_driver0
=
415 ata_insw
, /* These are intentionally the same as 16-bit routines */
419 static const struct ata_BusDriver amiga_driver1
=
426 ata_insw
, /* These are intentionally the same as 16-bit routines */
430 static const struct ata_BusDriver amiga_driver_pcmcia
=
439 ata_CreateInterrupt_pcmcia
442 static BOOL
ata_amiga_ide_init(struct ataBase
*LIBBASE
)
444 struct amiga_driverdata
*ddata
;
445 struct amiga_busdata
*bdata
;
447 ddata
= AllocVec(sizeof(struct amiga_driverdata
), MEMF_CLEAR
| MEMF_PUBLIC
);
452 ddata
->gaylebase
= getport(ddata
);
453 bdata
= AllocVec(sizeof(struct amiga_busdata
) * (ddata
->doubler
== 2 ? 2 : 1), MEMF_CLEAR
| MEMF_PUBLIC
);
454 if (bdata
&& ddata
->gaylebase
) {
455 LIBBASE
->ata_NoDMA
= TRUE
;
456 bdata
->ddata
= ddata
;
457 bdata
->port
= ddata
->gaylebase
;
458 ata_RegisterBus(0, ddata
->doubler
? -1 : 0x1010, 2, 0, ARBF_EarlyInterrupt
, &amiga_driver0
, bdata
, LIBBASE
);
459 if (ddata
->doubler
== 2) {
460 D(bug("[ATA] Adding secondary bus\n"));
462 bdata
->ddata
= ddata
;
463 bdata
->port
= ddata
->gaylebase
+ 0x1000;
464 ata_RegisterBus(0, -1, 2, 0, ARBF_EarlyInterrupt
, &amiga_driver1
, bdata
, LIBBASE
);
473 static BOOL
detectcard(struct amiga_pcmcia_driverdata
*ddata
)
476 struct CardHandle
*ch
;
477 UBYTE tuple
[256 + 2];
482 ch
= &ddata
->cardhandle
;
483 CardResource
= ddata
->CardResource
;
485 ddata
->configmask
= 1;
486 ddata
->configbase
= 0x0200;
489 CardMiscControl(ch
, CARD_ENABLEF_DIGAUDIO
| CARD_DISABLEF_WP
);
493 if (!CopyTuple(ch
, tuple
, PCCARD_TPL_DEVICE
, sizeof(tuple
) - 2))
495 if (!DeviceTuple(tuple
, &ddata
->dtd
))
497 if (ddata
->dtd
.dtd_DTtype
!= PCCARD_DTYPE_FUNCSPEC
)
500 if (!CopyTuple(ch
, tuple
, PCCARD_TPL_FUNCID
, sizeof(tuple
) - 2))
502 if (tuple
[2] != PCCARD_FUNC_FIXED
)
505 for (cnt1
= 0; TRUE
; cnt1
++) {
506 if (!CopyTuple(ch
, tuple
, PCCARD_TPL_FUNCE
| (cnt1
<< 16), sizeof(tuple
) - 2))
508 if (tuple
[2] != 1 || tuple
[3] != 1)
516 if (!CopyTuple(ch
, tuple
, PCCARD_TPL_CONFIG
, sizeof(tuple
) - 2))
520 //lastindex = tuple[3] & 0x3f;
522 cnt2
= (tuple
[2] & 3) + 1;
523 for (cnt1
= 0; cnt1
< cnt2
; cnt1
++) {
524 ddata
->configbase
|= (*tp
) << (cnt1
* 8);
527 cnt2
= ((tuple
[2] >> 3) & 15) + 1;
528 for (cnt1
= 0; cnt1
< cnt2
; cnt1
++) {
529 ddata
->configmask
|= (*tp
) << (cnt1
* 8);
537 static void initializecard(struct amiga_pcmcia_driverdata
*ddata
)
539 struct CardHandle
*ch
;
540 UBYTE tuple
[256 + 2];
543 volatile UBYTE
*attrbase
;
545 ch
= &ddata
->cardhandle
;
546 CardResource
= ddata
->CardResource
;
548 D(bug("Detected PCMCIA IDE. ConfigBase=%08x RMask=%08x\n", ddata
->configbase
, ddata
->configmask
);
549 memset(tuple
, 0, sizeof tuple
);
550 if (CopyTuple(ch
, tuple
, PCCARD_TPL_VERS1
, sizeof(tuple
) - 2)) {
553 while (*tp
!= 0xff) {
555 tp
+= strlen(tp
) + 1;
560 CardAccessSpeed(ch
, ddata
->dtd
.dtd_DTspeed
);
561 attrbase
= ddata
->cmm
->cmm_AttributeMemory
;
562 attrbase
[ddata
->configbase
+ 2 * 3] = 0; /* Socket and copy. Must be written first. */
563 attrbase
[ddata
->configbase
+ 2 * 2] = 0x0f; /* Pin replacement. */
564 attrbase
[ddata
->configbase
+ 2 * 1] = 0; /* Configuration and Status. */
565 attrbase
[ddata
->configbase
+ 2 * 0] = 0x41; /* Configure option. Configure as IO linear mode. */
566 /* Now we have IDE registers at iobase */
569 static BOOL
ata_amiga_pcmcia_init(struct ataBase
*LIBBASE
)
571 struct CardResource
*CardResource
;
572 struct amiga_pcmcia_driverdata
*ddata
;
573 struct amiga_busdata
*bdata
;
574 struct CardHandle
*ch
;
576 CardResource
= OpenResource("card.resource");
579 if (CardInterface() != CARD_INTERFACE_AMIGA_0
)
582 ddata
= AllocVec(sizeof(struct amiga_pcmcia_driverdata
) + sizeof(struct amiga_busdata
), MEMF_CLEAR
| MEMF_PUBLIC
);
585 bdata
= (struct amiga_busdata
*)(ddata
+ 1);
587 ch
= &ddata
->cardhandle
;
588 ddata
->CardResource
= CardResource
;
589 ddata
->cmm
= GetCardMap();
591 ch
->cah_CardFlags
= CARDF_IFAVAILABLE
| CARDF_POSTSTATUS
;
592 ch
->cah_CardNode
.ln_Name
= LIBBASE
->ata_Device
.dd_Library
.lib_Node
.ln_Name
;
593 ch
->cah_CardStatus
= &ddata
->statusint
;
594 ch
->cah_CardRemoved
= &ddata
->removalint
;
595 ch
->cah_CardInserted
= &ddata
->insertint
;
596 ch
->cah_CardStatus
->is_Data
= ddata
;
597 ch
->cah_CardStatus
->is_Code
= (void*)IDE_PCMCIA_Handler
;
599 ch
->cah_CardRemoved
->is_Data
= ddata
;
600 ch
->cah_CardRemoved
->is_Code
= (void*)IDE_PCMCIA_Removed
;
601 ch
->cah_CardInserted
->is_Data
= ddata
;
602 ch
->cah_CardInserted
->is_Code
= (void*)IDE_PCMCIA_Inserted
608 if (detectcard(ddata
)) {
609 initializecard(ddata
);
610 bdata
->ddata
= ddata
;
611 bdata
->port
= (UBYTE
*)ddata
->cmm
->cmm_IOMemory
;
612 LIBBASE
->ata_NoDMA
= TRUE
;
613 ata_RegisterBus((IPTR
)ddata
->cmm
->cmm_IOMemory
, (IPTR
)(ddata
->cmm
->cmm_IOMemory
+ 14 - ata_AltControl
), 2, 0, ARBF_EarlyInterrupt
, &amiga_driver_pcmcia
, bdata
, LIBBASE
);
618 ReleaseCard(ch
, CARDF_REMOVEHANDLE
);
626 static int ata_amiga_init(struct ataBase
*LIBBASE
)
628 BOOL r_ide
, r_pcmcia
;
630 r_ide
= ata_amiga_ide_init(LIBBASE
);
631 r_pcmcia
= ata_amiga_pcmcia_init(LIBBASE
);
632 return (r_ide
|| r_pcmcia
) ? 1 : 0;
635 ADD2INITLIB(ata_amiga_init
, 20)