sdk-world v2026.11.05
PS2 SDK - world tier (copyleft-allowed, non-essential packages)
Loading...
Searching...
No Matches
mmceigr.c
1#include <string.h>
2#include <sysclib.h>
3#include <tamtypes.h>
4
5#include "ioplib.h"
6#include "mmce_cmds.h"
7#include "sio2regs.h"
8#include "irx_imports.h"
9
10static u32 mmce_sio2_port_ctrl1;
11static u32 mmce_sio2_port_ctrl2;
12
13static inline void delay_us(int us)
14{
15 for (int i = 0; i < us; i++) {
16 for (int j = 0; j < 36; j++) {
17 asm volatile("nop");
18 }
19 }
20}
21
22static int mmce_sio2_tx_rx_pio(int port, u8 tx_size, u8 rx_size, u8 *tx_buf, u8 *rx_buf)
23{
24 //Reset SIO2 + FIFO pointers, disable interrupts
25 inl_sio2_ctrl_set(0xBC);
26
27 //Add transfer to queue
28 inl_sio2_regN_set(0,
29 TR_CTRL_PORT_NR(port) |
30 TR_CTRL_PAUSE(0) |
31 TR_CTRL_TX_MODE_PIO_DMA(0) |
32 TR_CTRL_RX_MODE_PIO_DMA(0) |
33 TR_CTRL_NORMAL_TR(1) |
34 TR_CTRL_SPECIAL_TR(0) |
35 TR_CTRL_BAUD_DIV(0) |
36 TR_CTRL_WAIT_ACK_FOREVER(0) |
37 TR_CTRL_TX_DATA_SZ(tx_size) |
38 TR_CTRL_RX_DATA_SZ(rx_size));
39
40 //Copy data to TX FIFO
41 for (int i = 0; i < tx_size; i++) {
42 inl_sio2_data_out(tx_buf[i]);
43 }
44
45 //Start transfer
46 inl_sio2_ctrl_set(0xB1);
47
48 //Wait for transfer to complete
49 while ((inl_sio2_stat6c_get() & (1 << 12)) == 0) {
50 //Polling stat6c too frequently on FATs can cause the SIO2 freeze
51 delay_us(5);
52 }
53
54 //Timeout detected
55 if ((inl_sio2_stat6c_get() & 0x8000) != 0)
56 return -1;
57
58 //Copy data out of RX FIFO
59 for (int i = 0; i < rx_size; i++) {
60 rx_buf[i] = inl_sio2_data_in();
61 }
62
63 return 0;
64}
65
66static int cmd_get_status(int port)
67{
68 int res;
69
70 u8 wrbuf[0x3];
71 u8 rdbuf[0x6];
72
73 wrbuf[0x0] = MMCE_ID; //identifier
74 wrbuf[0x1] = MMCE_CMD_GET_STATUS; //command
75 wrbuf[0x2] = MMCE_RESERVED; //reserved byte
76
77 res = mmce_sio2_tx_rx_pio(port, sizeof(wrbuf), sizeof(rdbuf), wrbuf, rdbuf);
78 if (res == -1)
79 return -1;
80
81 if (rdbuf[0x1] == MMCE_REPLY_CONST)
82 res = rdbuf[0x3] << 8 | rdbuf[0x4];
83 else
84 res = -1;
85
86 return res;
87}
88
89static int cmd_set_card(int port, u8 type, u8 mode, u16 num)
90{
91 int res;
92
93 u8 wrbuf[0x8];
94 u8 rdbuf[0x2];
95
96 wrbuf[0x0] = MMCE_ID; //identifier
97 wrbuf[0x1] = MMCE_CMD_SET_CARD; //command
98 wrbuf[0x2] = MMCE_RESERVED; //reserved byte
99 wrbuf[0x3] = type; //card type (0 = regular, 1 = boot)
100 wrbuf[0x4] = mode; //set mode (num, next, prev)
101 wrbuf[0x5] = num >> 8; //card number upper 8 bits
102 wrbuf[0x6] = num & 0xFF; //card number lower 8 bits
103
104 res = mmce_sio2_tx_rx_pio(port, sizeof(wrbuf), sizeof(rdbuf), wrbuf, rdbuf);
105 if (res == -1)
106 return -1;
107
108 if (rdbuf[0x1] != MMCE_REPLY_CONST)
109 return -1;
110
111 return 0;
112}
113
114int _start(int argc, char *argv[])
115{
116 int res;
117 int slot[2] = {0};
118
119 if (argc < 1)
120 return MODULE_NO_RESIDENT_END;
121
122 if (argv[1][0] == '1')
123 slot[0] = 1;
124
125 if (argv[1][1] == '1')
126 slot[1] = 1;
127
128 mmce_sio2_port_ctrl1 =
129 PCTRL0_ATT_LOW_PER(0x5) |
130 PCTRL0_ATT_MIN_HIGH_PER(0x0) |
131 PCTRL0_BAUD0_DIV(0x2) |
132 PCTRL0_BAUD1_DIV(0xff);
133
134 mmce_sio2_port_ctrl2 =
135 PCTRL1_ACK_TIMEOUT_AFTER(0xffff) |
136 PCTRL1_WAIT_CYCLES_AFTER_ACK_LOW(0x5) |
137 PCTRL1_UNK24(0x0) |
138 PCTRL1_IF_MODE_SPI_DIFF(0x0);
139
140 u32 sio2_state = inl_sio2_ctrl_get();
141
142 for (int i = 0; i < 2; i++) {
143 if (slot[i] == 1) {
144 //Set port ctrls
145 inl_sio2_portN_ctrl1_set(i + 2, mmce_sio2_port_ctrl1);
146 inl_sio2_portN_ctrl2_set(i + 2, mmce_sio2_port_ctrl2);
147
148 //Send set card BOOTCARD
149 res = cmd_set_card(i + 2, 1, 0, 0);
150 if (res != -1) {
151 //Poll for ~7.5s
152 for (int j = 0; j < 15; j++) {
153
154 delay_us(500000); //500ms
155 res = cmd_get_status(i + 2);
156
157 //Not busy, switch done
158 if ((res & 1) == 0)
159 break;
160 }
161 }
162 }
163 }
164
165 //restore SIO2 state + reset
166 inl_sio2_ctrl_set(sio2_state | 0xc);
167
168 return MODULE_NO_RESIDENT_END;
169}