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 
mg_base(void)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 
mg_dump_status(const char * msg,unsigned int stat,unsigned err)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 
mg_wait(u32 expect,u32 msec)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 	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 
mg_get_disk_id(void)128 static 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 
mg_disk_reset(void)178 static 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 
mg_out(unsigned int sect_num,unsigned int sect_cnt,unsigned int cmd)218 static 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 
mg_do_read_sects(void * buff,u32 sect_num,u32 sect_cnt)239 static 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 
mg_disk_read_sects(void * buff,u32 sect_num,u32 sect_cnt)277 unsigned 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 
mg_block_read(int dev,unsigned long start,lbaint_t blkcnt,void * buffer)302 unsigned 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 
mg_disk_read(u32 addr,u8 * buff,u32 len)312 unsigned 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 
374 mg_read_exit:
375 	free(sect_buff);
376 
377 	return err;
378 }
mg_do_write_sects(void * buff,u32 sect_num,u32 sect_cnt)379 static 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 
mg_disk_write_sects(void * buff,u32 sect_num,u32 sect_cnt)415 unsigned 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 
mg_block_write(int dev,unsigned long start,lbaint_t blkcnt,const void * buffer)441 unsigned 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 
mg_disk_write(u32 addr,u8 * buff,u32 len)451 unsigned 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 
519 mg_write_exit:
520 	free(sect_buff);
521 
522 	return err;
523 }
524 
mg_disk_get_dev(int dev)525 block_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 */
mg_get_drv_data(void)531 struct 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 
mg_disk_init(void)537 unsigned 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 }
583