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 $
30 #include "ioman_add.h"
34 #include "speedregs.h"
37 #define MODNAME "dev9_driver"
38 #define DRIVERNAME "dev9"
39 IRX_ID(MODNAME
, 1, 1);
42 #define M_PRINTF(format, args...) \
43 printf(MODNAME ": " format, ## args)
45 #define M_PRINTF(format, args...) \
50 #define BANNER "\nDEV9 device driver v%s - Copyright (c) 2003 Marcus R. Brown\n\n"
54 /* SSBUS registers. */
55 #define SSBUS_R_1418 0xbf801418
56 #define SSBUS_R_141c 0xbf80141c
57 #define SSBUS_R_1420 0xbf801420
59 static int dev9type
= -1; /* 0 for PCMCIA, 1 for expansion bay */
61 static int using_aif
= 0; /* 1 if using AIF on a T10K */
64 static void (*p_dev9_intr_cb
)(int flag
) = NULL
;
65 static int dma_lock_sem
= -1; /* used to arbitrate DMA */
66 static int dma_complete_sem
= -1; /* signalled on DMA transfer completion. */
69 static int pcic_cardtype
; /* Translated value of bits 0-1 of 0xbf801462 */
70 static int pcic_voltage
; /* Translated value of bits 2-3 of 0xbf801462 */
73 static s16 eeprom_data
[5]; /* 2-byte EEPROM status (0/-1 = invalid, 1 = valid),
75 2-byte MAC address checksum. */
77 /* Each driver can register callbacks that correspond to each bit of the
78 SMAP interrupt status register (0xbx000028). */
79 static dev9_intr_cb_t dev9_intr_cbs
[16];
81 static dev9_shutdown_cb_t dev9_shutdown_cbs
[16];
83 static dev9_dma_cb_t dev9_predma_cbs
[4], dev9_postdma_cbs
[4];
85 static int dev9_intr_dispatch(int flag
);
86 static int dev9_dma_intr(void *arg
);
89 static void dev9x_on_shutdown(void*);
92 static void smap_set_stat(int stat
);
93 static int read_eeprom_data(void);
95 static int smap_device_probe(void);
96 static int smap_device_reset(void);
97 static int smap_subsys_init(void);
98 static int smap_device_init(void);
101 static void pcmcia_set_stat(int stat
);
102 static int pcic_ssbus_mode(int voltage
);
103 static int pcmcia_device_probe(void);
104 static int pcmcia_device_reset(void);
105 static int card_find_manfid(u32 manfid
);
106 static int pcmcia_init(void);
109 static void expbay_set_stat(int stat
);
110 static int expbay_device_probe(void);
111 static int expbay_device_reset(void);
112 static int expbay_init(void);
114 struct irx_export_table _exp_dev9
;
117 int dev9x_dummy() { return 0; }
118 int dev9x_devctl(iop_file_t
*f
, const char *name
, int cmd
, void *args
, int arglen
, void *buf
, int buflen
)
126 /* driver ops func tab */
127 void *dev9x_ops
[27] = {
157 /* driver descriptor */
158 static iop_ext_device_t dev9x_dev
= {
160 IOP_DT_FS
| 0x10000000, /* EXT FS */
163 (struct _iop_ext_device_ops
*)&dev9x_ops
167 int _start(int argc
, char **argv
)
173 M_PRINTF(BANNER
, VERSION
);
176 iop_library_table_t
*libtable
;
177 iop_library_t
*libptr
;
178 libtable
= GetLibraryEntryTable();
179 libptr
= libtable
->tail
;
180 while ((libptr
!= 0))
183 for (i
= 0; i
<= sizeof(DRIVERNAME
); i
++) {
184 if (libptr
->name
[i
] != DRIVERNAME
[i
])
187 if (i
> sizeof(DRIVERNAME
)) {
188 M_PRINTF("Driver already loaded.\n");
191 libptr
= libptr
->prev
;
195 for (idx
= 0; idx
< 16; idx
++)
196 dev9_shutdown_cbs
[idx
] = NULL
;
198 dev9hw
= DEV9_REG(DEV9_R_REV
) & 0xf0;
199 if (dev9hw
== 0x20) { /* CXD9566 (PCMCIA) */
206 } else if (dev9hw
== 0x30) { /* CXD9611 (Expansion Bay) */
216 AddDrv((iop_device_t
*)&dev9x_dev
);
219 if (RegisterLibraryEntries(&_exp_dev9
) != 0) {
223 AddPowerOffHandler(dev9x_on_shutdown
, 0);
225 /* Normal termination. */
226 M_PRINTF("Dev9 loaded.\n");
231 int __attribute__((unused
)) shutdown() { return 0; }
234 void dev9RegisterIntrCb(int intr
, dev9_intr_cb_t cb
)
236 dev9_intr_cbs
[intr
] = cb
;
240 void dev9RegisterPreDmaCb(int ctrl
, dev9_dma_cb_t cb
){
241 dev9_predma_cbs
[ctrl
] = cb
;
245 void dev9RegisterPostDmaCb(int ctrl
, dev9_dma_cb_t cb
){
246 dev9_postdma_cbs
[ctrl
] = cb
;
249 /* flag is 1 if a card (pcmcia) was removed or added */
250 static int dev9_intr_dispatch(int flag
)
256 for (i
= 0; i
< 16; i
++)
257 if (dev9_intr_cbs
[i
] != NULL
)
258 dev9_intr_cbs
[i
](flag
);
261 while (SPD_REG16(SPD_R_INTR_STAT
) & SPD_REG16(SPD_R_INTR_MASK
)) {
262 for (i
= 0; i
< 16; i
++) {
263 if (dev9_intr_cbs
[i
] != NULL
) {
264 bit
= (SPD_REG16(SPD_R_INTR_STAT
) &
265 SPD_REG16(SPD_R_INTR_MASK
)) >> i
;
267 dev9_intr_cbs
[i
](flag
);
275 /* Signal the end of a DMA transfer. */
276 static int dev9_dma_intr(void *arg
)
278 int sem
= *(int *)arg
;
284 static void smap_set_stat(int stat
)
288 pcmcia_set_stat(stat
);
292 else if (dev9type
== 1)
293 expbay_set_stat(stat
);
296 static int smap_device_probe()
300 return pcmcia_device_probe();
304 else if (dev9type
== 1)
305 return expbay_device_probe();
310 static int smap_device_reset()
314 return pcmcia_device_reset();
318 else if (dev9type
== 1)
319 return expbay_device_reset();
330 for (idx
= 0; idx
< 16; idx
++)
331 if (dev9_shutdown_cbs
[idx
])
332 dev9_shutdown_cbs
[idx
]();
334 if (dev9type
== 0) { /* PCMCIA */
336 DEV9_REG(DEV9_R_POWER
) = 0;
337 DEV9_REG(DEV9_R_1474
) = 0;
339 } else if (dev9type
== 1) {
340 DEV9_REG(DEV9_R_1466
) = 1;
341 DEV9_REG(DEV9_R_1464
) = 0;
342 DEV9_REG(DEV9_R_1460
) = DEV9_REG(DEV9_R_1464
);
343 DEV9_REG(DEV9_R_POWER
) = DEV9_REG(DEV9_R_POWER
) & ~4;
344 DEV9_REG(DEV9_R_POWER
) = DEV9_REG(DEV9_R_POWER
) & ~1;
346 DelayThread(1000000);
350 void dev9IntrEnable(int mask
)
355 CpuSuspendIntr(&flags
);
356 SPD_REG16(SPD_R_INTR_MASK
) = SPD_REG16(SPD_R_INTR_MASK
) | mask
;
357 CpuResumeIntr(flags
);
361 void dev9IntrDisable(int mask
)
366 CpuSuspendIntr(&flags
);
367 SPD_REG16(SPD_R_INTR_MASK
) = SPD_REG16(SPD_R_INTR_MASK
) & ~mask
;
368 CpuResumeIntr(flags
);
372 /* This differs from the "official" dev9 in that it puts the calling thread to
373 sleep when doing the actual DMA transfer. I'm not sure why SCEI didn't do
374 this in dev9.irx, when they do it in PS2Linux's dmarelay.irx. Anyway,
375 since this no longer blocks, it should speed up anything else on the IOP
376 when HDD or SMAP are doing DMA. */
377 int dev9DmaTransfer(int ctrl
, void *buf
, int bcr
, int dir
)
380 volatile iop_dmac_chan_t
*dev9_chan
= (iop_dmac_chan_t
*)DEV9_DMAC_BASE
;
381 int stat
, res
= 0, dmactrl
;
385 case 1: dmactrl
= ctrl
;
390 if (dev9_predma_cbs
[ctrl
] == NULL
) return -1;
391 if (dev9_postdma_cbs
[ctrl
] == NULL
) return -1;
392 dmactrl
= (4 << ctrl
);
399 if ((res
= WaitSema(dma_lock_sem
)) < 0)
402 if (SPD_REG16(SPD_R_REV_1
) < 17)
403 dmactrl
= (dmactrl
& 0x03) | 0x04;
405 dmactrl
= (dmactrl
& 0x01) | 0x06;
406 SPD_REG16(SPD_R_DMA_CTRL
) = dmactrl
;
408 if (dev9_predma_cbs
[ctrl
])
409 dev9_predma_cbs
[ctrl
](bcr
, dir
);
411 EnableIntr(IOP_IRQ_DMA_DEV9
);
412 dev9_chan
->madr
= (u32
)buf
;
413 dev9_chan
->bcr
= bcr
;
414 dev9_chan
->chcr
= DMAC_CHCR_30
|DMAC_CHCR_TR
|DMAC_CHCR_CO
|
415 (dir
& DMAC_CHCR_DR
);
417 /* Wait for DMA to complete. */
418 if ((res
= WaitSema(dma_complete_sem
)) >= 0)
421 DisableIntr(IOP_IRQ_DMA_DEV9
, &stat
);
423 if (dev9_postdma_cbs
[ctrl
])
424 dev9_postdma_cbs
[ctrl
](bcr
, dir
);
426 SignalSema(dma_lock_sem
);
430 static int read_eeprom_data()
436 if (eeprom_data
[0] < 0)
439 SPD_REG8(SPD_R_PIO_DIR
) = 0xe1;
441 SPD_REG8(SPD_R_PIO_DATA
) = 0x80;
444 for (i
= 0; i
< 2; i
++) {
445 SPD_REG8(SPD_R_PIO_DATA
) = 0xa0;
447 SPD_REG8(SPD_R_PIO_DATA
) = 0xe0;
450 for (i
= 0; i
< 7; i
++) {
451 SPD_REG8(SPD_R_PIO_DATA
) = 0x80;
453 SPD_REG8(SPD_R_PIO_DATA
) = 0xc0;
456 SPD_REG8(SPD_R_PIO_DATA
) = 0xc0;
459 val
= SPD_REG8(SPD_R_PIO_DATA
);
461 if (val
& 0x10) { /* Error. */
462 SPD_REG8(SPD_R_PIO_DATA
) = 0;
469 SPD_REG8(SPD_R_PIO_DATA
) = 0x80;
472 /* Read the MAC address and checksum from the EEPROM. */
473 for (i
= 0; i
< 4; i
++) {
474 eeprom_data
[i
+1] = 0;
476 for (j
= 15; j
>= 0; j
--) {
477 SPD_REG8(SPD_R_PIO_DATA
) = 0xc0;
479 val
= SPD_REG8(SPD_R_PIO_DATA
);
481 eeprom_data
[i
+1] |= (1<<j
);
482 SPD_REG8(SPD_R_PIO_DATA
) = 0x80;
487 SPD_REG8(SPD_R_PIO_DATA
) = 0;
489 eeprom_data
[0] = 1; /* The EEPROM data is valid. */
493 SPD_REG8(SPD_R_PIO_DIR
) = 1;
498 int dev9GetEEPROM(u16
*buf
)
504 if (eeprom_data
[0] < 0)
507 /* We only return the MAC address and checksum. */
508 for (i
= 0; i
< 4; i
++)
509 buf
[i
] = eeprom_data
[i
+1];
515 void dev9LEDCtl(int ctl
)
518 SPD_REG8(SPD_R_PIO_DATA
) = (ctl
== 0);
522 int dev9RegisterShutdownCb(int idx
, dev9_shutdown_cb_t cb
){
525 dev9_shutdown_cbs
[idx
] = cb
;
531 static int smap_subsys_init(void)
535 if ((dma_lock_sem
= CreateMutex(IOP_MUTEX_UNLOCKED
)) < 0)
537 if ((dma_complete_sem
= CreateMutex(IOP_MUTEX_LOCKED
)) < 0)
540 DisableIntr(IOP_IRQ_DMA_DEV9
, &stat
);
541 CpuSuspendIntr(&flags
);
542 /* Enable the DEV9 DMAC channel. */
543 RegisterIntrHandler(IOP_IRQ_DMA_DEV9
, 1, dev9_dma_intr
, &dma_complete_sem
);
544 dmac_set_dpcr2(dmac_get_dpcr2() | 0x80);
545 CpuResumeIntr(flags
);
547 /* Not quite sure what this enables yet. */
548 smap_set_stat(0x103);
550 /* Disable all device interrupts. */
551 dev9IntrDisable(0xffff);
553 p_dev9_intr_cb
= (void *)dev9_intr_dispatch
;
555 /* Reset the SMAP interrupt callback table. */
556 for (i
= 0; i
< 16; i
++)
557 dev9_intr_cbs
[i
] = NULL
;
559 for (i
= 0; i
< 4; i
++){
560 dev9_predma_cbs
[i
] = NULL
;
561 dev9_postdma_cbs
[i
] = NULL
;
564 /* Read in the MAC address. */
566 /* Turn the LED off. */
571 static int smap_device_init(void)
575 const char *spdnames
[] = { "(unknown)", "TS", "ES1", "ES2" };
582 if (smap_device_probe() < 0) {
583 M_PRINTF("PC card or expansion device isn't connected.\n");
592 /* Locate the SPEED Lite chip and get the bus ready for the
595 if ((res
= card_find_manfid(0xf15300)))
596 M_PRINTF("SPEED Lite not found.\n");
598 if (!res
&& (res
= pcic_ssbus_mode(5)))
599 M_PRINTF("Unable to change SSBUS mode.\n");
609 /* Print out the SPEED chip revision. */
610 spdrev
= SPD_REG16(SPD_R_REV_1
);
611 idx
= (spdrev
& 0xffff) - 14;
614 else if (spdrev
< 9 || (spdrev
< 16 || spdrev
> 17))
615 idx
= 0; /* Unknown revision */
617 M_PRINTF("SPEED chip '%s', revision 0x%0X\n", spdnames
[idx
], spdrev
);
624 static int pcic_get_cardtype()
627 u16 val
= DEV9_REG(DEV9_R_1462
) & 0x03;
630 return 1; /* 16-bit */
633 return 2; /* CardBus */
637 static int pcic_get_voltage()
640 u16 val
= DEV9_REG(DEV9_R_1462
) & 0x0c;
644 if (val
== 0 || val
== 0x08)
651 static int pcic_power(int voltage
, int flag
)
655 u16 val
= (voltage
== 1) << 2;
657 DEV9_REG(DEV9_R_POWER
) = 0;
664 DEV9_REG(DEV9_R_POWER
) = val
;
667 if (DEV9_REG(DEV9_R_1462
) & 0x100)
670 DEV9_REG(DEV9_R_POWER
) = 0;
671 DEV9_REG(DEV9_R_1464
) = cstc1
= DEV9_REG(DEV9_R_1464
);
672 DEV9_REG(DEV9_R_1466
) = cstc2
= DEV9_REG(DEV9_R_1466
);
676 static void pcmcia_set_stat(int stat
)
679 u16 val
= stat
& 0x01;
699 DEV9_REG(DEV9_R_1476
) = val
& 0xff;
702 static int pcic_ssbus_mode(int voltage
)
706 u16 stat
= DEV9_REG(DEV9_R_1474
) & 7;
708 if (voltage
!= 3 && voltage
!= 5)
711 DEV9_REG(DEV9_R_1460
) = 2;
716 DEV9_REG(DEV9_R_1474
) = 1;
717 DEV9_REG(DEV9_R_1460
) = 1;
719 DEV9_REG(DEV9_R_1474
) = voltage
;
720 } else if (voltage
== 5) {
721 DEV9_REG(DEV9_R_1474
) = voltage
;
722 DEV9_REG(DEV9_R_1460
) = 1;
724 DEV9_REG(DEV9_R_1474
) = 7;
726 _sw(0xe01a3043, SSBUS_R_1418
);
729 DEV9_REG(DEV9_R_POWER
) = DEV9_REG(DEV9_R_POWER
) & ~1;
733 static int pcmcia_device_probe()
736 const char *pcic_ct_names
[] = { "No", "16-bit", "CardBus" };
740 pcic_voltage
= pcic_get_voltage();
741 pcic_cardtype
= pcic_get_cardtype();
742 voltage
= (pcic_voltage
== 2 ? 5 : (pcic_voltage
== 1 ? 3 : 0));
744 M_PRINTF("%s PCMCIA card detected. Vcc = %dV\n",
745 pcic_ct_names
[pcic_cardtype
], voltage
);
747 if (pcic_voltage
== 3 || pcic_cardtype
!= 1)
753 static int pcmcia_device_reset(void)
758 /* The card must be 16-bit (type 2?) */
759 if (pcic_cardtype
!= 1)
762 DEV9_REG(DEV9_R_147E
) = 1;
763 if (pcic_power(pcic_voltage
, 1) < 0)
766 DEV9_REG(DEV9_R_POWER
) = DEV9_REG(DEV9_R_POWER
) | 0x02;
769 DEV9_REG(DEV9_R_POWER
) = DEV9_REG(DEV9_R_POWER
) | 0x01;
770 DEV9_REG(DEV9_R_1464
) = cstc1
= DEV9_REG(DEV9_R_1464
);
771 DEV9_REG(DEV9_R_1466
) = cstc2
= DEV9_REG(DEV9_R_1466
);
775 static int card_find_manfid(u32 manfid
)
779 u32 spdaddr
, spdend
, next
, tuple
;
782 DEV9_REG(DEV9_R_1460
) = 2;
783 _sw(0x1a00bb, SSBUS_R_1418
);
785 /* Scan the card for the MANFID tuple. */
788 /* I hate this code, and it hates me. */
789 while (spdaddr
< spdend
) {
790 hdr
= SPD_REG8(spdaddr
) & 0xff;
796 if (spdaddr
>= spdend
)
799 ofs
= SPD_REG8(spdaddr
) & 0xff;
804 next
= spdaddr
+ (ofs
* 2);
809 if ((spdaddr
+ 8) >= spdend
)
812 tuple
= (SPD_REG8(spdaddr
+ 2) << 24)|
813 (SPD_REG8(spdaddr
) << 16)|
814 (SPD_REG8(spdaddr
+ 6) << 8)|
815 SPD_REG8(spdaddr
+ 4);
818 M_PRINTF("MANFID 0x%08lx doesn't match expected 0x%08lx\n",
825 M_PRINTF("MANFID 0x%08lx not found.\n", manfid
);
828 M_PRINTF("Invalid tuples at offset 0x%08lx.\n", spdaddr
- SPD_REGBASE
);
832 static int pcmcia_intr(void *unused
)
837 cstc1
= DEV9_REG(DEV9_R_1464
);
838 cstc2
= DEV9_REG(DEV9_R_1466
);
841 if (_lh(0xb4000004) & 0x04)
842 _sh(0x04, 0xb4000004);
844 return 0; /* Unknown interrupt. */
847 /* Acknowledge the interrupt. */
848 DEV9_REG(DEV9_R_1464
) = cstc1
;
849 DEV9_REG(DEV9_R_1466
) = cstc2
;
850 if (cstc1
& 0x03 || cstc2
& 0x03) { /* Card removed or added? */
854 /* Shutdown the card. */
855 DEV9_REG(DEV9_R_POWER
) = 0;
856 DEV9_REG(DEV9_R_1474
) = 0;
858 pcmcia_device_probe();
860 if (cstc1
& 0x80 || cstc2
& 0x80) {
865 DEV9_REG(DEV9_R_147E
) = 1;
866 DEV9_REG(DEV9_R_147E
) = 0;
870 static int pcmcia_init(void)
877 _sw(0x51011, SSBUS_R_1420
);
878 _sw(0x1a00bb, SSBUS_R_1418
);
879 _sw(0xef1a3043, SSBUS_R_141c
);
881 /* If we are a T10K, then we go through AIF. */
882 if ((mode
= QueryBootMode(6)) != NULL
) {
883 if ((*(u16
*)mode
& 0xfe) == 0x60) {
884 if (_lh(0xb4000000) == 0xa1) {
888 M_PRINTF("T10k detected, but AIF not detected.\n");
894 if (DEV9_REG(DEV9_R_POWER
) == 0) {
895 DEV9_REG(DEV9_R_POWER
) = 0;
896 DEV9_REG(DEV9_R_147E
) = 1;
897 DEV9_REG(DEV9_R_1460
) = 0;
898 DEV9_REG(DEV9_R_1474
) = 0;
899 DEV9_REG(DEV9_R_1464
) = cstc1
= DEV9_REG(DEV9_R_1464
);
900 DEV9_REG(DEV9_R_1466
) = cstc2
= DEV9_REG(DEV9_R_1466
);
901 DEV9_REG(DEV9_R_1468
) = 0x10;
902 DEV9_REG(DEV9_R_146A
) = 0x90;
903 DEV9_REG(DEV9_R_147C
) = 1;
904 DEV9_REG(DEV9_R_147A
) = DEV9_REG(DEV9_R_147C
);
906 pcic_voltage
= pcic_get_voltage();
907 pcic_cardtype
= pcic_get_cardtype();
909 if (smap_device_init() != 0)
912 _sw(0xe01a3043, SSBUS_R_1418
);
915 if (smap_subsys_init() != 0)
918 CpuSuspendIntr(&flags
);
919 RegisterIntrHandler(DEV9_INTR
, 1, pcmcia_intr
, NULL
);
920 EnableIntr(DEV9_INTR
);
921 CpuResumeIntr(flags
);
923 DEV9_REG(DEV9_R_147E
) = 0;
924 M_PRINTF("CXD9566 (PCMCIA type) initialized.\n");
929 static void expbay_set_stat(int stat
)
932 DEV9_REG(DEV9_R_1464
) = stat
& 0x3f;
935 static int expbay_device_probe()
938 return (DEV9_REG(DEV9_R_1462
) & 0x01) ? -1 : 0;
941 static int expbay_device_reset(void)
945 if (expbay_device_probe() < 0)
948 DEV9_REG(DEV9_R_POWER
) = (DEV9_REG(DEV9_R_POWER
) & ~1) | 0x04; /* power on */
951 DEV9_REG(DEV9_R_1460
) = DEV9_REG(DEV9_R_1460
) | 0x01;
952 DEV9_REG(DEV9_R_POWER
) = DEV9_REG(DEV9_R_POWER
) | 0x01;
957 static int expbay_intr(void *unused
)
964 DEV9_REG(DEV9_R_1466
) = 1;
965 DEV9_REG(DEV9_R_1466
) = 0;
969 static int expbay_init(void)
974 _sw(0x51011, SSBUS_R_1420
);
975 _sw(0xe01a3043, SSBUS_R_1418
);
976 _sw(0xef1a3043, SSBUS_R_141c
);
978 if ((DEV9_REG(DEV9_R_POWER
) & 0x04) == 0) { /* if not already powered */
979 DEV9_REG(DEV9_R_1466
) = 1;
980 DEV9_REG(DEV9_R_1464
) = 0;
981 DEV9_REG(DEV9_R_1460
) = DEV9_REG(DEV9_R_1464
);
983 if (smap_device_init() != 0)
987 if (smap_subsys_init() != 0)
990 CpuSuspendIntr(&flags
);
991 RegisterIntrHandler(DEV9_INTR
, 1, expbay_intr
, NULL
);
992 EnableIntr(DEV9_INTR
);
993 CpuResumeIntr(flags
);
995 DEV9_REG(DEV9_R_1466
) = 0;
996 M_PRINTF("CXD9611 (Expansion Bay type) initialized.\n");
1001 static void dev9x_on_shutdown(void*p
)
1003 M_PRINTF("shutdown\n");
1004 dev9IntrDisable(-1);