PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
ps2dev9.c
Go to the documentation of this file.
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.
9*/
10
16#include <types.h>
17#include <defs.h>
18#include <loadcore.h>
19#include <intrman.h>
20#include <iomanX.h>
21#include <dmacman.h>
22#include <thbase.h>
23#include <thsemap.h>
24#include <stdio.h>
25#include <sysclib.h>
26#include <dev9.h>
27#ifdef DEV9_ENABLE_AIF
28#include <aifdev9.h>
29#endif
30
31#include <aifregs.h>
32#include <dev9regs.h>
33#include <speedregs.h>
34#include <smapregs.h>
35
36#define MODNAME "dev9"
37#define DRIVERNAME "dev9"
38// This is version from last SDK 3.1.0
39IRX_ID(MODNAME, 2, 8);
40
41#define M_PRINTF(format, args...) \
42 printf(MODNAME ": " format, ##args)
43
44#define VERSION "1.0"
45#define BANNER "\nDEV9 device driver v%s - Copyright (c) 2003 Marcus R. Brown\n\n"
46
47/* SSBUS registers. */
48#define SSBUS_R_1418 0xbf801418
49#define SSBUS_R_141c 0xbf80141c
50#define SSBUS_R_1420 0xbf801420
51
52static int semaAttrGlobal; /* Semaphore attribute value to use. */
53static const char *mod_name; /* Module name. */
54static int dev9type = -1; /* 0 for PCMCIA, 1 for expansion bay */
55static int using_aif = 0; /* 1 if using AIF on a T10K */
56
57static int dma_lock_sem; /* used to arbitrate DMA */
58
59enum PC_CARD_TYPE {
60 PC_CARD_TYPE_NONE = 0,
61 PC_CARD_TYPE_PCMCIA,
62 PC_CARD_TYPE_CARDBUS,
63};
64
65enum PC_CARD_VOLTAGE {
66 PC_CARD_VOLTAGE_INVALID = 0,
67 PC_CARD_VOLTAGE_3V,
68 PC_CARD_VOLTAGE_5V,
69 PC_CARD_VOLTAGE_04h
70};
71
72static int pcic_cardtype; /* Translated value of bits 0-1 of 0xbf801462 */
73static int pcic_voltage; /* Translated value of bits 2-3 of 0xbf801462 */
74
75static s16 eeprom_data[5]; /* 2-byte EEPROM status (0/-1 = invalid, 1 = valid),
76 6-byte MAC address,
77 2-byte MAC address checksum. */
78
79typedef int (*dev9IntrDispatchCb_t)(int flag);
80static dev9IntrDispatchCb_t p_dev9_intr_cb = NULL;
81static void dev9RegisterIntrDispatchCb(dev9IntrDispatchCb_t callback);
82
83/* Each driver can register callbacks that correspond to each bit of the
84 SMAP interrupt status register (0xbx000028). */
85static dev9_intr_cb_t dev9_intr_cbs[16];
86#ifdef DEV9_ENABLE_AIF
87static aif_intr_cb_t aif_intr_cbs[AIF_INUM_COUNT];
88#endif
89
90static dev9_shutdown_cb_t dev9_shutdown_cbs[16];
91#ifdef DEV9_ENABLE_AIF
92static dev9_shutdown_cb_t aif_shutdown_cbs[AIF_INUM_COUNT];
93#endif
94
95static dev9_dma_cb_t dev9_predma_cbs[4], dev9_postdma_cbs[4];
96
97static u8 dev9_has_dvr_capability = 0;
98
99static int dev9_intr_dispatch(int flag);
100
101static void dev9_set_stat(int stat);
102static int dev9_ssbus_mode(int mode);
103static int dev9_device_probe(void);
104static int dev9_device_reset(void);
105static int dev9_card_find_manfid(u32 manfid);
106
107static int read_eeprom_data(void);
108static int dev9_init(int sema_attr);
109static int speed_device_init(void);
110
111static void pcmcia_set_stat(int stat);
112static int pcic_ssbus_mode(int mode);
113static int pcmcia_device_probe(void);
114static int pcmcia_device_reset(void);
115static int card_find_manfid(u32 manfid);
116static int pcmcia_init(int sema_attr);
117
118static void expbay_set_stat(int stat);
119static int expbay_device_probe(void);
120static int expbay_device_reset(void);
121static int expbay_init(int sema_attr);
122
123extern struct irx_export_table _exp_dev9;
124
125static int dev9x_dummy(void)
126{
127 return 0;
128}
129
130static int dev9x_devctl(iop_file_t *f, const char *name, int cmd, void *args, unsigned int arglen, void *buf, unsigned int buflen)
131{
132 (void)f;
133 (void)name;
134 (void)arglen;
135 (void)buf;
136 (void)buflen;
137 switch (cmd) {
138 case DDIOC_MODEL:
139 return dev9type;
140 case DDIOC_OFF:
141 Dev9CardStop();
142 return 0;
143 case DDIOC_SETPIO3:
144 dev9ControlPIO3(((u32 *)args)[0]);
145 return 0;
146 case DDIOC_LED2CTL:
147 dev9LED2Ctl(((u32 *)args)[0]);
148 return 0;
149 default:
150 return 0;
151 }
152}
153
154static iop_device_ops_t dev9x_ops =
155 {
156 (void *)&dev9x_dummy,
157 (void *)&dev9x_dummy,
158 (void *)&dev9x_dummy,
159 (void *)&dev9x_dummy,
160 (void *)&dev9x_dummy,
161 (void *)&dev9x_dummy,
162 (void *)&dev9x_dummy,
163 (void *)&dev9x_dummy,
164 (void *)&dev9x_dummy,
165 (void *)&dev9x_dummy,
166 (void *)&dev9x_dummy,
167 (void *)&dev9x_dummy,
168 (void *)&dev9x_dummy,
169 (void *)&dev9x_dummy,
170 (void *)&dev9x_dummy,
171 (void *)&dev9x_dummy,
172 (void *)&dev9x_dummy,
173 (void *)&dev9x_dummy,
174 (void *)&dev9x_dummy,
175 (void *)&dev9x_dummy,
176 (void *)&dev9x_dummy,
177 (void *)&dev9x_dummy,
178 (void *)&dev9x_dummy,
179 &dev9x_devctl,
180 (void *)&dev9x_dummy,
181 (void *)&dev9x_dummy,
182 (void *)&dev9x_dummy,
183};
184
185static iop_device_t dev9x_device =
186 {
187 "dev9x",
188 IOP_DT_FS | IOP_DT_FSEXT,
189 1,
190 "DEV9",
191 &dev9x_ops,
192};
193
194static int print_help(void)
195{ // The original made a printf() call for each line.
196 printf("Usage:\n"
197 " %s [-sa] <attribute>]\n"
198 " -sa You can specify attibute of sempahore for queuing thread.\n"
199 " List of possible <attribute>:\n"
200 " SA_THPRI(default), SA_THFIFO\n",
201 mod_name);
202
203 return MODULE_NO_RESIDENT_END;
204}
205
206int _start(int argc, char *argv[])
207{
208 USE_DEV9_REGS;
209 const char *pModName;
210 int idx, res;
211 u16 dev9hw;
212
213 semaAttrGlobal = SA_THPRI;
214
215 printf(BANNER, VERSION);
216
217 mod_name = (pModName = strrchr(argv[0], '/')) != NULL ? pModName + 1 : argv[0];
218
219 for (--argc, ++argv; argc > 0; argc--, argv++) {
220 if ((*argv)[0] != '-')
221 break;
222
223 if (strcmp("-sa", *argv) == 0) {
224 --argc;
225 ++argv;
226 if (argc > 0) {
227 if (strcmp("SA_THFIFO", *argv) == 0) {
228 semaAttrGlobal = SA_THFIFO;
229 } else if (strcmp("SA_THPRI", *argv) == 0) {
230 semaAttrGlobal = SA_THPRI;
231 } else {
232 return print_help();
233 }
234 } else {
235 return print_help();
236 }
237 } else {
238 return print_help();
239 }
240 }
241
242 for (idx = 0; idx < 16; idx++)
243 dev9_shutdown_cbs[idx] = NULL;
244
245#ifdef DEV9_ENABLE_AIF
246 for (idx = 0; idx < AIF_INUM_COUNT; idx++)
247 aif_shutdown_cbs[idx] = NULL;
248#endif
249
250 dev9hw = DEV9_REG(DEV9_R_REV) & 0xf0;
251 if (dev9hw == 0x20) { /* CXD9566 (PCMCIA) */
252 dev9type = DEV9_TYPE_PCMCIA;
253 M_PRINTF("CXD9566 detected.\n");
254 res = pcmcia_init(semaAttrGlobal);
255 } else if (dev9hw == 0x30) { /* CXD9611 (Expansion Bay) */
256 dev9type = DEV9_TYPE_EXPBAY;
257 M_PRINTF("CXD9611 detected.\n");
258 res = expbay_init(semaAttrGlobal);
259 } else {
260 M_PRINTF("unknown dev9 hardware.\n");
261 res = MODULE_NO_RESIDENT_END;
262 }
263
264 if (res)
265 return res;
266
267 DelDrv(dev9x_device.name);
268 if (AddDrv(&dev9x_device) != 0) {
269 return MODULE_NO_RESIDENT_END;
270 }
271
272 return MODULE_RESIDENT_END;
273}
274
275int _exit(void) { return MODULE_RESIDENT_END; }
276
277/* Export 4 */
278void SpdRegisterIntrHandler(int intr, dev9_intr_cb_t cb)
279{
280 dev9_intr_cbs[intr] = cb;
281}
282
283/* Export 12 */
284void dev9RegisterPreDmaCb(int ctrl, dev9_dma_cb_t cb)
285{
286 dev9_predma_cbs[ctrl] = cb;
287}
288
289/* Export 13 */
290void dev9RegisterPostDmaCb(int ctrl, dev9_dma_cb_t cb)
291{
292 dev9_postdma_cbs[ctrl] = cb;
293}
294
295// flag is 1 if a card (pcmcia) was removed or added
296static int dev9_intr_dispatch(int flag)
297{
298 USE_SPD_REGS;
299 int i, bit;
300
301 if (flag) {
302 for (i = 0; i < 16; i++)
303 if (dev9_intr_cbs[i] != NULL)
304 dev9_intr_cbs[i](flag);
305 }
306
307 while (SPD_REG16(SPD_R_INTR_STAT) & SPD_REG16(SPD_R_INTR_MASK)) {
308 for (i = 0; i < 16; i++) {
309 if (dev9_intr_cbs[i] != NULL) {
310 bit = (SPD_REG16(SPD_R_INTR_STAT) &
311 SPD_REG16(SPD_R_INTR_MASK)) >>
312 i;
313 if (bit & 0x01)
314 dev9_intr_cbs[i](flag);
315 }
316 }
317 }
318
319 return 0;
320}
321
322static void dev9_set_stat(int stat)
323{
324 switch (dev9type) {
325 case DEV9_TYPE_PCMCIA:
326 pcmcia_set_stat(stat);
327 break;
328 case DEV9_TYPE_EXPBAY:
329 expbay_set_stat(stat);
330 break;
331 }
332}
333
334static int dev9_ssbus_mode(int mode)
335{
336 switch (dev9type) {
337 case DEV9_TYPE_PCMCIA:
338 return pcic_ssbus_mode(mode);
339 case DEV9_TYPE_EXPBAY:
340 return 0;
341 }
342
343 return -1;
344}
345
346static int dev9_device_probe(void)
347{
348 switch (dev9type) {
349 case DEV9_TYPE_PCMCIA:
350 return pcmcia_device_probe();
351 case DEV9_TYPE_EXPBAY:
352 return expbay_device_probe();
353 }
354
355 return -1;
356}
357
358static int dev9_device_reset(void)
359{
360 switch (dev9type) {
361 case DEV9_TYPE_PCMCIA:
362 return pcmcia_device_reset();
363 case DEV9_TYPE_EXPBAY:
364 return expbay_device_reset();
365 }
366
367 return -1;
368}
369
370/* Export 6 */
371void Dev9CardStop(void)
372{
373 int idx;
374 USE_DEV9_REGS;
375
376 for (idx = 0; idx < 16; idx++)
377 if (dev9_shutdown_cbs[idx])
378 dev9_shutdown_cbs[idx]();
379
380#ifdef DEV9_ENABLE_AIF
381 for (idx = 0; idx < AIF_INUM_COUNT; idx++)
382 if (aif_shutdown_cbs[idx])
383 aif_shutdown_cbs[idx]();
384#endif
385
386 if (dev9type == DEV9_TYPE_PCMCIA) { /* PCMCIA */
387 DEV9_REG(DEV9_R_POWER) = 0;
388 DEV9_REG(DEV9_R_1474) = 0;
389 } else if (dev9type == DEV9_TYPE_EXPBAY) {
390 DEV9_REG(DEV9_R_1466) = 1;
391 DEV9_REG(DEV9_R_1464) = 0;
392 DEV9_REG(DEV9_R_1460) = DEV9_REG(DEV9_R_1464);
393 DEV9_REG(DEV9_R_POWER) = DEV9_REG(DEV9_R_POWER) & ~4;
394 DEV9_REG(DEV9_R_POWER) = DEV9_REG(DEV9_R_POWER) & ~1;
395 }
396 DelayThread(1000000);
397}
398
399static int dev9_card_find_manfid(u32 manfid)
400{
401 switch (dev9type) {
402 case DEV9_TYPE_PCMCIA:
403 return card_find_manfid(manfid);
404 case DEV9_TYPE_EXPBAY:
405 return 0;
406 }
407
408 return -1;
409}
410
411/* Export 7 */
412void SpdIntrEnable(int mask)
413{
414 USE_SPD_REGS;
415 int flags;
416
417 CpuSuspendIntr(&flags);
418 SPD_REG16(SPD_R_INTR_MASK) = SPD_REG16(SPD_R_INTR_MASK) | mask;
419 CpuResumeIntr(flags);
420}
421
422/* Export 8 */
423void SpdIntrDisable(int mask)
424{
425 USE_SPD_REGS;
426 int flags;
427
428 CpuSuspendIntr(&flags);
429 SPD_REG16(SPD_R_INTR_MASK) = SPD_REG16(SPD_R_INTR_MASK) & ~mask;
430 CpuResumeIntr(flags);
431}
432
433/* Export 5 */
434int SpdDmaTransfer(int device, void *buf, int bcr, int dir)
435{
436 USE_SPD_REGS;
437 volatile iop_dmac_chan_t *dev9_chan = (iop_dmac_chan_t *)DEV9_DMAC_BASE;
438 int res, dmactrl, OldState;
439
440 if (device >= 4) {
441 return -1;
442 } else if (device >= 2) {
443 if (dev9_predma_cbs[device] == NULL)
444 return -1;
445 if (dev9_postdma_cbs[device] == NULL)
446 return -1;
447 }
448
449 if ((res = WaitSema(dma_lock_sem)) < 0)
450 return res;
451
452 switch (device) {
453 case 0:
454 dmactrl = 0;
455 break;
456 case 1:
457 dmactrl = 1;
458 break;
459#ifdef DEV9_PSX_SUPPORT
460 // Used for the PSX
461 case 2:
462 dmactrl = 0x10;
463 break;
464 case 3:
465 dmactrl = 0x20;
466 break;
467#endif
468 default:
469 dmactrl = 0;
470 }
471
472 SPD_REG16(SPD_R_DMA_CTRL) = (SPD_REG16(SPD_R_REV_1) < 17) ? (dmactrl & 0x03) | 0x04 : dmactrl | 0x06;
473
474 if (dev9_predma_cbs[device])
475 dev9_predma_cbs[device](bcr, dir);
476
477 dev9_chan->madr = (u32)buf;
478
479 /* Older versions of DEV9 do not suspend interrupts. Not sure why this must be done though. */
480 CpuSuspendIntr(&OldState);
481 dev9_chan->bcr = bcr;
482 dev9_chan->chcr = DMAC_CHCR_30 | DMAC_CHCR_TR | DMAC_CHCR_CO | (dir & DMAC_CHCR_DR);
483 CpuResumeIntr(OldState);
484
485 /* Wait for DMA to complete. Do not use a semaphore as thread switching hurts throughput greatly. */
486 while (dev9_chan->chcr & DMAC_CHCR_TR) {}
487
488 if (dev9_postdma_cbs[device])
489 dev9_postdma_cbs[device](bcr, dir);
490
491 SignalSema(dma_lock_sem);
492 return 0;
493}
494
495static int read_eeprom_data(void)
496{
497 USE_SPD_REGS;
498 int i, j, res = -2;
499 u8 val;
500
501 if (eeprom_data[0] < 0)
502 goto out;
503
504 SPD_REG8(SPD_R_PIO_DIR) = 0xe0 | (dev9_has_dvr_capability ? 7 : 1);
505 DelayThread(1);
506 SPD_REG8(SPD_R_PIO_DATA) = 0x80;
507 DelayThread(1);
508
509 for (i = 0; i < 2; i++) {
510 SPD_REG8(SPD_R_PIO_DATA) = 0xa0;
511 DelayThread(1);
512 SPD_REG8(SPD_R_PIO_DATA) = 0xe0;
513 DelayThread(1);
514 }
515 for (i = 0; i < 7; i++) {
516 SPD_REG8(SPD_R_PIO_DATA) = 0x80;
517 DelayThread(1);
518 SPD_REG8(SPD_R_PIO_DATA) = 0xc0;
519 DelayThread(1);
520 }
521 SPD_REG8(SPD_R_PIO_DATA) = 0xc0;
522 DelayThread(1);
523
524 val = SPD_REG8(SPD_R_PIO_DATA);
525 DelayThread(1);
526 if (val & 0x10) { /* Error. */
527 SPD_REG8(SPD_R_PIO_DATA) = 0;
528 DelayThread(1);
529 res = -1;
530 eeprom_data[0] = 0;
531 goto out;
532 }
533
534 SPD_REG8(SPD_R_PIO_DATA) = 0x80;
535 DelayThread(1);
536
537 /* Read the MAC address and checksum from the EEPROM. */
538 for (i = 0; i < 4; i++) {
539 eeprom_data[i + 1] = 0;
540
541 for (j = 15; j >= 0; j--) {
542 SPD_REG8(SPD_R_PIO_DATA) = 0xc0;
543 DelayThread(1);
544 val = SPD_REG8(SPD_R_PIO_DATA);
545 if (val & 0x10)
546 eeprom_data[i + 1] |= (1 << j);
547 SPD_REG8(SPD_R_PIO_DATA) = 0x80;
548 DelayThread(1);
549 }
550 }
551
552 SPD_REG8(SPD_R_PIO_DATA) = 0;
553 DelayThread(1);
554 eeprom_data[0] = 1; /* The EEPROM data is valid. */
555 res = 0;
556
557out:
558 SPD_REG8(SPD_R_PIO_DIR) = dev9_has_dvr_capability ? 7 : 1;
559 return res;
560}
561
562/* Export 9 */
563int SpdGetEthernetID(u16 *buf)
564{
565 int i;
566
567 if (!eeprom_data[0])
568 return -1;
569 if (eeprom_data[0] < 0)
570 return -2;
571
572 /* We only return the MAC address and checksum. */
573 for (i = 0; i < 4; i++)
574 buf[i] = eeprom_data[i + 1];
575
576 return 0;
577}
578
579// Exerpt from Wisi's SPEED.txt:
580// 1:0 Dev9 LED Control. 0=On/1=Off.
581// Clearing either to 0 will light the LED.
582// Each is connected to the cathode of a diode, sharing a common anode.
583// The anode has a 10kohm pull-up to Vcc, and is connected to the base of an PNP transistor,
584// with collector grounded and emitter, connecting through a 240ohm resistor to the ACS_LED
585// pin (90) of the Expansion Bay connector. It connects to the cathode of the HDD Activity LED
586// in the PS2, the anode of which connects through 180ohm resistor to +5V.
587
588// The specific LED part used is the Citizen CITILED CL-200TLY-C, which has a "Lemon Yellow" color.
589
590/* Export 10 */
591void SpdSetLED(int ctl)
592{
593 USE_SPD_REGS;
594 if (dev9_has_dvr_capability) {
595 SPD_REG8(SPD_R_PIO_DIR) |= 1;
596 SPD_REG8(SPD_R_PIO_DATA) = (SPD_REG8(SPD_R_PIO_DATA) & 0xE) | (ctl ? 0 : 1);
597 } else {
598 SPD_REG8(SPD_R_PIO_DATA) = (ctl == 0);
599 }
600}
601
602/* Export 15 */
603void dev9LED2Ctl(int ctl)
604{
605 if (dev9_has_dvr_capability) {
606 USE_SPD_REGS;
607 SPD_REG8(SPD_R_PIO_DIR) |= 2;
608 DelayThread(1);
609 SPD_REG8(SPD_R_PIO_DATA) = (SPD_REG8(SPD_R_PIO_DATA) & 0xD) | (ctl ? 0 : 2);
610 DelayThread(1);
611 }
612}
613
614// Exerpt from Wisi's SPEED.txt:
615// 3:2 On SCPH-70000, each is connected through 10kohm R to Vcc, so they were inputs once.
616// On the SCPH-10350 Network Adapter - as well.
617
618/* Export 14 */
619void dev9ControlPIO3(int ctl)
620{
621 if (dev9_has_dvr_capability) {
622 USE_SPD_REGS;
623 SPD_REG8(SPD_R_PIO_DIR) |= 4;
624 DelayThread(1);
625 SPD_REG8(SPD_R_PIO_DATA) = (SPD_REG8(SPD_R_PIO_DATA) & 0xB) | (ctl ? 0 : 4);
626 DelayThread(1);
627 }
628}
629
630static void dev9RegisterIntrDispatchCb(dev9IntrDispatchCb_t callback)
631{
632 p_dev9_intr_cb = callback;
633}
634
635/* Export 11 */
636int Dev9RegisterPowerOffHandler(int idx, dev9_shutdown_cb_t cb)
637{
638 if (idx < 16) {
639 dev9_shutdown_cbs[idx] = cb;
640 return 0;
641 }
642 return -1;
643}
644
645static int dev9_init(int sema_attr)
646{
647 iop_sema_t sema;
648 int i, flags;
649
650 sema.attr = sema_attr;
651 sema.initial = 1;
652 sema.max = 1;
653 if ((dma_lock_sem = CreateSema(&sema)) < 0)
654 return -1;
655
656 CpuSuspendIntr(&flags);
657 /* Enable the DEV9 DMAC channel. */
658 dmac_set_dpcr2(dmac_get_dpcr2() | 0x80);
659 CpuResumeIntr(flags);
660
661 /* Not quite sure what this enables yet. */
662 dev9_set_stat(0x103);
663
664 /* Disable all device interrupts. */
665 SpdIntrDisable(0xffff);
666
667#ifdef DEV9_ENABLE_AIF
668 if (using_aif)
669 aifIntrDisable(0xffff);
670#endif
671
672 /* Register interrupt dispatch callback handler. */
673 dev9RegisterIntrDispatchCb(&dev9_intr_dispatch);
674
675 /* Reset the SMAP interrupt callback table. */
676 for (i = 0; i < 16; i++)
677 dev9_intr_cbs[i] = NULL;
678#ifdef DEV9_ENABLE_AIF
679 for (i = 0; i < AIF_INUM_COUNT; i++)
680 aif_intr_cbs[i] = NULL;
681#endif
682
683 for (i = 0; i < 4; i++) {
684 dev9_predma_cbs[i] = NULL;
685 dev9_postdma_cbs[i] = NULL;
686 }
687
688 /* Read in the MAC address. */
689 read_eeprom_data();
690
691 dev9LED2Ctl(0);
692 dev9ControlPIO3(0);
693
694 /* Turn the LED off. */
695 SpdSetLED(0);
696 return 0;
697}
698
699#ifndef DEV9_SKIP_SMAP_INIT
700static int dev9_smap_read_phy(volatile u8 *emac3_regbase, unsigned int address, unsigned int *data)
701{
702 unsigned int i, PHYRegisterValue;
703 int result;
704
705 PHYRegisterValue = (address & SMAP_E3_PHY_REG_ADDR_MSK) | SMAP_E3_PHY_READ | ((SMAP_DsPHYTER_ADDRESS & SMAP_E3_PHY_ADDR_MSK) << SMAP_E3_PHY_ADDR_BITSFT);
706
707 i = 0;
708 result = 0;
709 SMAP_EMAC3_SET(SMAP_R_EMAC3_STA_CTRL, PHYRegisterValue);
710
711 do {
712 if (SMAP_EMAC3_GET(SMAP_R_EMAC3_STA_CTRL) & SMAP_E3_PHY_OP_COMP) {
713 if (SMAP_EMAC3_GET(SMAP_R_EMAC3_STA_CTRL) & SMAP_E3_PHY_OP_COMP) {
714 if ((result = SMAP_EMAC3_GET(SMAP_R_EMAC3_STA_CTRL)) & SMAP_E3_PHY_OP_COMP) {
715 result >>= SMAP_E3_PHY_DATA_BITSFT;
716 break;
717 }
718 }
719 }
720
721 DelayThread(1000);
722 i++;
723 } while (i < 100);
724
725 if (i >= 100) {
726 return 1;
727 } else {
728 *data = result;
729 return 0;
730 }
731}
732
733static int dev9_smap_write_phy(volatile u8 *emac3_regbase, unsigned char address, unsigned short int value)
734{
735 unsigned int i, PHYRegisterValue;
736
737 PHYRegisterValue = (address & SMAP_E3_PHY_REG_ADDR_MSK) | SMAP_E3_PHY_WRITE | ((SMAP_DsPHYTER_ADDRESS & SMAP_E3_PHY_ADDR_MSK) << SMAP_E3_PHY_ADDR_BITSFT);
738 PHYRegisterValue |= ((unsigned int)value) << SMAP_E3_PHY_DATA_BITSFT;
739
740 i = 0;
741 SMAP_EMAC3_SET(SMAP_R_EMAC3_STA_CTRL, PHYRegisterValue);
742
743 for (; !(SMAP_EMAC3_GET(SMAP_R_EMAC3_STA_CTRL) & SMAP_E3_PHY_OP_COMP); i++) {
744 DelayThread(1000);
745 if (i >= 100)
746 break;
747 }
748
749 return ((i >= 100) ? 1 : 0);
750}
751
752static int dev9_smap_init(void)
753{
754 unsigned int value;
755 USE_SPD_REGS;
756 USE_SMAP_REGS;
757 USE_SMAP_EMAC3_REGS;
758 USE_SMAP_TX_BD;
759 USE_SMAP_RX_BD;
760 int i;
761
762 // Do not perform SMAP initialization if the SPEED device does not have such an interface
763 if (!(SPD_REG16(SPD_R_REV_3) & SPD_CAPS_SMAP)
764#ifdef DEV9_GAMESTAR_WORKAROUND
765 /* If this adaptor is a compatible adaptor, do not initialize SMAP.
766 Official adaptors appear to have a 0x0001 set for this register, but not compatibles.
767 While official I/O to this register are 8-bit, some compatibles have a 0x01 for the lower 8-bits,
768 but the upper 8-bits contain some random value. Hence perform a 16-bit read instead. */
769 || (SPD_REG16(0x20) != 1)
770#endif
771 )
772 return 0;
773
774 SMAP_REG8(SMAP_R_TXFIFO_CTRL) = SMAP_TXFIFO_RESET;
775 for (i = 9; SMAP_REG8(SMAP_R_TXFIFO_CTRL) & SMAP_TXFIFO_RESET; i--) {
776 if (i <= 0)
777 return 1;
778 DelayThread(1000);
779 }
780
781 SMAP_REG8(SMAP_R_RXFIFO_CTRL) = SMAP_RXFIFO_RESET;
782 for (i = 9; SMAP_REG8(SMAP_R_RXFIFO_CTRL) & SMAP_RXFIFO_RESET; i--) {
783 if (i <= 0)
784 return 1;
785 DelayThread(1000);
786 }
787
788 SMAP_EMAC3_SET(SMAP_R_EMAC3_MODE0, SMAP_E3_SOFT_RESET);
789 for (i = 9; SMAP_EMAC3_GET(SMAP_R_EMAC3_MODE0) & SMAP_E3_SOFT_RESET; i--) {
790 if (i <= 0)
791 return 3;
792 DelayThread(1000);
793 }
794
795 // Unlike the SMAP driver, this reset operation is done in big-endian.
796 if (SPD_REG16(SPD_R_REV_1) >= 0x11)
797 SMAP_REG8(SMAP_R_BD_MODE) = SMAP_BD_SWAP;
798
799 for (i = 0; i < SMAP_BD_MAX_ENTRY; i++) {
800 tx_bd[i].ctrl_stat = 0;
801 tx_bd[i].reserved = 0;
802 tx_bd[i].length = 0;
803 tx_bd[i].pointer = 0;
804 }
805
806 for (i = 0; i < SMAP_BD_MAX_ENTRY; i++) {
807 rx_bd[i].ctrl_stat = 0x80; // SMAP_BD_RX_EMPTY
808 rx_bd[i].reserved = 0;
809 rx_bd[i].length = 0;
810 rx_bd[i].pointer = 0;
811 }
812
813 SMAP_REG16(SMAP_R_INTR_CLR) = SMAP_INTR_BITMSK;
814 if (SPD_REG16(SPD_R_REV_1) < 0x11)
815 SPD_REG8(0x100) = 1;
816
817 SMAP_EMAC3_SET(SMAP_R_EMAC3_MODE1, SMAP_E3_FDX_ENABLE | SMAP_E3_IGNORE_SQE | SMAP_E3_MEDIA_100M | SMAP_E3_RXFIFO_2K | SMAP_E3_TXFIFO_1K | SMAP_E3_TXREQ0_MULTI | SMAP_E3_TXREQ1_SINGLE);
818 SMAP_EMAC3_SET(SMAP_R_EMAC3_TxMODE1, 7 << SMAP_E3_TX_LOW_REQ_BITSFT | 15 << SMAP_E3_TX_URG_REQ_BITSFT);
819 SMAP_EMAC3_SET(SMAP_R_EMAC3_RxMODE, SMAP_E3_RX_RX_RUNT_FRAME | SMAP_E3_RX_RX_FCS_ERR | SMAP_E3_RX_RX_TOO_LONG_ERR | SMAP_E3_RX_RX_IN_RANGE_ERR | SMAP_E3_RX_PROP_PF | SMAP_E3_RX_PROMISC);
820 SMAP_EMAC3_SET(SMAP_R_EMAC3_INTR_STAT, SMAP_E3_INTR_TX_ERR_0 | SMAP_E3_INTR_SQE_ERR_0 | SMAP_E3_INTR_DEAD_0);
821 SMAP_EMAC3_SET(SMAP_R_EMAC3_INTR_ENABLE, SMAP_E3_INTR_TX_ERR_0 | SMAP_E3_INTR_SQE_ERR_0 | SMAP_E3_INTR_DEAD_0);
822 SMAP_EMAC3_SET(SMAP_R_EMAC3_ADDR_HI, 0);
823 SMAP_EMAC3_SET(SMAP_R_EMAC3_ADDR_LO, 0);
824 SMAP_EMAC3_SET(SMAP_R_EMAC3_PAUSE_TIMER, 0xFFFF);
825 SMAP_EMAC3_SET(SMAP_R_EMAC3_INTER_FRAME_GAP, 4);
826 SMAP_EMAC3_SET(SMAP_R_EMAC3_TX_THRESHOLD, 12 << SMAP_E3_TX_THRESHLD_BITSFT);
827 SMAP_EMAC3_SET(SMAP_R_EMAC3_RX_WATERMARK, 16 << SMAP_E3_RX_LO_WATER_BITSFT | 128 << SMAP_E3_RX_HI_WATER_BITSFT);
828
829 dev9_smap_write_phy(emac3_regbase, SMAP_DsPHYTER_BMCR, SMAP_PHY_BMCR_RST);
830 for (i = 9;; i--) {
831 if (dev9_smap_read_phy(emac3_regbase, SMAP_DsPHYTER_BMCR, &value))
832 return 4;
833 if (!(value & SMAP_PHY_BMCR_RST))
834 break;
835 if (i <= 0)
836 return 5;
837 }
838
839 dev9_smap_write_phy(emac3_regbase, SMAP_DsPHYTER_BMCR, SMAP_PHY_BMCR_LPBK | SMAP_PHY_BMCR_100M | SMAP_PHY_BMCR_DUPM);
840 DelayThread(10000);
841 SMAP_EMAC3_SET(SMAP_R_EMAC3_MODE0, SMAP_E3_TXMAC_ENABLE | SMAP_E3_RXMAC_ENABLE);
842 value = SMAP_REG16(SMAP_R_TXFIFO_WR_PTR) + SMAP_TX_BASE;
843
844 for (i = 0; i < 0x5EA; i += 4)
845 SMAP_REG32(SMAP_R_TXFIFO_DATA) = i;
846
847 tx_bd[0].length = 0xEA05;
848 tx_bd[0].pointer = (value >> 8) | (value << 8);
849 SMAP_REG8(SMAP_R_TXFIFO_FRAME_INC) = 0;
850 tx_bd[0].ctrl_stat = 0x83; // SMAP_BD_TX_READY|SMAP_BD_TX_GENFCS|SMAP_BD_TX_GENPAD
851
852 SMAP_EMAC3_SET(SMAP_R_EMAC3_TxMODE0, SMAP_E3_TX_GNP_0);
853 for (i = 9;; i--) {
854 value = SPD_REG16(SPD_R_INTR_STAT);
855
856 if ((value & (SMAP_INTR_RXEND | SMAP_INTR_TXEND | SMAP_INTR_TXDNV)) == (SMAP_INTR_RXEND | SMAP_INTR_TXEND | SMAP_INTR_TXDNV))
857 break;
858 if (i <= 0)
859 return 6;
860 DelayThread(1000);
861 }
862 SMAP_EMAC3_SET(SMAP_R_EMAC3_MODE0, SMAP_E3_SOFT_RESET);
863
864 return 0;
865}
866#endif
867
868static int speed_device_init(void)
869{
870 USE_SPD_REGS;
871 const char *spdnames[] = {"(unknown)", "TS", "ES1", "ES2"};
872 int idx, res;
873 u16 spdrev;
874#ifndef DEV9_SKIP_SMAP_INIT
875 int i;
876#endif
877
878 eeprom_data[0] = 0;
879
880#ifndef DEV9_SKIP_SMAP_INIT
881 for (i = 0; i < 8; i++) {
882#endif
883 if (dev9_device_probe() < 0) {
884 M_PRINTF("No device.\n");
885#ifdef DEV9_ENABLE_AIF
886 return (using_aif ? 0 : -1);
887#else
888 return -1;
889#endif
890 }
891
892 dev9_device_reset();
893
894 /* Locate the SPEED Lite chip and get the bus ready for the
895 PCMCIA device. */
896 if ((res = dev9_card_find_manfid(0xf15300)))
897 M_PRINTF("SPEED Lite not found.\n");
898
899 if (!res && (res = dev9_ssbus_mode(5)))
900 M_PRINTF("Unable to change SSBUS mode.\n");
901
902 if (res) {
903 Dev9CardStop();
904 return -1;
905 }
906
907#ifndef DEV9_SKIP_SMAP_INIT
908 if ((res = dev9_smap_init()) == 0) {
909 break;
910 }
911
912 Dev9CardStop();
913 DelayThread(4500000);
914 }
915
916 if (res) {
917 M_PRINTF("SMAP initialization failed: %d\n", res);
918 eeprom_data[0] = -1;
919 }
920#endif
921
922 /* Print out the SPEED chip revision. */
923 spdrev = SPD_REG16(SPD_R_REV_1);
924 idx = (spdrev & 0xffff) - 14;
925 if (spdrev == 9)
926 idx = 1; /* TS */
927 else if (spdrev < 9 || (spdrev < 16 || spdrev > 17))
928 idx = 0; /* Unknown revision */
929
930 M_PRINTF("SPEED chip '%s', revision %0x\n", spdnames[idx], spdrev);
931 return 0;
932}
933
934static int pcic_get_cardtype(void)
935{
936 USE_DEV9_REGS;
937 u16 val = DEV9_REG(DEV9_R_1462) & 0x03;
938
939 if (val == 0)
940 return PC_CARD_TYPE_PCMCIA; /* 16-bit */
941 else if (val < 3) // If the bit pattern is either 10b or 01b
942 return PC_CARD_TYPE_CARDBUS; /* CardBus */
943 return PC_CARD_TYPE_NONE;
944}
945
946static int pcic_get_voltage(void)
947{
948 USE_DEV9_REGS;
949 u16 val = DEV9_REG(DEV9_R_1462) & 0x0c;
950
951 if (val == 0x04)
952 return PC_CARD_VOLTAGE_04h;
953 if (val == 0 || val == 0x08)
954 return PC_CARD_VOLTAGE_3V;
955 if (val == 0x0c)
956 return PC_CARD_VOLTAGE_5V;
957 return PC_CARD_VOLTAGE_INVALID;
958}
959
960static int pcic_power(int voltage, int flag)
961{
962 USE_DEV9_REGS;
963 u16 cstc1, cstc2;
964 u16 val = (voltage == 1) << 2;
965
966 DEV9_REG(DEV9_R_POWER) = 0;
967
968 if (voltage == 2)
969 val |= 0x08;
970 if (flag == 1)
971 val |= 0x10;
972
973 DEV9_REG(DEV9_R_POWER) = val;
974 DelayThread(22000);
975
976 if (DEV9_REG(DEV9_R_1462) & 0x100)
977 return 0;
978
979 DEV9_REG(DEV9_R_POWER) = 0;
980 DEV9_REG(DEV9_R_1464) = cstc1 = DEV9_REG(DEV9_R_1464);
981 DEV9_REG(DEV9_R_1466) = cstc2 = DEV9_REG(DEV9_R_1466);
982 return -1;
983}
984
985static void pcmcia_set_stat(int stat)
986{
987 USE_DEV9_REGS;
988 u16 val = stat & 0x01;
989
990 if (stat & 0x10)
991 val = 1;
992 if (stat & 0x02)
993 val |= 0x02;
994 if (stat & 0x20)
995 val |= 0x02;
996 if (stat & 0x04)
997 val |= 0x08;
998 if (stat & 0x08)
999 val |= 0x10;
1000 if (stat & 0x200)
1001 val |= 0x20;
1002 if (stat & 0x100)
1003 val |= 0x40;
1004 if (stat & 0x400)
1005 val |= 0x80;
1006 if (stat & 0x800)
1007 val |= 0x04;
1008 DEV9_REG(DEV9_R_1476) = val & 0xff;
1009}
1010
1011static int pcic_ssbus_mode(int mode)
1012{
1013 USE_DEV9_REGS;
1014 USE_SPD_REGS;
1015 u16 stat = DEV9_REG(DEV9_R_1474) & 7;
1016
1017 if (mode != 3 && mode != 5)
1018 return -1;
1019
1020 DEV9_REG(DEV9_R_1460) = 2;
1021 if (stat)
1022 return -1;
1023
1024 if (mode == 3) {
1025 DEV9_REG(DEV9_R_1474) = 1;
1026 DEV9_REG(DEV9_R_1460) = 1;
1027 SPD_REG8(0x20) = 1;
1028 DEV9_REG(DEV9_R_1474) = mode;
1029 } else if (mode == 5) {
1030 DEV9_REG(DEV9_R_1474) = mode;
1031 DEV9_REG(DEV9_R_1460) = 1;
1032 SPD_REG8(0x20) = 1;
1033 DEV9_REG(DEV9_R_1474) = 7;
1034 }
1035 _sw(0xe01a3043, SSBUS_R_1418);
1036
1037 DelayThread(5000);
1038 DEV9_REG(DEV9_R_POWER) = DEV9_REG(DEV9_R_POWER) & ~1;
1039 return 0;
1040}
1041
1042static int pcmcia_device_probe(void)
1043{
1044 const char *pcic_ct_names[] = {"No", "16-bit", "CardBus"};
1045 int voltage;
1046
1047 pcic_voltage = pcic_get_voltage();
1048 pcic_cardtype = pcic_get_cardtype();
1049 voltage = (pcic_voltage == PC_CARD_VOLTAGE_5V ? 5 : (pcic_voltage == PC_CARD_VOLTAGE_3V ? 3 : 0));
1050
1051 M_PRINTF("%s PCMCIA card detected. Vcc = %dV\n",
1052 pcic_ct_names[pcic_cardtype], voltage);
1053
1054 if (pcic_voltage == PC_CARD_VOLTAGE_04h || pcic_cardtype != PC_CARD_TYPE_PCMCIA)
1055 return -1;
1056
1057 return 0;
1058}
1059
1060static int pcmcia_device_reset(void)
1061{
1062 USE_DEV9_REGS;
1063 u16 cstc1, cstc2;
1064
1065 /* The card must be 16-bit (type 2?) */
1066 if ((DEV9_REG(DEV9_R_1462) & 0x03) != 0)
1067 return -1;
1068
1069 DEV9_REG(DEV9_R_147E) = 1;
1070 if (pcic_power(pcic_voltage, 1) < 0)
1071 return -1;
1072
1073 DEV9_REG(DEV9_R_POWER) = DEV9_REG(DEV9_R_POWER) | 0x02;
1074 DelayThread(500000);
1075
1076 DEV9_REG(DEV9_R_POWER) = DEV9_REG(DEV9_R_POWER) | 0x01;
1077 DEV9_REG(DEV9_R_1464) = cstc1 = DEV9_REG(DEV9_R_1464);
1078 DEV9_REG(DEV9_R_1466) = cstc2 = DEV9_REG(DEV9_R_1466);
1079 return 0;
1080}
1081
1082static int card_find_manfid(u32 manfid)
1083{
1084 USE_DEV9_REGS;
1085 USE_SPD_REGS;
1086 u32 spdaddr, spdend, next, tuple;
1087 u8 hdr, ofs;
1088
1089 DEV9_REG(DEV9_R_1460) = 2;
1090 _sw(0x1a00bb, SSBUS_R_1418);
1091
1092 /* Scan the card for the MANFID tuple. */
1093 spdaddr = 0;
1094 spdend = 0x1000;
1095 /* I hate this code, and it hates me. */
1096 while (spdaddr < spdend) {
1097 hdr = SPD_REG8(spdaddr) & 0xff;
1098 spdaddr += 2;
1099 if (!hdr)
1100 continue;
1101 if (hdr == 0xff)
1102 break;
1103 if (spdaddr >= spdend)
1104 goto error;
1105
1106 ofs = SPD_REG8(spdaddr) & 0xff;
1107 spdaddr += 2;
1108 if (ofs == 0xff)
1109 break;
1110
1111 next = spdaddr + (ofs * 2);
1112 if (next >= spdend)
1113 goto error;
1114
1115 if (hdr == 0x20) {
1116 if ((spdaddr + 8) >= spdend)
1117 goto error;
1118
1119 tuple = (SPD_REG8(spdaddr + 2) << 24) |
1120 (SPD_REG8(spdaddr) << 16) |
1121 (SPD_REG8(spdaddr + 6) << 8) |
1122 SPD_REG8(spdaddr + 4);
1123 if (manfid == tuple)
1124 return 0;
1125 M_PRINTF("MANFID 0x%08lx doesn't match expected 0x%08lx\n",
1126 tuple, manfid);
1127 return -1;
1128 }
1129 spdaddr = next;
1130 }
1131
1132 M_PRINTF("MANFID 0x%08lx not found.\n", manfid);
1133 return -1;
1134error:
1135 M_PRINTF("Invalid tuples at offset 0x%08lx.\n", spdaddr - SPD_REGBASE);
1136 return -1;
1137}
1138
1139static int pcmcia_intr(void *unused)
1140{
1141 USE_AIF_REGS;
1142 USE_DEV9_REGS;
1143 u16 cstc1, cstc2;
1144
1145 (void)unused;
1146
1147 cstc1 = DEV9_REG(DEV9_R_1464);
1148 cstc2 = DEV9_REG(DEV9_R_1466);
1149
1150 if (using_aif) {
1151 if (aif_regs[AIF_INTSR] & AIF_INTR_PCMCIA)
1152 aif_regs[AIF_INTCL] = AIF_INTR_PCMCIA;
1153 else
1154 return 0; /* Unknown interrupt. */
1155 }
1156
1157 /* Acknowledge the interrupt. */
1158 DEV9_REG(DEV9_R_1464) = cstc1;
1159 DEV9_REG(DEV9_R_1466) = cstc2;
1160 if (cstc1 & 0x03 || cstc2 & 0x03) { /* Card removed or added? */
1161 if (p_dev9_intr_cb)
1162 p_dev9_intr_cb(1);
1163
1164 /* Shutdown the card. */
1165 DEV9_REG(DEV9_R_POWER) = 0;
1166 DEV9_REG(DEV9_R_1474) = 0;
1167
1168 pcmcia_device_probe();
1169 }
1170 if (cstc1 & 0x80 || cstc2 & 0x80) {
1171 if (p_dev9_intr_cb)
1172 p_dev9_intr_cb(0);
1173 }
1174
1175 DEV9_REG(DEV9_R_147E) = 1;
1176 DEV9_REG(DEV9_R_147E) = 0;
1177 return 1;
1178}
1179
1180#ifdef DEV9_ENABLE_AIF
1181static int aif_pcmcia_intr_handler(void)
1182{
1183 USE_AIF_REGS;
1184
1185 aif_regs[AIF_INTCL] = AIF_INTR_PCMCIA;
1186 pcmcia_intr(NULL);
1187
1188 return 1;
1189}
1190
1191static int aif_intr(void *unused)
1192{
1193 USE_AIF_REGS;
1194 unsigned int i;
1195
1196 while ((aif_regs[AIF_INTSR] & aif_regs[AIF_INTEN]) != 0) {
1197 for (i = 0; i < AIF_INUM_COUNT; i++) {
1198 if ((aif_intr_cbs[i] != NULL) && ((aif_regs[AIF_INTSR] & aif_regs[AIF_INTEN]) & (1 << i))) {
1199 aif_intr_cbs[i]();
1200 }
1201 }
1202 }
1203
1204 return 1;
1205}
1206#endif
1207
1208
1209static int pcmcia_init(int sema_attr)
1210{
1211 USE_DEV9_REGS;
1212 USE_AIF_REGS;
1213 int *mode;
1214 int flags;
1215 u16 cstc1, cstc2;
1216
1217 _sw(0x51011, SSBUS_R_1420);
1218 _sw(0x1a00bb, SSBUS_R_1418);
1219 _sw(0xef1a3043, SSBUS_R_141c);
1220
1221 /* If we are a T10K, then we go through AIF. */
1222 if ((mode = QueryBootMode(6)) != NULL) {
1223 if ((*(u16 *)mode & 0xfe) == 0x60) {
1224 M_PRINTF("T10K detected.\n");
1225
1226 if (aif_regs[AIF_IDENT] == 0xa1) {
1227#ifdef DEV9_ENABLE_AIF
1228 M_PRINTF("AIF controller revision: %d.\n", aif_regs[AIF_REVISION]);
1229 aif_regs[AIF_INTCL] = 7; // Clear interrupts.
1230#else
1231 aif_regs[AIF_INTEN] = AIF_INTR_PCMCIA;
1232#endif
1233 using_aif = 1;
1234 } else {
1235 M_PRINTF("AIF not detected.\n");
1236 return 1;
1237 }
1238 }
1239 }
1240
1241 if (DEV9_REG(DEV9_R_POWER) == 0) {
1242 DEV9_REG(DEV9_R_POWER) = 0;
1243 DEV9_REG(DEV9_R_147E) = 1;
1244 DEV9_REG(DEV9_R_1460) = 0;
1245 DEV9_REG(DEV9_R_1474) = 0;
1246 DEV9_REG(DEV9_R_1464) = cstc1 = DEV9_REG(DEV9_R_1464);
1247 DEV9_REG(DEV9_R_1466) = cstc2 = DEV9_REG(DEV9_R_1466);
1248 DEV9_REG(DEV9_R_1468) = 0x10;
1249 DEV9_REG(DEV9_R_146A) = 0x90;
1250 DEV9_REG(DEV9_R_147C) = 1;
1251 DEV9_REG(DEV9_R_147A) = DEV9_REG(DEV9_R_147C);
1252
1253 pcic_voltage = pcic_get_voltage();
1254 pcic_cardtype = pcic_get_cardtype();
1255
1256 if (speed_device_init() != 0)
1257 return 1;
1258 } else {
1259 _sw(0xe01a3043, SSBUS_R_1418);
1260 }
1261
1262 if (dev9_init(sema_attr) != 0)
1263 return 1;
1264
1265 CpuSuspendIntr(&flags);
1266#ifdef DEV9_ENABLE_AIF
1267 if (using_aif) {
1268 RegisterIntrHandler(IOP_IRQ_DEV9, 1, &aif_intr, NULL);
1269 aifRegisterIntrCb(AIF_INUM_PCMCIA, &aif_pcmcia_intr_handler);
1270 aifIntrEnable(AIF_INTR_PCMCIA);
1271 } else
1272#endif
1273 {
1274 RegisterIntrHandler(IOP_IRQ_DEV9, 1, &pcmcia_intr, NULL);
1275 }
1276 EnableIntr(IOP_IRQ_DEV9);
1277 CpuResumeIntr(flags);
1278
1279 DEV9_REG(DEV9_R_147E) = 0;
1280
1281 if (RegisterLibraryEntries(&_exp_dev9) != 0)
1282 return 1;
1283
1284 M_PRINTF("CXD9566 (PCMCIA) driver start.\n");
1285 return 0;
1286}
1287
1288static void expbay_set_stat(int stat)
1289{
1290 USE_DEV9_REGS;
1291 DEV9_REG(DEV9_R_1464) = stat & 0x3f;
1292}
1293
1294static int expbay_device_probe(void)
1295{
1296 USE_DEV9_REGS;
1297 return (DEV9_REG(DEV9_R_1462) & 0x01) ? -1 : 0;
1298}
1299
1300static int expbay_device_reset(void)
1301{
1302 USE_DEV9_REGS;
1303
1304 if (expbay_device_probe() < 0)
1305 return -1;
1306
1307 DEV9_REG(DEV9_R_POWER) = (DEV9_REG(DEV9_R_POWER) & ~1) | 0x04; // power on
1308 DelayThread(500000);
1309
1310 DEV9_REG(DEV9_R_1460) = DEV9_REG(DEV9_R_1460) | 0x01;
1311 DEV9_REG(DEV9_R_POWER) = DEV9_REG(DEV9_R_POWER) | 0x01;
1312 DelayThread(500000);
1313 return 0;
1314}
1315
1316static int expbay_intr(void *unused)
1317{
1318 USE_DEV9_REGS;
1319
1320 (void)unused;
1321
1322 if (p_dev9_intr_cb)
1323 p_dev9_intr_cb(0);
1324
1325 if (!dev9_has_dvr_capability) {
1326 DEV9_REG(DEV9_R_1466) = 1;
1327 }
1328 DEV9_REG(DEV9_R_1466) = 0;
1329 return 1;
1330}
1331
1332static int expbay_init(int sema_attr)
1333{
1334 USE_DEV9_REGS;
1335 USE_SPD_REGS;
1336 int flags;
1337
1338 _sw(0x51011, SSBUS_R_1420);
1339 _sw(0xe01a3043, SSBUS_R_1418);
1340 _sw(0xef1a3043, SSBUS_R_141c);
1341
1342 if ((DEV9_REG(DEV9_R_POWER) & 0x04) == 0) { // if not already powered
1343 DEV9_REG(DEV9_R_1466) = 1;
1344 DEV9_REG(DEV9_R_1464) = 0;
1345 DEV9_REG(DEV9_R_1460) = DEV9_REG(DEV9_R_1464);
1346
1347 if (speed_device_init() != 0)
1348 return 1;
1349 }
1350
1351 /* Disable control of LED 2 and PIO 3 if the dev9 device does not have DVR capabilities. */
1352 dev9_has_dvr_capability = (SPD_REG16(SPD_R_REV_3) & SPD_CAPS_DVR) ? 1 : 0;
1353
1354 if (dev9_init(sema_attr) != 0)
1355 return 1;
1356
1357 CpuSuspendIntr(&flags);
1358 RegisterIntrHandler(IOP_IRQ_DEV9, 1, &expbay_intr, NULL);
1359 EnableIntr(IOP_IRQ_DEV9);
1360 CpuResumeIntr(flags);
1361
1362 DEV9_REG(DEV9_R_1466) = 0;
1363
1364 if (RegisterLibraryEntries(&_exp_dev9) != 0)
1365 return 1;
1366
1367 M_PRINTF("CXD9611 (SSBUS Buffer) driver start.\n");
1368 return 0;
1369}
1370
1371#ifdef DEV9_ENABLE_AIF
1372int aifIsDetected(void)
1373{
1374 return using_aif;
1375}
1376
1377void aifIntrEnable(int mask)
1378{
1379 USE_AIF_REGS;
1380 int OldState;
1381
1382 CpuSuspendIntr(&OldState);
1383 aif_regs[AIF_INTEN] |= mask;
1384 CpuResumeIntr(OldState);
1385}
1386
1387void aifIntrDisable(int mask)
1388{
1389 USE_AIF_REGS;
1390 int OldState;
1391
1392 CpuSuspendIntr(&OldState);
1393 aif_regs[AIF_INTEN] &= ~mask;
1394 CpuResumeIntr(OldState);
1395}
1396
1397void aifRegisterIntrCb(int intr, aif_intr_cb_t cb)
1398{
1399 if (intr < AIF_INUM_COUNT) {
1400 aif_intr_cbs[intr] = cb;
1401 }
1402}
1403
1404int aifRegisterShutdownCb(int idx, dev9_shutdown_cb_t cb)
1405{
1406 if (idx < AIF_INUM_COUNT) {
1407 aif_shutdown_cbs[idx] = cb;
1408 return 0;
1409 }
1410 return -1;
1411}
1412
1413unsigned char aifRTCReadData(unsigned short int address)
1414{
1415 USE_AIF_REGS;
1416 USE_AIF_RTC_REGS;
1417
1418 return aif_rtc_regs[address & 0x7F];
1419}
1420
1421void aifRTCWriteData(unsigned char data, unsigned short int address)
1422{
1423 USE_AIF_REGS;
1424 USE_AIF_RTC_REGS;
1425
1426 aif_rtc_regs[address & 0x7F] = data;
1427}
1428#endif
#define DMAC_CHCR_TR
Definition dmacman.h:35
#define DMAC_CHCR_DR
Definition dmacman.h:42
#define DMAC_CHCR_CO
Definition dmacman.h:39
int CpuResumeIntr(int state)
Definition intrman.c:227
int RegisterIntrHandler(int irq, int mode, int(*handler)(void *), void *arg)
Definition intrman.c:125
int CpuSuspendIntr(int *state)
Definition intrman.c:205
int EnableIntr(int irq)
Definition intrman.c:346
#define IOP_DT_FSEXT
Definition iomanX.h:66
#define SMAP_E3_TX_URG_REQ_BITSFT
Definition smapregs.h:169
#define SMAP_E3_PHY_OP_COMP
Definition smapregs.h:256
#define SMAP_E3_TX_LOW_REQ_BITSFT
Definition smapregs.h:165
#define SMAP_E3_RX_PROP_PF
Definition smapregs.h:179
#define SMAP_E3_TX_GNP_0
Definition smapregs.h:154