]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/block/mg_disk.c
Merge commit '7b2fac7654f7420c2787f74ec3b1540fa3b343e9'
[karo-tx-uboot.git] / drivers / block / mg_disk.c
1 /*
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
37 static struct mg_host host;
38
39 static inline u32 mg_base(void)
40 {
41         return host.drv_data->base;
42 }
43
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,
49         .priv = &host };
50
51 static 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
88 static unsigned int mg_wait (u32 expect, u32 msec)
89 {
90         u8 status;
91         u32 from, cur, err;
92
93         err = MG_ERR_NONE;
94 #ifdef CONFIG_SYS_LOW_RES_TIMER
95         reset_timer();
96 #endif
97         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
130 static 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
180 static 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
220 static 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
241 static 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
279 unsigned 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
304 unsigned 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
314 unsigned 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
376 mg_read_exit:
377         free(sect_buff);
378
379         return err;
380 }
381 static 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
417 unsigned 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
443 unsigned 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
453 unsigned 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
521 mg_write_exit:
522         free(sect_buff);
523
524         return err;
525 }
526
527 #ifdef CONFIG_PARTITIONS
528 block_dev_desc_t *mg_disk_get_dev(int dev)
529 {
530         return ((block_dev_desc_t *) & mg_disk_dev);
531 }
532 #endif
533
534 /* must override this function */
535 struct 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
541 unsigned 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 }