2 Copyright © 1995-2014, The AROS Development Team. All rights reserved.
10 #include <aros/debug.h>
11 #include <exec/types.h>
12 #include <exec/exec.h>
13 #include <proto/exec.h>
14 #include <proto/cardres.h>
15 #include <graphics/gfxbase.h>
16 #include <hardware/custom.h>
17 #include <hardware/intbits.h>
18 #include <resources/card.h>
19 #include <libraries/pccard.h>
20 #include <aros/symbolsets.h>
25 #define GAYLE_BASE_4000 0xdd2022 /* 0xdd2020.W, 0xdd2026.B, 0xdd202a.B ... (argh!) */
26 #define GAYLE_IRQ_4000 0xdd3020
28 #define GAYLE_BASE_1200 0xda0000 /* 0xda0000.W, 0xda0004.B, 0xda0008.B ... */
29 #define GAYLE_IRQ_1200 0xda9000
30 #define GAYLE_INT_1200 0xdaa000
32 #define GAYLE_IRQ_IDE 0x80
33 #define GAYLE_INT_IDE 0x80
35 struct amiga_driverdata
37 struct amiga_busdata
*bus
[2];
38 struct Interrupt ideint
;
46 struct amiga_pcmcia_driverdata
48 struct amiga_busdata
*bus
[1];
49 struct CardHandle cardhandle
;
50 struct Interrupt statusint
;
51 struct Interrupt insertint
;
52 struct Interrupt removalint
;
53 struct CardResource
*CardResource
;
55 ULONG configbase
, configmask
;
56 struct DeviceTData dtd
;
57 struct CardMemoryMap
*cmm
;
69 static void ata_insw(APTR address
, UWORD port
, ULONG count
, void *data
)
71 struct amiga_busdata
*bdata
= data
;
72 volatile ULONG
*addr
= (ULONG
*)(bdata
->port
+ (port
& ~3));
80 static void ata_outsw(APTR address
, UWORD port
, ULONG count
, APTR data
)
82 struct amiga_busdata
*bdata
= data
;
83 volatile ULONG
*addr
= (ULONG
*)(bdata
->port
+ (port
& ~3));
91 static void ata_pcmcia_insw(APTR address
, UWORD port
, ULONG count
, void *data
)
93 struct amiga_busdata
*bdata
= data
;
94 volatile UWORD
*addr
= (UWORD
*)(bdata
->port
+ port
);
102 static void ata_pcmcia_outsw(APTR address
, UWORD port
, ULONG count
, APTR data
)
104 struct amiga_busdata
*bdata
= data
;
105 volatile UWORD
*addr
= (UWORD
*)(bdata
->port
+ port
);
106 UWORD
*dst
= address
;
114 static void ata_outl(ULONG val
, UWORD offset
, IPTR port
, APTR data
)
118 static void ata_out(UBYTE val
, UWORD offset
, IPTR port
, APTR data
)
120 struct amiga_busdata
*bdata
= data
;
121 volatile UBYTE
*addr
;
124 bug("ata_out(%x,%x)=%x:%x\n", offset
, port
, (UBYTE
*)(bdata
->port
+ port
) + offset
* 4, val
);
126 /* IDE doubler hides Alternate Status/Device Control register */
128 if (bdata
->reset
== 0 && (val
& 4)) {
129 ata_out(0x40, ata_DevHead
, 0, bdata
);
130 D(bug("[ATA] Emulating reset\n"));
131 ata_out(ATA_EXECUTE_DIAG
, ata_Command
, 0, bdata
);
133 bdata
->reset
= (val
& 4) != 0;
136 addr
= (UBYTE
*)(bdata
->port
+ port
);
137 addr
[offset
* 4] = val
;
140 static UBYTE
ata_in(UWORD offset
, IPTR port
, APTR data
)
142 struct amiga_busdata
*bdata
= data
;
143 volatile UBYTE
*addr
;
147 bug("ata_in(%x,%x)=%x\n", offset
, port
, (UBYTE
*)(bdata
->port
+ port
) + offset
* 4);
153 addr
= (UBYTE
*)(bdata
->port
+ port
);
154 v
= addr
[offset
* 4];
161 static void gayledebug(void)
164 volatile UBYTE
*g
= (UBYTE
*)0xa00200;
165 volatile UBYTE
*gstatus
= (UBYTE
*)0xda8000;
166 volatile UBYTE
*gintreq
= (UBYTE
*)0xda9000;
167 volatile UBYTE
*gintena
= (UBYTE
*)0xdaa000;
168 volatile UBYTE
*gconfig
= (UBYTE
*)0xdab000;
169 bug ("%02x %02x %02x %02x %02x\n",
170 *g
, *gstatus
, *gintreq
, *gintena
, *gconfig
);
174 static void ata_pcmcia_out(UBYTE val
, UWORD offset
, IPTR port
, APTR data
)
176 volatile UBYTE
*addr
;
180 /* Error / Feature not available when using Amiga PCMCIA */
182 } else if (offset
& 1) {
188 bug("pcmcia_ata_out(%x,%x)=%p=%x\n", offset
, port
, &addr
[offset
], val
);
192 static UBYTE
ata_pcmcia_in(UWORD offset
, IPTR port
, APTR data
)
194 volatile UBYTE
*addr
;
201 /* Error / Feature not available when using Amiga PCMCIA */
203 } else if (offset
& 1) {
209 bug("pcmcia_ata_in(%x,%x)=%p=%x (%02X)\n", offset
, port
, &addr
[offset
], v
);
218 static BOOL
custom_check(APTR addr
)
220 volatile struct Custom
*custom
= (struct Custom
*)0xdff000;
221 volatile struct Custom
*maybe_custom
= (struct Custom
*)addr
;
223 BOOL iscustom
= TRUE
;
225 intena
= custom
->intenar
;
226 custom
->intena
= 0x7fff;
227 custom
->intena
= 0xc000;
228 maybe_custom
->intena
= 0x7fff;
229 if (custom
->intenar
== 0x4000) {
230 maybe_custom
->intena
= 0x7fff;
231 if (custom
->intenar
== 0x4000)
234 custom
->intena
= 0x7fff;
235 custom
->intena
= intena
| 0x8000;
239 static UBYTE
*getport(struct amiga_driverdata
*ddata
)
241 UBYTE id
, status1
, status2
;
242 volatile UBYTE
*port
, *altport
;
246 gfx
= (struct GfxBase
*)TaggedOpenLibrary(TAGGEDOPEN_GRAPHICS
);
250 port
= (UBYTE
*)GAYLE_BASE_1200
;
251 ddata
->gayleirqbase
= (UBYTE
*)GAYLE_IRQ_1200
;
253 // in AGA this area is never custom mirror but lets make sure..
254 if (!custom_check((APTR
)0xdd4000) && (gfx
->ChipRevBits0
& GFXF_AA_ALICE
)) {
255 port
= (UBYTE
*)GAYLE_BASE_4000
;
257 ddata
->gayleirqbase
= (UBYTE
*)GAYLE_IRQ_4000
;
261 CloseLibrary((struct Library
*)gfx
);
263 D(bug("[ATA] Gayle ID=%02x. Possible IDE port=%08x.\n", id
, (ULONG
)port
& ~3));
267 altport
= port
+ 0x1010;
269 port
[ata_DevHead
* 4] = ATAF_ERROR
;
270 /* If nothing connected, we get back what we wrote, ATAF_ERROR set */
271 status1
= port
[ata_Status
* 4];
272 port
[ata_DevHead
* 4] = ATAF_DATAREQ
;
273 status2
= port
[ata_Status
* 4];
274 port
[ata_DevHead
* 4] = 0;
276 D(bug("[ATA] Status=%02x,%02x\n", status1
, status2
));
277 // BUSY and DRDY both active or ERROR/DATAREQ = no drive(s) = do not install driver
278 if ( (((status1
| status2
) & (ATAF_BUSY
| ATAF_DRDY
)) == (ATAF_BUSY
| ATAF_DRDY
))
279 || ((status1
| status2
) & (ATAF_ERROR
| ATAF_DATAREQ
)))
281 D(bug("[ATA] Drives not detected\n"));
284 if (ddata
->doubler
) {
286 /* check if AltControl is both readable and writable
287 * It is either floating or DevHead if IDE doubler is connected.
288 * AltControl = DevHead (R)
289 * Device Control = DevHead (W)
292 altport
[ata_AltControl
* 4] = 0;
293 port
[ata_DevHead
* 4] = 1;
294 v1
= altport
[ata_AltControl
* 4];
295 altport
[ata_AltControl
* 4] = 2;
296 port
[ata_DevHead
* 4] = 4;
297 v2
= altport
[ata_AltControl
* 4];
298 altport
[ata_AltControl
* 4] = 0;
299 port
[ata_DevHead
* 4] = 0;
301 if ((v1
== 0 && v2
== 2) || (v1
== 1 && v2
== 4) || (v1
== 0xff && v2
== 0xff)) {
306 D(bug("[ATA] IDE doubler check (%02X, %02X) = %d\n", v1
, v2
, ddata
->doubler
));
308 /* we may have connected drives */
311 static void ackint(struct amiga_driverdata
*ddata
)
315 /* Clear A600/A1200 IDE interrupt. (Stupid Gayle hardware) */
316 *ddata
->gayleirqbase
= 0x7c | (*ddata
->gayleirqbase
& 3);
318 static void ata_AckInterrupt(struct ata_Bus
*bus
)
320 struct amiga_busdata
*bdata
= bus
->ab_DriverData
;
321 struct amiga_driverdata
*ddata
= bdata
->ddata
;
325 static void callbusirq(struct amiga_driverdata
*ddata
)
327 volatile UBYTE
*port
;
328 UBYTE status1
, status2
;
329 BOOL handled
= FALSE
;
332 handled
|= ata_HandleIRQ(ddata
->bus
[0]->bus
);
334 handled
|= ata_HandleIRQ(ddata
->bus
[1]->bus
);
338 /* Handle spurious interrupt */
339 port
= ddata
->gaylebase
;
340 status1
= port
[ata_Status
* 4];
342 if (ddata
->doubler
== 2)
343 status2
= port
[0x1000 + ata_Status
* 4];
345 bug("[ATA] Spurious interrupt: %02X %02X\n", status1
, status2
);
348 AROS_INTH1(IDE_Handler_A1200
, struct amiga_driverdata
*, ddata
)
352 UBYTE irqmask
= *ddata
->gayleirqbase
;
353 if (irqmask
& GAYLE_IRQ_IDE
) {
361 AROS_INTH1(IDE_Handler_A4000
, struct amiga_driverdata
*, ddata
)
365 /* A4000 interrupt clears when register is read */
366 UWORD irqmask
= *((UWORD
*)ddata
->gayleirqbase
);
367 if (irqmask
& (GAYLE_IRQ_IDE
<< 8)) {
375 static AROS_CARDH(IDE_PCMCIA_Handler
, void *, data
, status
)
379 struct amiga_pcmcia_driverdata
*ddata
= data
;
382 ata_HandleIRQ(ddata
->bus
[0]->bus
);
389 static BOOL
ata_CreateInterrupt(struct ata_Bus
*bus
, UBYTE num
)
391 struct amiga_busdata
*bdata
= bus
->ab_DriverData
;
392 struct amiga_driverdata
*ddata
= bdata
->ddata
;
393 struct Interrupt
*irq
= &ddata
->ideint
;
394 volatile UBYTE
*gayleintbase
= NULL
;
397 ddata
->bus
[num
] = bdata
;
399 if (ddata
->ideintdone
)
401 ddata
->ideintdone
= TRUE
;
404 irq
->is_Code
= (APTR
)IDE_Handler_A4000
;
406 gayleintbase
= (UBYTE
*)GAYLE_INT_1200
;
407 irq
->is_Code
= (APTR
)IDE_Handler_A1200
;
410 irq
->is_Node
.ln_Pri
= 20;
411 irq
->is_Node
.ln_Type
= NT_INTERRUPT
;
412 irq
->is_Node
.ln_Name
= "AT-IDE";
413 irq
->is_Data
= ddata
;
414 AddIntServer(INTB_PORTS
, irq
);
417 *gayleintbase
|= GAYLE_INT_IDE
;
421 static BOOL
ata_CreateInterrupt0(struct ata_Bus
*bus
)
423 return ata_CreateInterrupt(bus
, 0);
425 static BOOL
ata_CreateInterrupt1(struct ata_Bus
*bus
)
427 return ata_CreateInterrupt(bus
, 1);
429 static BOOL
ata_CreateInterrupt_pcmcia(struct ata_Bus
*bus
)
431 struct amiga_busdata
*bdata
= bus
->ab_DriverData
;
432 struct amiga_pcmcia_driverdata
*ddata
= bdata
->ddata
;
435 ddata
->bus
[0] = bdata
;
441 static const struct ata_BusDriver amiga_driver0
=
448 ata_insw
, /* These are intentionally the same as 16-bit routines */
450 ata_CreateInterrupt0
,
453 static const struct ata_BusDriver amiga_driver1
=
460 ata_insw
, /* These are intentionally the same as 16-bit routines */
462 ata_CreateInterrupt1
,
465 static const struct ata_BusDriver amiga_driver_pcmcia
=
474 ata_CreateInterrupt_pcmcia
,
478 static BOOL
ata_amiga_ide_init(struct ataBase
*LIBBASE
)
480 struct amiga_driverdata
*ddata
;
481 struct amiga_busdata
*bdata
;
483 ddata
= AllocVec(sizeof(struct amiga_driverdata
), MEMF_CLEAR
| MEMF_PUBLIC
);
488 ddata
->gaylebase
= getport(ddata
);
489 bdata
= AllocVec(sizeof(struct amiga_busdata
) * (ddata
->doubler
== 2 ? 2 : 1), MEMF_CLEAR
| MEMF_PUBLIC
);
490 if (bdata
&& ddata
->gaylebase
) {
491 LIBBASE
->ata_NoDMA
= TRUE
;
492 bdata
->ddata
= ddata
;
493 bdata
->port
= ddata
->gaylebase
;
494 ata_RegisterBus(0, ddata
->doubler
? -1 : 0x1010, 2, 0, ARBF_EarlyInterrupt
, &amiga_driver0
, bdata
, LIBBASE
);
495 if (ddata
->doubler
== 2) {
496 D(bug("[ATA] Adding secondary bus\n"));
498 bdata
->ddata
= ddata
;
499 bdata
->port
= ddata
->gaylebase
+ 0x1000;
500 ata_RegisterBus(0, -1, 2, 0, ARBF_EarlyInterrupt
, &amiga_driver1
, bdata
, LIBBASE
);
509 static BOOL
detectcard(struct amiga_pcmcia_driverdata
*ddata
)
512 struct CardHandle
*ch
;
513 UBYTE tuple
[256 + 2];
518 ch
= &ddata
->cardhandle
;
519 CardResource
= ddata
->CardResource
;
522 /* Some cards refuse to work if CARD_ENABLEF_DIGAUDIO is enabled at this point */
523 CardMiscControl(ch
, CARD_DISABLEF_WP
);
527 if (!CopyTuple(ch
, tuple
, PCCARD_TPL_DEVICE
, sizeof(tuple
) - 2))
529 if (!DeviceTuple(tuple
, &ddata
->dtd
))
531 if (ddata
->dtd
.dtd_DTtype
!= PCCARD_DTYPE_FUNCSPEC
)
534 if (!CopyTuple(ch
, tuple
, PCCARD_TPL_FUNCID
, sizeof(tuple
) - 2))
536 if (tuple
[2] != PCCARD_FUNC_FIXED
)
539 for (cnt1
= 0; TRUE
; cnt1
++) {
540 if (!CopyTuple(ch
, tuple
, PCCARD_TPL_FUNCE
| (cnt1
<< 16), sizeof(tuple
) - 2))
542 if (tuple
[2] != 1 || tuple
[3] != 1)
550 if (!CopyTuple(ch
, tuple
, PCCARD_TPL_CONFIG
, sizeof(tuple
) - 2))
554 //lastindex = tuple[3] & 0x3f;
556 cnt2
= (tuple
[2] & 3) + 1;
557 for (cnt1
= 0; cnt1
< cnt2
; cnt1
++) {
558 ddata
->configbase
|= (*tp
) << (cnt1
* 8);
561 cnt2
= ((tuple
[2] >> 3) & 15) + 1;
562 for (cnt1
= 0; cnt1
< cnt2
&& cnt1
< 4; cnt1
++) {
563 ddata
->configmask
|= (*tp
) << (cnt1
* 8);
571 static void pcmcia_config_write(struct amiga_pcmcia_driverdata
*ddata
, UBYTE reg
, UBYTE data
)
573 volatile UBYTE
*attrbase
= ddata
->cmm
->cmm_AttributeMemory
;
574 volatile UBYTE
*gstatus
= (UBYTE
*)0xda8000;
576 struct CardHandle
*ch
;
578 CardResource
= ddata
->CardResource
;
579 ch
= &ddata
->cardhandle
;
580 if (!(ddata
->configmask
& (1 << reg
)))
582 bug("%02x -> %p\n", data
, &attrbase
[ddata
->configbase
+ 2 * reg
]);
587 UBYTE status
= *gstatus
;
588 if (!(status
& CARD_STATUSF_BSY
) || !(status
& CARD_STATUSF_CCDET
))
591 CardMiscControl(ch
, CARD_DISABLEF_WP
);
592 attrbase
[ddata
->configbase
+ 2 * reg
] = data
;
593 CardMiscControl(ch
, 0);
595 UBYTE status
= *gstatus
;
596 if (!(status
& CARD_STATUSF_BSY
) || !(status
& CARD_STATUSF_CCDET
))
599 data
= attrbase
[ddata
->configbase
+ 2 * reg
];
600 bug("=%02X\n", data
);
606 static void initializecard(struct ataBase
*LIBBASE
, struct amiga_pcmcia_driverdata
*ddata
)
608 struct CardHandle
*ch
;
609 UBYTE tuple
[256 + 2];
612 struct IORequest
*req
;
614 ch
= &ddata
->cardhandle
;
615 CardResource
= ddata
->CardResource
;
617 D(bug("Detected PCMCIA IDE. ConfigBase=%08x RMask=%08x\n", ddata
->configbase
, ddata
->configmask
);
618 memset(tuple
, 0, sizeof tuple
);
619 if (CopyTuple(ch
, tuple
, PCCARD_TPL_VERS1
, sizeof(tuple
) - 2)) {
622 while (*tp
!= 0xff) {
624 tp
+= strlen(tp
) + 1;
629 req
= ata_OpenTimer(LIBBASE
);
630 CardAccessSpeed(ch
, ddata
->dtd
.dtd_DTspeed
);
632 pcmcia_config_write(ddata
, 3, 0); /* Socket and copy. Must be written first. */
633 pcmcia_config_write(ddata
, 0, 0x80);
635 ata_WaitTO(req
, 0, 20000, 0);
636 pcmcia_config_write(ddata
, 0, 0x00);
638 ata_WaitTO(req
, 0, 20000, 0);
640 UBYTE status
= ReadCardStatus();
641 if (!(status
& CARD_STATUSF_BSY
) || !(status
& CARD_STATUSF_CCDET
))
646 pcmcia_config_write(ddata
, 3, 0); /* Socket and copy. Must be written first. */
647 pcmcia_config_write(ddata
, 2, 0); /* Pin replacement. */
648 pcmcia_config_write(ddata
, 1, 0); /* Configuration and Status. */
649 /* NOTE: We must use index #2 because some buggy cards won't work properly if using config index #1 */
650 pcmcia_config_write(ddata
, 0, 0x42); /* Configure option. Level interrupt (0x40) + config index (2). */
653 ata_WaitTO(req
, 0, 50000, 0);
654 pcmcia_config_write(ddata
, 1, 0); /* Configuration and Status. */
655 CardMiscControl(ch
, CARD_ENABLEF_DIGAUDIO
| CARD_DISABLEF_WP
);
657 /* Now we have IDE registers at iobase + 0x1f0 to 0x1f7 and 0x3f6 to 0x3f7 */
658 /* CARD_ENABLEF_DIGAUDIO must be enabled now */
661 static BOOL
ata_amiga_pcmcia_init(struct ataBase
*LIBBASE
)
663 struct CardResource
*CardResource
;
664 struct amiga_pcmcia_driverdata
*ddata
;
665 struct amiga_busdata
*bdata
;
666 struct CardHandle
*ch
;
668 CardResource
= OpenResource("card.resource");
671 if (CardInterface() != CARD_INTERFACE_AMIGA_0
)
674 ddata
= AllocVec(sizeof(struct amiga_pcmcia_driverdata
) + sizeof(struct amiga_busdata
), MEMF_CLEAR
| MEMF_PUBLIC
);
677 bdata
= (struct amiga_busdata
*)(ddata
+ 1);
679 ch
= &ddata
->cardhandle
;
680 ddata
->CardResource
= CardResource
;
681 ddata
->cmm
= GetCardMap();
683 ch
->cah_CardFlags
= CARDF_IFAVAILABLE
| CARDF_POSTSTATUS
;
684 ch
->cah_CardNode
.ln_Name
= LIBBASE
->ata_Device
.dd_Library
.lib_Node
.ln_Name
;
685 ch
->cah_CardStatus
= &ddata
->statusint
;
686 ch
->cah_CardRemoved
= &ddata
->removalint
;
687 ch
->cah_CardInserted
= &ddata
->insertint
;
688 ch
->cah_CardStatus
->is_Data
= ddata
;
689 ch
->cah_CardStatus
->is_Code
= (VOID_FUNC
)IDE_PCMCIA_Handler
;
691 ch
->cah_CardRemoved
->is_Data
= ddata
;
692 ch
->cah_CardRemoved
->is_Code
= (void*)IDE_PCMCIA_Removed
;
693 ch
->cah_CardInserted
->is_Data
= ddata
;
694 ch
->cah_CardInserted
->is_Code
= (void*)IDE_PCMCIA_Inserted
700 if (detectcard(ddata
)) {
701 initializecard(LIBBASE
, ddata
);
702 bdata
->ddata
= ddata
;
703 bdata
->port
= (UBYTE
*)ddata
->cmm
->cmm_IOMemory
;
705 LIBBASE
->ata_NoDMA
= TRUE
;
706 ata_RegisterBus((IPTR
)ddata
->cmm
->cmm_IOMemory
+ 0x1f0, (IPTR
)(ddata
->cmm
->cmm_IOMemory
+ 0x3f6 - ata_AltControl
), 2, 0, ARBF_EarlyInterrupt
, &amiga_driver_pcmcia
, bdata
, LIBBASE
);
711 ReleaseCard(ch
, CARDF_REMOVEHANDLE
);
719 static int ata_amiga_init(struct ataBase
*LIBBASE
)
721 BOOL r_ide
, r_pcmcia
;
723 r_ide
= ata_amiga_ide_init(LIBBASE
);
724 r_pcmcia
= ata_amiga_pcmcia_init(LIBBASE
);
725 return (r_ide
|| r_pcmcia
) ? 1 : 0;
728 ADD2INITLIB(ata_amiga_init
, 20)