071-bcma-add-functions-to-write-to-nand-flash.patch 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. --- a/drivers/bcma/driver_chipcommon_nflash.c
  2. +++ b/drivers/bcma/driver_chipcommon_nflash.c
  3. @@ -2,16 +2,23 @@
  4. * Broadcom specific AMBA
  5. * ChipCommon NAND flash interface
  6. *
  7. + * Copyright 2011, Tathagata Das <[email protected]>
  8. + * Copyright 2010, Broadcom Corporation
  9. + *
  10. * Licensed under the GNU/GPL. See COPYING for details.
  11. */
  12. +#include <linux/delay.h>
  13. +#include <linux/mtd/bcm47xx_nand.h>
  14. +#include <linux/mtd/nand.h>
  15. #include <linux/platform_device.h>
  16. #include <linux/bcma/bcma.h>
  17. +#include <linux/bcma/bcma_driver_chipcommon.h>
  18. #include "bcma_private.h"
  19. struct platform_device bcma_nflash_dev = {
  20. - .name = "bcma_nflash",
  21. + .name = "bcm47xx-nflash",
  22. .num_resources = 0,
  23. };
  24. @@ -31,6 +38,11 @@ int bcma_nflash_init(struct bcma_drv_cc
  25. return -ENODEV;
  26. }
  27. + if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
  28. + bcma_err(bus, "NAND flash support for BCM4706 not implemented\n");
  29. + return -ENOTSUPP;
  30. + }
  31. +
  32. cc->nflash.present = true;
  33. if (cc->core->id.rev == 38 &&
  34. (cc->status & BCMA_CC_CHIPST_5357_NAND_BOOT))
  35. @@ -42,3 +54,141 @@ int bcma_nflash_init(struct bcma_drv_cc
  36. return 0;
  37. }
  38. +
  39. +/* Issue a nand flash command */
  40. +static inline void bcma_nflash_cmd(struct bcma_drv_cc *cc, u32 opcode)
  41. +{
  42. + bcma_cc_write32(cc, NAND_CMD_START, opcode);
  43. + bcma_cc_read32(cc, NAND_CMD_START);
  44. +}
  45. +
  46. +/* Check offset and length */
  47. +static int bcma_nflash_offset_is_valid(struct bcma_drv_cc *cc, u32 offset, u32 len, u32 mask)
  48. +{
  49. + if ((offset & mask) != 0 || (len & mask) != 0) {
  50. + pr_err("%s(): Address is not aligned. offset: %x, len: %x, mask: %x\n", __func__, offset, len, mask);
  51. + return 1;
  52. + }
  53. +
  54. + if ((((offset + len) >> 20) >= cc->nflash.size) &&
  55. + (((offset + len) & ((1 << 20) - 1)) != 0)) {
  56. + pr_err("%s(): Address is outside Flash memory region. offset: %x, len: %x, mask: %x\n", __func__, offset, len, mask);
  57. + return 1;
  58. + }
  59. +
  60. + return 0;
  61. +}
  62. +
  63. +#define NF_RETRIES 1000000
  64. +
  65. +/* Poll for command completion. Returns zero when complete. */
  66. +int bcma_nflash_poll(struct bcma_drv_cc *cc)
  67. +{
  68. + u32 retries = NF_RETRIES;
  69. + u32 pollmask = NIST_CTRL_READY|NIST_FLASH_READY;
  70. + u32 mask;
  71. +
  72. + while (retries--) {
  73. + mask = bcma_cc_read32(cc, NAND_INTFC_STATUS) & pollmask;
  74. + if (mask == pollmask)
  75. + return 0;
  76. + cpu_relax();
  77. + }
  78. +
  79. + if (!retries) {
  80. + pr_err("bcma_nflash_poll: not ready\n");
  81. + return -1;
  82. + }
  83. +
  84. + return 0;
  85. +}
  86. +
  87. +/* Read len bytes starting at offset into buf. Returns number of bytes read. */
  88. +int bcma_nflash_read(struct bcma_drv_cc *cc, u32 offset, u32 len, u8 *buf)
  89. +{
  90. + u32 mask;
  91. + int i;
  92. + u32 *to, val, res;
  93. +
  94. + mask = NFL_SECTOR_SIZE - 1;
  95. + if (bcma_nflash_offset_is_valid(cc, offset, len, mask))
  96. + return 0;
  97. +
  98. + to = (u32 *)buf;
  99. + res = len;
  100. + while (res > 0) {
  101. + bcma_cc_write32(cc, NAND_CMD_ADDR, offset);
  102. + bcma_nflash_cmd(cc, NCMD_PAGE_RD);
  103. + if (bcma_nflash_poll(cc) < 0)
  104. + break;
  105. + val = bcma_cc_read32(cc, NAND_INTFC_STATUS);
  106. + if ((val & NIST_CACHE_VALID) == 0)
  107. + break;
  108. + bcma_cc_write32(cc, NAND_CACHE_ADDR, 0);
  109. + for (i = 0; i < NFL_SECTOR_SIZE; i += 4, to++) {
  110. + *to = bcma_cc_read32(cc, NAND_CACHE_DATA);
  111. + }
  112. + res -= NFL_SECTOR_SIZE;
  113. + offset += NFL_SECTOR_SIZE;
  114. + }
  115. + return (len - res);
  116. +}
  117. +
  118. +/* Write len bytes starting at offset into buf. Returns success (0) or failure (!0).
  119. + * Should poll for completion.
  120. + */
  121. +int bcma_nflash_write(struct bcma_drv_cc *cc, u32 offset, u32 len,
  122. + const u8 *buf)
  123. +{
  124. + u32 mask;
  125. + int i;
  126. + u32 *from, res, reg;
  127. +
  128. + mask = cc->nflash.pagesize - 1;
  129. + if (bcma_nflash_offset_is_valid(cc, offset, len, mask))
  130. + return 1;
  131. +
  132. + /* disable partial page enable */
  133. + reg = bcma_cc_read32(cc, NAND_ACC_CONTROL);
  134. + reg &= ~NAC_PARTIAL_PAGE_EN;
  135. + bcma_cc_write32(cc, NAND_ACC_CONTROL, reg);
  136. +
  137. + from = (u32 *)buf;
  138. + res = len;
  139. + while (res > 0) {
  140. + bcma_cc_write32(cc, NAND_CACHE_ADDR, 0);
  141. + for (i = 0; i < cc->nflash.pagesize; i += 4, from++) {
  142. + if (i % 512 == 0)
  143. + bcma_cc_write32(cc, NAND_CMD_ADDR, i);
  144. + bcma_cc_write32(cc, NAND_CACHE_DATA, *from);
  145. + }
  146. + bcma_cc_write32(cc, NAND_CMD_ADDR, offset + cc->nflash.pagesize - 512);
  147. + bcma_nflash_cmd(cc, NCMD_PAGE_PROG);
  148. + if (bcma_nflash_poll(cc) < 0)
  149. + break;
  150. + res -= cc->nflash.pagesize;
  151. + offset += cc->nflash.pagesize;
  152. + }
  153. +
  154. + if (res <= 0)
  155. + return 0;
  156. + else
  157. + return (len - res);
  158. +}
  159. +
  160. +/* Erase a region. Returns success (0) or failure (-1).
  161. + * Poll for completion.
  162. + */
  163. +int bcma_nflash_erase(struct bcma_drv_cc *cc, u32 offset)
  164. +{
  165. + if ((offset >> 20) >= cc->nflash.size)
  166. + return -1;
  167. + if ((offset & (cc->nflash.blocksize - 1)) != 0)
  168. + return -1;
  169. +
  170. + bcma_cc_write32(cc, NAND_CMD_ADDR, offset);
  171. + bcma_nflash_cmd(cc, NCMD_BLOCK_ERASE);
  172. + if (bcma_nflash_poll(cc) < 0)
  173. + return -1;
  174. + return 0;
  175. +}
  176. --- a/include/linux/bcma/bcma_driver_chipcommon.h
  177. +++ b/include/linux/bcma/bcma_driver_chipcommon.h
  178. @@ -5,6 +5,7 @@
  179. #include <linux/gpio.h>
  180. #include <linux/mtd/bcm47xx_sflash.h>
  181. +#include <linux/mtd/bcm47xx_nand.h>
  182. /** ChipCommon core registers. **/
  183. #define BCMA_CC_ID 0x0000
  184. @@ -523,17 +524,6 @@ struct bcma_pflash {
  185. };
  186. -#ifdef CONFIG_BCMA_NFLASH
  187. -struct mtd_info;
  188. -
  189. -struct bcma_nflash {
  190. - bool present;
  191. - bool boot; /* This is the flash the SoC boots from */
  192. -
  193. - struct mtd_info *mtd;
  194. -};
  195. -#endif
  196. -
  197. struct bcma_serial_port {
  198. void *regs;
  199. unsigned long clockspeed;
  200. @@ -559,7 +549,7 @@ struct bcma_drv_cc {
  201. struct bcm47xx_sflash sflash;
  202. #endif
  203. #ifdef CONFIG_BCMA_NFLASH
  204. - struct bcma_nflash nflash;
  205. + struct bcm47xx_nflash nflash;
  206. #endif
  207. int nr_serial_ports;
  208. @@ -628,4 +618,13 @@ extern void bcma_chipco_regctl_maskset(s
  209. u32 offset, u32 mask, u32 set);
  210. extern void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid);
  211. +#ifdef CONFIG_BCMA_NFLASH
  212. +/* Chipcommon nflash support. */
  213. +int bcma_nflash_read(struct bcma_drv_cc *cc, u32 offset, u32 len, u8 *buf);
  214. +int bcma_nflash_poll(struct bcma_drv_cc *cc);
  215. +int bcma_nflash_write(struct bcma_drv_cc *cc, u32 offset, u32 len, const u8 *buf);
  216. +int bcma_nflash_erase(struct bcma_drv_cc *cc, u32 offset);
  217. +int bcma_nflash_commit(struct bcma_drv_cc *cc, u32 offset, u32 len, const u8 *buf);
  218. +#endif
  219. +
  220. #endif /* LINUX_BCMA_DRIVER_CC_H_ */