micron.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (c) 2016-2017 Micron Technology, Inc.
  4. *
  5. * Authors:
  6. * Peter Pan <peterpandong@micron.com>
  7. */
  8. #ifndef __UBOOT__
  9. #include <malloc.h>
  10. #include <linux/device.h>
  11. #include <linux/kernel.h>
  12. #endif
  13. #include <linux/bitops.h>
  14. #include <linux/mtd/spinand.h>
  15. #define SPINAND_MFR_MICRON 0x2c
  16. #define MICRON_STATUS_ECC_MASK GENMASK(7, 4)
  17. #define MICRON_STATUS_ECC_NO_BITFLIPS (0 << 4)
  18. #define MICRON_STATUS_ECC_1TO3_BITFLIPS (1 << 4)
  19. #define MICRON_STATUS_ECC_4TO6_BITFLIPS (3 << 4)
  20. #define MICRON_STATUS_ECC_7TO8_BITFLIPS (5 << 4)
  21. #define MICRON_CFG_CR BIT(0)
  22. static SPINAND_OP_VARIANTS(read_cache_variants,
  23. SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
  24. SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
  25. SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
  26. SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
  27. SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
  28. SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
  29. static SPINAND_OP_VARIANTS(write_cache_variants,
  30. SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
  31. SPINAND_PROG_LOAD(true, 0, NULL, 0));
  32. static SPINAND_OP_VARIANTS(update_cache_variants,
  33. SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
  34. SPINAND_PROG_LOAD(false, 0, NULL, 0));
  35. static int micron_8_ooblayout_ecc(struct mtd_info *mtd, int section,
  36. struct mtd_oob_region *region)
  37. {
  38. if (section)
  39. return -ERANGE;
  40. region->offset = mtd->oobsize / 2;
  41. region->length = mtd->oobsize / 2;
  42. return 0;
  43. }
  44. static int micron_8_ooblayout_free(struct mtd_info *mtd, int section,
  45. struct mtd_oob_region *region)
  46. {
  47. if (section)
  48. return -ERANGE;
  49. /* Reserve 2 bytes for the BBM. */
  50. region->offset = 2;
  51. region->length = (mtd->oobsize / 2) - 2;
  52. return 0;
  53. }
  54. static const struct mtd_ooblayout_ops micron_8_ooblayout = {
  55. .ecc = micron_8_ooblayout_ecc,
  56. .rfree = micron_8_ooblayout_free,
  57. };
  58. static int micron_8_ecc_get_status(struct spinand_device *spinand,
  59. u8 status)
  60. {
  61. switch (status & MICRON_STATUS_ECC_MASK) {
  62. case STATUS_ECC_NO_BITFLIPS:
  63. return 0;
  64. case STATUS_ECC_UNCOR_ERROR:
  65. return -EBADMSG;
  66. case MICRON_STATUS_ECC_1TO3_BITFLIPS:
  67. return 3;
  68. case MICRON_STATUS_ECC_4TO6_BITFLIPS:
  69. return 6;
  70. case MICRON_STATUS_ECC_7TO8_BITFLIPS:
  71. return 8;
  72. default:
  73. break;
  74. }
  75. return -EINVAL;
  76. }
  77. static const struct spinand_info micron_spinand_table[] = {
  78. /* M79A 2Gb 3.3V */
  79. SPINAND_INFO("MT29F2G01ABAGD", 0x24,
  80. NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 1),
  81. NAND_ECCREQ(8, 512),
  82. SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
  83. &write_cache_variants,
  84. &update_cache_variants),
  85. 0,
  86. SPINAND_ECCINFO(&micron_8_ooblayout,
  87. micron_8_ecc_get_status)),
  88. /* M79A 2Gb 1.8V */
  89. SPINAND_INFO("MT29F2G01ABBGD", 0x25,
  90. NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 1),
  91. NAND_ECCREQ(8, 512),
  92. SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
  93. &write_cache_variants,
  94. &update_cache_variants),
  95. 0,
  96. SPINAND_ECCINFO(&micron_8_ooblayout,
  97. micron_8_ecc_get_status)),
  98. /* M78A 1Gb 3.3V */
  99. SPINAND_INFO("MT29F1G01ABAFD", 0x14,
  100. NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
  101. NAND_ECCREQ(8, 512),
  102. SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
  103. &write_cache_variants,
  104. &update_cache_variants),
  105. 0,
  106. SPINAND_ECCINFO(&micron_8_ooblayout,
  107. micron_8_ecc_get_status)),
  108. /* M78A 1Gb 1.8V */
  109. SPINAND_INFO("MT29F1G01ABAFD", 0x15,
  110. NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
  111. NAND_ECCREQ(8, 512),
  112. SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
  113. &write_cache_variants,
  114. &update_cache_variants),
  115. 0,
  116. SPINAND_ECCINFO(&micron_8_ooblayout,
  117. micron_8_ecc_get_status)),
  118. };
  119. static int micron_spinand_detect(struct spinand_device *spinand)
  120. {
  121. u8 *id = spinand->id.data;
  122. int ret;
  123. /*
  124. * Micron SPI NAND read ID need a dummy byte,
  125. * so the first byte in raw_id is dummy.
  126. */
  127. if (id[1] != SPINAND_MFR_MICRON)
  128. return 0;
  129. ret = spinand_match_and_init(spinand, micron_spinand_table,
  130. ARRAY_SIZE(micron_spinand_table), id[2]);
  131. if (ret)
  132. return ret;
  133. return 1;
  134. }
  135. static int micron_spinand_init(struct spinand_device *spinand)
  136. {
  137. /*
  138. * M70A device series enable Continuous Read feature at Power-up,
  139. * which is not supported. Disable this bit to avoid any possible
  140. * failure.
  141. */
  142. if (spinand->flags & SPINAND_HAS_CR_FEAT_BIT)
  143. return spinand_upd_cfg(spinand, MICRON_CFG_CR, 0);
  144. return 0;
  145. }
  146. static const struct spinand_manufacturer_ops micron_spinand_manuf_ops = {
  147. .detect = micron_spinand_detect,
  148. .init = micron_spinand_init,
  149. };
  150. const struct spinand_manufacturer micron_spinand_manufacturer = {
  151. .id = SPINAND_MFR_MICRON,
  152. .name = "Micron",
  153. .ops = &micron_spinand_manuf_ops,
  154. };