2 # _____ ___ ____ ___ ____
3 # ____| | ____| | | |____|
4 # | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5 #-----------------------------------------------------------------------
6 # Copyright (c) 2003 Marcus R. Brown <mrbrown@0xd6.org>
7 # Licenced under Academic Free License version 2.0
8 # Review ps2sdk README & LICENSE files for further details.
10 # $Id: ps2dev9.c 1454 2007-11-04 23:19:57Z roman_ps2dev $
22 #include <speedregs.h>
28 #include "ioman_add.h"
31 extern int atad_inited
;
35 #define M_PRINTF(format, args...) \
36 printf(MODNAME ": " format, ## args)
38 #define M_PRINTF(format, args...) \
43 #define BANNER "\nDEV9 device driver v%s - Copyright (c) 2003 Marcus R. Brown\n\n"
47 /* SSBUS registers. */
48 #define SSBUS_R_1418 0xbf801418
49 #define SSBUS_R_141c 0xbf80141c
50 #define SSBUS_R_1420 0xbf801420
52 static int dev9type
= -1; /* 0 for PCMCIA, 1 for expansion bay */
54 static int using_aif
= 0; /* 1 if using AIF on a T10K */
57 static void (*p_dev9_intr_cb
)(int flag
) = NULL
;
58 static int dma_lock_sem
= -1; /* used to arbitrate DMA */
59 static int dma_complete_sem
= -1; /* signalled on DMA transfer completion. */
62 static int pcic_cardtype
; /* Translated value of bits 0-1 of 0xbf801462 */
63 static int pcic_voltage
; /* Translated value of bits 2-3 of 0xbf801462 */
66 static s16 eeprom_data
[5]; /* 2-byte EEPROM status (0/-1 = invalid, 1 = valid),
68 2-byte MAC address checksum. */
70 /* Each driver can register callbacks that correspond to each bit of the
71 SMAP interrupt status register (0xbx000028). */
72 static dev9_intr_cb_t dev9_intr_cbs
[16];
74 static dev9_shutdown_cb_t dev9_shutdown_cbs
[16];
76 static dev9_dma_cb_t dev9_predma_cbs
[4], dev9_postdma_cbs
[4];
78 static int dev9_intr_dispatch(int flag
);
79 static int dev9_dma_intr(void *arg
);
81 static void smap_set_stat(int stat
);
82 static int read_eeprom_data(void);
84 static int smap_device_probe(void);
85 static int smap_device_reset(void);
86 static int smap_subsys_init(void);
87 static int smap_device_init(void);
90 static void pcmcia_set_stat(int stat
);
91 static int pcic_ssbus_mode(int voltage
);
92 static int pcmcia_device_probe(void);
93 static int pcmcia_device_reset(void);
94 static int card_find_manfid(u32 manfid
);
95 static int pcmcia_init(void);
97 static void expbay_set_stat(int stat
);
98 static int expbay_device_probe(void);
99 static int expbay_device_reset(void);
100 static int expbay_init(void);
103 int dev9x_dummy() { return 0; }
104 int dev9x_devctl(iop_file_t
*f
, const char *name
, int cmd
, void *args
, int arglen
, void *buf
, int buflen
)
112 /* driver ops func tab */
113 void *dev9x_ops
[27] = {
143 /* driver descriptor */
144 static iop_ext_device_t dev9x_dev
= {
146 IOP_DT_FS
| 0x10000000, /* EXT FS */
149 (struct _iop_ext_device_ops
*)&dev9x_ops
158 M_PRINTF(BANNER
, VERSION
);
160 for (idx
= 0; idx
< 16; idx
++)
161 dev9_shutdown_cbs
[idx
] = NULL
;
163 dev9hw
= DEV9_REG(DEV9_R_REV
) & 0xf0;
164 if (dev9hw
== 0x20) { /* CXD9566 (PCMCIA) */
171 } else if (dev9hw
== 0x30) { /* CXD9611 (Expansion Bay) */
184 AddDrv((iop_device_t
*)&dev9x_dev
);
190 void dev9RegisterIntrCb(int intr
, dev9_intr_cb_t cb
)
198 dev9_intr_cbs
[intr
] = cb
;
202 void dev9RegisterPreDmaCb(int ctrl
, dev9_dma_cb_t cb
){
203 dev9_predma_cbs
[ctrl
] = cb
;
207 void dev9RegisterPostDmaCb(int ctrl
, dev9_dma_cb_t cb
){
208 dev9_postdma_cbs
[ctrl
] = cb
;
211 /* flag is 1 if a card (pcmcia) was removed or added */
212 static int dev9_intr_dispatch(int flag
)
218 for (i
= 0; i
< 16; i
++)
219 if (dev9_intr_cbs
[i
] != NULL
)
220 dev9_intr_cbs
[i
](flag
);
223 while (SPD_REG16(SPD_R_INTR_STAT
) & SPD_REG16(SPD_R_INTR_MASK
)) {
224 for (i
= 0; i
< 16; i
++) {
225 if (dev9_intr_cbs
[i
] != NULL
) {
226 bit
= (SPD_REG16(SPD_R_INTR_STAT
) &
227 SPD_REG16(SPD_R_INTR_MASK
)) >> i
;
229 dev9_intr_cbs
[i
](flag
);
237 /* Signal the end of a DMA transfer. */
238 static int dev9_dma_intr(void *arg
)
240 int sem
= *(int *)arg
;
246 static void smap_set_stat(int stat
)
250 pcmcia_set_stat(stat
);
254 else if (dev9type
== 1)
256 expbay_set_stat(stat
);
262 static int smap_device_probe()
266 return pcmcia_device_probe();
270 else if (dev9type
== 1)
272 return expbay_device_probe();
279 static int smap_device_reset()
283 return pcmcia_device_reset();
287 else if (dev9type
== 1)
289 return expbay_device_reset();
302 for (idx
= 0; idx
< 16; idx
++)
303 if (dev9_shutdown_cbs
[idx
])
304 dev9_shutdown_cbs
[idx
]();
306 if (dev9type
== 0) { /* PCMCIA */
308 DEV9_REG(DEV9_R_POWER
) = 0;
309 DEV9_REG(DEV9_R_1474
) = 0;
311 } else if (dev9type
== 1) {
313 DEV9_REG(DEV9_R_1466
) = 1;
314 DEV9_REG(DEV9_R_1464
) = 0;
315 DEV9_REG(DEV9_R_1460
) = DEV9_REG(DEV9_R_1464
);
316 DEV9_REG(DEV9_R_POWER
) = DEV9_REG(DEV9_R_POWER
) & ~4;
317 DEV9_REG(DEV9_R_POWER
) = DEV9_REG(DEV9_R_POWER
) & ~1;
320 DelayThread(1000000);
324 void dev9IntrEnable(int mask
)
329 CpuSuspendIntr(&flags
);
330 SPD_REG16(SPD_R_INTR_MASK
) = SPD_REG16(SPD_R_INTR_MASK
) | mask
;
331 CpuResumeIntr(flags
);
335 void dev9IntrDisable(int mask
)
340 CpuSuspendIntr(&flags
);
341 SPD_REG16(SPD_R_INTR_MASK
) = SPD_REG16(SPD_R_INTR_MASK
) & ~mask
;
342 CpuResumeIntr(flags
);
346 /* This differs from the "official" dev9 in that it puts the calling thread to
347 sleep when doing the actual DMA transfer. I'm not sure why SCEI didn't do
348 this in dev9.irx, when they do it in PS2Linux's dmarelay.irx. Anyway,
349 since this no longer blocks, it should speed up anything else on the IOP
350 when HDD or SMAP are doing DMA. */
351 int dev9DmaTransfer(int ctrl
, void *buf
, int bcr
, int dir
)
354 volatile iop_dmac_chan_t
*dev9_chan
= (iop_dmac_chan_t
*)DEV9_DMAC_BASE
;
355 int stat
, res
= 0, dmactrl
;
359 case 1: dmactrl
= ctrl
;
364 if (dev9_predma_cbs
[ctrl
] == NULL
) return -1;
365 if (dev9_postdma_cbs
[ctrl
] == NULL
) return -1;
366 dmactrl
= (4 << ctrl
);
373 if ((res
= WaitSema(dma_lock_sem
)) < 0)
376 if (SPD_REG16(SPD_R_REV_1
) < 17)
377 dmactrl
= (dmactrl
& 0x03) | 0x04;
379 dmactrl
= (dmactrl
& 0x01) | 0x06;
380 SPD_REG16(SPD_R_DMA_CTRL
) = dmactrl
;
382 if (dev9_predma_cbs
[ctrl
])
383 dev9_predma_cbs
[ctrl
](bcr
, dir
);
385 EnableIntr(IOP_IRQ_DMA_DEV9
);
386 dev9_chan
->madr
= (u32
)buf
;
387 dev9_chan
->bcr
= bcr
;
388 dev9_chan
->chcr
= DMAC_CHCR_30
|DMAC_CHCR_TR
|DMAC_CHCR_CO
|
389 (dir
& DMAC_CHCR_DR
);
391 /* Wait for DMA to complete. */
392 if ((res
= WaitSema(dma_complete_sem
)) >= 0)
395 DisableIntr(IOP_IRQ_DMA_DEV9
, &stat
);
397 if (dev9_postdma_cbs
[ctrl
])
398 dev9_postdma_cbs
[ctrl
](bcr
, dir
);
400 SignalSema(dma_lock_sem
);
404 static int read_eeprom_data()
410 if (eeprom_data
[0] < 0)
413 SPD_REG8(SPD_R_PIO_DIR
) = 0xe1;
415 SPD_REG8(SPD_R_PIO_DATA
) = 0x80;
418 for (i
= 0; i
< 2; i
++) {
419 SPD_REG8(SPD_R_PIO_DATA
) = 0xa0;
421 SPD_REG8(SPD_R_PIO_DATA
) = 0xe0;
424 for (i
= 0; i
< 7; i
++) {
425 SPD_REG8(SPD_R_PIO_DATA
) = 0x80;
427 SPD_REG8(SPD_R_PIO_DATA
) = 0xc0;
430 SPD_REG8(SPD_R_PIO_DATA
) = 0xc0;
433 val
= SPD_REG8(SPD_R_PIO_DATA
);
435 if (val
& 0x10) { /* Error. */
436 SPD_REG8(SPD_R_PIO_DATA
) = 0;
443 SPD_REG8(SPD_R_PIO_DATA
) = 0x80;
446 /* Read the MAC address and checksum from the EEPROM. */
447 for (i
= 0; i
< 4; i
++) {
448 eeprom_data
[i
+1] = 0;
450 for (j
= 15; j
>= 0; j
--) {
451 SPD_REG8(SPD_R_PIO_DATA
) = 0xc0;
453 val
= SPD_REG8(SPD_R_PIO_DATA
);
455 eeprom_data
[i
+1] |= (1<<j
);
456 SPD_REG8(SPD_R_PIO_DATA
) = 0x80;
461 SPD_REG8(SPD_R_PIO_DATA
) = 0;
463 eeprom_data
[0] = 1; /* The EEPROM data is valid. */
467 SPD_REG8(SPD_R_PIO_DIR
) = 1;
472 int dev9GetEEPROM(u16
*buf
)
478 if (eeprom_data
[0] < 0)
481 /* We only return the MAC address and checksum. */
482 for (i
= 0; i
< 4; i
++)
483 buf
[i
] = eeprom_data
[i
+1];
489 void dev9LEDCtl(int ctl
)
492 SPD_REG8(SPD_R_PIO_DATA
) = (ctl
== 0);
496 int dev9RegisterShutdownCb(int idx
, dev9_shutdown_cb_t cb
){
499 dev9_shutdown_cbs
[idx
] = cb
;
505 static int smap_subsys_init(void)
509 if ((dma_lock_sem
= CreateMutex(IOP_MUTEX_UNLOCKED
)) < 0)
511 if ((dma_complete_sem
= CreateMutex(IOP_MUTEX_LOCKED
)) < 0)
514 DisableIntr(IOP_IRQ_DMA_DEV9
, &stat
);
515 CpuSuspendIntr(&flags
);
516 /* Enable the DEV9 DMAC channel. */
517 ReleaseIntrHandler(IOP_IRQ_DMA_DEV9
);
518 RegisterIntrHandler(IOP_IRQ_DMA_DEV9
, 1, dev9_dma_intr
, &dma_complete_sem
);
519 dmac_set_dpcr2(dmac_get_dpcr2() | 0x80);
520 CpuResumeIntr(flags
);
522 /* Not quite sure what this enables yet. */
523 smap_set_stat(0x103);
525 /* Disable all device interrupts. */
526 dev9IntrDisable(0xffff);
528 p_dev9_intr_cb
= (void *)dev9_intr_dispatch
;
530 /* Reset the SMAP interrupt callback table. */
531 for (i
= 0; i
< 16; i
++)
532 dev9_intr_cbs
[i
] = NULL
;
534 for (i
= 0; i
< 4; i
++){
535 dev9_predma_cbs
[i
] = NULL
;
536 dev9_postdma_cbs
[i
] = NULL
;
539 /* Read in the MAC address. */
541 /* Turn the LED off. */
546 static int smap_device_init(void)
550 const char *spdnames
[] = { "(unknown)", "TS", "ES1", "ES2" };
557 if (smap_device_probe() < 0) {
558 M_PRINTF("PC card or expansion device isn't connected.\n");
567 /* Locate the SPEED Lite chip and get the bus ready for the
570 if ((res
= card_find_manfid(0xf15300)))
571 M_PRINTF("SPEED Lite not found.\n");
573 if (!res
&& (res
= pcic_ssbus_mode(5)))
574 M_PRINTF("Unable to change SSBUS mode.\n");
584 /* Print out the SPEED chip revision. */
585 spdrev
= SPD_REG16(SPD_R_REV_1
);
586 idx
= (spdrev
& 0xffff) - 14;
589 else if (spdrev
< 9 || (spdrev
< 16 || spdrev
> 17))
590 idx
= 0; /* Unknown revision */
592 M_PRINTF("SPEED chip '%s', revision 0x%0X\n", spdnames
[idx
], spdrev
);
599 static int pcic_get_cardtype()
602 u16 val
= DEV9_REG(DEV9_R_1462
) & 0x03;
605 return 1; /* 16-bit */
608 return 2; /* CardBus */
612 static int pcic_get_voltage()
615 u16 val
= DEV9_REG(DEV9_R_1462
) & 0x0c;
619 if (val
== 0 || val
== 0x08)
626 static int pcic_power(int voltage
, int flag
)
630 u16 val
= (voltage
== 1) << 2;
632 DEV9_REG(DEV9_R_POWER
) = 0;
639 DEV9_REG(DEV9_R_POWER
) = val
;
642 if (DEV9_REG(DEV9_R_1462
) & 0x100)
645 DEV9_REG(DEV9_R_POWER
) = 0;
646 DEV9_REG(DEV9_R_1464
) = cstc1
= DEV9_REG(DEV9_R_1464
);
647 DEV9_REG(DEV9_R_1466
) = cstc2
= DEV9_REG(DEV9_R_1466
);
651 static void pcmcia_set_stat(int stat
)
654 u16 val
= stat
& 0x01;
674 DEV9_REG(DEV9_R_1476
) = val
& 0xff;
677 static int pcic_ssbus_mode(int voltage
)
681 u16 stat
= DEV9_REG(DEV9_R_1474
) & 7;
683 if (voltage
!= 3 && voltage
!= 5)
686 DEV9_REG(DEV9_R_1460
) = 2;
691 DEV9_REG(DEV9_R_1474
) = 1;
692 DEV9_REG(DEV9_R_1460
) = 1;
694 DEV9_REG(DEV9_R_1474
) = voltage
;
695 } else if (voltage
== 5) {
696 DEV9_REG(DEV9_R_1474
) = voltage
;
697 DEV9_REG(DEV9_R_1460
) = 1;
699 DEV9_REG(DEV9_R_1474
) = 7;
701 _sw(0xe01a3043, SSBUS_R_1418
);
704 DEV9_REG(DEV9_R_POWER
) = DEV9_REG(DEV9_R_POWER
) & ~1;
708 static int pcmcia_device_probe()
711 const char *pcic_ct_names
[] = { "No", "16-bit", "CardBus" };
715 pcic_voltage
= pcic_get_voltage();
716 pcic_cardtype
= pcic_get_cardtype();
717 voltage
= (pcic_voltage
== 2 ? 5 : (pcic_voltage
== 1 ? 3 : 0));
719 M_PRINTF("%s PCMCIA card detected. Vcc = %dV\n",
720 pcic_ct_names
[pcic_cardtype
], voltage
);
722 if (pcic_voltage
== 3 || pcic_cardtype
!= 1)
728 static int pcmcia_device_reset(void)
733 /* The card must be 16-bit (type 2?) */
734 if (pcic_cardtype
!= 1)
737 DEV9_REG(DEV9_R_147E
) = 1;
738 if (pcic_power(pcic_voltage
, 1) < 0)
741 DEV9_REG(DEV9_R_POWER
) = DEV9_REG(DEV9_R_POWER
) | 0x02;
744 DEV9_REG(DEV9_R_POWER
) = DEV9_REG(DEV9_R_POWER
) | 0x01;
745 DEV9_REG(DEV9_R_1464
) = cstc1
= DEV9_REG(DEV9_R_1464
);
746 DEV9_REG(DEV9_R_1466
) = cstc2
= DEV9_REG(DEV9_R_1466
);
750 static int card_find_manfid(u32 manfid
)
754 u32 spdaddr
, spdend
, next
, tuple
;
757 DEV9_REG(DEV9_R_1460
) = 2;
758 _sw(0x1a00bb, SSBUS_R_1418
);
760 /* Scan the card for the MANFID tuple. */
763 /* I hate this code, and it hates me. */
764 while (spdaddr
< spdend
) {
765 hdr
= SPD_REG8(spdaddr
) & 0xff;
771 if (spdaddr
>= spdend
)
774 ofs
= SPD_REG8(spdaddr
) & 0xff;
779 next
= spdaddr
+ (ofs
* 2);
784 if ((spdaddr
+ 8) >= spdend
)
787 tuple
= (SPD_REG8(spdaddr
+ 2) << 24)|
788 (SPD_REG8(spdaddr
) << 16)|
789 (SPD_REG8(spdaddr
+ 6) << 8)|
790 SPD_REG8(spdaddr
+ 4);
793 M_PRINTF("MANFID 0x%08lx doesn't match expected 0x%08lx\n",
800 M_PRINTF("MANFID 0x%08lx not found.\n", manfid
);
803 M_PRINTF("Invalid tuples at offset 0x%08lx.\n", spdaddr
- SPD_REGBASE
);
807 static int pcmcia_intr(void *unused
)
812 cstc1
= DEV9_REG(DEV9_R_1464
);
813 cstc2
= DEV9_REG(DEV9_R_1466
);
816 if (_lh(0xb4000004) & 0x04)
817 _sh(0x04, 0xb4000004);
819 return 0; /* Unknown interrupt. */
822 /* Acknowledge the interrupt. */
823 DEV9_REG(DEV9_R_1464
) = cstc1
;
824 DEV9_REG(DEV9_R_1466
) = cstc2
;
825 if (cstc1
& 0x03 || cstc2
& 0x03) { /* Card removed or added? */
829 /* Shutdown the card. */
830 DEV9_REG(DEV9_R_POWER
) = 0;
831 DEV9_REG(DEV9_R_1474
) = 0;
833 pcmcia_device_probe();
835 if (cstc1
& 0x80 || cstc2
& 0x80) {
840 DEV9_REG(DEV9_R_147E
) = 1;
841 DEV9_REG(DEV9_R_147E
) = 0;
845 static int pcmcia_init(void)
852 _sw(0x51011, SSBUS_R_1420
);
853 _sw(0x1a00bb, SSBUS_R_1418
);
854 _sw(0xef1a3043, SSBUS_R_141c
);
856 /* If we are a T10K, then we go through AIF. */
857 if ((mode
= QueryBootMode(6)) != NULL
) {
858 if ((*(u16
*)mode
& 0xfe) == 0x60) {
859 if (_lh(0xb4000000) == 0xa1) {
863 M_PRINTF("T10k detected, but AIF not detected.\n");
869 if (DEV9_REG(DEV9_R_POWER
) == 0) {
870 DEV9_REG(DEV9_R_POWER
) = 0;
871 DEV9_REG(DEV9_R_147E
) = 1;
872 DEV9_REG(DEV9_R_1460
) = 0;
873 DEV9_REG(DEV9_R_1474
) = 0;
874 DEV9_REG(DEV9_R_1464
) = cstc1
= DEV9_REG(DEV9_R_1464
);
875 DEV9_REG(DEV9_R_1466
) = cstc2
= DEV9_REG(DEV9_R_1466
);
876 DEV9_REG(DEV9_R_1468
) = 0x10;
877 DEV9_REG(DEV9_R_146A
) = 0x90;
878 DEV9_REG(DEV9_R_147C
) = 1;
879 DEV9_REG(DEV9_R_147A
) = DEV9_REG(DEV9_R_147C
);
881 pcic_voltage
= pcic_get_voltage();
882 pcic_cardtype
= pcic_get_cardtype();
884 if (smap_device_init() != 0)
887 _sw(0xe01a3043, SSBUS_R_1418
);
890 if (smap_subsys_init() != 0)
893 CpuSuspendIntr(&flags
);
894 RegisterIntrHandler(DEV9_INTR
, 1, pcmcia_intr
, NULL
);
895 EnableIntr(DEV9_INTR
);
896 CpuResumeIntr(flags
);
898 DEV9_REG(DEV9_R_147E
) = 0;
899 M_PRINTF("CXD9566 (PCMCIA type) initialized.\n");
904 static void expbay_set_stat(int stat
)
907 DEV9_REG(DEV9_R_1464
) = stat
& 0x3f;
910 static int expbay_device_probe()
913 return (DEV9_REG(DEV9_R_1462
) & 0x01) ? -1 : 0;
916 static int expbay_device_reset(void)
920 if (expbay_device_probe() < 0)
923 DEV9_REG(DEV9_R_POWER
) = (DEV9_REG(DEV9_R_POWER
) & ~1) | 0x04; /* power on */
926 DEV9_REG(DEV9_R_1460
) = DEV9_REG(DEV9_R_1460
) | 0x01;
927 DEV9_REG(DEV9_R_POWER
) = DEV9_REG(DEV9_R_POWER
) | 0x01;
932 static int expbay_intr(void *unused
)
939 DEV9_REG(DEV9_R_1466
) = 1;
940 DEV9_REG(DEV9_R_1466
) = 0;
944 static int expbay_init(void)
949 _sw(0x51011, SSBUS_R_1420
);
950 _sw(0xe01a3043, SSBUS_R_1418
);
951 _sw(0xef1a3043, SSBUS_R_141c
);
953 if ((DEV9_REG(DEV9_R_POWER
) & 0x04) == 0) { /* if not already powered */
954 DEV9_REG(DEV9_R_1466
) = 1;
955 DEV9_REG(DEV9_R_1464
) = 0;
956 DEV9_REG(DEV9_R_1460
) = DEV9_REG(DEV9_R_1464
);
958 if (smap_device_init() != 0)
962 if (smap_subsys_init() != 0)
965 CpuSuspendIntr(&flags
);
966 ReleaseIntrHandler(DEV9_INTR
);
967 RegisterIntrHandler(DEV9_INTR
, 1, expbay_intr
, NULL
);
968 EnableIntr(DEV9_INTR
);
969 CpuResumeIntr(flags
);
971 DEV9_REG(DEV9_R_1466
) = 0;
972 M_PRINTF("CXD9611 (Expansion Bay type) initialized.\n");