117-mtd-nand-add-hynix-init.patch 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. From 5c5e3963a1b58be1669da5da93f51dc339cd73d7 Mon Sep 17 00:00:00 2001
  2. From: Boris BREZILLON <b.brezillon.dev@gmail.com>
  3. Date: Mon, 24 Feb 2014 16:30:22 +0100
  4. Subject: [PATCH] mtd: nand: Add hynix specific initializer
  5. Add an hynix initiliazer to manage read retries on h27uxgt8t2a chip.
  6. Signed-off-by: Boris BREZILLON <b.brezillon.dev@gmail.com>
  7. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
  8. ---
  9. drivers/mtd/nand/Makefile | 2 +-
  10. drivers/mtd/nand/nand_hynix.c | 159 ++++++++++++++++++++++++++++++++++++++++++
  11. drivers/mtd/nand/nand_ids.c | 3 +-
  12. include/linux/mtd/nand.h | 2 +
  13. 4 files changed, 164 insertions(+), 2 deletions(-)
  14. create mode 100644 drivers/mtd/nand/nand_hynix.c
  15. --- a/drivers/mtd/nand/Makefile
  16. +++ b/drivers/mtd/nand/Makefile
  17. @@ -5,7 +5,7 @@
  18. obj-$(CONFIG_MTD_NAND) += nand.o
  19. obj-$(CONFIG_MTD_NAND_ECC) += nand_ecc.o
  20. obj-$(CONFIG_MTD_NAND_BCH) += nand_bch.o
  21. -obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o
  22. +obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o nand_hynix.o
  23. obj-$(CONFIG_MTD_SM_COMMON) += sm_common.o
  24. obj-$(CONFIG_MTD_NAND_CAFE) += cafe_nand.o
  25. --- /dev/null
  26. +++ b/drivers/mtd/nand/nand_hynix.c
  27. @@ -0,0 +1,159 @@
  28. +/*
  29. + * Copyright (C) 2014 Boris BREZILLON <b.brezillon.dev@gmail.com>
  30. + *
  31. + * This program is free software; you can redistribute it and/or modify
  32. + * it under the terms of the GNU General Public License as published by
  33. + * the Free Software Foundation; either version 2 of the License, or
  34. + * (at your option) any later version.
  35. + *
  36. + * This program is distributed in the hope that it will be useful,
  37. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  38. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  39. + * GNU General Public License for more details.
  40. + */
  41. +
  42. +#include <linux/module.h>
  43. +#include <linux/mtd/nand.h>
  44. +#include <linux/slab.h>
  45. +
  46. +static u8 h27ucg8t2a_read_retry_regs[] = {
  47. + 0xcc, 0xbf, 0xaa, 0xab, 0xcd, 0xad, 0xae, 0xaf
  48. +};
  49. +
  50. +struct hynix_read_retry {
  51. + u8 *regs;
  52. + u8 values[64];
  53. +};
  54. +
  55. +struct hynix_nand {
  56. + struct hynix_read_retry read_retry;
  57. +};
  58. +
  59. +int nand_setup_read_retry_hynix(struct mtd_info *mtd, int retry_mode)
  60. +{
  61. + struct nand_chip *chip = mtd->priv;
  62. + struct hynix_nand *hynix = chip->manuf_priv;
  63. + int offset = retry_mode * 8;
  64. + int status;
  65. + int i;
  66. +
  67. + chip->cmdfunc(mtd, 0x36, -1, -1);
  68. + for (i = 0; i < 8; i++) {
  69. + int column = hynix->read_retry.regs[i];
  70. + column |= column << 8;
  71. + chip->cmdfunc(mtd, NAND_CMD_NONE, column, -1);
  72. + chip->write_byte(mtd, hynix->read_retry.values[offset + i]);
  73. + }
  74. + chip->cmdfunc(mtd, 0x16, -1, -1);
  75. +
  76. + status = chip->waitfunc(mtd, chip);
  77. + if (status & NAND_STATUS_FAIL)
  78. + return -EIO;
  79. +
  80. + return 0;
  81. +}
  82. +
  83. +static void h27ucg8t2a_cleanup(struct mtd_info *mtd)
  84. +{
  85. + struct nand_chip *chip = mtd->priv;
  86. + kfree(chip->manuf_priv);
  87. +}
  88. +
  89. +static int h27ucg8t2a_init(struct mtd_info *mtd, const uint8_t *id)
  90. +{
  91. + struct nand_chip *chip = mtd->priv;
  92. + struct hynix_nand *hynix;
  93. + u8 * buf = NULL;
  94. + int i, j;
  95. + int ret;
  96. +
  97. + buf = kzalloc(1024, GFP_KERNEL);
  98. + if (!buf)
  99. + return -ENOMEM;
  100. +
  101. + chip->select_chip(mtd, 0);
  102. + chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
  103. + chip->cmdfunc(mtd, 0x36, 0xff, -1);
  104. + chip->write_byte(mtd, 0x40);
  105. + chip->cmdfunc(mtd, NAND_CMD_NONE, 0xcc, -1);
  106. + chip->write_byte(mtd, 0x4d);
  107. + chip->cmdfunc(mtd, 0x16, -1, -1);
  108. + chip->cmdfunc(mtd, 0x17, -1, -1);
  109. + chip->cmdfunc(mtd, 0x04, -1, -1);
  110. + chip->cmdfunc(mtd, 0x19, -1, -1);
  111. + chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, 0x200);
  112. +
  113. + chip->read_buf(mtd, buf, 2);
  114. + if (buf[0] != 0x8 || buf[1] != 0x8) {
  115. + ret = -EINVAL;
  116. + goto leave;
  117. + }
  118. + chip->read_buf(mtd, buf, 1024);
  119. +
  120. + ret = 0;
  121. + for (j = 0; j < 8; j++) {
  122. + for (i = 0; i < 64; i++) {
  123. + u8 *tmp = buf + (128 * j);
  124. + if ((tmp[i] | tmp[i + 64]) != 0xff) {
  125. + ret = -EINVAL;
  126. + goto leave;
  127. + }
  128. + }
  129. + }
  130. +
  131. + chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
  132. + chip->cmdfunc(mtd, 0x38, -1, -1);
  133. + chip->select_chip(mtd, -1);
  134. +
  135. + if (!ret) {
  136. + hynix = kzalloc(sizeof(*hynix), GFP_KERNEL);
  137. + if (!hynix) {
  138. + ret = -ENOMEM;
  139. + goto leave;
  140. + }
  141. +
  142. + hynix->read_retry.regs = h27ucg8t2a_read_retry_regs;
  143. + memcpy(hynix->read_retry.values, buf, 64);
  144. + chip->manuf_priv = hynix;
  145. + chip->setup_read_retry = nand_setup_read_retry_hynix;
  146. + chip->read_retries = 8;
  147. + chip->manuf_cleanup = h27ucg8t2a_cleanup;
  148. + }
  149. +
  150. +leave:
  151. + kfree(buf);
  152. +
  153. + return ret;
  154. +}
  155. +
  156. +struct hynix_nand_initializer {
  157. + u8 id[6];
  158. + int (*init)(struct mtd_info *mtd, const uint8_t *id);
  159. +};
  160. +
  161. +struct hynix_nand_initializer initializers[] = {
  162. + {
  163. + .id = {NAND_MFR_HYNIX, 0xde, 0x94, 0xda, 0x74, 0xc4},
  164. + .init = h27ucg8t2a_init,
  165. + },
  166. +};
  167. +
  168. +int hynix_nand_init(struct mtd_info *mtd, const uint8_t *id)
  169. +{
  170. + int i;
  171. +
  172. + for (i = 0; i < ARRAY_SIZE(initializers); i++) {
  173. + struct hynix_nand_initializer *initializer = &initializers[i];
  174. + if (memcmp(id, initializer->id, sizeof(initializer->id)))
  175. + continue;
  176. +
  177. + return initializer->init(mtd, id);
  178. + }
  179. +
  180. + return 0;
  181. +}
  182. +EXPORT_SYMBOL(hynix_nand_init);
  183. +
  184. +MODULE_LICENSE("GPL");
  185. +MODULE_AUTHOR("Boris BREZILLON <b.brezillon.dev@gmail.com>");
  186. +MODULE_DESCRIPTION("Hynix NAND specific code");
  187. --- a/drivers/mtd/nand/nand_ids.c
  188. +++ b/drivers/mtd/nand/nand_ids.c
  189. @@ -163,6 +163,7 @@ struct nand_flash_dev nand_flash_ids[] =
  190. {NULL}
  191. };
  192. +
  193. /* Manufacturer IDs */
  194. struct nand_manufacturers nand_manuf_ids[] = {
  195. {NAND_MFR_TOSHIBA, "Toshiba"},
  196. @@ -171,7 +172,7 @@ struct nand_manufacturers nand_manuf_ids
  197. {NAND_MFR_NATIONAL, "National"},
  198. {NAND_MFR_RENESAS, "Renesas"},
  199. {NAND_MFR_STMICRO, "ST Micro"},
  200. - {NAND_MFR_HYNIX, "Hynix"},
  201. + {NAND_MFR_HYNIX, "Hynix", hynix_nand_init},
  202. {NAND_MFR_MICRON, "Micron"},
  203. {NAND_MFR_AMD, "AMD/Spansion"},
  204. {NAND_MFR_MACRONIX, "Macronix"},
  205. --- a/include/linux/mtd/nand.h
  206. +++ b/include/linux/mtd/nand.h
  207. @@ -959,6 +959,8 @@ struct nand_manufacturers {
  208. extern struct nand_flash_dev nand_flash_ids[];
  209. extern struct nand_manufacturers nand_manuf_ids[];
  210. +int hynix_nand_init(struct mtd_info *mtd, const uint8_t *id);
  211. +
  212. extern int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd);
  213. extern int nand_default_bbt(struct mtd_info *mtd);
  214. extern int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs);