blob: d77e05647b873c885b6c314320c21481645151cd [file] [log] [blame]
Dave Chapman205be712006-01-18 10:01:35 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Tomasz Malesinski
11 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000012 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
Dave Chapman205be712006-01-18 10:01:35 +000016 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "ata.h"
23#include <stdbool.h>
24#include <string.h>
25
26#if CONFIG_CPU == PNX0101
27#include "pnx0101.h"
28#endif
29
30/*
31#include "kernel.h"
32#include "thread.h"
33#include "led.h"
34#include "cpu.h"
35#include "system.h"
36#include "debug.h"
37#include "panic.h"
38#include "usb.h"
39#include "power.h"
40#include "string.h"
Dave Chapman205be712006-01-18 10:01:35 +000041*/
42
43#define SECTOR_SIZE (512)
44
45static unsigned short identify_info[SECTOR_SIZE];
46int ata_spinup_time = 0;
47long last_disk_activity = -1;
48
49#if CONFIG_FLASH == FLASH_IFP7XX
50static unsigned char flash_ce[4] = {0x20, 0x02, 0x10, 0x08};
51
52#define FLASH_IO_BASE 0x28000000
53#define FLASH_REG_DATA (*((volatile unsigned char*)(FLASH_IO_BASE)))
54#define FLASH_REG_CMD (*((volatile unsigned char*)(FLASH_IO_BASE + 4)))
55#define FLASH_REG_ADDR (*((volatile unsigned char*)(FLASH_IO_BASE + 8)))
56
57#define SEGMENT_SIZE 1000
Tomasz Malesinskic1810b32006-08-12 22:51:18 +000058#define MAX_N_SEGMENTS 8
Dave Chapman205be712006-01-18 10:01:35 +000059
60#endif
61
62#define FLASH_MODEL_NONE 0
63#define FLASH_MODEL_256 1
Tomasz Malesinskic1810b32006-08-12 22:51:18 +000064#define FLASH_MODEL_512 2
Dave Chapman205be712006-01-18 10:01:35 +000065
66struct flash_disk
67{
Dave Chapman205be712006-01-18 10:01:35 +000068 unsigned short block_map[MAX_N_SEGMENTS][SEGMENT_SIZE];
69 short cur_block;
70 int cur_phblock_start;
Tomasz Malesinskic1810b32006-08-12 22:51:18 +000071 int n_chips;
72 unsigned char chip_no[4];
73 unsigned char model;
Dave Chapman205be712006-01-18 10:01:35 +000074};
75
76static struct flash_disk flash_disk;
77
78void flash_select_chip(int no, int sel)
79{
80#if CONFIG_FLASH == FLASH_IFP7XX
81 if (sel)
82 GPIO5_CLR = flash_ce[no];
83 else
84 GPIO5_SET = flash_ce[no];
85#endif
86}
87
Tomasz Malesinskic1810b32006-08-12 22:51:18 +000088static inline unsigned char flash_read_data(void)
Dave Chapman205be712006-01-18 10:01:35 +000089{
90 return FLASH_REG_DATA;
91}
92
Tomasz Malesinskic1810b32006-08-12 22:51:18 +000093static inline void flash_write_data(unsigned char data)
Dave Chapman205be712006-01-18 10:01:35 +000094{
95 FLASH_REG_DATA = data;
96}
97
Tomasz Malesinskic1810b32006-08-12 22:51:18 +000098/* TODO: these two doesn't work when inlined, probably some
99 delay is required */
100
101static void flash_write_cmd(unsigned char cmd)
Dave Chapman205be712006-01-18 10:01:35 +0000102{
103 FLASH_REG_CMD = cmd;
104}
105
Tomasz Malesinskic1810b32006-08-12 22:51:18 +0000106static void flash_write_addr(unsigned char addr)
Dave Chapman205be712006-01-18 10:01:35 +0000107{
108 FLASH_REG_ADDR = addr;
109}
110
Tomasz Malesinskic1810b32006-08-12 22:51:18 +0000111static void flash_wait_ready(void)
Dave Chapman205be712006-01-18 10:01:35 +0000112{
113 int i;
114 for (i = 0; i < 5; i++)
115 while ((GPIO6_READ & 8) == 0);
116}
117
Tomasz Malesinskic1810b32006-08-12 22:51:18 +0000118static unsigned char model_n_sectors_order[] = {0, 19, 20};
119
Dave Chapman205be712006-01-18 10:01:35 +0000120int flash_map_sector(int sector, int* chip, int* chip_sector)
121{
Tomasz Malesinskic1810b32006-08-12 22:51:18 +0000122 int ord, c;
123 if (flash_disk.model == FLASH_MODEL_NONE)
124 return -1;
125
126 ord = model_n_sectors_order[flash_disk.model];
127 c = sector >> ord;
128 *chip_sector = sector & ((1 << ord) - 1);
129
130 if (c >= flash_disk.n_chips)
131 return -1;
132
133 *chip = flash_disk.chip_no[c];
134 return 0;
Dave Chapman205be712006-01-18 10:01:35 +0000135}
136
137int flash_read_id(int no) {
138 int id;
139
140 flash_select_chip(no, 1);
141 flash_write_cmd(0x90);
142 flash_write_addr(0);
143
144 flash_read_data();
145 id = flash_read_data();
146
147 flash_select_chip(no, 0);
148 return id;
149}
150
151int flash_read_sector(int sector, unsigned char* buf,
152 unsigned char* oob)
153{
Tomasz Malesinski7d1eedd2007-09-22 22:53:29 +0000154 unsigned long *bufl = (unsigned long *)buf;
Dave Chapman205be712006-01-18 10:01:35 +0000155 int chip, chip_sector;
156 int i;
157
158 if (flash_map_sector(sector, &chip, &chip_sector) < 0)
159 return -1;
160
161 flash_select_chip(chip, 1);
162
163 flash_write_cmd(0x00);
164 flash_write_addr(0);
165 flash_write_addr((chip_sector << 1) & 7);
166 flash_write_addr((chip_sector >> 2) & 0xff);
167 flash_write_addr((chip_sector >> 10) & 0xff);
168 flash_write_addr((chip_sector >> 18) & 0xff);
169 flash_write_cmd(0x30);
170
171 flash_wait_ready();
172
Tomasz Malesinski7d1eedd2007-09-22 22:53:29 +0000173 if ((unsigned long)buf & 3)
174 {
175 for (i = 0; i < 512; i++)
176 buf[i] = flash_read_data();
177 }
178 else
179 {
180 for (i = 0; i < 512 / 4; i++) {
181 unsigned long v;
182#ifdef ROCKBOX_LITTLE_ENDIAN
183 v = flash_read_data();
184 v |= (unsigned long)flash_read_data() << 8;
185 v |= (unsigned long)flash_read_data() << 16;
186 v |= (unsigned long)flash_read_data() << 24;
187#else
188 v = (unsigned long)flash_read_data() << 24;
189 v |= (unsigned long)flash_read_data() << 16;
190 v |= (unsigned long)flash_read_data() << 8;
191 v |= flash_read_data();
192#endif
193 bufl[i] = v;
194 }
195 }
Dave Chapman205be712006-01-18 10:01:35 +0000196
197 flash_write_cmd(0x05);
198 flash_write_addr((chip_sector & 3) * 0x10);
199 flash_write_addr(8);
200 flash_write_cmd(0xe0);
201
202 for (i = 0; i < 16; i++)
203 oob[i] = flash_read_data();
204
205 flash_select_chip(chip, 0);
206 return 0;
207}
208
209int flash_read_sector_oob(int sector, unsigned char* oob)
210{
211 int chip, chip_sector;
212 int i;
213
214 if (flash_map_sector(sector, &chip, &chip_sector) < 0)
215 return -1;
216
217 flash_select_chip(chip, 1);
218
219 flash_write_cmd(0x00);
220 flash_write_addr((chip_sector & 3) * 0x10);
221 flash_write_addr(8);
222 flash_write_addr((chip_sector >> 2) & 0xff);
223 flash_write_addr((chip_sector >> 10) & 0xff);
224 flash_write_addr((chip_sector >> 18) & 0xff);
225 flash_write_cmd(0x30);
226
227 flash_wait_ready();
228
229 for (i = 0; i < 16; i++)
230 oob[i] = flash_read_data();
231
232 flash_select_chip(chip, 0);
233 return 0;
234}
235
Tomasz Malesinskic1810b32006-08-12 22:51:18 +0000236static unsigned char model_n_segments[] = {0, 2, 4};
Dave Chapman205be712006-01-18 10:01:35 +0000237
Tomasz Malesinskic1810b32006-08-12 22:51:18 +0000238static inline int flash_get_n_segments(void)
Dave Chapman205be712006-01-18 10:01:35 +0000239{
Tomasz Malesinskic1810b32006-08-12 22:51:18 +0000240 return model_n_segments[flash_disk.model] * flash_disk.n_chips;
Dave Chapman205be712006-01-18 10:01:35 +0000241}
242
Tomasz Malesinskic1810b32006-08-12 22:51:18 +0000243static inline int flash_get_n_phblocks(void)
Dave Chapman205be712006-01-18 10:01:35 +0000244{
245 return 1024;
246}
247
Tomasz Malesinskic1810b32006-08-12 22:51:18 +0000248static int model_n_sectors_in_block[] = {0, 256, 256};
Dave Chapman205be712006-01-18 10:01:35 +0000249
250static int flash_get_n_sectors_in_block(void)
251{
252 return model_n_sectors_in_block[flash_disk.model];
253}
254
255static int flash_phblock_to_sector(int segment, int block)
256{
257 return (segment * flash_get_n_phblocks() + block)
258 * flash_get_n_sectors_in_block();
259}
260
261static int flash_is_bad_block(unsigned char* oob)
262{
263 /* TODO: should we check two pages? (see datasheet) */
264 return oob[0] != 0xff;
265}
266
267static int count_1(int n) {
268 int r = 0;
269 while (n != 0) {
270 r += (n & 1);
271 n >>= 1;
272 }
273 return r;
274}
275
276static int flash_get_logical_block_no(unsigned char* oob)
277{
278 int no1, no2;
279 no1 = oob[6] + (oob[7] << 8);
280 no2 = oob[11] + (oob[12] << 8);
281
282 if (no1 == no2 && (no1 & 0xf000) == 0x1000)
283 return (no1 & 0xfff) >> 1;
284
285 if (count_1(no1 ^ no2) > 1)
286 return -1;
287
288 if ((no1 & 0xf000) == 0x1000
289 && (count_1(no1) & 1) == 0)
290 return (no1 & 0xfff) >> 1;
291
292 if ((no2 & 0xf000) == 0x1000
293 && (count_1(no2) & 1) == 0)
294 return (no2 & 0xfff) >> 1;
295
296 return -1;
297}
298
299int flash_disk_scan(void)
300{
301 int n_segments, n_phblocks;
302 unsigned char oob[16];
303 int s, b;
304
305 /* TODO: checking for double blocks */
306
307 n_segments = flash_get_n_segments();
308 n_phblocks = flash_get_n_phblocks();
309
310 flash_disk.cur_block = -1;
311 flash_disk.cur_phblock_start = -1;
312
313 for (s = 0; s < n_segments; s++)
314 {
315 for (b = 0; b < n_phblocks; b++)
316 {
317 int r;
318 r = flash_read_sector_oob(flash_phblock_to_sector(s, b),
319 oob);
320 if (r >= 0 && !flash_is_bad_block(oob))
321 {
322 int lb;
323 lb = flash_get_logical_block_no(oob);
324 if (lb >= 0 && lb < SEGMENT_SIZE)
325 flash_disk.block_map[s][lb] = b;
326 }
327 }
328 }
329 return 0;
330}
331
332int flash_disk_find_block(int block)
333{
334 int seg, bmod, phb;
335 unsigned char oob[16];
336 int r;
337
338 if (block >= SEGMENT_SIZE * flash_get_n_segments())
339 return -1;
340
341 if (block == flash_disk.cur_block)
342 return flash_disk.cur_phblock_start;
343
344 seg = block / SEGMENT_SIZE;
345 bmod = block % SEGMENT_SIZE;
346
347 phb = flash_disk.block_map[seg][bmod];
348 r = flash_read_sector_oob(flash_phblock_to_sector(seg, phb), oob);
349 if (r < 0)
350 return -1;
351 if (flash_is_bad_block(oob))
352 return -1;
353 if (flash_get_logical_block_no(oob) != bmod)
354 return -1;
355
356 flash_disk.cur_block = block;
357 flash_disk.cur_phblock_start = flash_phblock_to_sector(seg, phb);
358 return flash_disk.cur_phblock_start;
359}
360
361int flash_disk_read_sectors(unsigned long start,
362 int count,
363 void* buf)
364{
365 int block, secmod, done;
366 int phb;
367 char oob[16];
368
369 block = start / flash_get_n_sectors_in_block();
370 secmod = start % flash_get_n_sectors_in_block();
371
372 phb = flash_disk_find_block(block);
373 done = 0;
374 while (count > 0 && secmod < flash_get_n_sectors_in_block())
375 {
376 if (phb >= 0)
377 flash_read_sector(phb + secmod, buf, oob);
378 else
379 memset(buf, 0, SECTOR_SIZE);
380
381 buf += SECTOR_SIZE;
382 count--;
383 secmod++;
384 done++;
385 }
386 return done;
387}
388
389int ata_read_sectors(IF_MV2(int drive,)
390 unsigned long start,
391 int incount,
392 void* inbuf)
393{
394 while (incount > 0)
395 {
396 int done = flash_disk_read_sectors(start, incount, inbuf);
397 if (done < 0)
398 return -1;
Tomasz Malesinskic1810b32006-08-12 22:51:18 +0000399 start += done;
Dave Chapman205be712006-01-18 10:01:35 +0000400 incount -= done;
401 inbuf += SECTOR_SIZE * done;
402 }
403 return 0;
404}
405
406int ata_write_sectors(IF_MV2(int drive,)
407 unsigned long start,
408 int count,
409 const void* buf)
410{
411 (void)start;
412 (void)count;
413 (void)buf;
414 return -1;
415}
416
417/* schedule a single sector write, executed with the the next spinup
418 (volume 0 only, used for config sector) */
419extern void ata_delayed_write(unsigned long sector, const void* buf)
420{
421 (void)sector;
422 (void)buf;
423}
424
425/* write the delayed sector to volume 0 */
426extern void ata_flush(void)
427{
428
429}
430
431void ata_spindown(int seconds)
432{
433 (void)seconds;
434}
435
436bool ata_disk_is_active(void)
437{
438 return 0;
439}
440
441void ata_sleep(void)
442{
443}
444
445void ata_spin(void)
446{
447}
448
449/* Hardware reset protocol as specified in chapter 9.1, ATA spec draft v5 */
450int ata_hard_reset(void)
451{
452 return 0;
453}
454
455int ata_soft_reset(void)
456{
457 return 0;
458}
459
460void ata_enable(bool on)
461{
462 (void)on;
463}
464
465unsigned short* ata_get_identify(void)
466{
467 return identify_info;
468}
469
470int ata_init(void)
471{
Tomasz Malesinskic1810b32006-08-12 22:51:18 +0000472 int i, id, id2;
Dave Chapman205be712006-01-18 10:01:35 +0000473
474 id = flash_read_id(0);
475 switch (id)
476 {
477 case 0xda:
478 flash_disk.model = FLASH_MODEL_256;
479 break;
Tomasz Malesinskic1810b32006-08-12 22:51:18 +0000480 case 0xdc:
481 flash_disk.model = FLASH_MODEL_512;
482 break;
Dave Chapman205be712006-01-18 10:01:35 +0000483 default:
484 flash_disk.model = FLASH_MODEL_NONE;
485 return -1;
486 }
487
Tomasz Malesinskic1810b32006-08-12 22:51:18 +0000488 flash_disk.n_chips = 1;
489 flash_disk.chip_no[0] = 0;
490 for (i = 1; i < 4; i++)
491 {
492 id2 = flash_read_id(i);
493 if (id2 == id)
494 flash_disk.chip_no[flash_disk.n_chips++] = i;
495 }
496
Dave Chapman205be712006-01-18 10:01:35 +0000497 if (flash_disk_scan() < 0)
498 return -2;
499
500 return 0;
501}