070-bcma-add-functions-to-write-to-serial-flash.patch 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. --- a/drivers/bcma/driver_chipcommon_sflash.c
  2. +++ b/drivers/bcma/driver_chipcommon_sflash.c
  3. @@ -1,15 +1,22 @@
  4. /*
  5. * Broadcom specific AMBA
  6. * ChipCommon serial flash interface
  7. + * Copyright 2011, Jonas Gorski <[email protected]>
  8. + * Copyright 2011, 2012, Hauke Mehrtens <[email protected]>
  9. + * Copyright 2010, Broadcom Corporation
  10. *
  11. * Licensed under the GNU/GPL. See COPYING for details.
  12. */
  13. #include <linux/platform_device.h>
  14. +#include <linux/delay.h>
  15. #include <linux/bcma/bcma.h>
  16. +#include <linux/bcma/bcma_driver_chipcommon.h>
  17. #include "bcma_private.h"
  18. +#define NUM_RETRIES 3
  19. +
  20. static struct resource bcma_sflash_resource = {
  21. .name = "bcma_sflash",
  22. .start = BCMA_SOC_FLASH2,
  23. @@ -18,7 +25,7 @@ static struct resource bcma_sflash_resou
  24. };
  25. struct platform_device bcma_sflash_dev = {
  26. - .name = "bcma_sflash",
  27. + .name = "bcm47xx-sflash",
  28. .resource = &bcma_sflash_resource,
  29. .num_resources = 1,
  30. };
  31. @@ -30,7 +37,7 @@ struct bcma_sflash_tbl_e {
  32. u16 numblocks;
  33. };
  34. -static struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
  35. +static const struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
  36. { "M25P20", 0x11, 0x10000, 4, },
  37. { "M25P40", 0x12, 0x10000, 8, },
  38. @@ -41,7 +48,7 @@ static struct bcma_sflash_tbl_e bcma_sfl
  39. { 0 },
  40. };
  41. -static struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
  42. +static const struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
  43. { "SST25WF512", 1, 0x1000, 16, },
  44. { "SST25VF512", 0x48, 0x1000, 16, },
  45. { "SST25WF010", 2, 0x1000, 32, },
  46. @@ -59,7 +66,7 @@ static struct bcma_sflash_tbl_e bcma_sfl
  47. { 0 },
  48. };
  49. -static struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
  50. +static const struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
  51. { "AT45DB011", 0xc, 256, 512, },
  52. { "AT45DB021", 0x14, 256, 1024, },
  53. { "AT45DB041", 0x1c, 256, 2048, },
  54. @@ -84,12 +91,230 @@ static void bcma_sflash_cmd(struct bcma_
  55. bcma_err(cc->core->bus, "SFLASH control command failed (timeout)!\n");
  56. }
  57. +static void bcma_sflash_write_u8(struct bcma_drv_cc *cc, u32 offset, u8 byte)
  58. +{
  59. + bcma_cc_write32(cc, BCMA_CC_FLASHADDR, offset);
  60. + bcma_cc_write32(cc, BCMA_CC_FLASHDATA, byte);
  61. +}
  62. +
  63. +/* Read len bytes starting at offset into buf. Returns number of bytes read. */
  64. +static int bcma_sflash_read(struct bcm47xx_sflash *dev, u32 offset, u32 len, u8 *buf)
  65. +{
  66. + u8 *from, *to;
  67. + u32 cnt, i;
  68. + struct bcma_drv_cc *cc = dev->bcc;
  69. +
  70. + if (!len)
  71. + return 0;
  72. +
  73. + if ((offset + len) > cc->sflash.size)
  74. + return -EINVAL;
  75. +
  76. + if ((len >= 4) && (offset & 3))
  77. + cnt = 4 - (offset & 3);
  78. + else if ((len >= 4) && ((u32)buf & 3))
  79. + cnt = 4 - ((u32)buf & 3);
  80. + else
  81. + cnt = len;
  82. +
  83. + from = (u8 *)KSEG0ADDR(BCMA_SOC_FLASH2 + offset);
  84. +
  85. + to = (u8 *)buf;
  86. +
  87. + if (cnt < 4) {
  88. + for (i = 0; i < cnt; i++) {
  89. + *to = readb(from);
  90. + from++;
  91. + to++;
  92. + }
  93. + return cnt;
  94. + }
  95. +
  96. + while (cnt >= 4) {
  97. + *(u32 *)to = readl(from);
  98. + from += 4;
  99. + to += 4;
  100. + cnt -= 4;
  101. + }
  102. +
  103. + return len - cnt;
  104. +}
  105. +
  106. +/* Poll for command completion. Returns zero when complete. */
  107. +static int bcma_sflash_poll(struct bcm47xx_sflash *dev, u32 offset)
  108. +{
  109. + struct bcma_drv_cc *cc = dev->bcc;
  110. +
  111. + if (offset >= cc->sflash.size)
  112. + return -22;
  113. +
  114. + switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
  115. + case BCMA_CC_FLASHT_STSER:
  116. + /* Check for ST Write In Progress bit */
  117. + bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_RDSR);
  118. + return bcma_cc_read32(cc, BCMA_CC_FLASHDATA)
  119. + & BCMA_CC_FLASHDATA_ST_WIP;
  120. + case BCMA_CC_FLASHT_ATSER:
  121. + /* Check for Atmel Ready bit */
  122. + bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_STATUS);
  123. + return !(bcma_cc_read32(cc, BCMA_CC_FLASHDATA)
  124. + & BCMA_CC_FLASHDATA_AT_READY);
  125. + }
  126. +
  127. + return 0;
  128. +}
  129. +
  130. +
  131. +static int sflash_st_write(struct bcm47xx_sflash *dev, u32 offset, u32 len,
  132. + const u8 *buf)
  133. +{
  134. + int written = 1;
  135. + struct bcma_drv_cc *cc = dev->bcc;
  136. +
  137. + /* Enable writes */
  138. + bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_WREN);
  139. + bcma_sflash_write_u8(cc, offset, *buf++);
  140. + /* Issue a page program with CSA bit set */
  141. + bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_CSA | BCMA_CC_FLASHCTL_ST_PP);
  142. + offset++;
  143. + len--;
  144. + while (len > 0) {
  145. + if ((offset & 255) == 0) {
  146. + /* Page boundary, poll droping cs and return */
  147. + bcma_cc_write32(cc, BCMA_CC_FLASHCTL, 0);
  148. + udelay(1);
  149. + if (!bcma_sflash_poll(dev, offset)) {
  150. + /* Flash rejected command */
  151. + return -EAGAIN;
  152. + }
  153. + return written;
  154. + } else {
  155. + /* Write single byte */
  156. + bcma_sflash_cmd(cc,
  157. + BCMA_CC_FLASHCTL_ST_CSA |
  158. + *buf++);
  159. + }
  160. + written++;
  161. + offset++;
  162. + len--;
  163. + }
  164. + /* All done, drop cs & poll */
  165. + bcma_cc_write32(cc, BCMA_CC_FLASHCTL, 0);
  166. + udelay(1);
  167. + if (!bcma_sflash_poll(dev, offset)) {
  168. + /* Flash rejected command */
  169. + return -EAGAIN;
  170. + }
  171. + return written;
  172. +}
  173. +
  174. +static int sflash_at_write(struct bcm47xx_sflash *dev, u32 offset, u32 len,
  175. + const u8 *buf)
  176. +{
  177. + struct bcma_drv_cc *cc = dev->bcc;
  178. + u32 page, byte, mask;
  179. + int ret = 0;
  180. +
  181. + mask = dev->blocksize - 1;
  182. + page = (offset & ~mask) << 1;
  183. + byte = offset & mask;
  184. + /* Read main memory page into buffer 1 */
  185. + if (byte || (len < dev->blocksize)) {
  186. + int i = 100;
  187. + bcma_cc_write32(cc, BCMA_CC_FLASHADDR, page);
  188. + bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_BUF1_LOAD);
  189. + /* 250 us for AT45DB321B */
  190. + while (i > 0 && bcma_sflash_poll(dev, offset)) {
  191. + udelay(10);
  192. + i--;
  193. + }
  194. + BUG_ON(!bcma_sflash_poll(dev, offset));
  195. + }
  196. + /* Write into buffer 1 */
  197. + for (ret = 0; (ret < (int)len) && (byte < dev->blocksize); ret++) {
  198. + bcma_sflash_write_u8(cc, byte++, *buf++);
  199. + bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_BUF1_WRITE);
  200. + }
  201. + /* Write buffer 1 into main memory page */
  202. + bcma_cc_write32(cc, BCMA_CC_FLASHADDR, page);
  203. + bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_BUF1_PROGRAM);
  204. +
  205. + return ret;
  206. +}
  207. +
  208. +/* Write len bytes starting at offset into buf. Returns number of bytes
  209. + * written. Caller should poll for completion.
  210. + */
  211. +static int bcma_sflash_write(struct bcm47xx_sflash *dev, u32 offset, u32 len,
  212. + const u8 *buf)
  213. +{
  214. + int ret = 0, tries = NUM_RETRIES;
  215. + struct bcma_drv_cc *cc = dev->bcc;
  216. +
  217. + if (!len)
  218. + return 0;
  219. +
  220. + if ((offset + len) > cc->sflash.size)
  221. + return -EINVAL;
  222. +
  223. + switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
  224. + case BCMA_CC_FLASHT_STSER:
  225. + do {
  226. + ret = sflash_st_write(dev, offset, len, buf);
  227. + tries--;
  228. + } while (ret == -EAGAIN && tries > 0);
  229. +
  230. + if (ret == -EAGAIN && tries == 0) {
  231. + bcma_info(cc->core->bus, "ST Flash rejected write\n");
  232. + ret = -EIO;
  233. + }
  234. + break;
  235. + case BCMA_CC_FLASHT_ATSER:
  236. + ret = sflash_at_write(dev, offset, len, buf);
  237. + break;
  238. + }
  239. +
  240. + return ret;
  241. +}
  242. +
  243. +/* Erase a region. Returns number of bytes scheduled for erasure.
  244. + * Caller should poll for completion.
  245. + */
  246. +static int bcma_sflash_erase(struct bcm47xx_sflash *dev, u32 offset)
  247. +{
  248. + struct bcma_drv_cc *cc = dev->bcc;
  249. +
  250. + if (offset >= cc->sflash.size)
  251. + return -EINVAL;
  252. +
  253. + switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
  254. + case BCMA_CC_FLASHT_STSER:
  255. + bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_WREN);
  256. + bcma_cc_write32(cc, BCMA_CC_FLASHADDR, offset);
  257. + /* Newer flashes have "sub-sectors" which can be erased independently
  258. + * with a new command: ST_SSE. The ST_SE command erases 64KB just as
  259. + * before.
  260. + */
  261. + if (dev->blocksize < (64 * 1024))
  262. + bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_SSE);
  263. + else
  264. + bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_SE);
  265. + return dev->blocksize;
  266. + case BCMA_CC_FLASHT_ATSER:
  267. + bcma_cc_write32(cc, BCMA_CC_FLASHADDR, offset << 1);
  268. + bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_PAGE_ERASE);
  269. + return dev->blocksize;
  270. + }
  271. +
  272. + return 0;
  273. +}
  274. +
  275. /* Initialize serial flash access */
  276. int bcma_sflash_init(struct bcma_drv_cc *cc)
  277. {
  278. struct bcma_bus *bus = cc->core->bus;
  279. - struct bcma_sflash *sflash = &cc->sflash;
  280. - struct bcma_sflash_tbl_e *e;
  281. + struct bcm47xx_sflash *sflash = &cc->sflash;
  282. + const struct bcma_sflash_tbl_e *e;
  283. u32 id, id2;
  284. switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
  285. @@ -150,6 +375,12 @@ int bcma_sflash_init(struct bcma_drv_cc
  286. sflash->numblocks = e->numblocks;
  287. sflash->size = sflash->blocksize * sflash->numblocks;
  288. sflash->present = true;
  289. + sflash->read = bcma_sflash_read;
  290. + sflash->poll = bcma_sflash_poll;
  291. + sflash->write = bcma_sflash_write;
  292. + sflash->erase = bcma_sflash_erase;
  293. + sflash->type = BCM47XX_SFLASH_BCMA;
  294. + sflash->bcc = cc;
  295. bcma_info(bus, "Found %s serial flash (size: %dKiB, blocksize: 0x%X, blocks: %d)\n",
  296. e->name, sflash->size / 1024, sflash->blocksize,
  297. --- a/include/linux/bcma/bcma_driver_chipcommon.h
  298. +++ b/include/linux/bcma/bcma_driver_chipcommon.h
  299. @@ -4,6 +4,8 @@
  300. #include <linux/platform_device.h>
  301. #include <linux/gpio.h>
  302. +#include <linux/mtd/bcm47xx_sflash.h>
  303. +
  304. /** ChipCommon core registers. **/
  305. #define BCMA_CC_ID 0x0000
  306. #define BCMA_CC_ID_ID 0x0000FFFF
  307. @@ -520,17 +522,6 @@ struct bcma_pflash {
  308. u32 window_size;
  309. };
  310. -#ifdef CONFIG_BCMA_SFLASH
  311. -struct bcma_sflash {
  312. - bool present;
  313. - u32 window;
  314. - u32 blocksize;
  315. - u16 numblocks;
  316. - u32 size;
  317. -
  318. - struct mtd_info *mtd;
  319. -};
  320. -#endif
  321. #ifdef CONFIG_BCMA_NFLASH
  322. struct mtd_info;
  323. @@ -565,7 +556,7 @@ struct bcma_drv_cc {
  324. #ifdef CONFIG_BCMA_DRIVER_MIPS
  325. struct bcma_pflash pflash;
  326. #ifdef CONFIG_BCMA_SFLASH
  327. - struct bcma_sflash sflash;
  328. + struct bcm47xx_sflash sflash;
  329. #endif
  330. #ifdef CONFIG_BCMA_NFLASH
  331. struct bcma_nflash nflash;