adding i18n strings
[open-ps2-loader.git] / modules / dev9 / ps2dev9.c
blobeccc5ede701133e24224fd07ed9361010440aad1
1 /*
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 $
11 # DEV9 Device Driver.
14 #include "types.h"
15 #include "defs.h"
16 #include "loadcore.h"
17 #include "intrman.h"
18 #include "dmacman.h"
19 #include "thbase.h"
20 #include "thsemap.h"
21 #ifdef DEBUG
22 #include "stdio.h"
23 #endif
24 #include "dev9.h"
25 #ifdef POWEROFF
26 #include "poweroff.h"
27 #endif
28 #ifdef DEV9X_DEV
29 #include "ioman.h"
30 #include "ioman_add.h"
31 #endif
33 #include "dev9regs.h"
34 #include "speedregs.h"
35 #include "smapregs.h"
37 #define MODNAME "dev9_driver"
38 #define DRIVERNAME "dev9"
39 IRX_ID(MODNAME, 1, 1);
41 #ifdef DEBUG
42 #define M_PRINTF(format, args...) \
43 printf(MODNAME ": " format, ## args)
44 #else
45 #define M_PRINTF(format, args...) \
46 do {} while (0)
47 #endif
49 #define VERSION "1.0"
50 #define BANNER "\nDEV9 device driver v%s - Copyright (c) 2003 Marcus R. Brown\n\n"
52 #define DEV9_INTR 13
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 */
60 #ifdef PCMCIA
61 static int using_aif = 0; /* 1 if using AIF on a T10K */
62 #endif
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. */
68 #ifdef PCMCIA
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 */
71 #endif
73 static s16 eeprom_data[5]; /* 2-byte EEPROM status (0/-1 = invalid, 1 = valid),
74 6-byte MAC address,
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);
88 #ifdef POWEROFF
89 static void dev9x_on_shutdown(void*);
90 #endif
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);
100 #ifdef PCMCIA
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);
107 #endif
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;
116 #ifdef DEV9X_DEV
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)
120 if (cmd == 0x4401)
121 return dev9type;
123 return 0;
126 /* driver ops func tab */
127 void *dev9x_ops[27] = {
128 (void*)dev9x_dummy,
129 (void*)dev9x_dummy,
130 (void*)dev9x_dummy,
131 (void*)dev9x_dummy,
132 (void*)dev9x_dummy,
133 (void*)dev9x_dummy,
134 (void*)dev9x_dummy,
135 (void*)dev9x_dummy,
136 (void*)dev9x_dummy,
137 (void*)dev9x_dummy,
138 (void*)dev9x_dummy,
139 (void*)dev9x_dummy,
140 (void*)dev9x_dummy,
141 (void*)dev9x_dummy,
142 (void*)dev9x_dummy,
143 (void*)dev9x_dummy,
144 (void*)dev9x_dummy,
145 (void*)dev9x_dummy,
146 (void*)dev9x_dummy,
147 (void*)dev9x_dummy,
148 (void*)dev9x_dummy,
149 (void*)dev9x_dummy,
150 (void*)dev9x_dummy,
151 (void*)dev9x_devctl,
152 (void*)dev9x_dummy,
153 (void*)dev9x_dummy,
154 (void*)dev9x_dummy
157 /* driver descriptor */
158 static iop_ext_device_t dev9x_dev = {
159 "dev9x",
160 IOP_DT_FS | 0x10000000, /* EXT FS */
162 "DEV9",
163 (struct _iop_ext_device_ops *)&dev9x_ops
165 #endif
167 int _start(int argc, char **argv)
169 USE_DEV9_REGS;
170 int idx, res = 1;
171 u16 dev9hw;
173 M_PRINTF(BANNER, VERSION);
175 #ifdef CHECK_LOADED
176 iop_library_table_t *libtable;
177 iop_library_t *libptr;
178 libtable = GetLibraryEntryTable();
179 libptr = libtable->tail;
180 while ((libptr != 0))
182 int i;
183 for (i = 0; i <= sizeof(DRIVERNAME); i++) {
184 if (libptr->name[i] != DRIVERNAME[i])
185 break;
187 if (i > sizeof(DRIVERNAME)) {
188 M_PRINTF("Driver already loaded.\n");
189 return 1;
191 libptr = libptr->prev;
193 #endif
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) */
200 dev9type = 0;
201 #ifdef PCMCIA
202 res = pcmcia_init();
203 #else
204 return 1;
205 #endif
206 } else if (dev9hw == 0x30) { /* CXD9611 (Expansion Bay) */
207 dev9type = 1;
208 res = expbay_init();
211 if (res)
212 return res;
214 #ifdef DEV9X_DEV
215 DelDrv("dev9x");
216 AddDrv((iop_device_t *)&dev9x_dev);
217 #endif
219 if (RegisterLibraryEntries(&_exp_dev9) != 0) {
220 return 1;
222 #ifdef POWEROFF
223 AddPowerOffHandler(dev9x_on_shutdown, 0);
224 #endif
225 /* Normal termination. */
226 M_PRINTF("Dev9 loaded.\n");
228 return 0;
231 int __attribute__((unused)) shutdown() { return 0; }
233 /* Export 4 */
234 void dev9RegisterIntrCb(int intr, dev9_intr_cb_t cb)
236 dev9_intr_cbs[intr] = cb;
239 /* Export 12 */
240 void dev9RegisterPreDmaCb(int ctrl, dev9_dma_cb_t cb){
241 dev9_predma_cbs[ctrl] = cb;
244 /* Export 13 */
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)
252 USE_SPD_REGS;
253 int i, bit;
255 if (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;
266 if (bit & 0x01)
267 dev9_intr_cbs[i](flag);
272 return 0;
275 /* Signal the end of a DMA transfer. */
276 static int dev9_dma_intr(void *arg)
278 int sem = *(int *)arg;
280 iSignalSema(sem);
281 return 1;
284 static void smap_set_stat(int stat)
286 if (dev9type == 0)
287 #ifdef PCMCIA
288 pcmcia_set_stat(stat);
289 #else
290 return;
291 #endif
292 else if (dev9type == 1)
293 expbay_set_stat(stat);
296 static int smap_device_probe()
298 if (dev9type == 0)
299 #ifdef PCMCIA
300 return pcmcia_device_probe();
301 #else
302 return -1;
303 #endif
304 else if (dev9type == 1)
305 return expbay_device_probe();
307 return -1;
310 static int smap_device_reset()
312 if (dev9type == 0)
313 #ifdef PCMCIA
314 return pcmcia_device_reset();
315 #else
316 return -1;
317 #endif
318 else if (dev9type == 1)
319 return expbay_device_reset();
321 return -1;
324 /* Export 6 */
325 void dev9Shutdown()
327 int idx;
328 USE_DEV9_REGS;
330 for (idx = 0; idx < 16; idx++)
331 if (dev9_shutdown_cbs[idx])
332 dev9_shutdown_cbs[idx]();
334 if (dev9type == 0) { /* PCMCIA */
335 #ifdef PCMCIA
336 DEV9_REG(DEV9_R_POWER) = 0;
337 DEV9_REG(DEV9_R_1474) = 0;
338 #endif
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);
349 /* Export 7 */
350 void dev9IntrEnable(int mask)
352 USE_SPD_REGS;
353 int flags;
355 CpuSuspendIntr(&flags);
356 SPD_REG16(SPD_R_INTR_MASK) = SPD_REG16(SPD_R_INTR_MASK) | mask;
357 CpuResumeIntr(flags);
360 /* Export 8 */
361 void dev9IntrDisable(int mask)
363 USE_SPD_REGS;
364 int flags;
366 CpuSuspendIntr(&flags);
367 SPD_REG16(SPD_R_INTR_MASK) = SPD_REG16(SPD_R_INTR_MASK) & ~mask;
368 CpuResumeIntr(flags);
371 /* Export 5 */
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)
379 USE_SPD_REGS;
380 volatile iop_dmac_chan_t *dev9_chan = (iop_dmac_chan_t *)DEV9_DMAC_BASE;
381 int stat, res = 0, dmactrl;
383 switch(ctrl){
384 case 0:
385 case 1: dmactrl = ctrl;
386 break;
388 case 2:
389 case 3:
390 if (dev9_predma_cbs[ctrl] == NULL) return -1;
391 if (dev9_postdma_cbs[ctrl] == NULL) return -1;
392 dmactrl = (4 << ctrl);
393 break;
395 default:
396 return -1;
399 if ((res = WaitSema(dma_lock_sem)) < 0)
400 return res;
402 if (SPD_REG16(SPD_R_REV_1) < 17)
403 dmactrl = (dmactrl & 0x03) | 0x04;
404 else
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)
419 res = 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);
427 return res;
430 static int read_eeprom_data()
432 USE_SPD_REGS;
433 int i, j, res = -2;
434 u8 val;
436 if (eeprom_data[0] < 0)
437 goto out;
439 SPD_REG8(SPD_R_PIO_DIR) = 0xe1;
440 DelayThread(1);
441 SPD_REG8(SPD_R_PIO_DATA) = 0x80;
442 DelayThread(1);
444 for (i = 0; i < 2; i++) {
445 SPD_REG8(SPD_R_PIO_DATA) = 0xa0;
446 DelayThread(1);
447 SPD_REG8(SPD_R_PIO_DATA) = 0xe0;
448 DelayThread(1);
450 for (i = 0; i < 7; i++) {
451 SPD_REG8(SPD_R_PIO_DATA) = 0x80;
452 DelayThread(1);
453 SPD_REG8(SPD_R_PIO_DATA) = 0xc0;
454 DelayThread(1);
456 SPD_REG8(SPD_R_PIO_DATA) = 0xc0;
457 DelayThread(1);
459 val = SPD_REG8(SPD_R_PIO_DATA);
460 DelayThread(1);
461 if (val & 0x10) { /* Error. */
462 SPD_REG8(SPD_R_PIO_DATA) = 0;
463 DelayThread(1);
464 res = -1;
465 eeprom_data[0] = 0;
466 goto out;
469 SPD_REG8(SPD_R_PIO_DATA) = 0x80;
470 DelayThread(1);
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;
478 DelayThread(1);
479 val = SPD_REG8(SPD_R_PIO_DATA);
480 if (val & 0x10)
481 eeprom_data[i+1] |= (1<<j);
482 SPD_REG8(SPD_R_PIO_DATA) = 0x80;
483 DelayThread(1);
487 SPD_REG8(SPD_R_PIO_DATA) = 0;
488 DelayThread(1);
489 eeprom_data[0] = 1; /* The EEPROM data is valid. */
490 res = 0;
492 out:
493 SPD_REG8(SPD_R_PIO_DIR) = 1;
494 return res;
497 /* Export 9 */
498 int dev9GetEEPROM(u16 *buf)
500 int i;
502 if (!eeprom_data[0])
503 return -1;
504 if (eeprom_data[0] < 0)
505 return -2;
507 /* We only return the MAC address and checksum. */
508 for (i = 0; i < 4; i++)
509 buf[i] = eeprom_data[i+1];
511 return 0;
514 /* Export 10 */
515 void dev9LEDCtl(int ctl)
517 USE_SPD_REGS;
518 SPD_REG8(SPD_R_PIO_DATA) = (ctl == 0);
521 /* Export 11 */
522 int dev9RegisterShutdownCb(int idx, dev9_shutdown_cb_t cb){
523 if (idx < 16)
525 dev9_shutdown_cbs[idx] = cb;
526 return 0;
528 return -1;
531 static int smap_subsys_init(void)
533 int i, stat, flags;
535 if ((dma_lock_sem = CreateMutex(IOP_MUTEX_UNLOCKED)) < 0)
536 return -1;
537 if ((dma_complete_sem = CreateMutex(IOP_MUTEX_LOCKED)) < 0)
538 return -1;
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. */
565 read_eeprom_data();
566 /* Turn the LED off. */
567 dev9LEDCtl(0);
568 return 0;
571 static int smap_device_init(void)
573 #ifdef DEBUG
574 USE_SPD_REGS;
575 const char *spdnames[] = { "(unknown)", "TS", "ES1", "ES2" };
576 int idx;
577 u16 spdrev;
578 #endif
580 eeprom_data[0] = 0;
582 if (smap_device_probe() < 0) {
583 M_PRINTF("PC card or expansion device isn't connected.\n");
584 return -1;
587 smap_device_reset();
589 #ifdef PCMCIA
590 int res;
592 /* Locate the SPEED Lite chip and get the bus ready for the
593 PCMCIA device. */
594 if (dev9type == 0) {
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");
601 if (res) {
602 dev9Shutdown();
603 return -1;
606 #endif
608 #ifdef DEBUG
609 /* Print out the SPEED chip revision. */
610 spdrev = SPD_REG16(SPD_R_REV_1);
611 idx = (spdrev & 0xffff) - 14;
612 if (spdrev == 9)
613 idx = 1; /* TS */
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);
618 #endif
620 return 0;
623 #ifdef PCMCIA
624 static int pcic_get_cardtype()
626 USE_DEV9_REGS;
627 u16 val = DEV9_REG(DEV9_R_1462) & 0x03;
629 if (val == 0)
630 return 1; /* 16-bit */
631 else
632 if (val < 3)
633 return 2; /* CardBus */
634 return 0;
637 static int pcic_get_voltage()
639 USE_DEV9_REGS;
640 u16 val = DEV9_REG(DEV9_R_1462) & 0x0c;
642 if (val == 0x04)
643 return 3;
644 if (val == 0 || val == 0x08)
645 return 1;
646 if (val == 0x0c)
647 return 2;
648 return 0;
651 static int pcic_power(int voltage, int flag)
653 USE_DEV9_REGS;
654 u16 cstc1, cstc2;
655 u16 val = (voltage == 1) << 2;
657 DEV9_REG(DEV9_R_POWER) = 0;
659 if (voltage == 2)
660 val |= 0x08;
661 if (flag == 1)
662 val |= 0x10;
664 DEV9_REG(DEV9_R_POWER) = val;
665 DelayThread(22000);
667 if (DEV9_REG(DEV9_R_1462) & 0x100)
668 return 0;
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);
673 return -1;
676 static void pcmcia_set_stat(int stat)
678 USE_DEV9_REGS;
679 u16 val = stat & 0x01;
681 if (stat & 0x10)
682 val = 1;
683 if (stat & 0x02)
684 val |= 0x02;
685 if (stat & 0x20)
686 val |= 0x02;
687 if (stat & 0x04)
688 val |= 0x08;
689 if (stat & 0x08)
690 val |= 0x10;
691 if (stat & 0x200)
692 val |= 0x20;
693 if (stat & 0x100)
694 val |= 0x40;
695 if (stat & 0x400)
696 val |= 0x80;
697 if (stat & 0x800)
698 val |= 0x04;
699 DEV9_REG(DEV9_R_1476) = val & 0xff;
702 static int pcic_ssbus_mode(int voltage)
704 USE_DEV9_REGS;
705 USE_SPD_REGS;
706 u16 stat = DEV9_REG(DEV9_R_1474) & 7;
708 if (voltage != 3 && voltage != 5)
709 return -1;
711 DEV9_REG(DEV9_R_1460) = 2;
712 if (stat)
713 return -1;
715 if (voltage == 3) {
716 DEV9_REG(DEV9_R_1474) = 1;
717 DEV9_REG(DEV9_R_1460) = 1;
718 SPD_REG8(0x20) = 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;
723 SPD_REG8(0x20) = 1;
724 DEV9_REG(DEV9_R_1474) = 7;
726 _sw(0xe01a3043, SSBUS_R_1418);
728 DelayThread(5000);
729 DEV9_REG(DEV9_R_POWER) = DEV9_REG(DEV9_R_POWER) & ~1;
730 return 0;
733 static int pcmcia_device_probe()
735 #ifdef DEBUG
736 const char *pcic_ct_names[] = { "No", "16-bit", "CardBus" };
737 #endif
738 int voltage;
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)
748 return -1;
750 return 0;
753 static int pcmcia_device_reset(void)
755 USE_DEV9_REGS;
756 u16 cstc1, cstc2;
758 /* The card must be 16-bit (type 2?) */
759 if (pcic_cardtype != 1)
760 return -1;
762 DEV9_REG(DEV9_R_147E) = 1;
763 if (pcic_power(pcic_voltage, 1) < 0)
764 return -1;
766 DEV9_REG(DEV9_R_POWER) = DEV9_REG(DEV9_R_POWER) | 0x02;
767 DelayThread(500000);
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);
772 return 0;
775 static int card_find_manfid(u32 manfid)
777 USE_DEV9_REGS;
778 USE_SPD_REGS;
779 u32 spdaddr, spdend, next, tuple;
780 u8 hdr, ofs;
782 DEV9_REG(DEV9_R_1460) = 2;
783 _sw(0x1a00bb, SSBUS_R_1418);
785 /* Scan the card for the MANFID tuple. */
786 spdaddr = 0;
787 spdend = 0x1000;
788 /* I hate this code, and it hates me. */
789 while (spdaddr < spdend) {
790 hdr = SPD_REG8(spdaddr) & 0xff;
791 spdaddr += 2;
792 if (!hdr)
793 continue;
794 if (hdr == 0xff)
795 break;
796 if (spdaddr >= spdend)
797 goto error;
799 ofs = SPD_REG8(spdaddr) & 0xff;
800 spdaddr += 2;
801 if (ofs == 0xff)
802 break;
804 next = spdaddr + (ofs * 2);
805 if (next >= spdend)
806 goto error;
808 if (hdr == 0x20) {
809 if ((spdaddr + 8) >= spdend)
810 goto error;
812 tuple = (SPD_REG8(spdaddr + 2) << 24)|
813 (SPD_REG8(spdaddr) << 16)|
814 (SPD_REG8(spdaddr + 6) << 8)|
815 SPD_REG8(spdaddr + 4);
816 if (manfid == tuple)
817 return 0;
818 M_PRINTF("MANFID 0x%08lx doesn't match expected 0x%08lx\n",
819 tuple, manfid);
820 return -1;
822 spdaddr = next;
825 M_PRINTF("MANFID 0x%08lx not found.\n", manfid);
826 return -1;
827 error:
828 M_PRINTF("Invalid tuples at offset 0x%08lx.\n", spdaddr - SPD_REGBASE);
829 return -1;
832 static int pcmcia_intr(void *unused)
834 USE_DEV9_REGS;
835 u16 cstc1, cstc2;
837 cstc1 = DEV9_REG(DEV9_R_1464);
838 cstc2 = DEV9_REG(DEV9_R_1466);
840 if (using_aif) {
841 if (_lh(0xb4000004) & 0x04)
842 _sh(0x04, 0xb4000004);
843 else
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? */
851 if (p_dev9_intr_cb)
852 p_dev9_intr_cb(1);
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) {
861 if (p_dev9_intr_cb)
862 p_dev9_intr_cb(0);
865 DEV9_REG(DEV9_R_147E) = 1;
866 DEV9_REG(DEV9_R_147E) = 0;
867 return 1;
870 static int pcmcia_init(void)
872 USE_DEV9_REGS;
873 int *mode;
874 int flags;
875 u16 cstc1, cstc2;
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) {
885 _sh(4, 0xb4000006);
886 using_aif = 1;
887 } else {
888 M_PRINTF("T10k detected, but AIF not detected.\n");
889 return 1;
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)
910 return 1;
911 } else {
912 _sw(0xe01a3043, SSBUS_R_1418);
915 if (smap_subsys_init() != 0)
916 return 1;
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");
925 return 0;
927 #endif
929 static void expbay_set_stat(int stat)
931 USE_DEV9_REGS;
932 DEV9_REG(DEV9_R_1464) = stat & 0x3f;
935 static int expbay_device_probe()
937 USE_DEV9_REGS;
938 return (DEV9_REG(DEV9_R_1462) & 0x01) ? -1 : 0;
941 static int expbay_device_reset(void)
943 USE_DEV9_REGS;
945 if (expbay_device_probe() < 0)
946 return -1;
948 DEV9_REG(DEV9_R_POWER) = (DEV9_REG(DEV9_R_POWER) & ~1) | 0x04; /* power on */
949 DelayThread(500000);
951 DEV9_REG(DEV9_R_1460) = DEV9_REG(DEV9_R_1460) | 0x01;
952 DEV9_REG(DEV9_R_POWER) = DEV9_REG(DEV9_R_POWER) | 0x01;
953 DelayThread(500000);
954 return 0;
957 static int expbay_intr(void *unused)
959 USE_DEV9_REGS;
961 if (p_dev9_intr_cb)
962 p_dev9_intr_cb(0);
964 DEV9_REG(DEV9_R_1466) = 1;
965 DEV9_REG(DEV9_R_1466) = 0;
966 return 1;
969 static int expbay_init(void)
971 USE_DEV9_REGS;
972 int flags;
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)
984 return 1;
987 if (smap_subsys_init() != 0)
988 return 1;
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");
997 return 0;
1000 #ifdef POWEROFF
1001 static void dev9x_on_shutdown(void*p)
1003 M_PRINTF("shutdown\n");
1004 dev9IntrDisable(-1);
1005 dev9Shutdown();
1007 #endif