2 * (C) Copyright 2009 mGine co.
3 * unsik Kim <donari75@gmail.com>
5 * See file CREDITS for list of people who contributed to this
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.
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.
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,
29 #include "mg_disk_prv.h"
31 #ifndef CONFIG_MG_DISK_RES
32 #define CONFIG_MG_DISK_RES 0
35 #define MG_RES_SEC ((CONFIG_MG_DISK_RES) << 1)
37 static struct mg_host host;
39 static inline u32 mg_base(void)
41 return host.drv_data->base;
44 static 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,
51 static void mg_dump_status (const char *msg, unsigned int stat, unsigned err)
53 char *name = MG_DEV_NAME;
55 printf("%s: %s: status=0x%02x { ", name, msg, stat & 0xff);
56 if (stat & MG_REG_STATUS_BIT_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)
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)
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 ");
88 static unsigned int mg_wait (u32 expect, u32 msec)
94 #ifdef CONFIG_SYS_LOW_RES_TIMER
99 status = readb(mg_base() + MG_REG_STATUS);
101 cur = get_timer(from);
102 if (status & MG_REG_STATUS_BIT_BUSY) {
103 if (expect == MG_REG_STATUS_BIT_BUSY)
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);
113 if (expect == MG_STAT_READY)
114 if (MG_READY_OK(status))
117 if (expect == MG_REG_STATUS_BIT_DATA_REQ)
118 if (status & MG_REG_STATUS_BIT_DATA_REQ)
121 status = readb(mg_base() + MG_REG_STATUS);
122 } while (cur < msec);
125 err = MG_ERR_TIMEOUT;
130 static int mg_get_disk_id (void)
132 u16 id[(MG_SECTOR_SIZE / sizeof(u16))];
133 hd_driveid_t *iop = (hd_driveid_t *)id;
136 writeb(MG_CMD_ID, mg_base() + MG_REG_COMMAND);
137 err = mg_wait(MG_REG_STATUS_BIT_DATA_REQ, 3000);
141 for(i = 0; i < (MG_SECTOR_SIZE / sizeof(u16)); i++)
142 id[i] = readw(mg_base() + MG_BUFF_OFFSET + i * 2);
144 writeb(MG_CMD_RD_CONF, mg_base() + MG_REG_COMMAND);
145 err = mg_wait(MG_STAT_READY, 3000);
149 ata_swap_buf_le16(id, MG_SECTOR_SIZE / sizeof(u16));
151 if((iop->field_valid & 1) == 0)
152 return MG_ERR_TRANSLATION;
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));
162 iop->lba_capacity = (iop->lba_capacity << 16) |
163 (iop->lba_capacity >> 16);
164 #endif /* __BIG_ENDIAN */
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);
176 mg_disk_dev.lba = iop->lba_capacity;
180 static int mg_disk_reset (void)
182 struct mg_drv_data *prv_data = host.drv_data;
187 prv_data->mg_hdrst_pin(0);
188 err = mg_wait(MG_REG_STATUS_BIT_BUSY, 300);
193 prv_data->mg_hdrst_pin(1);
194 err = mg_wait(MG_STAT_READY, 3000);
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);
206 writeb(MG_REG_CTRL_INTR_DISABLE, mg_base() + MG_REG_DRV_CTRL);
207 err = mg_wait(MG_STAT_READY, 3000);
211 init_status = readb(mg_base() + MG_REG_STATUS) & 0xf;
213 if (init_status == 0xf)
214 return MG_ERR_INIT_STAT;
220 static unsigned int mg_out(unsigned int sect_num,
221 unsigned int sect_cnt,
224 u32 err = MG_ERR_NONE;
226 err = mg_wait(MG_STAT_READY, 3000);
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);
241 static unsigned int mg_do_read_sects(void *buff, u32 sect_num, u32 sect_cnt)
245 union mg_uniwb uniwb;
247 err = mg_out(sect_num, sect_cnt, MG_CMD_RD);
251 for (i = 0; i < sect_cnt; i++) {
252 err = mg_wait(MG_REG_STATUS_BIT_DATA_REQ, 3000);
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
260 *buff_ptr++ = uniwb.b[0];
261 *buff_ptr++ = uniwb.b[1];
264 for(j = 0; j < MG_SECTOR_SIZE >> 1; j++) {
265 *(u16 *)buff_ptr = readw(mg_base() +
266 MG_BUFF_OFFSET + (j << 1));
270 writeb(MG_CMD_RD_CONF, mg_base() + MG_REG_COMMAND);
272 MG_DBG("%u (0x%8.8x) sector read", sect_num + i,
273 (sect_num + i) * MG_SECTOR_SIZE);
279 unsigned int mg_disk_read_sects(void *buff, u32 sect_num, u32 sect_cnt)
281 u32 quotient, residue, i, err;
284 quotient = sect_cnt >> 8;
285 residue = sect_cnt % 256;
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);
293 buff_ptr += 256 * MG_SECTOR_SIZE;
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);
304 unsigned long mg_block_read (int dev, unsigned long start,
305 lbaint_t blkcnt, void *buffer)
308 if (! mg_disk_read_sects(buffer, start, blkcnt))
314 unsigned int mg_disk_read (u32 addr, u8 *buff, u32 len)
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;
320 /* TODO : sanity chk */
323 end_addr = addr + len;
325 sect_buff = malloc(MG_SECTOR_SIZE);
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);
335 if (end_addr < next_sec_addr) {
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);
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;
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;
359 err = mg_disk_read_sects(buff_ptr, sect_num, cnt);
363 buff_ptr += cnt * MG_SECTOR_SIZE;
364 cur_addr += cnt * MG_SECTOR_SIZE;
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);
371 memcpy(buff_ptr, sect_buff, end_addr - cur_addr);
372 MG_DBG("copies %u byte", end_addr - cur_addr);
381 static int mg_do_write_sects(void *buff, u32 sect_num, u32 sect_cnt)
385 union mg_uniwb uniwb;
387 err = mg_out(sect_num, sect_cnt, MG_CMD_WR);
391 for (i = 0; i < sect_cnt; i++) {
392 err = mg_wait(MG_REG_STATUS_BIT_DATA_REQ, 3000);
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));
401 for(j = 0; j < MG_SECTOR_SIZE >> 1; j++) {
402 writew(*(u16 *)buff_ptr,
403 mg_base() + MG_BUFF_OFFSET +
408 writeb(MG_CMD_WR_CONF, mg_base() + MG_REG_COMMAND);
410 MG_DBG("%u (0x%8.8x) sector write",
411 sect_num + i, (sect_num + i) * MG_SECTOR_SIZE);
417 unsigned int mg_disk_write_sects(void *buff, u32 sect_num, u32 sect_cnt)
419 u32 quotient, residue, i;
420 u32 err = MG_ERR_NONE;
423 quotient = sect_cnt >> 8;
424 residue = sect_cnt % 256;
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);
432 buff_ptr += 256 * MG_SECTOR_SIZE;
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);
443 unsigned long mg_block_write (int dev, unsigned long start,
444 lbaint_t blkcnt, const void *buffer)
447 if (!mg_disk_write_sects((void *)buffer, start, blkcnt))
453 unsigned int mg_disk_write(u32 addr, u8 *buff, u32 len)
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;
459 /* TODO : sanity chk */
462 end_addr = addr + len;
464 sect_buff = malloc(MG_SECTOR_SIZE);
466 if (cur_addr & MG_SECTOR_SIZE_MASK) {
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);
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);
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;
490 err = mg_disk_write_sects(sect_buff, sect_num, 1);
495 if (cur_addr < end_addr) {
497 sect_num = cur_addr >> MG_SECTOR_SIZE_SHIFT;
498 cnt = ((end_addr & ~MG_SECTOR_SIZE_MASK) - cur_addr) >>
499 MG_SECTOR_SIZE_SHIFT;
502 err = mg_disk_write_sects(buff_ptr, sect_num, cnt);
506 buff_ptr += cnt * MG_SECTOR_SIZE;
507 cur_addr += cnt * MG_SECTOR_SIZE;
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);
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);
527 #ifdef CONFIG_PARTITIONS
528 block_dev_desc_t *mg_disk_get_dev(int dev)
530 return ((block_dev_desc_t *) & mg_disk_dev);
534 /* must override this function */
535 struct mg_drv_data * __attribute__((weak)) mg_get_drv_data (void)
537 puts ("### WARNING ### port mg_get_drv_data function\n");
541 unsigned int mg_disk_init (void)
543 struct mg_drv_data *prv_data;
544 u32 err = MG_ERR_NONE;
546 prv_data = mg_get_drv_data();
548 printf("%s:%d fail (no driver_data)\n", __func__, __LINE__);
549 err = MG_ERR_NO_DRV_DATA;
553 ((struct mg_host *)mg_disk_dev.priv)->drv_data = prv_data;
556 if (prv_data->mg_ctrl_pin_init)
557 prv_data->mg_ctrl_pin_init();
559 if (! prv_data->mg_hdrst_pin) {
560 err = MG_ERR_CTRL_RST;
565 err = mg_disk_reset();
567 printf("%s:%d fail (err code : %d)\n", __func__, __LINE__, err);
572 err = mg_get_disk_id();
574 printf("%s:%d fail (err code : %d)\n", __func__, __LINE__, err);
578 mg_disk_dev.block_read = mg_block_read;
579 mg_disk_dev.block_write = mg_block_write;
581 init_part(&mg_disk_dev);
583 dev_print(&mg_disk_dev);