xtx.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Author:
  4. * Felix Matouschek <[email protected]>
  5. */
  6. #include <linux/device.h>
  7. #include <linux/kernel.h>
  8. #include <linux/mtd/spinand.h>
  9. #define SPINAND_MFR_XTX 0x0B
  10. #define XT26G0XA_STATUS_ECC_MASK GENMASK(5, 2)
  11. #define XT26G0XA_STATUS_ECC_NO_DETECTED (0 << 2)
  12. #define XT26G0XA_STATUS_ECC_8_CORRECTED (3 << 4)
  13. #define XT26G0XA_STATUS_ECC_UNCOR_ERROR (2 << 4)
  14. static SPINAND_OP_VARIANTS(read_cache_variants,
  15. SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
  16. SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
  17. SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
  18. SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
  19. SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
  20. SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
  21. static SPINAND_OP_VARIANTS(write_cache_variants,
  22. SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
  23. SPINAND_PROG_LOAD(true, 0, NULL, 0));
  24. static SPINAND_OP_VARIANTS(update_cache_variants,
  25. SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
  26. SPINAND_PROG_LOAD(false, 0, NULL, 0));
  27. static int xt26g0xa_ooblayout_ecc(struct mtd_info *mtd, int section,
  28. struct mtd_oob_region *region)
  29. {
  30. if (section)
  31. return -ERANGE;
  32. region->offset = 48;
  33. region->length = 16;
  34. return 0;
  35. }
  36. static int xt26g0xa_ooblayout_free(struct mtd_info *mtd, int section,
  37. struct mtd_oob_region *region)
  38. {
  39. if (section)
  40. return -ERANGE;
  41. region->offset = 1;
  42. region->length = 47;
  43. return 0;
  44. }
  45. static const struct mtd_ooblayout_ops xt26g0xa_ooblayout = {
  46. .ecc = xt26g0xa_ooblayout_ecc,
  47. .free = xt26g0xa_ooblayout_free,
  48. };
  49. static int xt26g0xa_ecc_get_status(struct spinand_device *spinand,
  50. u8 status)
  51. {
  52. status = status & XT26G0XA_STATUS_ECC_MASK;
  53. switch (status) {
  54. case XT26G0XA_STATUS_ECC_NO_DETECTED:
  55. return 0;
  56. case XT26G0XA_STATUS_ECC_8_CORRECTED:
  57. return 8;
  58. case XT26G0XA_STATUS_ECC_UNCOR_ERROR:
  59. return -EBADMSG;
  60. default:
  61. break;
  62. }
  63. /* At this point values greater than (2 << 4) are invalid */
  64. if (status > XT26G0XA_STATUS_ECC_UNCOR_ERROR)
  65. return -EINVAL;
  66. /* (1 << 2) through (7 << 2) are 1-7 corrected errors */
  67. return status >> 2;
  68. }
  69. static const struct spinand_info xtx_spinand_table[] = {
  70. SPINAND_INFO("XT26G01A",
  71. SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xE1),
  72. NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
  73. NAND_ECCREQ(8, 512),
  74. SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
  75. &write_cache_variants,
  76. &update_cache_variants),
  77. SPINAND_HAS_QE_BIT,
  78. SPINAND_ECCINFO(&xt26g0xa_ooblayout,
  79. xt26g0xa_ecc_get_status)),
  80. SPINAND_INFO("XT26G02A",
  81. SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xE2),
  82. NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
  83. NAND_ECCREQ(8, 512),
  84. SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
  85. &write_cache_variants,
  86. &update_cache_variants),
  87. SPINAND_HAS_QE_BIT,
  88. SPINAND_ECCINFO(&xt26g0xa_ooblayout,
  89. xt26g0xa_ecc_get_status)),
  90. SPINAND_INFO("XT26G04A",
  91. SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xE3),
  92. NAND_MEMORG(1, 2048, 64, 128, 2048, 40, 1, 1, 1),
  93. NAND_ECCREQ(8, 512),
  94. SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
  95. &write_cache_variants,
  96. &update_cache_variants),
  97. SPINAND_HAS_QE_BIT,
  98. SPINAND_ECCINFO(&xt26g0xa_ooblayout,
  99. xt26g0xa_ecc_get_status)),
  100. };
  101. static const struct spinand_manufacturer_ops xtx_spinand_manuf_ops = {
  102. };
  103. const struct spinand_manufacturer xtx_spinand_manufacturer = {
  104. .id = SPINAND_MFR_XTX,
  105. .name = "XTX",
  106. .chips = xtx_spinand_table,
  107. .nchips = ARRAY_SIZE(xtx_spinand_table),
  108. .ops = &xtx_spinand_manuf_ops,
  109. };