2 Copyright (c) 2010 jimmikaelkael <jimmikaelkael@wanadoo.fr>
3 Copyright (c) 2003 Marcus R. Brown <mrbrown@0xd6.org>
4 Licenced under Academic Free License version 3.0
5 Review OpenPS2Loader README & LICENSE files for further details.
7 Code originally based on SMAP driver sources found in UDPTTY driver.
8 Optimized mips functions from Eugene Plotnikov.
17 #include <speedregs.h>
28 #define SMAP_RX_BUFSIZE 16384
29 #define SMAP_RX_BASE 0x4000
30 #define SMAP_RX_MINSIZE 14 // Ethernet header size
31 #define SMAP_RX_MAXSIZE (6+6+2+1500+4)
32 #define SMAP_TX_MAXSIZE (6+6+2+1500)
34 #define SMAP_BD_NEXT(x) (x)=(x)<(SMAP_BD_MAX_ENTRY-1) ? (x)+1:0
44 static smap_tx_stat_t tx_stat
;
48 u8 rxbdi
; // Index into current RX BD
52 static smap_rx_stat_t rx_stat
;
54 static int smap_xmit_mutex
= -1;
56 static u8 rcpt_buf
[SMAP_RX_MAXSIZE
] __attribute__((aligned(64)));
58 //-------------------------------------------------------------------------
59 void smap_CopyToFIFO(u16
, u32
*, int);
65 "smap_CopyToFIFO:\n\t"
68 "sh $a0, 4100($v1)\n\t"
70 "andi $a2, $a2, 0xF\n\t"
77 "lwl $t2, 11($a1)\n\t"
78 "lwr $t3, 12($a1)\n\t"
79 "lwl $t3, 15($a1)\n\t"
80 "addiu $at, $at, -1\n\t"
81 "sw $t0, 4352($v1)\n\t"
82 "sw $t1, 4352($v1)\n\t"
83 "sw $t2, 4352($v1)\n\t"
84 "addiu $a1, $a1, 16\n\t"
86 "sw $t3, 4352($v1)\n\t"
93 "addiu $a2, $a2, -4\n\t"
94 "sw $v0, 4352($v1)\n\t"
96 "addiu $a1, $a1, 4\n\t"
105 //-------------------------------------------------------------------------
106 void smap_CopyFromFIFO(u16
, u32
*, int);
112 "smap_CopyFromFIFO:\n\t"
114 "lui $a3, 0xB000\n\t"
115 "addiu $v1, $a2, 3\n\t"
116 "and $v1, $v1, $v0\n\t"
117 "srl $at, $v1, 5\n\t"
118 "sh $a0, 4148($a3)\n\t"
120 "andi $v1, $v1, 0x1F\n\t"
122 "lw $t0, 4608($a3)\n\t"
123 "lw $t1, 4608($a3)\n\t"
124 "lw $t2, 4608($a3)\n\t"
125 "lw $t3, 4608($a3)\n\t"
126 "lw $t4, 4608($a3)\n\t"
127 "lw $t5, 4608($a3)\n\t"
128 "lw $t6, 4608($a3)\n\t"
129 "lw $t7, 4608($a3)\n\t"
130 "addiu $at, $at, -1\n\t"
134 "sw $t3, 12($a1)\n\t"
135 "sw $t4, 16($a1)\n\t"
136 "sw $t5, 20($a1)\n\t"
137 "sw $t6, 24($a1)\n\t"
138 "sw $t7, 28($a1)\n\t"
140 "addiu $a1, $a1, 32\n\t"
145 "lw $v0, 4608($a3)\n\t"
146 "addiu $v1, $v1, -4\n\t"
149 "addiu $a1, $a1, 4\n\t"
158 //-------------------------------------------------------------------------
159 static int smap_phy_read(int reg
, u16
*data
)
164 val
= SMAP_E3_PHY_READ
|(SMAP_DsPHYTER_ADDRESS
<< SMAP_E3_PHY_ADDR_BITSFT
)|
165 (reg
& SMAP_E3_PHY_REG_ADDR_MSK
);
166 SMAP_EMAC3_SET(SMAP_R_EMAC3_STA_CTRL
, val
);
168 // Wait for the read operation to complete
169 for (i
= 0; i
< 100; i
++) {
170 if (SMAP_EMAC3_GET(SMAP_R_EMAC3_STA_CTRL
) & SMAP_E3_PHY_OP_COMP
)
174 if (i
== 100 || !data
)
177 *data
= SMAP_EMAC3_GET(SMAP_R_EMAC3_STA_CTRL
) >> SMAP_E3_PHY_DATA_BITSFT
;
181 //-------------------------------------------------------------------------
182 static int smap_phy_write(int reg
, u16 data
)
187 val
= ((data
& SMAP_E3_PHY_DATA_MSK
) << SMAP_E3_PHY_DATA_BITSFT
)|
188 SMAP_E3_PHY_WRITE
|(SMAP_DsPHYTER_ADDRESS
<< SMAP_E3_PHY_ADDR_BITSFT
)|
189 (reg
& SMAP_E3_PHY_REG_ADDR_MSK
);
190 SMAP_EMAC3_SET(SMAP_R_EMAC3_STA_CTRL
, val
);
192 // Wait for the write operation to complete
193 for (i
= 0; i
< 100; i
++) {
194 if (SMAP_EMAC3_GET(SMAP_R_EMAC3_STA_CTRL
) & SMAP_E3_PHY_OP_COMP
)
201 //-------------------------------------------------------------------------
202 static int smap_phy_init(void)
207 u16 phydata
, idr1
, idr2
;
210 smap_phy_write(SMAP_DsPHYTER_BMCR
, SMAP_PHY_BMCR_RST
);
211 // Wait for it to come out of reset
212 for (i
= 9; i
; i
--) {
213 smap_phy_read(SMAP_DsPHYTER_BMCR
, &phydata
);
214 if (!(phydata
& SMAP_PHY_BMCR_RST
))
221 // Confirm link status
224 smap_phy_read(SMAP_DsPHYTER_BMSR
, &phydata
);
225 if (phydata
& SMAP_PHY_BMSR_LINK
)
230 smap_phy_write(SMAP_DsPHYTER_BMCR
, SMAP_PHY_BMCR_100M
|SMAP_PHY_BMCR_DUPM
);
236 // Force 100 Mbps full duplex mode
237 val
= SMAP_EMAC3_GET(SMAP_R_EMAC3_MODE1
);
238 val
|= (SMAP_E3_FDX_ENABLE
|SMAP_E3_FLOWCTRL_ENABLE
|SMAP_E3_ALLOW_PF
);
239 val
&= ~SMAP_E3_MEDIA_MSK
;
240 val
|= SMAP_E3_MEDIA_100M
;
241 SMAP_EMAC3_SET(SMAP_R_EMAC3_MODE1
, val
);
244 smap_phy_read(SMAP_DsPHYTER_PHYIDR1
, &idr1
);
245 smap_phy_read(SMAP_DsPHYTER_PHYIDR2
, &idr2
);
247 if (idr1
== SMAP_PHY_IDR1_VAL
&&
248 ((idr2
& SMAP_PHY_IDR2_MSK
) == SMAP_PHY_IDR2_VAL
)) {
249 smap_phy_read(SMAP_DsPHYTER_PHYSTS
, &phydata
);
250 if (phydata
& SMAP_PHY_STS_10M
)
251 smap_phy_write(0x1a, 0x104);
253 smap_phy_write(0x13, 0x0001);
254 smap_phy_write(0x19, 0x1898);
255 smap_phy_write(0x1f, 0x0000);
256 smap_phy_write(0x1d, 0x5040);
257 smap_phy_write(0x1e, 0x008c);
258 smap_phy_write(0x13, 0x0000);
264 //-------------------------------------------------------------------------
265 int smap_xmit(void *buf
, int size
)
272 WaitSema(smap_xmit_mutex
);
274 // Get total length of the packet
275 if (size
> SMAP_TX_MAXSIZE
) {
280 txlen
= (size
+ 3) & 0xfffc;
282 // Get free mem in TX
283 int txfree
= ((tx_stat
.txwp_start
> tx_stat
.txwp_end
) ? \
284 (SMAP_TX_BUFSIZE
+ tx_stat
.txwp_end
- tx_stat
.txwp_start
) : \
285 (SMAP_TX_BUFSIZE
- tx_stat
.txwp_end
+ tx_stat
.txwp_start
));
286 if (txlen
> txfree
) {
291 // Check EMAC is ready
292 if (SMAP_EMAC3_GET(SMAP_R_EMAC3_TxMODE0
) & SMAP_E3_TX_GNP_0
) {
297 // Send from mem -> FIFO
298 smap_CopyToFIFO(tx_stat
.txwp_end
, buf
, txlen
);
301 tx_bd
[tx_stat
.txbdi_end
].length
= size
;
302 tx_bd
[tx_stat
.txbdi_end
].pointer
= tx_stat
.txwp_end
+ SMAP_TX_BASE
;
303 SMAP_REG8(SMAP_R_TXFIFO_FRAME_INC
) = 1;
304 tx_bd
[tx_stat
.txbdi_end
].ctrl_stat
= SMAP_BD_TX_READY
| SMAP_BD_TX_GENFCS
| SMAP_BD_TX_GENPAD
;
306 SMAP_EMAC3_SET(SMAP_R_EMAC3_TxMODE0
, SMAP_E3_TX_GNP_0
);
308 // Update tx pointers
309 tx_stat
.txwp_end
= (tx_stat
.txwp_end
+ txlen
) % SMAP_TX_BUFSIZE
;
310 SMAP_BD_NEXT(tx_stat
.txbdi_end
);
313 SignalSema(smap_xmit_mutex
);
318 //-------------------------------------------------------------------------
319 static int smap_tx_intr(int irq
)
323 register int txbdi
, stat
;
324 register int ret
= 1;
327 SMAP_REG16(SMAP_R_INTR_CLR
) = irq
& SMAP_INTR_BITMSK
;
329 while (tx_stat
.txbdi_start
!= tx_stat
.txbdi_end
) {
331 txbdi
= tx_stat
.txbdi_start
;
332 stat
= tx_bd
[txbdi
].ctrl_stat
;
334 if (stat
& SMAP_BD_TX_ERROR
)
337 if (stat
& SMAP_BD_TX_READY
)
340 tx_stat
.txwp_start
= (tx_stat
.txwp_start
+ ((tx_bd
[txbdi
].length
+ 3) & 0xfffc)) % SMAP_TX_BUFSIZE
;
341 SMAP_BD_NEXT(tx_stat
.txbdi_start
);
343 tx_bd
[txbdi
].ctrl_stat
= 0;
344 tx_bd
[txbdi
].reserved
= 0;
345 tx_bd
[txbdi
].length
= 0;
348 tx_stat
.txbdi_start
= tx_stat
.txbdi_end
;
354 //-------------------------------------------------------------------------
355 static int smap_rx_intr(int irq
)
360 register int rxbdi
, stat
;
361 register int ret
= 1;
364 irq
&= SMAP_INTR_RXDNV
| SMAP_INTR_RXEND
;
365 SMAP_REG16(SMAP_R_INTR_CLR
) = irq
& SMAP_INTR_BITMSK
;
369 rxbdi
= rx_stat
.rxbdi
;
370 stat
= rx_bd
[rxbdi
].ctrl_stat
;
372 if (stat
& SMAP_BD_RX_EMPTY
)
375 len
= rx_bd
[rxbdi
].length
;
377 // check for BD error and packet size
378 if ((stat
& SMAP_BD_RX_ERROR
) || ((len
< SMAP_RX_MINSIZE
) || (len
> SMAP_RX_MAXSIZE
)))
381 u16 rxrp
= ((rx_bd
[rxbdi
].pointer
- SMAP_RX_BASE
) % SMAP_RX_BUFSIZE
) & 0xfffc;
383 smap_CopyFromFIFO(rxrp
, (u32
*)rcpt_buf
, len
);
385 eth_hdr_t
*eth
= (eth_hdr_t
*)rcpt_buf
;
386 if (eth
->type
== 0x0008) { // IP packet
388 ip_hdr_t
*ip
= (ip_hdr_t
*)&rcpt_buf
[14];
389 if ((ip
->hlen
== 0x45) && (inet_chksum(ip
, 20) == 0)) { // Check IPv4 & IP checksum
390 if ((!(ip
->flags
& 0x3f)) && (ip
->frag_offset
== 0)) { // Drop IP fragments
391 if (ip
->proto
== 0x06) // Check it's TCP packet
392 tcp_input(rcpt_buf
, len
);
396 else if (eth
->type
== 0x0608) { // ARP packet
397 arp_input(rcpt_buf
, len
);
398 // ARP packet is then dropped
402 SMAP_REG8(SMAP_R_RXFIFO_FRAME_DEC
) = 1;
403 rx_bd
[rxbdi
].ctrl_stat
= SMAP_BD_RX_EMPTY
;
404 SMAP_BD_NEXT(rx_stat
.rxbdi
);
410 //-------------------------------------------------------------------------
411 static int smap_emac3_intr(int irq
)
417 stat
= SMAP_EMAC3_GET(SMAP_R_EMAC3_INTR_STAT
);
419 SMAP_EMAC3_SET(SMAP_R_EMAC3_INTR_STAT
, stat
);
422 SMAP_REG16(SMAP_R_INTR_CLR
) = SMAP_INTR_EMAC3
;
423 SMAP_EMAC3_SET(SMAP_R_EMAC3_INTR_STAT
, SMAP_E3_INTR_ALL
);
428 //-------------------------------------------------------------------------
429 static int smap_intr_handler(int state
)
434 irq
= SPD_REG16(SPD_R_INTR_STAT
) & SMAP_INTR_BITMSK
;
436 if (irq
& (SMAP_INTR_TXDNV
| SMAP_INTR_TXEND
)) { // TX intr
437 smap_tx_intr(irq
& (SMAP_INTR_TXDNV
| SMAP_INTR_TXEND
));
438 irq
= SPD_REG16(SPD_R_INTR_STAT
) & SMAP_INTR_BITMSK
;
441 if (irq
& (SMAP_INTR_RXDNV
| SMAP_INTR_RXEND
)) // RX intr
442 smap_rx_intr(irq
& (SMAP_INTR_RXDNV
| SMAP_INTR_RXEND
));
443 else if (irq
& SMAP_INTR_EMAC3
) // EMAC3 intr
444 smap_emac3_intr(irq
& SMAP_INTR_EMAC3
);
449 //-------------------------------------------------------------------------
450 int smap_init(u8
*eth_addr_src
)
456 USE_SMAP_TX_BD
; USE_SMAP_RX_BD
;
463 // Check out the SPEED chip revision
464 if (!(SPD_REG16(SPD_R_REV_3
) & SPD_CAPS_SMAP
) || SPD_REG16(SPD_R_REV_1
) <= 16)
467 dev9IntrDisable(SMAP_INTR_BITMSK
);
468 EnableIntr(IOP_IRQ_DEV9
);
471 // PCMCIA Card removed flag
472 DEV9_REG(DEV9_R_1464
) = 0x03;
474 // Get HW MAC address and check it
475 if ((dev9GetEEPROM(&MAC
[0]) < 0) || (!MAC
[0] && !MAC
[1] && !MAC
[2]))
479 if (MACcsum
!= MAC
[3])
481 mips_memcpy(eth_addr_src
, &MAC
[0], 6);
484 val
= SMAP_EMAC3_GET(SMAP_R_EMAC3_MODE0
);
485 val
&= ~(SMAP_E3_TXMAC_ENABLE
|SMAP_E3_RXMAC_ENABLE
);
486 SMAP_EMAC3_SET(SMAP_R_EMAC3_MODE0
, val
);
488 // Disable all EMAC3 interrupts
489 SMAP_EMAC3_SET(SMAP_R_EMAC3_INTR_ENABLE
, 0);
491 // Reset the transmit FIFO
492 SMAP_REG8(SMAP_R_TXFIFO_CTRL
) = SMAP_TXFIFO_RESET
;
493 for (i
= 9; i
; i
--) {
494 if (!(SMAP_REG8(SMAP_R_TXFIFO_CTRL
) & SMAP_TXFIFO_RESET
))
501 // Reset the receive FIFO
502 SMAP_REG8(SMAP_R_RXFIFO_CTRL
) = SMAP_RXFIFO_RESET
;
503 for (i
= 9; i
; i
--) {
504 if (!(SMAP_REG8(SMAP_R_RXFIFO_CTRL
) & SMAP_RXFIFO_RESET
))
511 // Perform soft reset of EMAC3
512 SMAP_EMAC3_SET(SMAP_R_EMAC3_MODE0
, SMAP_E3_SOFT_RESET
);
513 for (i
= 9; i
; i
--) {
514 if (!(SMAP_EMAC3_GET(SMAP_R_EMAC3_MODE0
) & SMAP_E3_SOFT_RESET
))
521 SMAP_REG8(SMAP_R_BD_MODE
) = 0;
523 // Initialize all RX and TX buffer descriptors
524 for (i
= 0; i
< SMAP_BD_MAX_ENTRY
; i
++, tx_bd
++) {
525 tx_bd
->ctrl_stat
= 0;
530 for (i
= 0; i
< SMAP_BD_MAX_ENTRY
; i
++, rx_bd
++) {
531 rx_bd
->ctrl_stat
= SMAP_BD_RX_EMPTY
;
538 SMAP_REG16(SMAP_R_INTR_CLR
) = SMAP_INTR_BITMSK
;
540 // EMAC3 operating MODE
541 val
= SMAP_E3_FDX_ENABLE
|SMAP_E3_IGNORE_SQE
|SMAP_E3_MEDIA_100M
|
542 SMAP_E3_RXFIFO_2K
|SMAP_E3_TXFIFO_1K
|SMAP_E3_TXREQ0_SINGLE
|SMAP_E3_TXREQ1_SINGLE
;
543 SMAP_EMAC3_SET(SMAP_R_EMAC3_MODE1
, val
);
545 // TX fifo value for request priority. low = 7*8=56, urgent = 15*8=120.
546 val
= (7 << SMAP_E3_TX_LOW_REQ_BITSFT
) | (15 << SMAP_E3_TX_URG_REQ_BITSFT
);
547 SMAP_EMAC3_SET(SMAP_R_EMAC3_TxMODE1
, val
);
550 val
= SMAP_E3_RX_STRIP_PAD
|SMAP_E3_RX_STRIP_FCS
|SMAP_E3_RX_INDIVID_ADDR
|SMAP_E3_RX_BCAST
;
551 SMAP_EMAC3_SET(SMAP_R_EMAC3_RxMODE
, val
);
553 // Set HW MAC address
554 mips_memcpy(hwaddr
, eth_addr_src
, 6);
555 val
= (u16
)((hwaddr
[0] << 8)|hwaddr
[1]);
556 SMAP_EMAC3_SET(SMAP_R_EMAC3_ADDR_HI
, val
);
557 val
= ((hwaddr
[2] << 24)|(hwaddr
[3] << 16)|(hwaddr
[4] << 8)|hwaddr
[5]);
558 SMAP_EMAC3_SET(SMAP_R_EMAC3_ADDR_LO
, val
);
561 SMAP_EMAC3_SET(SMAP_R_EMAC3_INTER_FRAME_GAP
, 4);
564 val
= 12 << SMAP_E3_TX_THRESHLD_BITSFT
;
565 SMAP_EMAC3_SET(SMAP_R_EMAC3_TX_THRESHOLD
, val
);
567 // RX watermark, low = 16*8=128, hi = 128*8=1024
568 val
= (16 << SMAP_E3_RX_LO_WATER_BITSFT
) | (128 << SMAP_E3_RX_HI_WATER_BITSFT
);
569 SMAP_EMAC3_SET(SMAP_R_EMAC3_RX_WATERMARK
, val
);
571 // Enable all EMAC3 interrupts
572 SMAP_EMAC3_SET(SMAP_R_EMAC3_INTR_ENABLE
, SMAP_E3_INTR_ALL
);
574 // Initialize the PHY
575 if ((i
= smap_phy_init()) != 0)
578 tx_stat
.txwp_start
= tx_stat
.txwp_end
= 0;
579 tx_stat
.txbdi_start
= tx_stat
.txbdi_end
= 0;
582 // Install the smap_intr_handler for all the SMAP interrupts
584 dev9RegisterIntrCb(i
, smap_intr_handler
);
587 SMAP_EMAC3_SET(SMAP_R_EMAC3_MODE0
, SMAP_E3_TXMAC_ENABLE
|SMAP_E3_RXMAC_ENABLE
);
590 dev9IntrEnable(SMAP_INTR_BITMSK
);
592 smap_xmit_mutex
= CreateMutex(IOP_MUTEX_UNLOCKED
);