blob: 4407006a6f80f870a5a020b71ff4e17f424626d0 [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;
Graeme Russ13ec42b2011-07-15 02:18:56 +000094#ifdef CONFIG_SYS_LOW_RES_TIMER
unsik Kimf0b1bdd2009-02-25 11:31:24 +090095 reset_timer();
Graeme Russ13ec42b2011-07-15 02:18:56 +000096#endif
unsik Kimf0b1bdd2009-02-25 11:31:24 +090097 from = get_timer(0);
98
99 status = readb(mg_base() + MG_REG_STATUS);
100 do {
101 cur = get_timer(from);
102 if (status & MG_REG_STATUS_BIT_BUSY) {
103 if (expect == MG_REG_STATUS_BIT_BUSY)
104 break;
105 } else {
106 /* Check the error condition! */
107 if (status & MG_REG_STATUS_BIT_ERROR) {
108 err = readb(mg_base() + MG_REG_ERROR);
109 mg_dump_status("mg_wait", status, err);
110 break;
111 }
112
113 if (expect == MG_STAT_READY)
114 if (MG_READY_OK(status))
115 break;
116
117 if (expect == MG_REG_STATUS_BIT_DATA_REQ)
118 if (status & MG_REG_STATUS_BIT_DATA_REQ)
119 break;
120 }
121 status = readb(mg_base() + MG_REG_STATUS);
122 } while (cur < msec);
123
124 if (cur >= msec)
125 err = MG_ERR_TIMEOUT;
126
127 return err;
128}
129
130static int mg_get_disk_id (void)
131{
132 u16 id[(MG_SECTOR_SIZE / sizeof(u16))];
133 hd_driveid_t *iop = (hd_driveid_t *)id;
134 u32 i, err, res;
135
136 writeb(MG_CMD_ID, mg_base() + MG_REG_COMMAND);
137 err = mg_wait(MG_REG_STATUS_BIT_DATA_REQ, 3000);
138 if (err)
139 return err;
140
141 for(i = 0; i < (MG_SECTOR_SIZE / sizeof(u16)); i++)
142 id[i] = readw(mg_base() + MG_BUFF_OFFSET + i * 2);
143
144 writeb(MG_CMD_RD_CONF, mg_base() + MG_REG_COMMAND);
145 err = mg_wait(MG_STAT_READY, 3000);
146 if (err)
147 return err;
148
149 ata_swap_buf_le16(id, MG_SECTOR_SIZE / sizeof(u16));
150
151 if((iop->field_valid & 1) == 0)
152 return MG_ERR_TRANSLATION;
153
154 ata_id_c_string(id, (unsigned char *)mg_disk_dev.revision,
155 ATA_ID_FW_REV, sizeof(mg_disk_dev.revision));
156 ata_id_c_string(id, (unsigned char *)mg_disk_dev.vendor,
157 ATA_ID_PROD, sizeof(mg_disk_dev.vendor));
158 ata_id_c_string(id, (unsigned char *)mg_disk_dev.product,
159 ATA_ID_SERNO, sizeof(mg_disk_dev.product));
160
161#ifdef __BIG_ENDIAN
162 iop->lba_capacity = (iop->lba_capacity << 16) |
163 (iop->lba_capacity >> 16);
164#endif /* __BIG_ENDIAN */
165
166 if (MG_RES_SEC) {
167 MG_DBG("MG_RES_SEC=%d\n", MG_RES_SEC);
168 iop->cyls = (iop->lba_capacity - MG_RES_SEC) /
169 iop->sectors / iop->heads;
170 res = iop->lba_capacity -
171 iop->cyls * iop->heads * iop->sectors;
172 iop->lba_capacity -= res;
173 printf("mg_disk: %d sectors reserved\n", res);
174 }
175
176 mg_disk_dev.lba = iop->lba_capacity;
177 return MG_ERR_NONE;
178}
179
180static int mg_disk_reset (void)
181{
182 struct mg_drv_data *prv_data = host.drv_data;
183 s32 err;
184 u8 init_status;
185
186 /* hdd rst low */
187 prv_data->mg_hdrst_pin(0);
188 err = mg_wait(MG_REG_STATUS_BIT_BUSY, 300);
189 if(err)
190 return err;
191
192 /* hdd rst high */
193 prv_data->mg_hdrst_pin(1);
194 err = mg_wait(MG_STAT_READY, 3000);
195 if(err)
196 return err;
197
198 /* soft reset on */
199 writeb(MG_REG_CTRL_RESET | MG_REG_CTRL_INTR_DISABLE,
200 mg_base() + MG_REG_DRV_CTRL);
201 err = mg_wait(MG_REG_STATUS_BIT_BUSY, 3000);
202 if(err)
203 return err;
204
205 /* soft reset off */
206 writeb(MG_REG_CTRL_INTR_DISABLE, mg_base() + MG_REG_DRV_CTRL);
207 err = mg_wait(MG_STAT_READY, 3000);
208 if(err)
209 return err;
210
211 init_status = readb(mg_base() + MG_REG_STATUS) & 0xf;
212
213 if (init_status == 0xf)
214 return MG_ERR_INIT_STAT;
215
216 return err;
217}
218
219
220static unsigned int mg_out(unsigned int sect_num,
221 unsigned int sect_cnt,
222 unsigned int cmd)
223{
224 u32 err = MG_ERR_NONE;
225
226 err = mg_wait(MG_STAT_READY, 3000);
227 if (err)
228 return err;
229
230 writeb((u8)sect_cnt, mg_base() + MG_REG_SECT_CNT);
231 writeb((u8)sect_num, mg_base() + MG_REG_SECT_NUM);
232 writeb((u8)(sect_num >> 8), mg_base() + MG_REG_CYL_LOW);
233 writeb((u8)(sect_num >> 16), mg_base() + MG_REG_CYL_HIGH);
234 writeb((u8)((sect_num >> 24) | MG_REG_HEAD_LBA_MODE),
235 mg_base() + MG_REG_DRV_HEAD);
236 writeb(cmd, mg_base() + MG_REG_COMMAND);
237
238 return err;
239}
240
241static unsigned int mg_do_read_sects(void *buff, u32 sect_num, u32 sect_cnt)
242{
243 u32 i, j, err;
244 u8 *buff_ptr = buff;
245 union mg_uniwb uniwb;
246
247 err = mg_out(sect_num, sect_cnt, MG_CMD_RD);
248 if (err)
249 return err;
250
251 for (i = 0; i < sect_cnt; i++) {
252 err = mg_wait(MG_REG_STATUS_BIT_DATA_REQ, 3000);
253 if (err)
254 return err;
255
256 if ((u32)buff_ptr & 1) {
257 for (j = 0; j < MG_SECTOR_SIZE >> 1; j++) {
258 uniwb.w = readw(mg_base() + MG_BUFF_OFFSET
259 + (j << 1));
260 *buff_ptr++ = uniwb.b[0];
261 *buff_ptr++ = uniwb.b[1];
262 }
263 } else {
264 for(j = 0; j < MG_SECTOR_SIZE >> 1; j++) {
265 *(u16 *)buff_ptr = readw(mg_base() +
266 MG_BUFF_OFFSET + (j << 1));
267 buff_ptr += 2;
268 }
269 }
270 writeb(MG_CMD_RD_CONF, mg_base() + MG_REG_COMMAND);
271
272 MG_DBG("%u (0x%8.8x) sector read", sect_num + i,
273 (sect_num + i) * MG_SECTOR_SIZE);
274 }
275
276 return err;
277}
278
279unsigned int mg_disk_read_sects(void *buff, u32 sect_num, u32 sect_cnt)
280{
281 u32 quotient, residue, i, err;
282 u8 *buff_ptr = buff;
283
284 quotient = sect_cnt >> 8;
285 residue = sect_cnt % 256;
286
287 for (i = 0; i < quotient; i++) {
288 MG_DBG("sect num : %u buff : 0x%8.8x", sect_num, (u32)buff_ptr);
289 err = mg_do_read_sects(buff_ptr, sect_num, 256);
290 if (err)
291 return err;
292 sect_num += 256;
293 buff_ptr += 256 * MG_SECTOR_SIZE;
294 }
295
296 if (residue) {
297 MG_DBG("sect num : %u buff : %8.8x", sect_num, (u32)buff_ptr);
298 err = mg_do_read_sects(buff_ptr, sect_num, residue);
299 }
300
301 return err;
302}
303
304unsigned long mg_block_read (int dev, unsigned long start,
305 lbaint_t blkcnt, void *buffer)
306{
307 start += MG_RES_SEC;
308 if (! mg_disk_read_sects(buffer, start, blkcnt))
309 return blkcnt;
310 else
311 return 0;
312}
313
314unsigned int mg_disk_read (u32 addr, u8 *buff, u32 len)
315{
316 u8 *sect_buff, *buff_ptr = buff;
317 u32 cur_addr, next_sec_addr, end_addr, cnt, sect_num;
318 u32 err = MG_ERR_NONE;
319
320 /* TODO : sanity chk */
321 cnt = 0;
322 cur_addr = addr;
323 end_addr = addr + len;
324
325 sect_buff = malloc(MG_SECTOR_SIZE);
326
327 if (cur_addr & MG_SECTOR_SIZE_MASK) {
328 next_sec_addr = (cur_addr + MG_SECTOR_SIZE) &
329 ~MG_SECTOR_SIZE_MASK;
330 sect_num = cur_addr >> MG_SECTOR_SIZE_SHIFT;
331 err = mg_disk_read_sects(sect_buff, sect_num, 1);
332 if (err)
333 goto mg_read_exit;
334
335 if (end_addr < next_sec_addr) {
336 memcpy(buff_ptr,
337 sect_buff + (cur_addr & MG_SECTOR_SIZE_MASK),
338 end_addr - cur_addr);
339 MG_DBG("copies %u byte from sector offset 0x%8.8x",
340 end_addr - cur_addr, cur_addr);
341 cur_addr = end_addr;
342 } else {
343 memcpy(buff_ptr,
344 sect_buff + (cur_addr & MG_SECTOR_SIZE_MASK),
345 next_sec_addr - cur_addr);
346 MG_DBG("copies %u byte from sector offset 0x%8.8x",
347 next_sec_addr - cur_addr, cur_addr);
348 buff_ptr += (next_sec_addr - cur_addr);
349 cur_addr = next_sec_addr;
350 }
351 }
352
353 if (cur_addr < end_addr) {
354 sect_num = cur_addr >> MG_SECTOR_SIZE_SHIFT;
355 cnt = ((end_addr & ~MG_SECTOR_SIZE_MASK) - cur_addr) >>
356 MG_SECTOR_SIZE_SHIFT;
357
358 if (cnt)
359 err = mg_disk_read_sects(buff_ptr, sect_num, cnt);
360 if (err)
361 goto mg_read_exit;
362
363 buff_ptr += cnt * MG_SECTOR_SIZE;
364 cur_addr += cnt * MG_SECTOR_SIZE;
365
366 if (cur_addr < end_addr) {
367 sect_num = cur_addr >> MG_SECTOR_SIZE_SHIFT;
368 err = mg_disk_read_sects(sect_buff, sect_num, 1);
369 if (err)
370 goto mg_read_exit;
371 memcpy(buff_ptr, sect_buff, end_addr - cur_addr);
372 MG_DBG("copies %u byte", end_addr - cur_addr);
373 }
374 }
375
376mg_read_exit:
377 free(sect_buff);
378
379 return err;
380}
381static int mg_do_write_sects(void *buff, u32 sect_num, u32 sect_cnt)
382{
383 u32 i, j, err;
384 u8 *buff_ptr = buff;
385 union mg_uniwb uniwb;
386
387 err = mg_out(sect_num, sect_cnt, MG_CMD_WR);
388 if (err)
389 return err;
390
391 for (i = 0; i < sect_cnt; i++) {
392 err = mg_wait(MG_REG_STATUS_BIT_DATA_REQ, 3000);
393 if (err)
394 return err;
395
396 if ((u32)buff_ptr & 1) {
397 uniwb.b[0] = *buff_ptr++;
398 uniwb.b[1] = *buff_ptr++;
399 writew(uniwb.w, mg_base() + MG_BUFF_OFFSET + (j << 1));
400 } else {
401 for(j = 0; j < MG_SECTOR_SIZE >> 1; j++) {
402 writew(*(u16 *)buff_ptr,
403 mg_base() + MG_BUFF_OFFSET +
404 (j << 1));
405 buff_ptr += 2;
406 }
407 }
408 writeb(MG_CMD_WR_CONF, mg_base() + MG_REG_COMMAND);
409
410 MG_DBG("%u (0x%8.8x) sector write",
411 sect_num + i, (sect_num + i) * MG_SECTOR_SIZE);
412 }
413
414 return err;
415}
416
417unsigned int mg_disk_write_sects(void *buff, u32 sect_num, u32 sect_cnt)
418{
419 u32 quotient, residue, i;
420 u32 err = MG_ERR_NONE;
421 u8 *buff_ptr = buff;
422
423 quotient = sect_cnt >> 8;
424 residue = sect_cnt % 256;
425
426 for (i = 0; i < quotient; i++) {
427 MG_DBG("sect num : %u buff : %8.8x", sect_num, (u32)buff_ptr);
428 err = mg_do_write_sects(buff_ptr, sect_num, 256);
429 if (err)
430 return err;
431 sect_num += 256;
432 buff_ptr += 256 * MG_SECTOR_SIZE;
433 }
434
435 if (residue) {
436 MG_DBG("sect num : %u buff : %8.8x", sect_num, (u32)buff_ptr);
437 err = mg_do_write_sects(buff_ptr, sect_num, residue);
438 }
439
440 return err;
441}
442
443unsigned long mg_block_write (int dev, unsigned long start,
444 lbaint_t blkcnt, const void *buffer)
445{
446 start += MG_RES_SEC;
447 if (!mg_disk_write_sects((void *)buffer, start, blkcnt))
448 return blkcnt;
449 else
450 return 0;
451}
452
453unsigned int mg_disk_write(u32 addr, u8 *buff, u32 len)
454{
455 u8 *sect_buff, *buff_ptr = buff;
456 u32 cur_addr, next_sec_addr, end_addr, cnt, sect_num;
457 u32 err = MG_ERR_NONE;
458
459 /* TODO : sanity chk */
460 cnt = 0;
461 cur_addr = addr;
462 end_addr = addr + len;
463
464 sect_buff = malloc(MG_SECTOR_SIZE);
465
466 if (cur_addr & MG_SECTOR_SIZE_MASK) {
467
468 next_sec_addr = (cur_addr + MG_SECTOR_SIZE) &
469 ~MG_SECTOR_SIZE_MASK;
470 sect_num = cur_addr >> MG_SECTOR_SIZE_SHIFT;
471 err = mg_disk_read_sects(sect_buff, sect_num, 1);
472 if (err)
473 goto mg_write_exit;
474
475 if (end_addr < next_sec_addr) {
476 memcpy(sect_buff + (cur_addr & MG_SECTOR_SIZE_MASK),
477 buff_ptr, end_addr - cur_addr);
478 MG_DBG("copies %u byte to sector offset 0x%8.8x",
479 end_addr - cur_addr, cur_addr);
480 cur_addr = end_addr;
481 } else {
482 memcpy(sect_buff + (cur_addr & MG_SECTOR_SIZE_MASK),
483 buff_ptr, next_sec_addr - cur_addr);
484 MG_DBG("copies %u byte to sector offset 0x%8.8x",
485 next_sec_addr - cur_addr, cur_addr);
486 buff_ptr += (next_sec_addr - cur_addr);
487 cur_addr = next_sec_addr;
488 }
489
490 err = mg_disk_write_sects(sect_buff, sect_num, 1);
491 if (err)
492 goto mg_write_exit;
493 }
494
495 if (cur_addr < end_addr) {
496
497 sect_num = cur_addr >> MG_SECTOR_SIZE_SHIFT;
498 cnt = ((end_addr & ~MG_SECTOR_SIZE_MASK) - cur_addr) >>
499 MG_SECTOR_SIZE_SHIFT;
500
501 if (cnt)
502 err = mg_disk_write_sects(buff_ptr, sect_num, cnt);
503 if (err)
504 goto mg_write_exit;
505
506 buff_ptr += cnt * MG_SECTOR_SIZE;
507 cur_addr += cnt * MG_SECTOR_SIZE;
508
509 if (cur_addr < end_addr) {
510 sect_num = cur_addr >> MG_SECTOR_SIZE_SHIFT;
511 err = mg_disk_read_sects(sect_buff, sect_num, 1);
512 if (err)
513 goto mg_write_exit;
514 memcpy(sect_buff, buff_ptr, end_addr - cur_addr);
515 MG_DBG("copies %u byte", end_addr - cur_addr);
516 err = mg_disk_write_sects(sect_buff, sect_num, 1);
517 }
518
519 }
520
521mg_write_exit:
522 free(sect_buff);
523
524 return err;
525}
526
Matthew McClintock6252b4f2011-05-24 05:31:19 +0000527#ifdef CONFIG_PARTITIONS
unsik Kimf0b1bdd2009-02-25 11:31:24 +0900528block_dev_desc_t *mg_disk_get_dev(int dev)
529{
530 return ((block_dev_desc_t *) & mg_disk_dev);
531}
Matthew McClintock6252b4f2011-05-24 05:31:19 +0000532#endif
unsik Kimf0b1bdd2009-02-25 11:31:24 +0900533
534/* must override this function */
535struct mg_drv_data * __attribute__((weak)) mg_get_drv_data (void)
536{
537 puts ("### WARNING ### port mg_get_drv_data function\n");
538 return NULL;
539}
540
541unsigned int mg_disk_init (void)
542{
543 struct mg_drv_data *prv_data;
544 u32 err = MG_ERR_NONE;
545
546 prv_data = mg_get_drv_data();
547 if (! prv_data) {
548 printf("%s:%d fail (no driver_data)\n", __func__, __LINE__);
549 err = MG_ERR_NO_DRV_DATA;
550 return err;
551 }
552
553 ((struct mg_host *)mg_disk_dev.priv)->drv_data = prv_data;
554
555 /* init ctrl pin */
556 if (prv_data->mg_ctrl_pin_init)
557 prv_data->mg_ctrl_pin_init();
558
559 if (! prv_data->mg_hdrst_pin) {
560 err = MG_ERR_CTRL_RST;
561 return err;
562 }
563
564 /* disk reset */
565 err = mg_disk_reset();
566 if (err) {
567 printf("%s:%d fail (err code : %d)\n", __func__, __LINE__, err);
568 return err;
569 }
570
571 /* get disk id */
572 err = mg_get_disk_id();
573 if (err) {
574 printf("%s:%d fail (err code : %d)\n", __func__, __LINE__, err);
575 return err;
576 }
577
578 mg_disk_dev.block_read = mg_block_read;
579 mg_disk_dev.block_write = mg_block_write;
580
581 init_part(&mg_disk_dev);
582
583 dev_print(&mg_disk_dev);
584
585 return err;
586}