You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

230 lines
6.2KB

  1. /***************************************************************************
  2. * Copyright (C) 2010 by Spencer Oliver *
  3. * spen@spen-soft.co.uk *
  4. * *
  5. * This program is free software; you can redistribute it and/or modify *
  6. * it under the terms of the GNU General Public License as published by *
  7. * the Free Software Foundation; either version 2 of the License, or *
  8. * (at your option) any later version. *
  9. * *
  10. * This program is distributed in the hope that it will be useful, *
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  13. * GNU General Public License for more details. *
  14. * *
  15. * You should have received a copy of the GNU General Public License *
  16. * along with this program; if not, write to the *
  17. * Free Software Foundation, Inc., *
  18. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
  19. ***************************************************************************/
  20. /*
  21. * NAND controller interface for Nuvoton NUC910
  22. */
  23. #ifdef HAVE_CONFIG_H
  24. #include "config.h"
  25. #endif
  26. #include "imp.h"
  27. #include "nuc910.h"
  28. #include "arm_io.h"
  29. #include <target/arm.h>
  30. struct nuc910_nand_controller {
  31. struct arm_nand_data io;
  32. };
  33. static int validate_target_state(struct nand_device *nand)
  34. {
  35. struct target *target = nand->target;
  36. if (target->state != TARGET_HALTED) {
  37. LOG_ERROR("Target not halted");
  38. return ERROR_NAND_OPERATION_FAILED;
  39. }
  40. return ERROR_OK;
  41. }
  42. static int nuc910_nand_command(struct nand_device *nand, uint8_t command)
  43. {
  44. struct target *target = nand->target;
  45. int result;
  46. result = validate_target_state(nand);
  47. if (result != ERROR_OK)
  48. return result;
  49. target_write_u8(target, NUC910_SMCMD, command);
  50. return ERROR_OK;
  51. }
  52. static int nuc910_nand_address(struct nand_device *nand, uint8_t address)
  53. {
  54. struct target *target = nand->target;
  55. int result;
  56. result = validate_target_state(nand);
  57. if (result != ERROR_OK)
  58. return result;
  59. target_write_u32(target, NUC910_SMADDR, ((address & 0xff) | NUC910_SMADDR_EOA));
  60. return ERROR_OK;
  61. }
  62. static int nuc910_nand_read(struct nand_device *nand, void *data)
  63. {
  64. struct target *target = nand->target;
  65. int result;
  66. result = validate_target_state(nand);
  67. if (result != ERROR_OK)
  68. return result;
  69. target_read_u8(target, NUC910_SMDATA, data);
  70. return ERROR_OK;
  71. }
  72. static int nuc910_nand_write(struct nand_device *nand, uint16_t data)
  73. {
  74. struct target *target = nand->target;
  75. int result;
  76. result = validate_target_state(nand);
  77. if (result != ERROR_OK)
  78. return result;
  79. target_write_u8(target, NUC910_SMDATA, data);
  80. return ERROR_OK;
  81. }
  82. static int nuc910_nand_read_block_data(struct nand_device *nand,
  83. uint8_t *data, int data_size)
  84. {
  85. struct nuc910_nand_controller *nuc910_nand = nand->controller_priv;
  86. int result;
  87. result = validate_target_state(nand);
  88. if (result != ERROR_OK)
  89. return result;
  90. nuc910_nand->io.chunk_size = nand->page_size;
  91. /* try the fast way first */
  92. result = arm_nandread(&nuc910_nand->io, data, data_size);
  93. if (result != ERROR_NAND_NO_BUFFER)
  94. return result;
  95. /* else do it slowly */
  96. while (data_size--)
  97. nuc910_nand_read(nand, data++);
  98. return ERROR_OK;
  99. }
  100. static int nuc910_nand_write_block_data(struct nand_device *nand,
  101. uint8_t *data, int data_size)
  102. {
  103. struct nuc910_nand_controller *nuc910_nand = nand->controller_priv;
  104. int result;
  105. result = validate_target_state(nand);
  106. if (result != ERROR_OK)
  107. return result;
  108. nuc910_nand->io.chunk_size = nand->page_size;
  109. /* try the fast way first */
  110. result = arm_nandwrite(&nuc910_nand->io, data, data_size);
  111. if (result != ERROR_NAND_NO_BUFFER)
  112. return result;
  113. /* else do it slowly */
  114. while (data_size--)
  115. nuc910_nand_write(nand, *data++);
  116. return ERROR_OK;
  117. }
  118. static int nuc910_nand_reset(struct nand_device *nand)
  119. {
  120. return nuc910_nand_command(nand, NAND_CMD_RESET);
  121. }
  122. static int nuc910_nand_ready(struct nand_device *nand, int timeout)
  123. {
  124. struct target *target = nand->target;
  125. uint32_t status;
  126. do {
  127. target_read_u32(target, NUC910_SMISR, &status);
  128. if (status & NUC910_SMISR_RB_)
  129. return 1;
  130. alive_sleep(1);
  131. } while (timeout-- > 0);
  132. return 0;
  133. }
  134. NAND_DEVICE_COMMAND_HANDLER(nuc910_nand_device_command)
  135. {
  136. struct nuc910_nand_controller *nuc910_nand;
  137. nuc910_nand = calloc(1, sizeof(struct nuc910_nand_controller));
  138. if (!nuc910_nand) {
  139. LOG_ERROR("no memory for nand controller");
  140. return ERROR_NAND_DEVICE_INVALID;
  141. }
  142. nand->controller_priv = nuc910_nand;
  143. return ERROR_OK;
  144. }
  145. static int nuc910_nand_init(struct nand_device *nand)
  146. {
  147. struct nuc910_nand_controller *nuc910_nand = nand->controller_priv;
  148. struct target *target = nand->target;
  149. int bus_width = nand->bus_width ? : 8;
  150. int result;
  151. result = validate_target_state(nand);
  152. if (result != ERROR_OK)
  153. return result;
  154. /* nuc910 only supports 8bit */
  155. if (bus_width != 8) {
  156. LOG_ERROR("nuc910 only supports 8 bit bus width, not %i", bus_width);
  157. return ERROR_NAND_OPERATION_NOT_SUPPORTED;
  158. }
  159. /* inform calling code about selected bus width */
  160. nand->bus_width = bus_width;
  161. nuc910_nand->io.target = target;
  162. nuc910_nand->io.data = NUC910_SMDATA;
  163. nuc910_nand->io.op = ARM_NAND_NONE;
  164. /* configure nand controller */
  165. target_write_u32(target, NUC910_FMICSR, NUC910_FMICSR_SM_EN);
  166. target_write_u32(target, NUC910_SMCSR, 0x010000a8); /* 2048 page size */
  167. target_write_u32(target, NUC910_SMTCR, 0x00010204);
  168. target_write_u32(target, NUC910_SMIER, 0x00000000);
  169. return ERROR_OK;
  170. }
  171. struct nand_flash_controller nuc910_nand_controller = {
  172. .name = "nuc910",
  173. .command = nuc910_nand_command,
  174. .address = nuc910_nand_address,
  175. .read_data = nuc910_nand_read,
  176. .write_data = nuc910_nand_write,
  177. .write_block_data = nuc910_nand_write_block_data,
  178. .read_block_data = nuc910_nand_read_block_data,
  179. .nand_ready = nuc910_nand_ready,
  180. .reset = nuc910_nand_reset,
  181. .nand_device_command = nuc910_nand_device_command,
  182. .init = nuc910_nand_init,
  183. };