blob: b74307ab6c49704c473c4ee44ca4b2d0917cda80 [file] [log] [blame]
unsik Kimf0b1bdd2009-02-25 11:31:24 +09001/*
2 * (C) Copyright 2009 mGine co.
3 * unsik Kim <donari75@gmail.com>
4 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 */
23
24#include <common.h>
25#include <malloc.h>
26#include <part.h>
27#include <ata.h>
28#include <asm/io.h>
29#include "mg_disk_prv.h"
30
31#ifndef CONFIG_MG_DISK_RES
32#define CONFIG_MG_DISK_RES 0
33#endif
34
35#define MG_RES_SEC ((CONFIG_MG_DISK_RES) << 1)
36
37static struct mg_host host;
38
39static inline u32 mg_base(void)
40{
41 return host.drv_data->base;
42}
43
44static block_dev_desc_t mg_disk_dev = {
45 .if_type = IF_TYPE_ATAPI,
46 .part_type = PART_TYPE_UNKNOWN,
47 .type = DEV_TYPE_HARDDISK,
48 .blksz = MG_SECTOR_SIZE,
49 .priv = &host };
50
51static void mg_dump_status (const char *msg, unsigned int stat, unsigned err)
52{
53 char *name = MG_DEV_NAME;
54
55 printf("%s: %s: status=0x%02x { ", name, msg, stat & 0xff);
56 if (stat & MG_REG_STATUS_BIT_BUSY)
57 printf("Busy ");
58 if (stat & MG_REG_STATUS_BIT_READY)
59 printf("DriveReady ");
60 if (stat & MG_REG_STATUS_BIT_WRITE_FAULT)
61 printf("WriteFault ");
62 if (stat & MG_REG_STATUS_BIT_SEEK_DONE)
63 printf("SeekComplete ");
64 if (stat & MG_REG_STATUS_BIT_DATA_REQ)
65 printf("DataRequest ");
66 if (stat & MG_REG_STATUS_BIT_CORRECTED_ERROR)
67 printf("CorrectedError ");
68 if (stat & MG_REG_STATUS_BIT_ERROR)
69 printf("Error ");
70 printf("}\n");
71
72 if ((stat & MG_REG_STATUS_BIT_ERROR)) {
73 printf("%s: %s: error=0x%02x { ", name, msg, err & 0xff);
74 if (err & MG_REG_ERR_BBK)
75 printf("BadSector ");
76 if (err & MG_REG_ERR_UNC)
77 printf("UncorrectableError ");
78 if (err & MG_REG_ERR_IDNF)
79 printf("SectorIdNotFound ");
80 if (err & MG_REG_ERR_ABRT)
81 printf("DriveStatusError ");
82 if (err & MG_REG_ERR_AMNF)
83 printf("AddrMarkNotFound ");
84 printf("}\n");
85 }
86}
87
88static unsigned int mg_wait (u32 expect, u32 msec)
89{
90 u8 status;
91 u32 from, cur, err;
92
93 err = MG_ERR_NONE;
94 reset_timer();
95 from = get_timer(0);
96
97 status = readb(mg_base() + MG_REG_STATUS);
98 do {
99 cur = get_timer(from);
100 if (status & MG_REG_STATUS_BIT_BUSY) {
101 if (expect == MG_REG_STATUS_BIT_BUSY)
102 break;
103 } else {
104 /* Check the error condition! */
105 if (status & MG_REG_STATUS_BIT_ERROR) {
106 err = readb(mg_base() + MG_REG_ERROR);
107 mg_dump_status("mg_wait", status, err);
108 break;
109 }
110
111 if (expect == MG_STAT_READY)
112 if (MG_READY_OK(status))
113 break;
114
115 if (expect == MG_REG_STATUS_BIT_DATA_REQ)
116 if (status & MG_REG_STATUS_BIT_DATA_REQ)
117 break;
118 }
119 status = readb(mg_base() + MG_REG_STATUS);
120 } while (cur < msec);
121
122 if (cur >= msec)
123 err = MG_ERR_TIMEOUT;
124
125 return err;
126}
127
128static int mg_get_disk_id (void)
129{
130 u16 id[(MG_SECTOR_SIZE / sizeof(u16))];
131 hd_driveid_t *iop = (hd_driveid_t *)id;
132 u32 i, err, res;
133
134 writeb(MG_CMD_ID, mg_base() + MG_REG_COMMAND);
135 err = mg_wait(MG_REG_STATUS_BIT_DATA_REQ, 3000);
136 if (err)
137 return err;
138
139 for(i = 0; i < (MG_SECTOR_SIZE / sizeof(u16)); i++)
140 id[i] = readw(mg_base() + MG_BUFF_OFFSET + i * 2);
141
142 writeb(MG_CMD_RD_CONF, mg_base() + MG_REG_COMMAND);
143 err = mg_wait(MG_STAT_READY, 3000);
144 if (err)
145 return err;
146
147 ata_swap_buf_le16(id, MG_SECTOR_SIZE / sizeof(u16));
148
149 if((iop->field_valid & 1) == 0)
150 return MG_ERR_TRANSLATION;
151
152 ata_id_c_string(id, (unsigned char *)mg_disk_dev.revision,
153 ATA_ID_FW_REV, sizeof(mg_disk_dev.revision));
154 ata_id_c_string(id, (unsigned char *)mg_disk_dev.vendor,
155 ATA_ID_PROD, sizeof(mg_disk_dev.vendor));
156 ata_id_c_string(id, (unsigned char *)mg_disk_dev.product,
157 ATA_ID_SERNO, sizeof(mg_disk_dev.product));
158
159#ifdef __BIG_ENDIAN
160 iop->lba_capacity = (iop->lba_capacity << 16) |
161 (iop->lba_capacity >> 16);
162#endif /* __BIG_ENDIAN */
163
164 if (MG_RES_SEC) {
165 MG_DBG("MG_RES_SEC=%d\n", MG_RES_SEC);
166 iop->cyls = (iop->lba_capacity - MG_RES_SEC) /
167 iop->sectors / iop->heads;
168 res = iop->lba_capacity -
169 iop->cyls * iop->heads * iop->sectors;
170 iop->lba_capacity -= res;
171 printf("mg_disk: %d sectors reserved\n", res);
172 }
173
174 mg_disk_dev.lba = iop->lba_capacity;
175 return MG_ERR_NONE;
176}
177
178static int mg_disk_reset (void)
179{
180 struct mg_drv_data *prv_data = host.drv_data;
181 s32 err;
182 u8 init_status;
183
184 /* hdd rst low */
185 prv_data->mg_hdrst_pin(0);
186 err = mg_wait(MG_REG_STATUS_BIT_BUSY, 300);
187 if(err)
188 return err;
189
190 /* hdd rst high */
191 prv_data->mg_hdrst_pin(1);
192 err = mg_wait(MG_STAT_READY, 3000);
193 if(err)
194 return err;
195
196 /* soft reset on */
197 writeb(MG_REG_CTRL_RESET | MG_REG_CTRL_INTR_DISABLE,
198 mg_base() + MG_REG_DRV_CTRL);
199 err = mg_wait(MG_REG_STATUS_BIT_BUSY, 3000);
200 if(err)
201 return err;
202
203 /* soft reset off */
204 writeb(MG_REG_CTRL_INTR_DISABLE, mg_base() + MG_REG_DRV_CTRL);
205 err = mg_wait(MG_STAT_READY, 3000);
206 if(err)
207 return err;
208
209 init_status = readb(mg_base() + MG_REG_STATUS) & 0xf;
210
211 if (init_status == 0xf)
212 return MG_ERR_INIT_STAT;
213
214 return err;
215}
216
217
218static unsigned int mg_out(unsigned int sect_num,
219 unsigned int sect_cnt,
220 unsigned int cmd)
221{
222 u32 err = MG_ERR_NONE;
223
224 err = mg_wait(MG_STAT_READY, 3000);
225 if (err)
226 return err;
227
228 writeb((u8)sect_cnt, mg_base() + MG_REG_SECT_CNT);
229 writeb((u8)sect_num, mg_base() + MG_REG_SECT_NUM);
230 writeb((u8)(sect_num >> 8), mg_base() + MG_REG_CYL_LOW);
231 writeb((u8)(sect_num >> 16), mg_base() + MG_REG_CYL_HIGH);
232 writeb((u8)((sect_num >> 24) | MG_REG_HEAD_LBA_MODE),
233 mg_base() + MG_REG_DRV_HEAD);
234 writeb(cmd, mg_base() + MG_REG_COMMAND);
235
236 return err;
237}
238
239static unsigned int mg_do_read_sects(void *buff, u32 sect_num, u32 sect_cnt)
240{
241 u32 i, j, err;
242 u8 *buff_ptr = buff;
243 union mg_uniwb uniwb;
244
245 err = mg_out(sect_num, sect_cnt, MG_CMD_RD);
246 if (err)
247 return err;
248
249 for (i = 0; i < sect_cnt; i++) {
250 err = mg_wait(MG_REG_STATUS_BIT_DATA_REQ, 3000);
251 if (err)
252 return err;
253
254 if ((u32)buff_ptr & 1) {
255 for (j = 0; j < MG_SECTOR_SIZE >> 1; j++) {
256 uniwb.w = readw(mg_base() + MG_BUFF_OFFSET
257 + (j << 1));
258 *buff_ptr++ = uniwb.b[0];
259 *buff_ptr++ = uniwb.b[1];
260 }
261 } else {
262 for(j = 0; j < MG_SECTOR_SIZE >> 1; j++) {
263 *(u16 *)buff_ptr = readw(mg_base() +
264 MG_BUFF_OFFSET + (j << 1));
265 buff_ptr += 2;
266 }
267 }
268 writeb(MG_CMD_RD_CONF, mg_base() + MG_REG_COMMAND);
269
270 MG_DBG("%u (0x%8.8x) sector read", sect_num + i,
271 (sect_num + i) * MG_SECTOR_SIZE);
272 }
273
274 return err;
275}
276
277unsigned int mg_disk_read_sects(void *buff, u32 sect_num, u32 sect_cnt)
278{
279 u32 quotient, residue, i, err;
280 u8 *buff_ptr = buff;
281
282 quotient = sect_cnt >> 8;
283 residue = sect_cnt % 256;
284
285 for (i = 0; i < quotient; i++) {
286 MG_DBG("sect num : %u buff : 0x%8.8x", sect_num, (u32)buff_ptr);
287 err = mg_do_read_sects(buff_ptr, sect_num, 256);
288 if (err)
289 return err;
290 sect_num += 256;
291 buff_ptr += 256 * MG_SECTOR_SIZE;
292 }
293
294 if (residue) {
295 MG_DBG("sect num : %u buff : %8.8x", sect_num, (u32)buff_ptr);
296 err = mg_do_read_sects(buff_ptr, sect_num, residue);
297 }
298
299 return err;
300}
301
302unsigned long mg_block_read (int dev, unsigned long start,
303 lbaint_t blkcnt, void *buffer)
304{
305 start += MG_RES_SEC;
306 if (! mg_disk_read_sects(buffer, start, blkcnt))
307 return blkcnt;
308 else
309 return 0;
310}
311
312unsigned int mg_disk_read (u32 addr, u8 *buff, u32 len)
313{
314 u8 *sect_buff, *buff_ptr = buff;
315 u32 cur_addr, next_sec_addr, end_addr, cnt, sect_num;
316 u32 err = MG_ERR_NONE;
317
318 /* TODO : sanity chk */
319 cnt = 0;
320 cur_addr = addr;
321 end_addr = addr + len;
322
323 sect_buff = malloc(MG_SECTOR_SIZE);
324
325 if (cur_addr & MG_SECTOR_SIZE_MASK) {
326 next_sec_addr = (cur_addr + MG_SECTOR_SIZE) &
327 ~MG_SECTOR_SIZE_MASK;
328 sect_num = cur_addr >> MG_SECTOR_SIZE_SHIFT;
329 err = mg_disk_read_sects(sect_buff, sect_num, 1);
330 if (err)
331 goto mg_read_exit;
332
333 if (end_addr < next_sec_addr) {
334 memcpy(buff_ptr,
335 sect_buff + (cur_addr & MG_SECTOR_SIZE_MASK),
336 end_addr - cur_addr);
337 MG_DBG("copies %u byte from sector offset 0x%8.8x",
338 end_addr - cur_addr, cur_addr);
339 cur_addr = end_addr;
340 } else {
341 memcpy(buff_ptr,
342 sect_buff + (cur_addr & MG_SECTOR_SIZE_MASK),
343 next_sec_addr - cur_addr);
344 MG_DBG("copies %u byte from sector offset 0x%8.8x",
345 next_sec_addr - cur_addr, cur_addr);
346 buff_ptr += (next_sec_addr - cur_addr);
347 cur_addr = next_sec_addr;
348 }
349 }
350
351 if (cur_addr < end_addr) {
352 sect_num = cur_addr >> MG_SECTOR_SIZE_SHIFT;
353 cnt = ((end_addr & ~MG_SECTOR_SIZE_MASK) - cur_addr) >>
354 MG_SECTOR_SIZE_SHIFT;
355
356 if (cnt)
357 err = mg_disk_read_sects(buff_ptr, sect_num, cnt);
358 if (err)
359 goto mg_read_exit;
360
361 buff_ptr += cnt * MG_SECTOR_SIZE;
362 cur_addr += cnt * MG_SECTOR_SIZE;
363
364 if (cur_addr < end_addr) {
365 sect_num = cur_addr >> MG_SECTOR_SIZE_SHIFT;
366 err = mg_disk_read_sects(sect_buff, sect_num, 1);
367 if (err)
368 goto mg_read_exit;
369 memcpy(buff_ptr, sect_buff, end_addr - cur_addr);
370 MG_DBG("copies %u byte", end_addr - cur_addr);
371 }
372 }
373
374mg_read_exit:
375 free(sect_buff);
376
377 return err;
378}
379static int mg_do_write_sects(void *buff, u32 sect_num, u32 sect_cnt)
380{
381 u32 i, j, err;
382 u8 *buff_ptr = buff;
383 union mg_uniwb uniwb;
384
385 err = mg_out(sect_num, sect_cnt, MG_CMD_WR);
386 if (err)
387 return err;
388
389 for (i = 0; i < sect_cnt; i++) {
390 err = mg_wait(MG_REG_STATUS_BIT_DATA_REQ, 3000);
391 if (err)
392 return err;
393
394 if ((u32)buff_ptr & 1) {
395 uniwb.b[0] = *buff_ptr++;
396 uniwb.b[1] = *buff_ptr++;
397 writew(uniwb.w, mg_base() + MG_BUFF_OFFSET + (j << 1));
398 } else {
399 for(j = 0; j < MG_SECTOR_SIZE >> 1; j++) {
400 writew(*(u16 *)buff_ptr,
401 mg_base() + MG_BUFF_OFFSET +
402 (j << 1));
403 buff_ptr += 2;
404 }
405 }
406 writeb(MG_CMD_WR_CONF, mg_base() + MG_REG_COMMAND);
407
408 MG_DBG("%u (0x%8.8x) sector write",
409 sect_num + i, (sect_num + i) * MG_SECTOR_SIZE);
410 }
411
412 return err;
413}
414
415unsigned int mg_disk_write_sects(void *buff, u32 sect_num, u32 sect_cnt)
416{
417 u32 quotient, residue, i;
418 u32 err = MG_ERR_NONE;
419 u8 *buff_ptr = buff;
420
421 quotient = sect_cnt >> 8;
422 residue = sect_cnt % 256;
423
424 for (i = 0; i < quotient; i++) {
425 MG_DBG("sect num : %u buff : %8.8x", sect_num, (u32)buff_ptr);
426 err = mg_do_write_sects(buff_ptr, sect_num, 256);
427 if (err)
428 return err;
429 sect_num += 256;
430 buff_ptr += 256 * MG_SECTOR_SIZE;
431 }
432
433 if (residue) {
434 MG_DBG("sect num : %u buff : %8.8x", sect_num, (u32)buff_ptr);
435 err = mg_do_write_sects(buff_ptr, sect_num, residue);
436 }
437
438 return err;
439}
440
441unsigned long mg_block_write (int dev, unsigned long start,
442 lbaint_t blkcnt, const void *buffer)
443{
444 start += MG_RES_SEC;
445 if (!mg_disk_write_sects((void *)buffer, start, blkcnt))
446 return blkcnt;
447 else
448 return 0;
449}
450
451unsigned int mg_disk_write(u32 addr, u8 *buff, u32 len)
452{
453 u8 *sect_buff, *buff_ptr = buff;
454 u32 cur_addr, next_sec_addr, end_addr, cnt, sect_num;
455 u32 err = MG_ERR_NONE;
456
457 /* TODO : sanity chk */
458 cnt = 0;
459 cur_addr = addr;
460 end_addr = addr + len;
461
462 sect_buff = malloc(MG_SECTOR_SIZE);
463
464 if (cur_addr & MG_SECTOR_SIZE_MASK) {
465
466 next_sec_addr = (cur_addr + MG_SECTOR_SIZE) &
467 ~MG_SECTOR_SIZE_MASK;
468 sect_num = cur_addr >> MG_SECTOR_SIZE_SHIFT;
469 err = mg_disk_read_sects(sect_buff, sect_num, 1);
470 if (err)
471 goto mg_write_exit;
472
473 if (end_addr < next_sec_addr) {
474 memcpy(sect_buff + (cur_addr & MG_SECTOR_SIZE_MASK),
475 buff_ptr, end_addr - cur_addr);
476 MG_DBG("copies %u byte to sector offset 0x%8.8x",
477 end_addr - cur_addr, cur_addr);
478 cur_addr = end_addr;
479 } else {
480 memcpy(sect_buff + (cur_addr & MG_SECTOR_SIZE_MASK),
481 buff_ptr, next_sec_addr - cur_addr);
482 MG_DBG("copies %u byte to sector offset 0x%8.8x",
483 next_sec_addr - cur_addr, cur_addr);
484 buff_ptr += (next_sec_addr - cur_addr);
485 cur_addr = next_sec_addr;
486 }
487
488 err = mg_disk_write_sects(sect_buff, sect_num, 1);
489 if (err)
490 goto mg_write_exit;
491 }
492
493 if (cur_addr < end_addr) {
494
495 sect_num = cur_addr >> MG_SECTOR_SIZE_SHIFT;
496 cnt = ((end_addr & ~MG_SECTOR_SIZE_MASK) - cur_addr) >>
497 MG_SECTOR_SIZE_SHIFT;
498
499 if (cnt)
500 err = mg_disk_write_sects(buff_ptr, sect_num, cnt);
501 if (err)
502 goto mg_write_exit;
503
504 buff_ptr += cnt * MG_SECTOR_SIZE;
505 cur_addr += cnt * MG_SECTOR_SIZE;
506
507 if (cur_addr < end_addr) {
508 sect_num = cur_addr >> MG_SECTOR_SIZE_SHIFT;
509 err = mg_disk_read_sects(sect_buff, sect_num, 1);
510 if (err)
511 goto mg_write_exit;
512 memcpy(sect_buff, buff_ptr, end_addr - cur_addr);
513 MG_DBG("copies %u byte", end_addr - cur_addr);
514 err = mg_disk_write_sects(sect_buff, sect_num, 1);
515 }
516
517 }
518
519mg_write_exit:
520 free(sect_buff);
521
522 return err;
523}
524
525block_dev_desc_t *mg_disk_get_dev(int dev)
526{
527 return ((block_dev_desc_t *) & mg_disk_dev);
528}
529
530/* must override this function */
531struct mg_drv_data * __attribute__((weak)) mg_get_drv_data (void)
532{
533 puts ("### WARNING ### port mg_get_drv_data function\n");
534 return NULL;
535}
536
537unsigned int mg_disk_init (void)
538{
539 struct mg_drv_data *prv_data;
540 u32 err = MG_ERR_NONE;
541
542 prv_data = mg_get_drv_data();
543 if (! prv_data) {
544 printf("%s:%d fail (no driver_data)\n", __func__, __LINE__);
545 err = MG_ERR_NO_DRV_DATA;
546 return err;
547 }
548
549 ((struct mg_host *)mg_disk_dev.priv)->drv_data = prv_data;
550
551 /* init ctrl pin */
552 if (prv_data->mg_ctrl_pin_init)
553 prv_data->mg_ctrl_pin_init();
554
555 if (! prv_data->mg_hdrst_pin) {
556 err = MG_ERR_CTRL_RST;
557 return err;
558 }
559
560 /* disk reset */
561 err = mg_disk_reset();
562 if (err) {
563 printf("%s:%d fail (err code : %d)\n", __func__, __LINE__, err);
564 return err;
565 }
566
567 /* get disk id */
568 err = mg_get_disk_id();
569 if (err) {
570 printf("%s:%d fail (err code : %d)\n", __func__, __LINE__, err);
571 return err;
572 }
573
574 mg_disk_dev.block_read = mg_block_read;
575 mg_disk_dev.block_write = mg_block_write;
576
577 init_part(&mg_disk_dev);
578
579 dev_print(&mg_disk_dev);
580
581 return err;
582}