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