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
)
97 status
= readb(mg_base() + MG_REG_STATUS
);
99 cur
= get_timer(from
);
100 if (status
& MG_REG_STATUS_BIT_BUSY
) {
101 if (expect
== MG_REG_STATUS_BIT_BUSY
)
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
);
111 if (expect
== MG_STAT_READY
)
112 if (MG_READY_OK(status
))
115 if (expect
== MG_REG_STATUS_BIT_DATA_REQ
)
116 if (status
& MG_REG_STATUS_BIT_DATA_REQ
)
119 status
= readb(mg_base() + MG_REG_STATUS
);
120 } while (cur
< msec
);
123 err
= MG_ERR_TIMEOUT
;
128 static int mg_get_disk_id (void)
130 u16 id
[(MG_SECTOR_SIZE
/ sizeof(u16
))];
131 hd_driveid_t
*iop
= (hd_driveid_t
*)id
;
134 writeb(MG_CMD_ID
, mg_base() + MG_REG_COMMAND
);
135 err
= mg_wait(MG_REG_STATUS_BIT_DATA_REQ
, 3000);
139 for(i
= 0; i
< (MG_SECTOR_SIZE
/ sizeof(u16
)); i
++)
140 id
[i
] = readw(mg_base() + MG_BUFF_OFFSET
+ i
* 2);
142 writeb(MG_CMD_RD_CONF
, mg_base() + MG_REG_COMMAND
);
143 err
= mg_wait(MG_STAT_READY
, 3000);
147 ata_swap_buf_le16(id
, MG_SECTOR_SIZE
/ sizeof(u16
));
149 if((iop
->field_valid
& 1) == 0)
150 return MG_ERR_TRANSLATION
;
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
));
160 iop
->lba_capacity
= (iop
->lba_capacity
<< 16) |
161 (iop
->lba_capacity
>> 16);
162 #endif /* __BIG_ENDIAN */
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
);
174 mg_disk_dev
.lba
= iop
->lba_capacity
;
178 static int mg_disk_reset (void)
180 struct mg_drv_data
*prv_data
= host
.drv_data
;
185 prv_data
->mg_hdrst_pin(0);
186 err
= mg_wait(MG_REG_STATUS_BIT_BUSY
, 300);
191 prv_data
->mg_hdrst_pin(1);
192 err
= mg_wait(MG_STAT_READY
, 3000);
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);
204 writeb(MG_REG_CTRL_INTR_DISABLE
, mg_base() + MG_REG_DRV_CTRL
);
205 err
= mg_wait(MG_STAT_READY
, 3000);
209 init_status
= readb(mg_base() + MG_REG_STATUS
) & 0xf;
211 if (init_status
== 0xf)
212 return MG_ERR_INIT_STAT
;
218 static unsigned int mg_out(unsigned int sect_num
,
219 unsigned int sect_cnt
,
222 u32 err
= MG_ERR_NONE
;
224 err
= mg_wait(MG_STAT_READY
, 3000);
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
);
239 static unsigned int mg_do_read_sects(void *buff
, u32 sect_num
, u32 sect_cnt
)
243 union mg_uniwb uniwb
;
245 err
= mg_out(sect_num
, sect_cnt
, MG_CMD_RD
);
249 for (i
= 0; i
< sect_cnt
; i
++) {
250 err
= mg_wait(MG_REG_STATUS_BIT_DATA_REQ
, 3000);
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
258 *buff_ptr
++ = uniwb
.b
[0];
259 *buff_ptr
++ = uniwb
.b
[1];
262 for(j
= 0; j
< MG_SECTOR_SIZE
>> 1; j
++) {
263 *(u16
*)buff_ptr
= readw(mg_base() +
264 MG_BUFF_OFFSET
+ (j
<< 1));
268 writeb(MG_CMD_RD_CONF
, mg_base() + MG_REG_COMMAND
);
270 MG_DBG("%u (0x%8.8x) sector read", sect_num
+ i
,
271 (sect_num
+ i
) * MG_SECTOR_SIZE
);
277 unsigned int mg_disk_read_sects(void *buff
, u32 sect_num
, u32 sect_cnt
)
279 u32 quotient
, residue
, i
, err
;
282 quotient
= sect_cnt
>> 8;
283 residue
= sect_cnt
% 256;
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);
291 buff_ptr
+= 256 * MG_SECTOR_SIZE
;
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
);
302 unsigned long mg_block_read (int dev
, unsigned long start
,
303 lbaint_t blkcnt
, void *buffer
)
306 if (! mg_disk_read_sects(buffer
, start
, blkcnt
))
312 unsigned int mg_disk_read (u32 addr
, u8
*buff
, u32 len
)
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
;
318 /* TODO : sanity chk */
321 end_addr
= addr
+ len
;
323 sect_buff
= malloc(MG_SECTOR_SIZE
);
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);
333 if (end_addr
< next_sec_addr
) {
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
);
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
;
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
;
357 err
= mg_disk_read_sects(buff_ptr
, sect_num
, cnt
);
361 buff_ptr
+= cnt
* MG_SECTOR_SIZE
;
362 cur_addr
+= cnt
* MG_SECTOR_SIZE
;
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);
369 memcpy(buff_ptr
, sect_buff
, end_addr
- cur_addr
);
370 MG_DBG("copies %u byte", end_addr
- cur_addr
);
379 static int mg_do_write_sects(void *buff
, u32 sect_num
, u32 sect_cnt
)
383 union mg_uniwb uniwb
;
385 err
= mg_out(sect_num
, sect_cnt
, MG_CMD_WR
);
389 for (i
= 0; i
< sect_cnt
; i
++) {
390 err
= mg_wait(MG_REG_STATUS_BIT_DATA_REQ
, 3000);
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));
399 for(j
= 0; j
< MG_SECTOR_SIZE
>> 1; j
++) {
400 writew(*(u16
*)buff_ptr
,
401 mg_base() + MG_BUFF_OFFSET
+
406 writeb(MG_CMD_WR_CONF
, mg_base() + MG_REG_COMMAND
);
408 MG_DBG("%u (0x%8.8x) sector write",
409 sect_num
+ i
, (sect_num
+ i
) * MG_SECTOR_SIZE
);
415 unsigned int mg_disk_write_sects(void *buff
, u32 sect_num
, u32 sect_cnt
)
417 u32 quotient
, residue
, i
;
418 u32 err
= MG_ERR_NONE
;
421 quotient
= sect_cnt
>> 8;
422 residue
= sect_cnt
% 256;
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);
430 buff_ptr
+= 256 * MG_SECTOR_SIZE
;
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
);
441 unsigned long mg_block_write (int dev
, unsigned long start
,
442 lbaint_t blkcnt
, const void *buffer
)
445 if (!mg_disk_write_sects((void *)buffer
, start
, blkcnt
))
451 unsigned int mg_disk_write(u32 addr
, u8
*buff
, u32 len
)
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
;
457 /* TODO : sanity chk */
460 end_addr
= addr
+ len
;
462 sect_buff
= malloc(MG_SECTOR_SIZE
);
464 if (cur_addr
& MG_SECTOR_SIZE_MASK
) {
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);
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
);
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
;
488 err
= mg_disk_write_sects(sect_buff
, sect_num
, 1);
493 if (cur_addr
< end_addr
) {
495 sect_num
= cur_addr
>> MG_SECTOR_SIZE_SHIFT
;
496 cnt
= ((end_addr
& ~MG_SECTOR_SIZE_MASK
) - cur_addr
) >>
497 MG_SECTOR_SIZE_SHIFT
;
500 err
= mg_disk_write_sects(buff_ptr
, sect_num
, cnt
);
504 buff_ptr
+= cnt
* MG_SECTOR_SIZE
;
505 cur_addr
+= cnt
* MG_SECTOR_SIZE
;
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);
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);
525 block_dev_desc_t
*mg_disk_get_dev(int dev
)
527 return ((block_dev_desc_t
*) & mg_disk_dev
);
530 /* must override this function */
531 struct mg_drv_data
* __attribute__((weak
)) mg_get_drv_data (void)
533 puts ("### WARNING ### port mg_get_drv_data function\n");
537 unsigned int mg_disk_init (void)
539 struct mg_drv_data
*prv_data
;
540 u32 err
= MG_ERR_NONE
;
542 prv_data
= mg_get_drv_data();
544 printf("%s:%d fail (no driver_data)\n", __func__
, __LINE__
);
545 err
= MG_ERR_NO_DRV_DATA
;
549 ((struct mg_host
*)mg_disk_dev
.priv
)->drv_data
= prv_data
;
552 if (prv_data
->mg_ctrl_pin_init
)
553 prv_data
->mg_ctrl_pin_init();
555 if (! prv_data
->mg_hdrst_pin
) {
556 err
= MG_ERR_CTRL_RST
;
561 err
= mg_disk_reset();
563 printf("%s:%d fail (err code : %d)\n", __func__
, __LINE__
, err
);
568 err
= mg_get_disk_id();
570 printf("%s:%d fail (err code : %d)\n", __func__
, __LINE__
, err
);
574 mg_disk_dev
.block_read
= mg_block_read
;
575 mg_disk_dev
.block_write
= mg_block_write
;
577 init_part(&mg_disk_dev
);
579 dev_print(&mg_disk_dev
);