mg_disk.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  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. #include <common.h>
  24. #include <malloc.h>
  25. #include <part.h>
  26. #include <ata.h>
  27. #include <asm/io.h>
  28. #include "mg_disk_prv.h"
  29. #ifndef CONFIG_MG_DISK_RES
  30. #define CONFIG_MG_DISK_RES 0
  31. #endif
  32. #define MG_RES_SEC ((CONFIG_MG_DISK_RES) << 1)
  33. static struct mg_host host;
  34. static inline u32 mg_base(void)
  35. {
  36. return host.drv_data->base;
  37. }
  38. static block_dev_desc_t mg_disk_dev = {
  39. .if_type = IF_TYPE_ATAPI,
  40. .part_type = PART_TYPE_UNKNOWN,
  41. .type = DEV_TYPE_HARDDISK,
  42. .blksz = MG_SECTOR_SIZE,
  43. .priv = &host };
  44. static void mg_dump_status (const char *msg, unsigned int stat, unsigned err)
  45. {
  46. char *name = MG_DEV_NAME;
  47. printf("%s: %s: status=0x%02x { ", name, msg, stat & 0xff);
  48. if (stat & MG_REG_STATUS_BIT_BUSY)
  49. printf("Busy ");
  50. if (stat & MG_REG_STATUS_BIT_READY)
  51. printf("DriveReady ");
  52. if (stat & MG_REG_STATUS_BIT_WRITE_FAULT)
  53. printf("WriteFault ");
  54. if (stat & MG_REG_STATUS_BIT_SEEK_DONE)
  55. printf("SeekComplete ");
  56. if (stat & MG_REG_STATUS_BIT_DATA_REQ)
  57. printf("DataRequest ");
  58. if (stat & MG_REG_STATUS_BIT_CORRECTED_ERROR)
  59. printf("CorrectedError ");
  60. if (stat & MG_REG_STATUS_BIT_ERROR)
  61. printf("Error ");
  62. printf("}\n");
  63. if ((stat & MG_REG_STATUS_BIT_ERROR)) {
  64. printf("%s: %s: error=0x%02x { ", name, msg, err & 0xff);
  65. if (err & MG_REG_ERR_BBK)
  66. printf("BadSector ");
  67. if (err & MG_REG_ERR_UNC)
  68. printf("UncorrectableError ");
  69. if (err & MG_REG_ERR_IDNF)
  70. printf("SectorIdNotFound ");
  71. if (err & MG_REG_ERR_ABRT)
  72. printf("DriveStatusError ");
  73. if (err & MG_REG_ERR_AMNF)
  74. printf("AddrMarkNotFound ");
  75. printf("}\n");
  76. }
  77. }
  78. static unsigned int mg_wait (u32 expect, u32 msec)
  79. {
  80. u8 status;
  81. u32 from, cur, err;
  82. err = MG_ERR_NONE;
  83. #ifdef CONFIG_SYS_LOW_RES_TIMER
  84. reset_timer();
  85. #endif
  86. from = get_timer(0);
  87. status = readb(mg_base() + MG_REG_STATUS);
  88. do {
  89. cur = get_timer(from);
  90. if (status & MG_REG_STATUS_BIT_BUSY) {
  91. if (expect == MG_REG_STATUS_BIT_BUSY)
  92. break;
  93. } else {
  94. /* Check the error condition! */
  95. if (status & MG_REG_STATUS_BIT_ERROR) {
  96. err = readb(mg_base() + MG_REG_ERROR);
  97. mg_dump_status("mg_wait", status, err);
  98. break;
  99. }
  100. if (expect == MG_STAT_READY)
  101. if (MG_READY_OK(status))
  102. break;
  103. if (expect == MG_REG_STATUS_BIT_DATA_REQ)
  104. if (status & MG_REG_STATUS_BIT_DATA_REQ)
  105. break;
  106. }
  107. status = readb(mg_base() + MG_REG_STATUS);
  108. } while (cur < msec);
  109. if (cur >= msec)
  110. err = MG_ERR_TIMEOUT;
  111. return err;
  112. }
  113. static int mg_get_disk_id (void)
  114. {
  115. u16 id[(MG_SECTOR_SIZE / sizeof(u16))];
  116. hd_driveid_t *iop = (hd_driveid_t *)id;
  117. u32 i, err, res;
  118. writeb(MG_CMD_ID, mg_base() + MG_REG_COMMAND);
  119. err = mg_wait(MG_REG_STATUS_BIT_DATA_REQ, 3000);
  120. if (err)
  121. return err;
  122. for(i = 0; i < (MG_SECTOR_SIZE / sizeof(u16)); i++)
  123. id[i] = readw(mg_base() + MG_BUFF_OFFSET + i * 2);
  124. writeb(MG_CMD_RD_CONF, mg_base() + MG_REG_COMMAND);
  125. err = mg_wait(MG_STAT_READY, 3000);
  126. if (err)
  127. return err;
  128. ata_swap_buf_le16(id, MG_SECTOR_SIZE / sizeof(u16));
  129. if((iop->field_valid & 1) == 0)
  130. return MG_ERR_TRANSLATION;
  131. ata_id_c_string(id, (unsigned char *)mg_disk_dev.revision,
  132. ATA_ID_FW_REV, sizeof(mg_disk_dev.revision));
  133. ata_id_c_string(id, (unsigned char *)mg_disk_dev.vendor,
  134. ATA_ID_PROD, sizeof(mg_disk_dev.vendor));
  135. ata_id_c_string(id, (unsigned char *)mg_disk_dev.product,
  136. ATA_ID_SERNO, sizeof(mg_disk_dev.product));
  137. #ifdef __BIG_ENDIAN
  138. iop->lba_capacity = (iop->lba_capacity << 16) |
  139. (iop->lba_capacity >> 16);
  140. #endif /* __BIG_ENDIAN */
  141. if (MG_RES_SEC) {
  142. MG_DBG("MG_RES_SEC=%d\n", MG_RES_SEC);
  143. iop->cyls = (iop->lba_capacity - MG_RES_SEC) /
  144. iop->sectors / iop->heads;
  145. res = iop->lba_capacity -
  146. iop->cyls * iop->heads * iop->sectors;
  147. iop->lba_capacity -= res;
  148. printf("mg_disk: %d sectors reserved\n", res);
  149. }
  150. mg_disk_dev.lba = iop->lba_capacity;
  151. return MG_ERR_NONE;
  152. }
  153. static int mg_disk_reset (void)
  154. {
  155. struct mg_drv_data *prv_data = host.drv_data;
  156. s32 err;
  157. u8 init_status;
  158. /* hdd rst low */
  159. prv_data->mg_hdrst_pin(0);
  160. err = mg_wait(MG_REG_STATUS_BIT_BUSY, 300);
  161. if(err)
  162. return err;
  163. /* hdd rst high */
  164. prv_data->mg_hdrst_pin(1);
  165. err = mg_wait(MG_STAT_READY, 3000);
  166. if(err)
  167. return err;
  168. /* soft reset on */
  169. writeb(MG_REG_CTRL_RESET | MG_REG_CTRL_INTR_DISABLE,
  170. mg_base() + MG_REG_DRV_CTRL);
  171. err = mg_wait(MG_REG_STATUS_BIT_BUSY, 3000);
  172. if(err)
  173. return err;
  174. /* soft reset off */
  175. writeb(MG_REG_CTRL_INTR_DISABLE, mg_base() + MG_REG_DRV_CTRL);
  176. err = mg_wait(MG_STAT_READY, 3000);
  177. if(err)
  178. return err;
  179. init_status = readb(mg_base() + MG_REG_STATUS) & 0xf;
  180. if (init_status == 0xf)
  181. return MG_ERR_INIT_STAT;
  182. return err;
  183. }
  184. static unsigned int mg_out(unsigned int sect_num,
  185. unsigned int sect_cnt,
  186. unsigned int cmd)
  187. {
  188. u32 err = MG_ERR_NONE;
  189. err = mg_wait(MG_STAT_READY, 3000);
  190. if (err)
  191. return err;
  192. writeb((u8)sect_cnt, mg_base() + MG_REG_SECT_CNT);
  193. writeb((u8)sect_num, mg_base() + MG_REG_SECT_NUM);
  194. writeb((u8)(sect_num >> 8), mg_base() + MG_REG_CYL_LOW);
  195. writeb((u8)(sect_num >> 16), mg_base() + MG_REG_CYL_HIGH);
  196. writeb((u8)((sect_num >> 24) | MG_REG_HEAD_LBA_MODE),
  197. mg_base() + MG_REG_DRV_HEAD);
  198. writeb(cmd, mg_base() + MG_REG_COMMAND);
  199. return err;
  200. }
  201. static unsigned int mg_do_read_sects(void *buff, u32 sect_num, u32 sect_cnt)
  202. {
  203. u32 i, j, err;
  204. u8 *buff_ptr = buff;
  205. union mg_uniwb uniwb;
  206. err = mg_out(sect_num, sect_cnt, MG_CMD_RD);
  207. if (err)
  208. return err;
  209. for (i = 0; i < sect_cnt; i++) {
  210. err = mg_wait(MG_REG_STATUS_BIT_DATA_REQ, 3000);
  211. if (err)
  212. return err;
  213. if ((u32)buff_ptr & 1) {
  214. for (j = 0; j < MG_SECTOR_SIZE >> 1; j++) {
  215. uniwb.w = readw(mg_base() + MG_BUFF_OFFSET
  216. + (j << 1));
  217. *buff_ptr++ = uniwb.b[0];
  218. *buff_ptr++ = uniwb.b[1];
  219. }
  220. } else {
  221. for(j = 0; j < MG_SECTOR_SIZE >> 1; j++) {
  222. *(u16 *)buff_ptr = readw(mg_base() +
  223. MG_BUFF_OFFSET + (j << 1));
  224. buff_ptr += 2;
  225. }
  226. }
  227. writeb(MG_CMD_RD_CONF, mg_base() + MG_REG_COMMAND);
  228. MG_DBG("%u (0x%8.8x) sector read", sect_num + i,
  229. (sect_num + i) * MG_SECTOR_SIZE);
  230. }
  231. return err;
  232. }
  233. unsigned int mg_disk_read_sects(void *buff, u32 sect_num, u32 sect_cnt)
  234. {
  235. u32 quotient, residue, i, err;
  236. u8 *buff_ptr = buff;
  237. quotient = sect_cnt >> 8;
  238. residue = sect_cnt % 256;
  239. for (i = 0; i < quotient; i++) {
  240. MG_DBG("sect num : %u buff : 0x%8.8x", sect_num, (u32)buff_ptr);
  241. err = mg_do_read_sects(buff_ptr, sect_num, 256);
  242. if (err)
  243. return err;
  244. sect_num += 256;
  245. buff_ptr += 256 * MG_SECTOR_SIZE;
  246. }
  247. if (residue) {
  248. MG_DBG("sect num : %u buff : %8.8x", sect_num, (u32)buff_ptr);
  249. err = mg_do_read_sects(buff_ptr, sect_num, residue);
  250. }
  251. return err;
  252. }
  253. unsigned long mg_block_read (int dev, unsigned long start,
  254. lbaint_t blkcnt, void *buffer)
  255. {
  256. start += MG_RES_SEC;
  257. if (! mg_disk_read_sects(buffer, start, blkcnt))
  258. return blkcnt;
  259. else
  260. return 0;
  261. }
  262. unsigned int mg_disk_read (u32 addr, u8 *buff, u32 len)
  263. {
  264. u8 *sect_buff, *buff_ptr = buff;
  265. u32 cur_addr, next_sec_addr, end_addr, cnt, sect_num;
  266. u32 err = MG_ERR_NONE;
  267. /* TODO : sanity chk */
  268. cnt = 0;
  269. cur_addr = addr;
  270. end_addr = addr + len;
  271. sect_buff = malloc(MG_SECTOR_SIZE);
  272. if (cur_addr & MG_SECTOR_SIZE_MASK) {
  273. next_sec_addr = (cur_addr + MG_SECTOR_SIZE) &
  274. ~MG_SECTOR_SIZE_MASK;
  275. sect_num = cur_addr >> MG_SECTOR_SIZE_SHIFT;
  276. err = mg_disk_read_sects(sect_buff, sect_num, 1);
  277. if (err)
  278. goto mg_read_exit;
  279. if (end_addr < next_sec_addr) {
  280. memcpy(buff_ptr,
  281. sect_buff + (cur_addr & MG_SECTOR_SIZE_MASK),
  282. end_addr - cur_addr);
  283. MG_DBG("copies %u byte from sector offset 0x%8.8x",
  284. end_addr - cur_addr, cur_addr);
  285. cur_addr = end_addr;
  286. } else {
  287. memcpy(buff_ptr,
  288. sect_buff + (cur_addr & MG_SECTOR_SIZE_MASK),
  289. next_sec_addr - cur_addr);
  290. MG_DBG("copies %u byte from sector offset 0x%8.8x",
  291. next_sec_addr - cur_addr, cur_addr);
  292. buff_ptr += (next_sec_addr - cur_addr);
  293. cur_addr = next_sec_addr;
  294. }
  295. }
  296. if (cur_addr < end_addr) {
  297. sect_num = cur_addr >> MG_SECTOR_SIZE_SHIFT;
  298. cnt = ((end_addr & ~MG_SECTOR_SIZE_MASK) - cur_addr) >>
  299. MG_SECTOR_SIZE_SHIFT;
  300. if (cnt)
  301. err = mg_disk_read_sects(buff_ptr, sect_num, cnt);
  302. if (err)
  303. goto mg_read_exit;
  304. buff_ptr += cnt * MG_SECTOR_SIZE;
  305. cur_addr += cnt * MG_SECTOR_SIZE;
  306. if (cur_addr < end_addr) {
  307. sect_num = cur_addr >> MG_SECTOR_SIZE_SHIFT;
  308. err = mg_disk_read_sects(sect_buff, sect_num, 1);
  309. if (err)
  310. goto mg_read_exit;
  311. memcpy(buff_ptr, sect_buff, end_addr - cur_addr);
  312. MG_DBG("copies %u byte", end_addr - cur_addr);
  313. }
  314. }
  315. mg_read_exit:
  316. free(sect_buff);
  317. return err;
  318. }
  319. static int mg_do_write_sects(void *buff, u32 sect_num, u32 sect_cnt)
  320. {
  321. u32 i, j, err;
  322. u8 *buff_ptr = buff;
  323. union mg_uniwb uniwb;
  324. err = mg_out(sect_num, sect_cnt, MG_CMD_WR);
  325. if (err)
  326. return err;
  327. for (i = 0; i < sect_cnt; i++) {
  328. err = mg_wait(MG_REG_STATUS_BIT_DATA_REQ, 3000);
  329. if (err)
  330. return err;
  331. if ((u32)buff_ptr & 1) {
  332. uniwb.b[0] = *buff_ptr++;
  333. uniwb.b[1] = *buff_ptr++;
  334. writew(uniwb.w, mg_base() + MG_BUFF_OFFSET + (j << 1));
  335. } else {
  336. for(j = 0; j < MG_SECTOR_SIZE >> 1; j++) {
  337. writew(*(u16 *)buff_ptr,
  338. mg_base() + MG_BUFF_OFFSET +
  339. (j << 1));
  340. buff_ptr += 2;
  341. }
  342. }
  343. writeb(MG_CMD_WR_CONF, mg_base() + MG_REG_COMMAND);
  344. MG_DBG("%u (0x%8.8x) sector write",
  345. sect_num + i, (sect_num + i) * MG_SECTOR_SIZE);
  346. }
  347. return err;
  348. }
  349. unsigned int mg_disk_write_sects(void *buff, u32 sect_num, u32 sect_cnt)
  350. {
  351. u32 quotient, residue, i;
  352. u32 err = MG_ERR_NONE;
  353. u8 *buff_ptr = buff;
  354. quotient = sect_cnt >> 8;
  355. residue = sect_cnt % 256;
  356. for (i = 0; i < quotient; i++) {
  357. MG_DBG("sect num : %u buff : %8.8x", sect_num, (u32)buff_ptr);
  358. err = mg_do_write_sects(buff_ptr, sect_num, 256);
  359. if (err)
  360. return err;
  361. sect_num += 256;
  362. buff_ptr += 256 * MG_SECTOR_SIZE;
  363. }
  364. if (residue) {
  365. MG_DBG("sect num : %u buff : %8.8x", sect_num, (u32)buff_ptr);
  366. err = mg_do_write_sects(buff_ptr, sect_num, residue);
  367. }
  368. return err;
  369. }
  370. unsigned long mg_block_write (int dev, unsigned long start,
  371. lbaint_t blkcnt, const void *buffer)
  372. {
  373. start += MG_RES_SEC;
  374. if (!mg_disk_write_sects((void *)buffer, start, blkcnt))
  375. return blkcnt;
  376. else
  377. return 0;
  378. }
  379. unsigned int mg_disk_write(u32 addr, u8 *buff, u32 len)
  380. {
  381. u8 *sect_buff, *buff_ptr = buff;
  382. u32 cur_addr, next_sec_addr, end_addr, cnt, sect_num;
  383. u32 err = MG_ERR_NONE;
  384. /* TODO : sanity chk */
  385. cnt = 0;
  386. cur_addr = addr;
  387. end_addr = addr + len;
  388. sect_buff = malloc(MG_SECTOR_SIZE);
  389. if (cur_addr & MG_SECTOR_SIZE_MASK) {
  390. next_sec_addr = (cur_addr + MG_SECTOR_SIZE) &
  391. ~MG_SECTOR_SIZE_MASK;
  392. sect_num = cur_addr >> MG_SECTOR_SIZE_SHIFT;
  393. err = mg_disk_read_sects(sect_buff, sect_num, 1);
  394. if (err)
  395. goto mg_write_exit;
  396. if (end_addr < next_sec_addr) {
  397. memcpy(sect_buff + (cur_addr & MG_SECTOR_SIZE_MASK),
  398. buff_ptr, end_addr - cur_addr);
  399. MG_DBG("copies %u byte to sector offset 0x%8.8x",
  400. end_addr - cur_addr, cur_addr);
  401. cur_addr = end_addr;
  402. } else {
  403. memcpy(sect_buff + (cur_addr & MG_SECTOR_SIZE_MASK),
  404. buff_ptr, next_sec_addr - cur_addr);
  405. MG_DBG("copies %u byte to sector offset 0x%8.8x",
  406. next_sec_addr - cur_addr, cur_addr);
  407. buff_ptr += (next_sec_addr - cur_addr);
  408. cur_addr = next_sec_addr;
  409. }
  410. err = mg_disk_write_sects(sect_buff, sect_num, 1);
  411. if (err)
  412. goto mg_write_exit;
  413. }
  414. if (cur_addr < end_addr) {
  415. sect_num = cur_addr >> MG_SECTOR_SIZE_SHIFT;
  416. cnt = ((end_addr & ~MG_SECTOR_SIZE_MASK) - cur_addr) >>
  417. MG_SECTOR_SIZE_SHIFT;
  418. if (cnt)
  419. err = mg_disk_write_sects(buff_ptr, sect_num, cnt);
  420. if (err)
  421. goto mg_write_exit;
  422. buff_ptr += cnt * MG_SECTOR_SIZE;
  423. cur_addr += cnt * MG_SECTOR_SIZE;
  424. if (cur_addr < end_addr) {
  425. sect_num = cur_addr >> MG_SECTOR_SIZE_SHIFT;
  426. err = mg_disk_read_sects(sect_buff, sect_num, 1);
  427. if (err)
  428. goto mg_write_exit;
  429. memcpy(sect_buff, buff_ptr, end_addr - cur_addr);
  430. MG_DBG("copies %u byte", end_addr - cur_addr);
  431. err = mg_disk_write_sects(sect_buff, sect_num, 1);
  432. }
  433. }
  434. mg_write_exit:
  435. free(sect_buff);
  436. return err;
  437. }
  438. #ifdef CONFIG_PARTITIONS
  439. block_dev_desc_t *mg_disk_get_dev(int dev)
  440. {
  441. return ((block_dev_desc_t *) & mg_disk_dev);
  442. }
  443. #endif
  444. /* must override this function */
  445. struct mg_drv_data * __attribute__((weak)) mg_get_drv_data (void)
  446. {
  447. puts ("### WARNING ### port mg_get_drv_data function\n");
  448. return NULL;
  449. }
  450. unsigned int mg_disk_init (void)
  451. {
  452. struct mg_drv_data *prv_data;
  453. u32 err = MG_ERR_NONE;
  454. prv_data = mg_get_drv_data();
  455. if (! prv_data) {
  456. printf("%s:%d fail (no driver_data)\n", __func__, __LINE__);
  457. err = MG_ERR_NO_DRV_DATA;
  458. return err;
  459. }
  460. ((struct mg_host *)mg_disk_dev.priv)->drv_data = prv_data;
  461. /* init ctrl pin */
  462. if (prv_data->mg_ctrl_pin_init)
  463. prv_data->mg_ctrl_pin_init();
  464. if (! prv_data->mg_hdrst_pin) {
  465. err = MG_ERR_CTRL_RST;
  466. return err;
  467. }
  468. /* disk reset */
  469. err = mg_disk_reset();
  470. if (err) {
  471. printf("%s:%d fail (err code : %d)\n", __func__, __LINE__, err);
  472. return err;
  473. }
  474. /* get disk id */
  475. err = mg_get_disk_id();
  476. if (err) {
  477. printf("%s:%d fail (err code : %d)\n", __func__, __LINE__, err);
  478. return err;
  479. }
  480. mg_disk_dev.block_read = mg_block_read;
  481. mg_disk_dev.block_write = mg_block_write;
  482. init_part(&mg_disk_dev);
  483. dev_print(&mg_disk_dev);
  484. return err;
  485. }