9#include "irx_imports.h"
17#define EF_SIO2_INTR_COMPLETE 0x00000200
18#define EF_SIO2_TRANSFER_TIMEOUT 0x00000400
23static u32 mmce_sio2_port_ctrl1;
24static u32 mmce_sio2_port_ctrl2;
26static u32 sio2_save_ctrl;
27static int event_flag = -1;
30int (*sio2man_intr_handler_ptr)(
void *arg);
31void *sio2man_intr_arg_ptr;
34int (*mmce_sio2_intr_handler_ptr)(
void *arg) = NULL;
35void *mmce_sio2_intr_arg_ptr = NULL;
37iop_sys_clock_t timeout_200ms;
38iop_sys_clock_t timeout_1s;
39iop_sys_clock_t timeout_2s;
41u8 mmce_sio2_use_alarm = 1;
43int mmce_sio2_intr_handler(
void *arg)
47 inl_sio2_stat_set(0x3);
49 iSetEventFlag(ef, EF_SIO2_INTR_COMPLETE);
54unsigned int mmce_sio2_timeout_handler(
void *arg)
57 iSetEventFlag(ef, EF_SIO2_TRANSFER_TIMEOUT);
66 rv = sio2man_hook_init();
68 DPRINTF(
"Failed to init sio2man hook\n");
79 event_flag = CreateEventFlag(&event);
81 DPRINTF(
"Failed to create event flag\n");
82 sio2man_hook_deinit();
87 mmce_sio2_intr_handler_ptr = &mmce_sio2_intr_handler;
88 mmce_sio2_intr_arg_ptr = &event_flag;
91 sceSetDMAPriority(IOP_DMAC_SIO2in, 3);
92 sceSetDMAPriority(IOP_DMAC_SIO2out, 3);
93 sceEnableDMAChannel(IOP_DMAC_SIO2in);
94 sceEnableDMAChannel(IOP_DMAC_SIO2out);
97 EnableIntr(IOP_IRQ_SIO2);
100 timeout_200ms.hi = 0x0;
101 timeout_200ms.lo = 0x708000;
105 timeout_1s.lo = 0x2328000;
109 timeout_2s.lo = 0x4650000;
111 mmce_sio2_port_ctrl1 =
112 PCTRL0_ATT_LOW_PER(0x5) |
113 PCTRL0_ATT_MIN_HIGH_PER(0x0) |
114 PCTRL0_BAUD0_DIV(0x2) |
115 PCTRL0_BAUD1_DIV(0xff);
117 mmce_sio2_port_ctrl2 =
118 PCTRL1_ACK_TIMEOUT_AFTER(0xffff) |
119 PCTRL1_WAIT_CYCLES_AFTER_ACK_LOW(0x5) |
121 PCTRL1_IF_MODE_SPI_DIFF(0x0);
126void mmce_sio2_deinit()
128 sio2man_hook_deinit();
129 DeleteEventFlag(event_flag);
137 sio2man_hook_sio2_lock();
139 sio2_save_ctrl = inl_sio2_ctrl_get();
142 CpuSuspendIntr(&state);
143 mmce_sio2_intrman_internals_ptr->interrupt_handler_table[17].handler = mmce_sio2_intr_handler_ptr;
144 mmce_sio2_intrman_internals_ptr->interrupt_handler_table[17].userdata = mmce_sio2_intr_arg_ptr;
145 CpuResumeIntr(state);
148 inl_sio2_portN_ctrl1_set(mmce_port, mmce_sio2_port_ctrl1);
149 inl_sio2_portN_ctrl2_set(mmce_port, mmce_sio2_port_ctrl2);
152void mmce_sio2_unlock()
157 CpuSuspendIntr(&state);
158 mmce_sio2_intrman_internals_ptr->interrupt_handler_table[17].handler = sio2man_intr_handler_ptr;
159 mmce_sio2_intrman_internals_ptr->interrupt_handler_table[17].userdata = sio2man_intr_arg_ptr;
160 CpuResumeIntr(state);
163 inl_sio2_ctrl_set(sio2_save_ctrl | 0xc);
166 sio2man_hook_sio2_unlock();
169void mmce_sio2_set_port(
int port)
174int mmce_sio2_get_port()
179void mmce_sio2_update_ack_wait_cycles(
int cycles)
181 DPRINTF(
"mmceman: setting cycles to: 0x%x\n", cycles);
183 mmce_sio2_port_ctrl2 =
184 PCTRL1_ACK_TIMEOUT_AFTER(0xffff) |
185 PCTRL1_WAIT_CYCLES_AFTER_ACK_LOW(cycles)|
187 PCTRL1_IF_MODE_SPI_DIFF(0x0);
190void mmce_sio2_set_use_alarm(
int value)
192 mmce_sio2_use_alarm = value;
195int mmce_sio2_tx_rx_pio(u8 tx_size, u8 rx_size, u8 *tx_buf, u8 *rx_buf, iop_sys_clock_t *timeout)
200 inl_sio2_ctrl_set(0x3ac);
204 TR_CTRL_PORT_NR(mmce_port) |
206 TR_CTRL_TX_MODE_PIO_DMA(0) |
207 TR_CTRL_RX_MODE_PIO_DMA(0) |
208 TR_CTRL_NORMAL_TR(1) |
209 TR_CTRL_SPECIAL_TR(0) |
210 TR_CTRL_BAUD_DIV(0) |
211 TR_CTRL_WAIT_ACK_FOREVER(0) |
212 TR_CTRL_TX_DATA_SZ(tx_size) |
213 TR_CTRL_RX_DATA_SZ(rx_size));
217 for (
int i = 0; i < tx_size; i++) {
218 inl_sio2_data_out(tx_buf[i]);
222 inl_sio2_ctrl_set(0x3a1);
225 SetAlarm(timeout, mmce_sio2_timeout_handler, &event_flag);
228 WaitEventFlag(event_flag, EF_SIO2_TRANSFER_TIMEOUT | EF_SIO2_INTR_COMPLETE, 1, &resbits);
229 if (resbits & EF_SIO2_TRANSFER_TIMEOUT) {
230 DPRINTF(
"Transfer timed out, resetting SIO2\n");
231 inl_sio2_ctrl_set(0x3ac);
232 ClearEventFlag(event_flag, ~(EF_SIO2_TRANSFER_TIMEOUT | EF_SIO2_INTR_COMPLETE));
237 CancelAlarm(mmce_sio2_timeout_handler, &event_flag);
240 ClearEventFlag(event_flag, ~(EF_SIO2_TRANSFER_TIMEOUT | EF_SIO2_INTR_COMPLETE));
243 for (
int i = 0; i < rx_size; i++) {
244 rx_buf[i] = inl_sio2_data_in();
251int mmce_sio2_rx_dma(u8 *buffer, u32 size)
256 u32 elements = size / 256;
259 u32 elements_done = 0;
262 u32 dma_element = TR_CTRL_PORT_NR(mmce_port) |
264 TR_CTRL_TX_MODE_PIO_DMA(0) |
265 TR_CTRL_RX_MODE_PIO_DMA(1) |
266 TR_CTRL_NORMAL_TR(1) |
267 TR_CTRL_SPECIAL_TR(0) |
268 TR_CTRL_BAUD_DIV(0) |
269 TR_CTRL_WAIT_ACK_FOREVER(0) |
270 TR_CTRL_TX_DATA_SZ(0) |
271 TR_CTRL_RX_DATA_SZ(256);
273 while (elements != 0) {
275 inl_sio2_ctrl_set(0x3ac);
277 elements_do = elements > 16 ? 16 : elements;
280 for (
int i = 0; i < elements_do; i++) {
281 inl_sio2_regN_set(i, dma_element);
285 sceSetSliceDMA(IOP_DMAC_SIO2out, &buffer[elements_done * 256], 0x100 >> 2, elements_do, DMAC_TO_MEM);
286 sceStartDMA(IOP_DMAC_SIO2out);
289 inl_sio2_ctrl_set(0x3a1);
292 if (mmce_sio2_use_alarm)
293 SetAlarm(&timeout_2s, mmce_sio2_timeout_handler, &event_flag);
296 WaitEventFlag(event_flag, EF_SIO2_TRANSFER_TIMEOUT | EF_SIO2_INTR_COMPLETE, 1, &resbits);
297 if (resbits & EF_SIO2_TRANSFER_TIMEOUT) {
298 DPRINTF(
"Transfer timed out, resetting SIO2\n");
299 inl_sio2_ctrl_set(0x3ac);
300 ClearEventFlag(event_flag, ~(EF_SIO2_TRANSFER_TIMEOUT | EF_SIO2_INTR_COMPLETE));
305 if (mmce_sio2_use_alarm)
306 CancelAlarm(mmce_sio2_timeout_handler, &event_flag);
309 ClearEventFlag(event_flag, ~(EF_SIO2_TRANSFER_TIMEOUT | EF_SIO2_INTR_COMPLETE));
311 elements -= elements_do;
312 elements_done += elements_do;
319int mmce_sio2_rx_mixed(u8 *buffer, u32 size)
324 u32 elements = size / 256;
327 u32 pio_size = size - (elements * 256);
336 u32 dma_element = TR_CTRL_PORT_NR(mmce_port) |
338 TR_CTRL_TX_MODE_PIO_DMA(0) |
339 TR_CTRL_RX_MODE_PIO_DMA(1) |
340 TR_CTRL_NORMAL_TR(1) |
341 TR_CTRL_SPECIAL_TR(0) |
342 TR_CTRL_BAUD_DIV(0) |
343 TR_CTRL_WAIT_ACK_FOREVER(0) |
344 TR_CTRL_TX_DATA_SZ(0) |
345 TR_CTRL_RX_DATA_SZ(256);
348 u32 pio_element = TR_CTRL_PORT_NR(mmce_port) |
350 TR_CTRL_TX_MODE_PIO_DMA(0) |
351 TR_CTRL_RX_MODE_PIO_DMA(0) |
352 TR_CTRL_NORMAL_TR(1) |
353 TR_CTRL_SPECIAL_TR(0) |
354 TR_CTRL_BAUD_DIV(0) |
355 TR_CTRL_WAIT_ACK_FOREVER(0) |
356 TR_CTRL_TX_DATA_SZ(0) |
357 TR_CTRL_RX_DATA_SZ(pio_size);
359 while (bytes_done < size) {
361 inl_sio2_ctrl_set(0x3ac);
366 elements_do = elements > 16 ? 16 : elements;
369 for (
int i = 0; i < elements_do; i++) {
370 inl_sio2_regN_set(i, dma_element);
373 bytes_done += elements_do * 256;
376 if (elements_do < 16) {
377 if (pio_size != 0x0) {
378 inl_sio2_regN_set(elements_do, pio_element);
380 offset_pio = bytes_done;
381 bytes_done += pio_size;
386 if (elements_do != 0) {
387 sceSetSliceDMA(IOP_DMAC_SIO2out, &buffer[offset], 0x100 >> 2, elements_do, DMAC_TO_MEM);
388 sceStartDMA(IOP_DMAC_SIO2out);
392 inl_sio2_ctrl_set(0x3a1);
395 if (mmce_sio2_use_alarm)
396 SetAlarm(&timeout_2s, mmce_sio2_timeout_handler, &event_flag);
399 WaitEventFlag(event_flag, EF_SIO2_TRANSFER_TIMEOUT | EF_SIO2_INTR_COMPLETE, 1, &resbits);
400 if (resbits & EF_SIO2_TRANSFER_TIMEOUT) {
401 DPRINTF(
"Detected transfer timeout, attempting to reset SIO2\n");
402 inl_sio2_ctrl_set(0x3ac);
403 ClearEventFlag(event_flag, ~(EF_SIO2_TRANSFER_TIMEOUT | EF_SIO2_INTR_COMPLETE));
408 if (mmce_sio2_use_alarm)
409 CancelAlarm(mmce_sio2_timeout_handler, &event_flag);
412 ClearEventFlag(event_flag, ~(EF_SIO2_TRANSFER_TIMEOUT | EF_SIO2_INTR_COMPLETE));
414 elements -= elements_do;
418 if (pio_size != 0x0) {
419 for (
int i = 0; i < pio_size; i++) {
420 buffer[offset_pio + i] = inl_sio2_data_in();
427int mmce_sio2_tx_mixed(u8 *buffer, u32 size)
433 u32 elements = size / 256;
436 u32 pio_size = size - (elements * 256);
445 u32 dma_element = TR_CTRL_PORT_NR(mmce_port) |
447 TR_CTRL_TX_MODE_PIO_DMA(1) |
448 TR_CTRL_RX_MODE_PIO_DMA(0) |
449 TR_CTRL_NORMAL_TR(1) |
450 TR_CTRL_SPECIAL_TR(0) |
451 TR_CTRL_BAUD_DIV(0) |
452 TR_CTRL_WAIT_ACK_FOREVER(0) |
453 TR_CTRL_TX_DATA_SZ(256) |
454 TR_CTRL_RX_DATA_SZ(0);
457 u32 pio_element = TR_CTRL_PORT_NR(mmce_port) |
459 TR_CTRL_TX_MODE_PIO_DMA(0) |
460 TR_CTRL_RX_MODE_PIO_DMA(0) |
461 TR_CTRL_NORMAL_TR(1) |
462 TR_CTRL_SPECIAL_TR(0) |
463 TR_CTRL_BAUD_DIV(0) |
464 TR_CTRL_WAIT_ACK_FOREVER(0) |
465 TR_CTRL_TX_DATA_SZ(pio_size) |
466 TR_CTRL_RX_DATA_SZ(0);
471 res = mmce_sio2_tx_rx_pio(0, 2, NULL, rx_buf, &timeout_2s);
473 DPRINTF(
"%s ERROR: Timed out waiting for ready\n", __func__);
477 if (bytes_done >= size)
484 }
else if (waiting == 0) {
485 elements_do = elements > 16 ? 16 : elements;
488 if (elements_do == 16) {
490 inl_sio2_ctrl_set(0x3ac);
492 for (
int i = 0; i < elements_do; i++) {
493 inl_sio2_regN_set(i, dma_element);
496 sceSetSliceDMA(IOP_DMAC_SIO2in, &buffer[bytes_done], 0x100 >> 2, elements_do, DMAC_FROM_MEM);
497 sceStartDMA(IOP_DMAC_SIO2in);
499 bytes_done += elements_do * 256;
500 elements -= elements_do;
503 inl_sio2_ctrl_set(0x3a1);
506 SetAlarm(&timeout_2s, mmce_sio2_timeout_handler, &event_flag);
509 WaitEventFlag(event_flag, EF_SIO2_TRANSFER_TIMEOUT | EF_SIO2_INTR_COMPLETE, 1, &resbits);
510 if (resbits & EF_SIO2_TRANSFER_TIMEOUT) {
511 DPRINTF(
"Detected transfer timeout, attempting to reset SIO2\n");
512 inl_sio2_ctrl_set(0x3ac);
513 ClearEventFlag(event_flag, ~(EF_SIO2_TRANSFER_TIMEOUT | EF_SIO2_INTR_COMPLETE));
518 CancelAlarm(mmce_sio2_timeout_handler, &event_flag);
521 ClearEventFlag(event_flag, ~(EF_SIO2_TRANSFER_TIMEOUT | EF_SIO2_INTR_COMPLETE));
528 if (elements_do != 0) {
531 inl_sio2_ctrl_set(0x3ac);
533 for (
int i = 0; i < elements_do; i++) {
534 inl_sio2_regN_set(i, dma_element);
537 sceSetSliceDMA(IOP_DMAC_SIO2in, &buffer[bytes_done], 0x100 >> 2, elements_do, DMAC_FROM_MEM);
538 sceStartDMA(IOP_DMAC_SIO2in);
540 bytes_done += elements_do * 256;
541 elements -= elements_do;
544 inl_sio2_ctrl_set(0x3a1);
547 SetAlarm(&timeout_2s, mmce_sio2_timeout_handler, &event_flag);
550 WaitEventFlag(event_flag, EF_SIO2_TRANSFER_TIMEOUT | EF_SIO2_INTR_COMPLETE, 1, &resbits);
551 if (resbits & EF_SIO2_TRANSFER_TIMEOUT) {
552 DPRINTF(
"Detected transfer timeout, attempting to reset SIO2\n");
553 inl_sio2_ctrl_set(0x3ac);
554 ClearEventFlag(event_flag, ~(EF_SIO2_TRANSFER_TIMEOUT | EF_SIO2_INTR_COMPLETE));
559 CancelAlarm(mmce_sio2_timeout_handler, &event_flag);
562 ClearEventFlag(event_flag, ~(EF_SIO2_TRANSFER_TIMEOUT | EF_SIO2_INTR_COMPLETE));
568 inl_sio2_ctrl_set(0x3ac);
570 inl_sio2_regN_set(0, pio_element);
573 for (
int i = 0; i < pio_size; i++) {
574 inl_sio2_data_out(buffer[bytes_done + i]);
577 bytes_done += pio_size;
581 inl_sio2_ctrl_set(0x3a1);
584 SetAlarm(&timeout_2s, mmce_sio2_timeout_handler, &event_flag);
587 WaitEventFlag(event_flag, EF_SIO2_TRANSFER_TIMEOUT | EF_SIO2_INTR_COMPLETE, 1, &resbits);
588 if (resbits & EF_SIO2_TRANSFER_TIMEOUT) {
589 DPRINTF(
"Detected transfer timeout, attempting to reset SIO2\n");
590 inl_sio2_ctrl_set(0x3ac);
591 ClearEventFlag(event_flag, ~(EF_SIO2_TRANSFER_TIMEOUT | EF_SIO2_INTR_COMPLETE));
596 CancelAlarm(mmce_sio2_timeout_handler, &event_flag);
599 ClearEventFlag(event_flag, ~(EF_SIO2_TRANSFER_TIMEOUT | EF_SIO2_INTR_COMPLETE));