099-1-mtd-nand-raw-qcom_nandc-add-boot_layout_mode-support.patch 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. From 6949d651e3be3ebbfedb6bbd5b541cfda6ee58a9 Mon Sep 17 00:00:00 2001
  2. From: Ansuel Smith <[email protected]>
  3. Date: Wed, 10 Feb 2021 10:40:17 +0100
  4. Subject: [PATCH 1/2] mtd: nand: raw: qcom_nandc: add boot_layout_mode support
  5. ipq806x nand have a special ecc configuration for the boot pages. The
  6. use of the non-boot pages configuration on boot pages cause I/O error
  7. and can cause broken data written to the nand. Add support for this
  8. special configuration if the page to be read/write is in the size of the
  9. boot pages set by the dts.
  10. Signed-off-by: Ansuel Smith <[email protected]>
  11. ---
  12. drivers/mtd/nand/raw/qcom_nandc.c | 82 +++++++++++++++++++++++++++++--
  13. 1 file changed, 77 insertions(+), 5 deletions(-)
  14. --- a/drivers/mtd/nand/raw/qcom_nandc.c
  15. +++ b/drivers/mtd/nand/raw/qcom_nandc.c
  16. @@ -158,6 +158,11 @@
  17. /* NAND_CTRL bits */
  18. #define BAM_MODE_EN BIT(0)
  19. +
  20. +#define UD_SIZE_BYTES_MASK (0x3ff << UD_SIZE_BYTES)
  21. +#define SPARE_SIZE_BYTES_MASK (0xf << SPARE_SIZE_BYTES)
  22. +#define ECC_NUM_DATA_BYTES_MASK (0x3ff << ECC_NUM_DATA_BYTES)
  23. +
  24. /*
  25. * the NAND controller performs reads/writes with ECC in 516 byte chunks.
  26. * the driver calls the chunks 'step' or 'codeword' interchangeably
  27. @@ -429,6 +434,13 @@ struct qcom_nand_controller {
  28. * @cfg0, cfg1, cfg0_raw..: NANDc register configurations needed for
  29. * ecc/non-ecc mode for the current nand flash
  30. * device
  31. + *
  32. + * @boot_pages_conf: keep track of the current ecc configuration used by
  33. + * the driver for read/write operation. (boot pages
  34. + * have different configuration than normal page)
  35. + * @boot_pages: number of pages starting from 0 used as boot pages
  36. + * where the driver will use the boot pages ecc
  37. + * configuration for read/write operation
  38. */
  39. struct qcom_nand_host {
  40. struct nand_chip chip;
  41. @@ -451,6 +463,9 @@ struct qcom_nand_host {
  42. u32 ecc_bch_cfg;
  43. u32 clrflashstatus;
  44. u32 clrreadstatus;
  45. +
  46. + bool boot_pages_conf;
  47. + u32 boot_pages;
  48. };
  49. /*
  50. @@ -459,12 +474,14 @@ struct qcom_nand_host {
  51. * @ecc_modes - ecc mode for NAND
  52. * @is_bam - whether NAND controller is using BAM
  53. * @is_qpic - whether NAND CTRL is part of qpic IP
  54. + * @has_boot_pages - whether NAND has different ecc settings for boot pages
  55. * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset
  56. */
  57. struct qcom_nandc_props {
  58. u32 ecc_modes;
  59. bool is_bam;
  60. bool is_qpic;
  61. + bool has_boot_pages;
  62. u32 dev_cmd_reg_start;
  63. };
  64. @@ -1603,7 +1620,7 @@ qcom_nandc_read_cw_raw(struct mtd_info *
  65. data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1);
  66. oob_size1 = host->bbm_size;
  67. - if (cw == (ecc->steps - 1)) {
  68. + if (cw == (ecc->steps - 1) && !host->boot_pages_conf) {
  69. data_size2 = ecc->size - data_size1 -
  70. ((ecc->steps - 1) * 4);
  71. oob_size2 = (ecc->steps * 4) + host->ecc_bytes_hw +
  72. @@ -1684,7 +1701,7 @@ check_for_erased_page(struct qcom_nand_h
  73. }
  74. for_each_set_bit(cw, &uncorrectable_cws, ecc->steps) {
  75. - if (cw == (ecc->steps - 1)) {
  76. + if (cw == (ecc->steps - 1) && !host->boot_pages_conf) {
  77. data_size = ecc->size - ((ecc->steps - 1) * 4);
  78. oob_size = (ecc->steps * 4) + host->ecc_bytes_hw;
  79. } else {
  80. @@ -1843,7 +1860,7 @@ static int read_page_ecc(struct qcom_nan
  81. for (i = 0; i < ecc->steps; i++) {
  82. int data_size, oob_size;
  83. - if (i == (ecc->steps - 1)) {
  84. + if (i == (ecc->steps - 1) && !host->boot_pages_conf) {
  85. data_size = ecc->size - ((ecc->steps - 1) << 2);
  86. oob_size = (ecc->steps << 2) + host->ecc_bytes_hw +
  87. host->spare_bytes;
  88. @@ -1940,6 +1957,30 @@ static int copy_last_cw(struct qcom_nand
  89. return ret;
  90. }
  91. +static void
  92. +check_boot_pages_conf(struct qcom_nand_host *host, int page)
  93. +{
  94. + bool boot_pages_conf = page < host->boot_pages;
  95. +
  96. + /* Skip conf write if we are already in the correct mode */
  97. + if (boot_pages_conf != host->boot_pages_conf) {
  98. + host->boot_pages_conf = boot_pages_conf;
  99. +
  100. + host->cw_data = boot_pages_conf ? 512 : 516;
  101. + host->spare_bytes = host->cw_size - host->ecc_bytes_hw -
  102. + host->bbm_size - host->cw_data;
  103. +
  104. + host->cfg0 &= ~(SPARE_SIZE_BYTES_MASK | UD_SIZE_BYTES_MASK);
  105. + host->cfg0 |= host->spare_bytes << SPARE_SIZE_BYTES |
  106. + host->cw_data << UD_SIZE_BYTES;
  107. +
  108. + host->ecc_bch_cfg &= ~ECC_NUM_DATA_BYTES_MASK;
  109. + host->ecc_bch_cfg |= host->cw_data << ECC_NUM_DATA_BYTES;
  110. + host->ecc_buf_cfg = (boot_pages_conf ? 0x1ff : 0x203) <<
  111. + NUM_STEPS;
  112. + }
  113. +}
  114. +
  115. /* implements ecc->read_page() */
  116. static int qcom_nandc_read_page(struct nand_chip *chip, uint8_t *buf,
  117. int oob_required, int page)
  118. @@ -1948,6 +1989,9 @@ static int qcom_nandc_read_page(struct n
  119. struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
  120. u8 *data_buf, *oob_buf = NULL;
  121. + if (host->boot_pages)
  122. + check_boot_pages_conf(host, page);
  123. +
  124. nand_read_page_op(chip, page, 0, NULL, 0);
  125. data_buf = buf;
  126. oob_buf = oob_required ? chip->oob_poi : NULL;
  127. @@ -1967,6 +2011,9 @@ static int qcom_nandc_read_page_raw(stru
  128. int cw, ret;
  129. u8 *data_buf = buf, *oob_buf = chip->oob_poi;
  130. + if (host->boot_pages)
  131. + check_boot_pages_conf(host, page);
  132. +
  133. for (cw = 0; cw < ecc->steps; cw++) {
  134. ret = qcom_nandc_read_cw_raw(mtd, chip, data_buf, oob_buf,
  135. page, cw);
  136. @@ -1987,6 +2034,9 @@ static int qcom_nandc_read_oob(struct na
  137. struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
  138. struct nand_ecc_ctrl *ecc = &chip->ecc;
  139. + if (host->boot_pages)
  140. + check_boot_pages_conf(host, page);
  141. +
  142. clear_read_regs(nandc);
  143. clear_bam_transaction(nandc);
  144. @@ -2007,6 +2057,9 @@ static int qcom_nandc_write_page(struct
  145. u8 *data_buf, *oob_buf;
  146. int i, ret;
  147. + if (host->boot_pages)
  148. + check_boot_pages_conf(host, page);
  149. +
  150. nand_prog_page_begin_op(chip, page, 0, NULL, 0);
  151. clear_read_regs(nandc);
  152. @@ -2022,7 +2075,7 @@ static int qcom_nandc_write_page(struct
  153. for (i = 0; i < ecc->steps; i++) {
  154. int data_size, oob_size;
  155. - if (i == (ecc->steps - 1)) {
  156. + if (i == (ecc->steps - 1) && !host->boot_pages_conf) {
  157. data_size = ecc->size - ((ecc->steps - 1) << 2);
  158. oob_size = (ecc->steps << 2) + host->ecc_bytes_hw +
  159. host->spare_bytes;
  160. @@ -2079,6 +2132,9 @@ static int qcom_nandc_write_page_raw(str
  161. u8 *data_buf, *oob_buf;
  162. int i, ret;
  163. + if (host->boot_pages)
  164. + check_boot_pages_conf(host, page);
  165. +
  166. nand_prog_page_begin_op(chip, page, 0, NULL, 0);
  167. clear_read_regs(nandc);
  168. clear_bam_transaction(nandc);
  169. @@ -2097,7 +2153,7 @@ static int qcom_nandc_write_page_raw(str
  170. data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1);
  171. oob_size1 = host->bbm_size;
  172. - if (i == (ecc->steps - 1)) {
  173. + if (i == (ecc->steps - 1) && !host->boot_pages_conf) {
  174. data_size2 = ecc->size - data_size1 -
  175. ((ecc->steps - 1) << 2);
  176. oob_size2 = (ecc->steps << 2) + host->ecc_bytes_hw +
  177. @@ -2157,6 +2213,9 @@ static int qcom_nandc_write_oob(struct n
  178. int data_size, oob_size;
  179. int ret;
  180. + if (host->boot_pages)
  181. + check_boot_pages_conf(host, page);
  182. +
  183. host->use_ecc = true;
  184. clear_bam_transaction(nandc);
  185. @@ -2805,6 +2864,7 @@ static int qcom_nand_host_init_and_regis
  186. struct nand_chip *chip = &host->chip;
  187. struct mtd_info *mtd = nand_to_mtd(chip);
  188. struct device *dev = nandc->dev;
  189. + u32 boot_pages_size;
  190. int ret;
  191. ret = of_property_read_u32(dn, "reg", &host->cs);
  192. @@ -2865,6 +2925,17 @@ static int qcom_nand_host_init_and_regis
  193. if (ret)
  194. nand_cleanup(chip);
  195. + if (nandc->props->has_boot_pages &&
  196. + of_property_read_bool(dn, "nand-is-boot-medium")) {
  197. + ret = of_property_read_u32(dn, "qcom,boot_pages_size",
  198. + &boot_pages_size);
  199. + if (ret)
  200. + dev_warn(dev, "can't get boot pages size");
  201. + else
  202. + /* Convert size to nand pages */
  203. + host->boot_pages = boot_pages_size / mtd->writesize;
  204. + }
  205. +
  206. return ret;
  207. }
  208. @@ -3030,6 +3101,7 @@ static int qcom_nandc_remove(struct plat
  209. static const struct qcom_nandc_props ipq806x_nandc_props = {
  210. .ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT),
  211. .is_bam = false,
  212. + .has_boot_pages = true,
  213. .dev_cmd_reg_start = 0x0,
  214. };