-
Notifications
You must be signed in to change notification settings - Fork 6
/
iompcf.c
230 lines (192 loc) · 5.04 KB
/
iompcf.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
#include "u.h"
#include "io.h"
#include "mem.h"
#include "arm7/card.h"
// CF Addresses
#define REG_CF_STS ((volatile ushort*)0x098C0000) // Status of the CF Card / Device control
#define REG_CF_CMD ((volatile ushort*)0x090E0000) // Commands sent to control chip and status return
#define REG_CF_ERR ((volatile ushort*)0x09020000) // Errors / Features
#define REG_CF_SEC ((volatile ushort*)0x09040000) // Number of sector to transfer
#define REG_CF_LBA1 ((volatile ushort*)0x09060000) // 1st byte of sector address
#define REG_CF_LBA2 ((volatile ushort*)0x09080000) // 2nd byte of sector address
#define REG_CF_LBA3 ((volatile ushort*)0x090A0000) // 3rd byte of sector address
#define REG_CF_LBA4 ((volatile ushort*)0x090C0000) // last nibble of sector address | 0xE0
#define REG_CF_DATA ((volatile ushort*)0x09000000) // Pointer to buffer of CF data transered from card
// CF Card status
#define CF_STS_INSERTED 0x50
#define CF_STS_REMOVED 0x00
#define CF_STS_READY 0x58
#define CF_STS_DRQ 0x08
#define CF_STS_BUSY 0x80
// CF Card commands
#define CF_CMD_LBA 0xE0
#define CF_CMD_READ 0x20
#define CF_CMD_WRITE 0x30
#define CF_CARD_TIMEOUT 10000000
static int
mpcf_init(void)
{
// See if there is a read/write register
ushort temp = *REG_CF_LBA1;
*REG_CF_LBA1 = (~temp & 0xFF);
temp = (~temp & 0xFF);
if (!(*REG_CF_LBA1 == temp)) {
return 0;
}
// Make sure it is 8 bit
*REG_CF_LBA1 = 0xAA55;
if (*REG_CF_LBA1 == 0xAA55) {
return 0;
}
return 1;
}
static int
mpcf_isin(void)
{
// Change register, then check if value did change
*REG_CF_STS = CF_STS_INSERTED;
return ((*REG_CF_STS & 0xff) == CF_STS_INSERTED);
}
static int
mpcf_clrstat(void)
{
int i;
// Wait until CF card is finished previous commands
i=0;
while ((*REG_CF_CMD & CF_STS_BUSY) && (i < CF_CARD_TIMEOUT)) {
i++;
}
// Wait until card is ready for commands
i = 0;
while ((!(*REG_CF_STS & CF_STS_INSERTED)) && (i < CF_CARD_TIMEOUT)) {
i++;
}
if (i >= CF_CARD_TIMEOUT)
return 0;
return 1;
}
static int
mpcf_read(ulong sector, ulong numSectors, void* buffer)
{
int i;
ushort *buff = (ushort*)buffer;
uchar *buff_uchar = (uchar*)buffer;
int temp;
// Wait until CF card is finished previous commands
i=0;
while ((*REG_CF_CMD & CF_STS_BUSY) && (i < CF_CARD_TIMEOUT)) {
i++;
}
// Wait until card is ready for commands
i = 0;
while ((!(*REG_CF_STS & CF_STS_INSERTED)) && (i < CF_CARD_TIMEOUT)) {
i++;
}
if (i >= CF_CARD_TIMEOUT)
return 0;
// Set number of sectors to read
*REG_CF_SEC = (numSectors < 256 ? numSectors : 0); // Read a maximum of 256 sectors, 0 means 256
// Set read sector
*REG_CF_LBA1 = sector & 0xFF; // 1st byte of sector number
*REG_CF_LBA2 = (sector >> 8) & 0xFF; // 2nd byte of sector number
*REG_CF_LBA3 = (sector >> 16) & 0xFF; // 3rd byte of sector number
*REG_CF_LBA4 = ((sector >> 24) & 0x0F )| CF_CMD_LBA; // last nibble of sector number
// Set command to read
*REG_CF_CMD = CF_CMD_READ;
while (numSectors--)
{
// Wait until card is ready for reading
i = 0;
while (((*REG_CF_STS & 0xff)!= CF_STS_READY) && (i < CF_CARD_TIMEOUT))
{
i++;
}
if (i >= CF_CARD_TIMEOUT)
return 0;
// Read data
i=256;
if ((ulong)buff_uchar & 0x01) {
while(i--)
{
temp = *((volatile ushort*)0x09000000);
*buff_uchar++ = temp & 0xFF;
*buff_uchar++ = temp >> 8;
}
} else {
while(i--)
*buff++ = *((volatile ushort*)0x09000000);
}
}
return 1;
}
static int
mpcf_write(ulong sector, ulong numSectors, void* buffer)
{
int i;
ushort *buff = (ushort*)buffer;
uchar *buff_uchar = (uchar*)buffer;
int temp;
// Wait until CF card is finished previous commands
i=0;
while ((*REG_CF_CMD & CF_STS_BUSY) && (i < CF_CARD_TIMEOUT))
{
i++;
}
// Wait until card is ready for commands
i = 0;
while ((!(*REG_CF_STS & CF_STS_INSERTED)) && (i < CF_CARD_TIMEOUT))
{
i++;
}
if (i >= CF_CARD_TIMEOUT)
return 0;
// Set number of sectors to write
*REG_CF_SEC = (numSectors < 256 ? numSectors : 0); // Write a maximum of 256 sectors, 0 means 256
// Set write sector
*REG_CF_LBA1 = sector & 0xFF; // 1st byte of sector number
*REG_CF_LBA2 = (sector >> 8) & 0xFF; // 2nd byte of sector number
*REG_CF_LBA3 = (sector >> 16) & 0xFF; // 3rd byte of sector number
*REG_CF_LBA4 = ((sector >> 24) & 0x0F )| CF_CMD_LBA; // last nibble of sector number
// Set command to write
*REG_CF_CMD = CF_CMD_WRITE;
while (numSectors--)
{
// Wait until card is ready for writing
i = 0;
while (((*REG_CF_STS & 0xff) != CF_STS_READY) && (i < CF_CARD_TIMEOUT))
{
i++;
}
if (i >= CF_CARD_TIMEOUT)
return 0;
// Write data
i=256;
if ((ulong)buff_uchar & 0x01) {
while(i--)
{
temp = *buff_uchar++;
temp |= *buff_uchar++ << 8;
*((volatile ushort*)0x09000000) = temp;
}
} else {
while(i--)
*((volatile ushort*)0x09000000) = *buff++;
}
}
return 1;
}
static Ioifc io_mpcf = {
"MPCF",
Cread|Cwrite|Cslotgba,
mpcf_init,
mpcf_isin,
(void*)mpcf_read,
(void*)mpcf_write,
mpcf_clrstat,
mpcf_clrstat,
};
void
iompcflink(void)
{
addioifc(&io_mpcf);
}