nand_samsung.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. /*
  2. * Copyright (C) 2017 Free Electrons
  3. * Copyright (C) 2017 NextThing Co
  4. *
  5. * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. */
  17. #include <linux/mtd/rawnand.h>
  18. static void samsung_nand_decode_id(struct nand_chip *chip)
  19. {
  20. struct mtd_info *mtd = nand_to_mtd(chip);
  21. /* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) */
  22. if (chip->id.len == 6 && !nand_is_slc(chip) &&
  23. chip->id.data[5] != 0x00) {
  24. u8 extid = chip->id.data[3];
  25. /* Get pagesize */
  26. mtd->writesize = 2048 << (extid & 0x03);
  27. extid >>= 2;
  28. /* Get oobsize */
  29. switch (((extid >> 2) & 0x4) | (extid & 0x3)) {
  30. case 1:
  31. mtd->oobsize = 128;
  32. break;
  33. case 2:
  34. mtd->oobsize = 218;
  35. break;
  36. case 3:
  37. mtd->oobsize = 400;
  38. break;
  39. case 4:
  40. mtd->oobsize = 436;
  41. break;
  42. case 5:
  43. mtd->oobsize = 512;
  44. break;
  45. case 6:
  46. mtd->oobsize = 640;
  47. break;
  48. default:
  49. /*
  50. * We should never reach this case, but if that
  51. * happens, this probably means Samsung decided to use
  52. * a different extended ID format, and we should find
  53. * a way to support it.
  54. */
  55. WARN(1, "Invalid OOB size value");
  56. break;
  57. }
  58. /* Get blocksize */
  59. extid >>= 2;
  60. mtd->erasesize = (128 * 1024) <<
  61. (((extid >> 1) & 0x04) | (extid & 0x03));
  62. /* Extract ECC requirements from 5th id byte*/
  63. extid = (chip->id.data[4] >> 4) & 0x07;
  64. if (extid < 5) {
  65. chip->ecc_step_ds = 512;
  66. chip->ecc_strength_ds = 1 << extid;
  67. } else {
  68. chip->ecc_step_ds = 1024;
  69. switch (extid) {
  70. case 5:
  71. chip->ecc_strength_ds = 24;
  72. break;
  73. case 6:
  74. chip->ecc_strength_ds = 40;
  75. break;
  76. case 7:
  77. chip->ecc_strength_ds = 60;
  78. break;
  79. default:
  80. WARN(1, "Could not decode ECC info");
  81. chip->ecc_step_ds = 0;
  82. }
  83. }
  84. } else {
  85. nand_decode_ext_id(chip);
  86. }
  87. }
  88. static int samsung_nand_init(struct nand_chip *chip)
  89. {
  90. struct mtd_info *mtd = nand_to_mtd(chip);
  91. if (mtd->writesize > 512)
  92. chip->options |= NAND_SAMSUNG_LP_OPTIONS;
  93. if (!nand_is_slc(chip))
  94. chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
  95. else
  96. chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
  97. return 0;
  98. }
  99. const struct nand_manufacturer_ops samsung_nand_manuf_ops = {
  100. .detect = samsung_nand_decode_id,
  101. .init = samsung_nand_init,
  102. };