PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
extflash.c
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# NAND Flash via Dev9 driver.
11*/
12
13#include "types.h"
14#include "defs.h"
15#include "irx.h"
16
17#include "loadcore.h"
18#include "thbase.h"
19#include "stdio.h"
20#include "sysclib.h"
21
22#include "dev9regs.h"
23#include "speedregs.h"
24
25#include "fls.h"
26
27#define MODNAME "flash"
28#define M_PRINTF(format, args...) \
29 printf(MODNAME ": " format, ## args)
30
31IRX_ID(MODNAME, 0, 0);
32
33#define FLASH_ID_64MBIT 0xe6
34#define FLASH_ID_128MBIT 0x73
35#define FLASH_ID_256MBIT 0x75
36#define FLASH_ID_512MBIT 0x76
37#define FLASH_ID_1024MBIT 0x79
38
39/* SmartMedia commands. */
40#define SM_CMD_READ1 0x00
41#define SM_CMD_READ2 0x01
42#define SM_CMD_READ3 0x50
43#define SM_CMD_RESET 0xff
44#define SM_CMD_WRITEDATA 0x80
45#define SM_CMD_PROGRAMPAGE 0x10
46#define SM_CMD_ERASEBLOCK 0x60
47#define SM_CMD_ERASECONFIRM 0xd0
48#define SM_CMD_GETSTATUS 0x70
49#define SM_CMD_READID 0x90
50
51static flash_info_t devices[] = {
52 { FLASH_ID_64MBIT, 64, 528, 16, 1024 },
53 { FLASH_ID_128MBIT, 128, 528, 32, 1024 },
54 { FLASH_ID_256MBIT, 256, 528, 32, 2048 },
55 { FLASH_ID_512MBIT, 512, 528, 32, 4096 },
56 { FLASH_ID_1024MBIT, 1024, 528, 32, 8192 }
57};
58#define NUM_DEVICES (sizeof(devices)/sizeof(flash_info_t))
59
60static iop_sys_clock_t timeout;
61static u32 timeout_cb(void *);
62
63extern struct irx_export_table _exp_fls;
64
65int _start(int argc, char *argv[])
66{
67 (void)argc;
68 (void)argv;
69
70 if (flash_detect() < 0)
71 return MODULE_NO_RESIDENT_END;
72
73 return (RegisterLibraryEntries(&_exp_fls) != 0) ? MODULE_NO_RESIDENT_END : MODULE_RESIDENT_END;
74}
75
76/* #4: Check to see if flash is connected to the expansion bay. */
77int flash_detect(void)
78{
79 USE_DEV9_REGS;
80 USE_SPD_REGS;
81 u16 rev;
82
83 if ((DEV9_REG(DEV9_R_REV) & 0xf0) != DEV9_DEV9C_9611) {
84 M_PRINTF("CXD9611 required for flash interface.\n");
85 return -1;
86 }
87
88 /* Check bit 5 of the revision register. */
89 if ((rev = SPD_REG16(SPD_R_REV_3)) & SPD_CAPS_FLASH) {
90 M_PRINTF("Detected flash (rev3 0x%02x).\n", rev);
91 return 0;
92 }
93
94 M_PRINTF("No flash detected (rev3 0x%02x).\n", rev);
95 return -1;
96}
97
98/* #5: Reset the device. */
99int flash_device_reset(void)
100{
101 USE_SPD_REGS;
102 u32 has_timedout = 0;
103
104 SPD_REG16(0x480c) = 0x100;
105 SPD_REG16(0x4804) = SM_CMD_RESET;
106 (void)(SPD_REG16(0x480c));
107 (void)(SPD_REG16(0x480c));
108
109 SetAlarm(&timeout, (void *)timeout_cb, &has_timedout);
110
111 while ((SPD_REG16(0x480c) & 0x01) == 0) {
112 if (has_timedout) {
113 if (SPD_REG16(0x480c) & 0x01)
114 break;
115
116 M_PRINTF("Device erase: timed out.\n");
117 return -3;
118 }
119 }
120
121 CancelAlarm((void *)timeout_cb, &has_timedout);
122
123 SPD_REG16(0x4804) = SM_CMD_GETSTATUS;
124 if (SPD_REG16(0x4814) & 0x01) {
125 M_PRINTF("Device erase: status error.\n");
126 return -6;
127 }
128
129 SPD_REG16(0x480c) = 0;
130 return 0;
131}
132
133/* #6: Get information about the attached device. */
134int flash_get_info(flash_info_t *info)
135{
136 USE_SPD_REGS;
137 int i;
138 u16 id;
139
140 SPD_REG16(0x480c) = 0x100;
141 SPD_REG16(0x4804) = SM_CMD_READID;
142 SPD_REG16(0x4808) = 0;
143 (void)(SPD_REG16(0x480c));
144 (void)(SPD_REG16(0x4814));
145 id = SPD_REG16(0x4814);
146 SPD_REG16(0x480c) = 0;
147
148 memset(info, 0, sizeof(flash_info_t));
149
150 for (i = 0; (u32)i < NUM_DEVICES; i++) {
151 if (id != devices[i].id)
152 continue;
153
154 memcpy(info, &devices[i], sizeof(flash_info_t));
155 M_PRINTF("Device: ID 0x%02x, %ld Mbit, %ld bytes/page, %ld pages/block, %ld blocks total.\n",
156 id, info->mbits, info->page_bytes, info->block_pages, info->blocks);
157 return 0;
158 }
159
160 return -5;
161}
162
163/* Set the page offset register based on the type of flash (id). */
164static void flash_set_page(u32 id, u32 pageofs)
165{
166 USE_SPD_REGS;
167
168 switch (id) {
169 case FLASH_ID_64MBIT:
170 SPD_REG16(0x4808) = ((pageofs >> 9) & 0xff) | 0x100;
171 SPD_REG16(0x4808) = ((pageofs >> 17) & 0x3f);
172 break;
173 case FLASH_ID_128MBIT:
174 SPD_REG16(0x4808) = ((pageofs >> 9) & 0xff) | 0x100;
175 SPD_REG16(0x4808) = ((pageofs >> 17) & 0x7f);
176 break;
177 case FLASH_ID_256MBIT:
178 SPD_REG16(0x4808) = ((pageofs >> 9) & 0xff) | 0x100;
179 SPD_REG16(0x4808) = ((pageofs >> 17) & 0xff);
180 break;
181 case FLASH_ID_512MBIT:
182 SPD_REG16(0x4808) = ((pageofs >> 17) & 0xff) | 0x100;
183 SPD_REG16(0x4808) = ((pageofs >> 25) & 0x01);
184 break;
185 case FLASH_ID_1024MBIT:
186 SPD_REG16(0x4808) = ((pageofs >> 17) & 0xff) | 0x100;
187 SPD_REG16(0x4808) = ((pageofs >> 25) & 0x02);
188 break;
189 }
190}
191
192/* #7: Erase a page. */
193int flash_page_erase(flash_info_t *info, u32 page)
194{
195 USE_SPD_REGS;
196 u32 pageofs = page * 512;
197 u32 has_timedout = 0;
198
199 SPD_REG16(0x480c) = 0x180;
200 SPD_REG16(0x4804) = SM_CMD_ERASEBLOCK;
201
202 flash_set_page(info->id, pageofs);
203
204 SPD_REG16(0x4804) = SM_CMD_ERASECONFIRM;
205 (void)(SPD_REG16(0x480c));
206 (void)(SPD_REG16(0x480c));
207
208 SetAlarm(&timeout, (void *)timeout_cb, &has_timedout);
209
210 while ((SPD_REG16(0x480c) & 0x01) == 0) {
211 if (has_timedout) {
212 if (SPD_REG16(0x480c) & 0x01)
213 break;
214
215 M_PRINTF("Page erase: timed out.\n");
216 return -3;
217 }
218 }
219
220 CancelAlarm((void *)timeout_cb, &has_timedout);
221
222 SPD_REG16(0x4804) = SM_CMD_GETSTATUS;
223 if (SPD_REG16(0x4814) & 0x01) {
224 M_PRINTF("Page erase: status error.\n");
225 return -6;
226 }
227
228 SPD_REG16(0x480c) = 0;
229 return 0;
230}
231
232/* #8: Read one or more pages. You can select how much of the page you want to
233 * read by setting the page_bytes member of the info struct. The default set
234 * by the driver is 528 bytes:
235 * Bytes 0 - 511: Data
236 * Bytes 512 - 527: Metadata?
237 *
238 * You can also set page_bytes to 512 or 16 bytes. */
239int flash_page_read(flash_info_t *info, u32 page, u32 count, void *buf)
240{
241 USE_SPD_REGS;
242 u32 *buf_w;
243 u16 *buf_h;
244 int i, j;
245 u32 byteofs, pageofs = page * 512;
246 u32 has_timedout;
247 u16 func = 0x100;
248
249 if (info->page_bytes == 512)
250 func = 0x1100;
251
252 SPD_REG16(0x480c) = func;
253
254 if (info->page_bytes == 16) {
255 SPD_REG16(0x4804) = SM_CMD_READ3;
256 byteofs = pageofs & 0x0f;
257 } else {
258 SPD_REG16(0x4804) = SM_CMD_READ1;
259 byteofs = pageofs & 0x1ff;
260 }
261
262 SPD_REG16(0x4808) = (byteofs & 0xff) | 0x100;
263 /* Set the rest of the page info. */
264 flash_set_page(info->id, pageofs);
265
266 buf_w = (u32 *)buf;
267 buf_h = (u16 *)buf;
268
269 for (i = 0; (u32)i < count; i++) {
270 (void)(SPD_REG16(0x480c));
271 (void)(SPD_REG16(0x480c));
272
273 has_timedout = 0;
274 SetAlarm(&timeout, (void *)timeout_cb, &has_timedout);
275
276 while ((SPD_REG16(0x480c) & 0x01) == 0) {
277 if (has_timedout) {
278 if (SPD_REG16(0x480c) & 0x01)
279 break;
280
281 M_PRINTF("Page read: timed out.\n");
282 return -3;
283 }
284 }
285
286 CancelAlarm((void *)timeout_cb, &has_timedout);
287
288 SPD_REG16(0x480c) = func | 0x800;
289
290 if (byteofs == 0) {
291 /* 32-bit copy. */
292 for (j = 0; (u32)j < (info->page_bytes / 4); j++)
293 *buf_w++ = SPD_REG32(0x4800);
294 } else {
295 /* 16-bit copy. */
296 for (j = (byteofs + (byteofs >> 31)) / 2; (u32)j < (info->page_bytes / 2); j++)
297 *buf_h++ = SPD_REG16(0x4800);
298 }
299
300 byteofs = 0;
301 SPD_REG16(0x480c) = func;
302 }
303
304 SPD_REG16(0x480c) = 0;
305 return 0;
306}
307
308/* #9: Write a single page.
309 * Bytes 0 - 511: Data
310 * Bytes 512 - 527: Metadata? */
311int flash_page_write(flash_info_t *info, u32 page, void *buf)
312{
313 USE_SPD_REGS;
314 u16 *buf_h = buf;
315 int i;
316 u32 pageofs = page * 512;
317 u32 has_timedout = 0;
318
319 SPD_REG16(0x480c) = 0x180;
320 SPD_REG16(0x4804) = SM_CMD_WRITEDATA;
321
322 SPD_REG16(0x4808) = 0x100;
323 flash_set_page(info->id, pageofs);
324
325 for (i = 0; (u32)i < (info->page_bytes / 2); i++)
326 SPD_REG16(0x4800) = *buf_h++;
327
328 SPD_REG16(0x4804) = SM_CMD_PROGRAMPAGE;
329 (void)(SPD_REG16(0x480c));
330 (void)(SPD_REG16(0x480c));
331
332 SetAlarm(&timeout, (void *)timeout_cb, &has_timedout);
333
334 while ((SPD_REG16(0x480c) & 0x01) == 0) {
335 if (has_timedout) {
336 if (SPD_REG16(0x480c) & 0x01)
337 break;
338
339 M_PRINTF("Page write: timed out.\n");
340 return -3;
341 }
342 }
343
344 CancelAlarm((void *)timeout_cb, &has_timedout);
345
346 SPD_REG16(0x4804) = SM_CMD_GETSTATUS;
347 if (SPD_REG16(0x4814) & 0x01) {
348 M_PRINTF("Page write: status error.\n");
349 return -6;
350 }
351
352 SPD_REG16(0x480c) = 0;
353 return 0;
354}
355
356static u32 timeout_cb(void *arg)
357{
358 u32 *has_timedout = (u32 *)arg;
359
360 *has_timedout = 1;
361 return 0;
362}
u32 count
start sector of fragmented bd/file