123-mtd-nand-sunxi-add-hw-randomizer-support.patch 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887
  1. From ef4bc8ab68979e5c1c30f061c5af1a7d6ec8eb52 Mon Sep 17 00:00:00 2001
  2. From: Boris Brezillon <boris.brezillon@free-electrons.com>
  3. Date: Tue, 21 Oct 2014 14:40:42 +0200
  4. Subject: [PATCH] mtd: nand: sunxi: Add HW randomizer support
  5. Add support for the HW randomizer available on the sunxi nand controller.
  6. Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
  7. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
  8. ---
  9. drivers/mtd/nand/sunxi_nand.c | 603 ++++++++++++++++++++++++++++++++++++++++--
  10. 1 file changed, 585 insertions(+), 18 deletions(-)
  11. --- a/drivers/mtd/nand/sunxi_nand.c
  12. +++ b/drivers/mtd/nand/sunxi_nand.c
  13. @@ -210,10 +210,12 @@ struct sunxi_nand_hw_ecc {
  14. *
  15. * @part: base paritition structure
  16. * @ecc: per-partition ECC info
  17. + * @rnd: per-partition randomizer info
  18. */
  19. struct sunxi_nand_part {
  20. struct nand_part part;
  21. struct nand_ecc_ctrl ecc;
  22. + struct nand_rnd_ctrl rnd;
  23. };
  24. static inline struct sunxi_nand_part *
  25. @@ -223,6 +225,29 @@ to_sunxi_nand_part(struct nand_part *par
  26. }
  27. /*
  28. + * sunxi NAND randomizer structure: stores NAND randomizer information
  29. + *
  30. + * @page: current page
  31. + * @column: current column
  32. + * @nseeds: seed table size
  33. + * @seeds: seed table
  34. + * @subseeds: pre computed sub seeds
  35. + * @step: step function
  36. + * @left: number of remaining bytes in the page
  37. + * @state: current randomizer state
  38. + */
  39. +struct sunxi_nand_hw_rnd {
  40. + int page;
  41. + int column;
  42. + int nseeds;
  43. + u16 *seeds;
  44. + u16 *subseeds;
  45. + u16 (*step)(struct mtd_info *mtd, u16 state, int column, int *left);
  46. + int left;
  47. + u16 state;
  48. +};
  49. +
  50. +/*
  51. * NAND chip structure: stores NAND chip device related information
  52. *
  53. * @node: used to store NAND chips into a list
  54. @@ -237,6 +262,7 @@ struct sunxi_nand_chip {
  55. struct list_head node;
  56. struct nand_chip nand;
  57. struct mtd_info mtd;
  58. + void *buffer;
  59. unsigned long clk_rate;
  60. int selected;
  61. int nsels;
  62. @@ -493,6 +519,185 @@ static void sunxi_nfc_write_buf(struct m
  63. }
  64. }
  65. +static u16 sunxi_nfc_hwrnd_step(struct sunxi_nand_hw_rnd *rnd, u16 state, int count)
  66. +{
  67. + state &= 0x7fff;
  68. + count *= 8;
  69. + while (count--)
  70. + state = ((state >> 1) |
  71. + ((((state >> 0) ^ (state >> 1)) & 1) << 14)) & 0x7fff;
  72. +
  73. + return state;
  74. +}
  75. +
  76. +static u16 sunxi_nfc_hwrnd_single_step(u16 state, int count)
  77. +{
  78. + state &= 0x7fff;
  79. + while (count--)
  80. + state = ((state >> 1) |
  81. + ((((state >> 0) ^ (state >> 1)) & 1) << 14)) & 0x7fff;
  82. +
  83. + return state;
  84. +}
  85. +
  86. +static int sunxi_nfc_hwrnd_config(struct mtd_info *mtd, int page, int column,
  87. + enum nand_rnd_action action)
  88. +{
  89. + struct nand_chip *nand = mtd->priv;
  90. + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
  91. + struct sunxi_nand_hw_rnd *rnd = nand->cur_rnd->priv;
  92. + u16 state;
  93. +
  94. + if (page < 0 && column < 0) {
  95. + rnd->page = -1;
  96. + rnd->column = -1;
  97. + return 0;
  98. + }
  99. +
  100. + if (column < 0)
  101. + column = 0;
  102. + if (page < 0)
  103. + page = rnd->page;
  104. +
  105. + if (page < 0)
  106. + return -EINVAL;
  107. +
  108. + if (page != rnd->page && action == NAND_RND_READ) {
  109. + int status;
  110. +
  111. + status = nand_page_get_status(mtd, page);
  112. + if (status == NAND_PAGE_STATUS_UNKNOWN) {
  113. + nand->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
  114. + sunxi_nfc_read_buf(mtd, sunxi_nand->buffer,
  115. + mtd->writesize + mtd->oobsize);
  116. +
  117. + if (nand_page_is_empty(mtd, sunxi_nand->buffer,
  118. + sunxi_nand->buffer +
  119. + mtd->writesize))
  120. + status = NAND_PAGE_EMPTY;
  121. + else
  122. + status = NAND_PAGE_FILLED;
  123. +
  124. + nand_page_set_status(mtd, page, status);
  125. + nand->cmdfunc(mtd, NAND_CMD_RNDOUT, column, -1);
  126. + }
  127. + }
  128. +
  129. + state = rnd->seeds[page % rnd->nseeds];
  130. + rnd->page = page;
  131. + rnd->column = column;
  132. +
  133. + if (rnd->step) {
  134. + rnd->state = rnd->step(mtd, state, column, &rnd->left);
  135. + } else {
  136. + rnd->state = sunxi_nfc_hwrnd_step(rnd, state, column % 4096);
  137. + rnd->left = mtd->oobsize + mtd->writesize - column;
  138. + }
  139. +
  140. + return 0;
  141. +}
  142. +
  143. +static void sunxi_nfc_hwrnd_write_buf(struct mtd_info *mtd, const uint8_t *buf,
  144. + int len)
  145. +{
  146. + struct nand_chip *nand = mtd->priv;
  147. + struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
  148. + struct sunxi_nand_hw_rnd *rnd = nand->cur_rnd->priv;
  149. + u32 tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
  150. + int cnt;
  151. + int offs = 0;
  152. + int rndactiv;
  153. +
  154. + tmp &= ~(NFC_RANDOM_DIRECTION | NFC_RANDOM_SEED | NFC_RANDOM_EN);
  155. + writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
  156. +
  157. + if (rnd->page < 0) {
  158. + sunxi_nfc_write_buf(mtd, buf, len);
  159. + return;
  160. + }
  161. +
  162. + while (len > offs) {
  163. + cnt = len - offs;
  164. + if (cnt > 1024)
  165. + cnt = 1024;
  166. +
  167. + rndactiv = nand_rnd_is_activ(mtd, rnd->page, rnd->column,
  168. + &cnt);
  169. + if (rndactiv > 0) {
  170. + writel(tmp | NFC_RANDOM_EN | (rnd->state << 16),
  171. + nfc->regs + NFC_REG_ECC_CTL);
  172. + if (rnd->left < cnt)
  173. + cnt = rnd->left;
  174. + }
  175. +
  176. + sunxi_nfc_write_buf(mtd, buf + offs, cnt);
  177. +
  178. + if (rndactiv > 0)
  179. + writel(tmp & ~NFC_RANDOM_EN,
  180. + nfc->regs + NFC_REG_ECC_CTL);
  181. +
  182. + offs += cnt;
  183. + if (len <= offs)
  184. + break;
  185. +
  186. + sunxi_nfc_hwrnd_config(mtd, -1, rnd->column + cnt, NAND_RND_WRITE);
  187. + }
  188. +}
  189. +
  190. +static void sunxi_nfc_hwrnd_read_buf(struct mtd_info *mtd, uint8_t *buf,
  191. + int len)
  192. +{
  193. + struct nand_chip *nand = mtd->priv;
  194. + struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
  195. + struct sunxi_nand_hw_rnd *rnd = nand->cur_rnd->priv;
  196. + u32 tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
  197. + int cnt;
  198. + int offs = 0;
  199. + int rndactiv;
  200. +
  201. + tmp &= ~(NFC_RANDOM_DIRECTION | NFC_RANDOM_SEED | NFC_RANDOM_EN);
  202. + writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
  203. +
  204. + if (rnd->page < 0) {
  205. + sunxi_nfc_read_buf(mtd, buf, len);
  206. + return;
  207. + }
  208. +
  209. + while (len > offs) {
  210. + cnt = len - offs;
  211. + if (cnt > 1024)
  212. + cnt = 1024;
  213. +
  214. + if (nand_page_get_status(mtd, rnd->page) != NAND_PAGE_EMPTY &&
  215. + nand_rnd_is_activ(mtd, rnd->page, rnd->column, &cnt) > 0)
  216. + rndactiv = 1;
  217. + else
  218. + rndactiv = 0;
  219. +
  220. + if (rndactiv > 0) {
  221. + writel(tmp | NFC_RANDOM_EN | (rnd->state << 16),
  222. + nfc->regs + NFC_REG_ECC_CTL);
  223. + if (rnd->left < cnt)
  224. + cnt = rnd->left;
  225. + }
  226. +
  227. + if (buf)
  228. + sunxi_nfc_read_buf(mtd, buf + offs, cnt);
  229. + else
  230. + sunxi_nfc_read_buf(mtd, NULL, cnt);
  231. +
  232. + if (rndactiv > 0)
  233. + writel(tmp & ~NFC_RANDOM_EN,
  234. + nfc->regs + NFC_REG_ECC_CTL);
  235. +
  236. + offs += cnt;
  237. + if (len <= offs)
  238. + break;
  239. +
  240. + sunxi_nfc_hwrnd_config(mtd, -1, rnd->column + cnt, NAND_RND_READ);
  241. + }
  242. +}
  243. +
  244. static uint8_t sunxi_nfc_read_byte(struct mtd_info *mtd)
  245. {
  246. uint8_t ret;
  247. @@ -542,16 +747,43 @@ static int sunxi_nfc_hw_ecc_read_page(st
  248. int oob_required, int page)
  249. {
  250. struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller);
  251. + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(chip);
  252. struct nand_ecc_ctrl *ecc = chip->cur_ecc;
  253. struct nand_ecclayout *layout = ecc->layout;
  254. struct sunxi_nand_hw_ecc *data = ecc->priv;
  255. unsigned int max_bitflips = 0;
  256. + int status;
  257. int offset;
  258. int ret;
  259. u32 tmp;
  260. int i;
  261. int cnt;
  262. + status = nand_page_get_status(mtd, page);
  263. + if (status == NAND_PAGE_STATUS_UNKNOWN) {
  264. + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
  265. + sunxi_nfc_read_buf(mtd, sunxi_nand->buffer,
  266. + mtd->writesize + mtd->oobsize);
  267. +
  268. + if (nand_page_is_empty(mtd, sunxi_nand->buffer,
  269. + sunxi_nand->buffer +
  270. + mtd->writesize)) {
  271. + status = NAND_PAGE_EMPTY;
  272. + } else {
  273. + status = NAND_PAGE_FILLED;
  274. + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
  275. + }
  276. +
  277. + nand_page_set_status(mtd, page, status);
  278. + }
  279. +
  280. + if (status == NAND_PAGE_EMPTY) {
  281. + memset(buf, 0xff, mtd->writesize);
  282. + if (oob_required)
  283. + memset(chip->oob_poi, 0xff, mtd->oobsize);
  284. + return 0;
  285. + }
  286. +
  287. tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
  288. tmp &= ~(NFC_ECC_MODE | NFC_ECC_PIPELINE | NFC_ECC_BLOCK_SIZE);
  289. tmp |= NFC_ECC_EN | (data->mode << NFC_ECC_MODE_SHIFT) |
  290. @@ -560,12 +792,15 @@ static int sunxi_nfc_hw_ecc_read_page(st
  291. writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
  292. for (i = 0; i < ecc->steps; i++) {
  293. + bool rndactiv = false;
  294. +
  295. if (i)
  296. chip->cmdfunc(mtd, NAND_CMD_RNDOUT, i * ecc->size, -1);
  297. offset = mtd->writesize + layout->eccpos[i * ecc->bytes] - 4;
  298. - chip->read_buf(mtd, NULL, ecc->size);
  299. + nand_rnd_config(mtd, page, i * ecc->size, NAND_RND_READ);
  300. + nand_rnd_read_buf(mtd, NULL, ecc->size);
  301. chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
  302. @@ -573,6 +808,25 @@ static int sunxi_nfc_hw_ecc_read_page(st
  303. if (ret)
  304. return ret;
  305. + if (i) {
  306. + cnt = ecc->bytes + 4;
  307. + if (nand_rnd_is_activ(mtd, page, offset, &cnt) > 0 &&
  308. + cnt == ecc->bytes + 4)
  309. + rndactiv = true;
  310. + } else {
  311. + cnt = ecc->bytes + 2;
  312. + if (nand_rnd_is_activ(mtd, page, offset + 2, &cnt) > 0 &&
  313. + cnt == ecc->bytes + 2)
  314. + rndactiv = true;
  315. + }
  316. +
  317. + if (rndactiv) {
  318. + tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
  319. + tmp &= ~(NFC_RANDOM_DIRECTION | NFC_ECC_EXCEPTION);
  320. + tmp |= NFC_RANDOM_EN;
  321. + writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
  322. + }
  323. +
  324. tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | (1 << 30);
  325. writel(tmp, nfc->regs + NFC_REG_CMD);
  326. @@ -583,6 +837,9 @@ static int sunxi_nfc_hw_ecc_read_page(st
  327. memcpy_fromio(buf + (i * ecc->size),
  328. nfc->regs + NFC_RAM0_BASE, ecc->size);
  329. + writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
  330. + nfc->regs + NFC_REG_ECC_CTL);
  331. +
  332. if (readl(nfc->regs + NFC_REG_ECC_ST) & 0x1) {
  333. mtd->ecc_stats.failed++;
  334. } else {
  335. @@ -598,9 +855,10 @@ static int sunxi_nfc_hw_ecc_read_page(st
  336. if (ret)
  337. return ret;
  338. + nand_rnd_config(mtd, -1, offset, NAND_RND_READ);
  339. offset -= mtd->writesize;
  340. - chip->read_buf(mtd, chip->oob_poi + offset,
  341. - ecc->bytes + 4);
  342. + nand_rnd_read_buf(mtd, chip->oob_poi + offset,
  343. + ecc->bytes + 4);
  344. }
  345. }
  346. @@ -610,11 +868,14 @@ static int sunxi_nfc_hw_ecc_read_page(st
  347. offset = mtd->writesize +
  348. ecc->layout->oobfree[ecc->steps].offset;
  349. chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
  350. + nand_rnd_config(mtd, -1, offset, NAND_RND_READ);
  351. offset -= mtd->writesize;
  352. - chip->read_buf(mtd, chip->oob_poi + offset, cnt);
  353. + nand_rnd_read_buf(mtd, chip->oob_poi + offset, cnt);
  354. }
  355. }
  356. + nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
  357. +
  358. tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
  359. tmp &= ~NFC_ECC_EN;
  360. @@ -631,6 +892,7 @@ static int sunxi_nfc_hw_ecc_write_page(s
  361. struct nand_ecc_ctrl *ecc = chip->cur_ecc;
  362. struct nand_ecclayout *layout = ecc->layout;
  363. struct sunxi_nand_hw_ecc *data = ecc->priv;
  364. + struct sunxi_nand_hw_rnd *rnd = chip->cur_rnd->priv;
  365. int offset;
  366. int ret;
  367. u32 tmp;
  368. @@ -645,17 +907,57 @@ static int sunxi_nfc_hw_ecc_write_page(s
  369. writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
  370. for (i = 0; i < ecc->steps; i++) {
  371. + bool rndactiv = false;
  372. + u8 oob_buf[4];
  373. +
  374. if (i)
  375. chip->cmdfunc(mtd, NAND_CMD_RNDIN, i * ecc->size, -1);
  376. - chip->write_buf(mtd, buf + (i * ecc->size), ecc->size);
  377. + nand_rnd_config(mtd, -1, i * ecc->size, NAND_RND_WRITE);
  378. + nand_rnd_write_buf(mtd, buf + (i * ecc->size), ecc->size);
  379. offset = layout->eccpos[i * ecc->bytes] - 4 + mtd->writesize;
  380. /* Fill OOB data in */
  381. - writel(NFC_BUF_TO_USER_DATA(chip->oob_poi +
  382. - layout->oobfree[i].offset),
  383. - nfc->regs + NFC_REG_USER_DATA_BASE);
  384. + if (!oob_required)
  385. + memset(oob_buf, 0xff, 4);
  386. + else
  387. + memcpy(oob_buf,
  388. + chip->oob_poi + layout->oobfree[i].offset,
  389. + 4);
  390. +
  391. +
  392. + memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE, oob_buf, 4);
  393. +
  394. + if (i) {
  395. + cnt = ecc->bytes + 4;
  396. + if (rnd &&
  397. + nand_rnd_is_activ(mtd, -1, offset, &cnt) > 0 &&
  398. + cnt == ecc->bytes + 4)
  399. + rndactiv = true;
  400. + } else {
  401. + cnt = ecc->bytes + 2;
  402. + if (rnd &&
  403. + nand_rnd_is_activ(mtd, -1, offset + 2, &cnt) > 0 &&
  404. + cnt == ecc->bytes + 2)
  405. + rndactiv = true;
  406. + }
  407. +
  408. + if (rndactiv) {
  409. + /* pre randomize to generate FF patterns on the NAND */
  410. + if (!i) {
  411. + u16 state = rnd->subseeds[rnd->page % rnd->nseeds];
  412. + state = sunxi_nfc_hwrnd_single_step(state, 15);
  413. + oob_buf[0] ^= state;
  414. + state = sunxi_nfc_hwrnd_step(rnd, state, 1);
  415. + oob_buf[1] ^= state;
  416. + memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE, oob_buf, 4);
  417. + }
  418. + tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
  419. + tmp &= ~(NFC_RANDOM_DIRECTION | NFC_ECC_EXCEPTION);
  420. + tmp |= NFC_RANDOM_EN;
  421. + writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
  422. + }
  423. chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1);
  424. @@ -669,6 +971,9 @@ static int sunxi_nfc_hw_ecc_write_page(s
  425. ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
  426. if (ret)
  427. return ret;
  428. +
  429. + writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
  430. + nfc->regs + NFC_REG_ECC_CTL);
  431. }
  432. if (oob_required) {
  433. @@ -677,11 +982,14 @@ static int sunxi_nfc_hw_ecc_write_page(s
  434. offset = mtd->writesize +
  435. ecc->layout->oobfree[i].offset;
  436. chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1);
  437. + nand_rnd_config(mtd, -1, offset, NAND_RND_WRITE);
  438. offset -= mtd->writesize;
  439. - chip->write_buf(mtd, chip->oob_poi + offset, cnt);
  440. + nand_rnd_write_buf(mtd, chip->oob_poi + offset, cnt);
  441. }
  442. }
  443. + nand_rnd_config(mtd, -1, -1, NAND_RND_WRITE);
  444. +
  445. tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
  446. tmp &= ~NFC_ECC_EN;
  447. @@ -690,22 +998,76 @@ static int sunxi_nfc_hw_ecc_write_page(s
  448. return 0;
  449. }
  450. +static u16 sunxi_nfc_hw_ecc_rnd_steps(struct mtd_info *mtd, u16 state,
  451. + int column, int *left)
  452. +{
  453. + struct nand_chip *chip = mtd->priv;
  454. + struct nand_ecc_ctrl *ecc = chip->cur_ecc;
  455. + struct sunxi_nand_hw_rnd *rnd = chip->cur_rnd->priv;
  456. + int nblks = mtd->writesize / ecc->size;
  457. + int modsize = ecc->size;
  458. + int steps;
  459. +
  460. + if (column < mtd->writesize) {
  461. + steps = column % modsize;
  462. + *left = modsize - steps;
  463. + } else if (column < mtd->writesize +
  464. + (nblks * (ecc->bytes + 4))) {
  465. + column -= mtd->writesize;
  466. + steps = column % (ecc->bytes + 4);
  467. + *left = ecc->bytes + 4 - steps;
  468. + state = rnd->subseeds[rnd->page % rnd->nseeds];
  469. + } else {
  470. + steps = column % 4096;
  471. + *left = mtd->writesize + mtd->oobsize - column;
  472. + }
  473. +
  474. + return sunxi_nfc_hwrnd_step(rnd, state, steps);
  475. +}
  476. +
  477. static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd,
  478. struct nand_chip *chip,
  479. uint8_t *buf, int oob_required,
  480. int page)
  481. {
  482. struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller);
  483. + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(chip);
  484. struct nand_ecc_ctrl *ecc = chip->cur_ecc;
  485. struct sunxi_nand_hw_ecc *data = ecc->priv;
  486. unsigned int max_bitflips = 0;
  487. uint8_t *oob = chip->oob_poi;
  488. int offset = 0;
  489. int ret;
  490. + int status;
  491. int cnt;
  492. u32 tmp;
  493. int i;
  494. + status = nand_page_get_status(mtd, page);
  495. + if (status == NAND_PAGE_STATUS_UNKNOWN) {
  496. + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
  497. + sunxi_nfc_read_buf(mtd, sunxi_nand->buffer,
  498. + mtd->writesize + mtd->oobsize);
  499. +
  500. + if (nand_page_is_empty(mtd, sunxi_nand->buffer,
  501. + sunxi_nand->buffer +
  502. + mtd->writesize)) {
  503. + status = NAND_PAGE_EMPTY;
  504. + } else {
  505. + status = NAND_PAGE_FILLED;
  506. + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
  507. + }
  508. +
  509. + nand_page_set_status(mtd, page, status);
  510. + }
  511. +
  512. + if (status == NAND_PAGE_EMPTY) {
  513. + memset(buf, 0xff, mtd->writesize);
  514. + if (oob_required)
  515. + memset(chip->oob_poi, 0xff, mtd->oobsize);
  516. + return 0;
  517. + }
  518. +
  519. tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
  520. tmp &= ~(NFC_ECC_MODE | NFC_ECC_PIPELINE | NFC_ECC_BLOCK_SIZE);
  521. tmp |= NFC_ECC_EN | (data->mode << NFC_ECC_MODE_SHIFT) |
  522. @@ -714,7 +1076,17 @@ static int sunxi_nfc_hw_syndrome_ecc_rea
  523. writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
  524. for (i = 0; i < ecc->steps; i++) {
  525. - chip->read_buf(mtd, NULL, ecc->size);
  526. + nand_rnd_config(mtd, page, offset, NAND_RND_READ);
  527. + nand_rnd_read_buf(mtd, NULL, ecc->size);
  528. +
  529. + cnt = ecc->bytes + 4;
  530. + if (nand_rnd_is_activ(mtd, page, offset, &cnt) > 0 &&
  531. + cnt == ecc->bytes + 4) {
  532. + tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
  533. + tmp &= ~(NFC_RANDOM_DIRECTION | NFC_ECC_EXCEPTION);
  534. + tmp |= NFC_RANDOM_EN;
  535. + writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
  536. + }
  537. tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | (1 << 30);
  538. writel(tmp, nfc->regs + NFC_REG_CMD);
  539. @@ -727,6 +1099,9 @@ static int sunxi_nfc_hw_syndrome_ecc_rea
  540. buf += ecc->size;
  541. offset += ecc->size;
  542. + writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
  543. + nfc->regs + NFC_REG_ECC_CTL);
  544. +
  545. if (readl(nfc->regs + NFC_REG_ECC_ST) & 0x1) {
  546. mtd->ecc_stats.failed++;
  547. } else {
  548. @@ -737,7 +1112,8 @@ static int sunxi_nfc_hw_syndrome_ecc_rea
  549. if (oob_required) {
  550. chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
  551. - chip->read_buf(mtd, oob, ecc->bytes + ecc->prepad);
  552. + nand_rnd_config(mtd, -1, offset, NAND_RND_READ);
  553. + nand_rnd_read_buf(mtd, oob, ecc->bytes + ecc->prepad);
  554. oob += ecc->bytes + ecc->prepad;
  555. }
  556. @@ -748,10 +1124,13 @@ static int sunxi_nfc_hw_syndrome_ecc_rea
  557. cnt = mtd->oobsize - (oob - chip->oob_poi);
  558. if (cnt > 0) {
  559. chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
  560. - chip->read_buf(mtd, oob, cnt);
  561. + nand_rnd_config(mtd, page, offset, NAND_RND_READ);
  562. + nand_rnd_read_buf(mtd, oob, cnt);
  563. }
  564. }
  565. + nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
  566. +
  567. writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN,
  568. nfc->regs + NFC_REG_ECC_CTL);
  569. @@ -766,6 +1145,7 @@ static int sunxi_nfc_hw_syndrome_ecc_wri
  570. struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller);
  571. struct nand_ecc_ctrl *ecc = chip->cur_ecc;
  572. struct sunxi_nand_hw_ecc *data = ecc->priv;
  573. + struct sunxi_nand_hw_rnd *rnd = chip->cur_rnd->priv;
  574. uint8_t *oob = chip->oob_poi;
  575. int offset = 0;
  576. int ret;
  577. @@ -781,13 +1161,24 @@ static int sunxi_nfc_hw_syndrome_ecc_wri
  578. writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
  579. for (i = 0; i < ecc->steps; i++) {
  580. - chip->write_buf(mtd, buf + (i * ecc->size), ecc->size);
  581. + nand_rnd_config(mtd, -1, offset, NAND_RND_WRITE);
  582. + nand_rnd_write_buf(mtd, buf + (i * ecc->size), ecc->size);
  583. offset += ecc->size;
  584. /* Fill OOB data in */
  585. writel(NFC_BUF_TO_USER_DATA(oob),
  586. nfc->regs + NFC_REG_USER_DATA_BASE);
  587. + cnt = ecc->bytes + 4;
  588. + if (rnd &&
  589. + nand_rnd_is_activ(mtd, rnd->page, offset, &cnt) > 0 &&
  590. + cnt == ecc->bytes + 4) {
  591. + tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
  592. + tmp &= ~(NFC_RANDOM_DIRECTION | NFC_ECC_EXCEPTION);
  593. + tmp |= NFC_RANDOM_EN;
  594. + writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
  595. + }
  596. +
  597. tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ACCESS_DIR |
  598. (1 << 30);
  599. writel(tmp, nfc->regs + NFC_REG_CMD);
  600. @@ -796,6 +1187,9 @@ static int sunxi_nfc_hw_syndrome_ecc_wri
  601. if (ret)
  602. return ret;
  603. + writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
  604. + nfc->regs + NFC_REG_ECC_CTL);
  605. +
  606. offset += ecc->bytes + ecc->prepad;
  607. oob += ecc->bytes + ecc->prepad;
  608. }
  609. @@ -804,9 +1198,11 @@ static int sunxi_nfc_hw_syndrome_ecc_wri
  610. cnt = mtd->oobsize - (oob - chip->oob_poi);
  611. if (cnt > 0) {
  612. chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1);
  613. - chip->write_buf(mtd, oob, cnt);
  614. + nand_rnd_config(mtd, -1, offset, NAND_RND_WRITE);
  615. + nand_rnd_write_buf(mtd, oob, cnt);
  616. }
  617. }
  618. + nand_rnd_config(mtd, -1, -1, NAND_RND_WRITE);
  619. tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
  620. tmp &= ~NFC_ECC_EN;
  621. @@ -816,6 +1212,128 @@ static int sunxi_nfc_hw_syndrome_ecc_wri
  622. return 0;
  623. }
  624. +static u16 sunxi_nfc_hw_syndrome_ecc_rnd_steps(struct mtd_info *mtd, u16 state,
  625. + int column, int *left)
  626. +{
  627. + struct nand_chip *chip = mtd->priv;
  628. + struct nand_ecc_ctrl *ecc = chip->cur_ecc;
  629. + struct sunxi_nand_hw_rnd *rnd = chip->cur_rnd->priv;
  630. + int eccsteps = mtd->writesize / ecc->size;
  631. + int modsize = ecc->size + ecc->prepad + ecc->bytes;
  632. + int steps;
  633. +
  634. + if (column < (eccsteps * modsize)) {
  635. + steps = column % modsize;
  636. + *left = modsize - steps;
  637. + if (steps >= ecc->size) {
  638. + steps -= ecc->size;
  639. + state = rnd->subseeds[rnd->page % rnd->nseeds];
  640. + }
  641. + } else {
  642. + steps = column % 4096;
  643. + *left = mtd->writesize + mtd->oobsize - column;
  644. + }
  645. +
  646. + return sunxi_nfc_hwrnd_step(rnd, state, steps);
  647. +}
  648. +
  649. +static u16 default_seeds[] = {0x4a80};
  650. +
  651. +static void sunxi_nand_rnd_ctrl_cleanup(struct nand_rnd_ctrl *rnd)
  652. +{
  653. + struct sunxi_nand_hw_rnd *hwrnd = rnd->priv;
  654. +
  655. + if (hwrnd->seeds != default_seeds)
  656. + kfree(hwrnd->seeds);
  657. + kfree(hwrnd->subseeds);
  658. + kfree(rnd->layout);
  659. + kfree(hwrnd);
  660. +}
  661. +
  662. +static int sunxi_nand_rnd_ctrl_init(struct mtd_info *mtd,
  663. + struct nand_rnd_ctrl *rnd,
  664. + struct nand_ecc_ctrl *ecc,
  665. + struct device_node *np)
  666. +{
  667. + struct sunxi_nand_hw_rnd *hwrnd;
  668. + struct nand_rnd_layout *layout = NULL;
  669. + int ret;
  670. +
  671. + hwrnd = kzalloc(sizeof(*hwrnd), GFP_KERNEL);
  672. + if (!hwrnd)
  673. + return -ENOMEM;
  674. +
  675. + hwrnd->seeds = default_seeds;
  676. + hwrnd->nseeds = ARRAY_SIZE(default_seeds);
  677. +
  678. + if (of_get_property(np, "nand-randomizer-seeds", &ret)) {
  679. + hwrnd->nseeds = ret / sizeof(*hwrnd->seeds);
  680. + hwrnd->seeds = kzalloc(hwrnd->nseeds * sizeof(*hwrnd->seeds),
  681. + GFP_KERNEL);
  682. + if (!hwrnd->seeds) {
  683. + ret = -ENOMEM;
  684. + goto err;
  685. + }
  686. +
  687. + ret = of_property_read_u16_array(np, "nand-randomizer-seeds",
  688. + hwrnd->seeds, hwrnd->nseeds);
  689. + if (ret)
  690. + goto err;
  691. + }
  692. +
  693. + switch (ecc->mode) {
  694. + case NAND_ECC_HW_SYNDROME:
  695. + hwrnd->step = sunxi_nfc_hw_syndrome_ecc_rnd_steps;
  696. + break;
  697. +
  698. + case NAND_ECC_HW:
  699. + hwrnd->step = sunxi_nfc_hw_ecc_rnd_steps;
  700. +
  701. + default:
  702. + layout = kzalloc(sizeof(*layout) + sizeof(struct nand_rndfree),
  703. + GFP_KERNEL);
  704. + if (!layout) {
  705. + ret = -ENOMEM;
  706. + goto err;
  707. + }
  708. + layout->nranges = 1;
  709. + layout->ranges[0].offset = mtd->writesize;
  710. + layout->ranges[0].length = 2;
  711. + rnd->layout = layout;
  712. + break;
  713. + }
  714. +
  715. + if (ecc->mode == NAND_ECC_HW_SYNDROME || ecc->mode == NAND_ECC_HW) {
  716. + int i;
  717. +
  718. + hwrnd->subseeds = kzalloc(hwrnd->nseeds *
  719. + sizeof(*hwrnd->subseeds),
  720. + GFP_KERNEL);
  721. + if (!hwrnd->subseeds) {
  722. + ret = -ENOMEM;
  723. + goto err;
  724. + }
  725. +
  726. + for (i = 0; i < hwrnd->nseeds; i++)
  727. + hwrnd->subseeds[i] = sunxi_nfc_hwrnd_step(hwrnd,
  728. + hwrnd->seeds[i],
  729. + ecc->size);
  730. + }
  731. +
  732. + rnd->config = sunxi_nfc_hwrnd_config;
  733. + rnd->read_buf = sunxi_nfc_hwrnd_read_buf;
  734. + rnd->write_buf = sunxi_nfc_hwrnd_write_buf;
  735. + rnd->priv = hwrnd;
  736. +
  737. + return 0;
  738. +
  739. +err:
  740. + kfree(hwrnd);
  741. + kfree(layout);
  742. +
  743. + return ret;
  744. +}
  745. +
  746. static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
  747. const struct nand_sdr_timings *timings)
  748. {
  749. @@ -1076,6 +1594,40 @@ static int sunxi_nand_hw_syndrome_ecc_ct
  750. return 0;
  751. }
  752. +static void sunxi_nand_rnd_cleanup(struct nand_rnd_ctrl *rnd)
  753. +{
  754. + switch (rnd->mode) {
  755. + case NAND_RND_HW:
  756. + sunxi_nand_rnd_ctrl_cleanup(rnd);
  757. + break;
  758. + default:
  759. + break;
  760. + }
  761. +}
  762. +
  763. +static int sunxi_nand_rnd_init(struct mtd_info *mtd,
  764. + struct nand_rnd_ctrl *rnd,
  765. + struct nand_ecc_ctrl *ecc,
  766. + struct device_node *np)
  767. +{
  768. + int ret;
  769. +
  770. + rnd->mode = NAND_RND_NONE;
  771. +
  772. + ret = of_get_nand_rnd_mode(np);
  773. + if (ret >= 0)
  774. + rnd->mode = ret;
  775. +
  776. + switch (rnd->mode) {
  777. + case NAND_RND_HW:
  778. + return sunxi_nand_rnd_ctrl_init(mtd, rnd, ecc, np);
  779. + default:
  780. + break;
  781. + }
  782. +
  783. + return 0;
  784. +}
  785. +
  786. static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc)
  787. {
  788. switch (ecc->mode) {
  789. @@ -1167,7 +1719,14 @@ struct nand_part *sunxi_ofnandpart_parse
  790. if (ret)
  791. goto err;
  792. + ret = sunxi_nand_rnd_init(master, &part->rnd, &part->ecc, pp);
  793. + if (ret) {
  794. + sunxi_nand_ecc_cleanup(&part->ecc);
  795. + goto err;
  796. + }
  797. +
  798. part->part.ecc = &part->ecc;
  799. + part->part.rnd = &part->rnd;
  800. return &part->part;
  801. @@ -1292,18 +1851,30 @@ static int sunxi_nand_chip_init(struct d
  802. if (ret)
  803. return ret;
  804. + chip->buffer = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
  805. + if (!chip->buffer)
  806. + return -ENOMEM;
  807. +
  808. ret = sunxi_nand_chip_init_timings(chip, np);
  809. if (ret) {
  810. dev_err(dev, "could not configure chip timings: %d\n", ret);
  811. return ret;
  812. }
  813. + ret = nand_pst_create(mtd);
  814. + if (ret)
  815. + return ret;
  816. +
  817. ret = sunxi_nand_ecc_init(mtd, &nand->ecc, np);
  818. if (ret) {
  819. dev_err(dev, "ECC init failed: %d\n", ret);
  820. return ret;
  821. }
  822. + ret = sunxi_nand_rnd_init(mtd, &nand->rnd, &nand->ecc, np);
  823. + if (ret)
  824. + return ret;
  825. +
  826. ret = nand_scan_tail(mtd);
  827. if (ret) {
  828. dev_err(dev, "nand_scan_tail failed: %d\n", ret);
  829. @@ -1360,6 +1931,8 @@ static void sunxi_nand_chips_cleanup(str
  830. nand_release(&chip->mtd);
  831. sunxi_nand_ecc_cleanup(&chip->nand.ecc);
  832. list_del(&chip->node);
  833. + sunxi_nand_rnd_cleanup(&chip->nand.rnd);
  834. + kfree(chip->buffer);
  835. }
  836. }