diff options
author | Uwe Kleine-König <u.kleine-koenig@pengutronix.de> | 2012-04-23 05:23:40 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2012-05-14 00:03:02 -0400 |
commit | f48d0f9aa93c8f1d38f21d2531d572cf96205d58 (patch) | |
tree | eb4b9fc47b235758956757baa4cb1fcb9bf269d3 /drivers | |
parent | 69d023be00e9bb5368ced679cead9fb25474ec69 (diff) |
mtd: mxc_nand: put several more fields into devtype_data
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mtd/nand/mxc_nand.c | 130 |
1 files changed, 94 insertions, 36 deletions
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 4a6d763ab7f7..35c928ac1901 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c | |||
@@ -156,6 +156,22 @@ struct mxc_nand_devtype_data { | |||
156 | void (*select_chip)(struct mtd_info *mtd, int chip); | 156 | void (*select_chip)(struct mtd_info *mtd, int chip); |
157 | int (*correct_data)(struct mtd_info *mtd, u_char *dat, | 157 | int (*correct_data)(struct mtd_info *mtd, u_char *dat, |
158 | u_char *read_ecc, u_char *calc_ecc); | 158 | u_char *read_ecc, u_char *calc_ecc); |
159 | |||
160 | /* | ||
161 | * On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked | ||
162 | * (CONFIG1:INT_MSK is set). To handle this the driver uses | ||
163 | * enable_irq/disable_irq_nosync instead of CONFIG1:INT_MSK | ||
164 | */ | ||
165 | int irqpending_quirk; | ||
166 | int needs_ip; | ||
167 | |||
168 | size_t regs_offset; | ||
169 | size_t spare0_offset; | ||
170 | size_t axi_offset; | ||
171 | |||
172 | int spare_len; | ||
173 | int eccbytes; | ||
174 | int eccsize; | ||
159 | }; | 175 | }; |
160 | 176 | ||
161 | struct mxc_nand_host { | 177 | struct mxc_nand_host { |
@@ -181,16 +197,8 @@ struct mxc_nand_host { | |||
181 | 197 | ||
182 | uint8_t *data_buf; | 198 | uint8_t *data_buf; |
183 | unsigned int buf_start; | 199 | unsigned int buf_start; |
184 | int spare_len; | ||
185 | 200 | ||
186 | const struct mxc_nand_devtype_data *devtype_data; | 201 | const struct mxc_nand_devtype_data *devtype_data; |
187 | |||
188 | /* | ||
189 | * On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked | ||
190 | * (CONFIG1:INT_MSK is set). To handle this the driver uses | ||
191 | * enable_irq/disable_irq_nosync instead of CONFIG1:INT_MSK | ||
192 | */ | ||
193 | int irqpending_quirk; | ||
194 | }; | 202 | }; |
195 | 203 | ||
196 | /* OOB placement block for use with hardware ecc generation */ | 204 | /* OOB placement block for use with hardware ecc generation */ |
@@ -284,7 +292,7 @@ static int check_int_v1_v2(struct mxc_nand_host *host) | |||
284 | if (!(tmp & NFC_V1_V2_CONFIG2_INT)) | 292 | if (!(tmp & NFC_V1_V2_CONFIG2_INT)) |
285 | return 0; | 293 | return 0; |
286 | 294 | ||
287 | if (!host->irqpending_quirk) | 295 | if (!host->devtype_data->irqpending_quirk) |
288 | writew(tmp & ~NFC_V1_V2_CONFIG2_INT, NFC_V1_V2_CONFIG2); | 296 | writew(tmp & ~NFC_V1_V2_CONFIG2_INT, NFC_V1_V2_CONFIG2); |
289 | 297 | ||
290 | return 1; | 298 | return 1; |
@@ -320,7 +328,7 @@ static void irq_control_v3(struct mxc_nand_host *host, int activate) | |||
320 | 328 | ||
321 | static void irq_control(struct mxc_nand_host *host, int activate) | 329 | static void irq_control(struct mxc_nand_host *host, int activate) |
322 | { | 330 | { |
323 | if (host->irqpending_quirk) { | 331 | if (host->devtype_data->irqpending_quirk) { |
324 | if (activate) | 332 | if (activate) |
325 | enable_irq(host->irq); | 333 | enable_irq(host->irq); |
326 | else | 334 | else |
@@ -405,7 +413,7 @@ static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq) | |||
405 | writew(cmd, NFC_V1_V2_FLASH_CMD); | 413 | writew(cmd, NFC_V1_V2_FLASH_CMD); |
406 | writew(NFC_CMD, NFC_V1_V2_CONFIG2); | 414 | writew(NFC_CMD, NFC_V1_V2_CONFIG2); |
407 | 415 | ||
408 | if (host->irqpending_quirk && (cmd == NAND_CMD_RESET)) { | 416 | if (host->devtype_data->irqpending_quirk && (cmd == NAND_CMD_RESET)) { |
409 | int max_retries = 100; | 417 | int max_retries = 100; |
410 | /* Reset completion is indicated by NFC_CONFIG2 */ | 418 | /* Reset completion is indicated by NFC_CONFIG2 */ |
411 | /* being set to 0 */ | 419 | /* being set to 0 */ |
@@ -780,7 +788,7 @@ static void copy_spare(struct mtd_info *mtd, bool bfrom) | |||
780 | u16 n = mtd->writesize >> 9; | 788 | u16 n = mtd->writesize >> 9; |
781 | u8 *d = host->data_buf + mtd->writesize; | 789 | u8 *d = host->data_buf + mtd->writesize; |
782 | u8 *s = host->spare0; | 790 | u8 *s = host->spare0; |
783 | u16 t = host->spare_len; | 791 | u16 t = host->devtype_data->spare_len; |
784 | 792 | ||
785 | j = (mtd->oobsize / n >> 1) << 1; | 793 | j = (mtd->oobsize / n >> 1) << 1; |
786 | 794 | ||
@@ -880,7 +888,7 @@ static void preset_v1(struct mtd_info *mtd) | |||
880 | if (nand_chip->ecc.mode == NAND_ECC_HW) | 888 | if (nand_chip->ecc.mode == NAND_ECC_HW) |
881 | config1 |= NFC_V1_V2_CONFIG1_ECC_EN; | 889 | config1 |= NFC_V1_V2_CONFIG1_ECC_EN; |
882 | 890 | ||
883 | if (!host->irqpending_quirk) | 891 | if (!host->devtype_data->irqpending_quirk) |
884 | config1 |= NFC_V1_V2_CONFIG1_INT_MSK; | 892 | config1 |= NFC_V1_V2_CONFIG1_INT_MSK; |
885 | 893 | ||
886 | host->eccsize = 1; | 894 | host->eccsize = 1; |
@@ -910,7 +918,7 @@ static void preset_v2(struct mtd_info *mtd) | |||
910 | 918 | ||
911 | config1 |= NFC_V2_CONFIG1_FP_INT; | 919 | config1 |= NFC_V2_CONFIG1_FP_INT; |
912 | 920 | ||
913 | if (!host->irqpending_quirk) | 921 | if (!host->devtype_data->irqpending_quirk) |
914 | config1 |= NFC_V1_V2_CONFIG1_INT_MSK; | 922 | config1 |= NFC_V1_V2_CONFIG1_INT_MSK; |
915 | 923 | ||
916 | if (mtd->writesize) { | 924 | if (mtd->writesize) { |
@@ -1125,7 +1133,7 @@ static struct nand_bbt_descr bbt_mirror_descr = { | |||
1125 | .pattern = mirror_pattern, | 1133 | .pattern = mirror_pattern, |
1126 | }; | 1134 | }; |
1127 | 1135 | ||
1128 | /* v1: i.MX21, i.MX27, i.MX31 */ | 1136 | /* v1 + irqpending_quirk: i.MX21 */ |
1129 | static const struct mxc_nand_devtype_data imx21_nand_devtype_data = { | 1137 | static const struct mxc_nand_devtype_data imx21_nand_devtype_data = { |
1130 | .preset = preset_v1, | 1138 | .preset = preset_v1, |
1131 | .send_cmd = send_cmd_v1_v2, | 1139 | .send_cmd = send_cmd_v1_v2, |
@@ -1141,6 +1149,39 @@ static const struct mxc_nand_devtype_data imx21_nand_devtype_data = { | |||
1141 | .ecclayout_4k = &nandv1_hw_eccoob_smallpage, /* XXX: needs fix */ | 1149 | .ecclayout_4k = &nandv1_hw_eccoob_smallpage, /* XXX: needs fix */ |
1142 | .select_chip = mxc_nand_select_chip_v1_v3, | 1150 | .select_chip = mxc_nand_select_chip_v1_v3, |
1143 | .correct_data = mxc_nand_correct_data_v1, | 1151 | .correct_data = mxc_nand_correct_data_v1, |
1152 | .irqpending_quirk = 1, | ||
1153 | .needs_ip = 0, | ||
1154 | .regs_offset = 0xe00, | ||
1155 | .spare0_offset = 0x800, | ||
1156 | .spare_len = 16, | ||
1157 | .eccbytes = 3, | ||
1158 | .eccsize = 1, | ||
1159 | }; | ||
1160 | |||
1161 | /* v1 + !irqpending_quirk: i.MX27, i.MX31 */ | ||
1162 | static const struct mxc_nand_devtype_data imx27_nand_devtype_data = { | ||
1163 | .preset = preset_v1, | ||
1164 | .send_cmd = send_cmd_v1_v2, | ||
1165 | .send_addr = send_addr_v1_v2, | ||
1166 | .send_page = send_page_v1, | ||
1167 | .send_read_id = send_read_id_v1_v2, | ||
1168 | .get_dev_status = get_dev_status_v1_v2, | ||
1169 | .check_int = check_int_v1_v2, | ||
1170 | .irq_control = irq_control_v1_v2, | ||
1171 | .get_ecc_status = get_ecc_status_v1, | ||
1172 | .ecclayout_512 = &nandv1_hw_eccoob_smallpage, | ||
1173 | .ecclayout_2k = &nandv1_hw_eccoob_largepage, | ||
1174 | .ecclayout_4k = &nandv1_hw_eccoob_smallpage, /* XXX: needs fix */ | ||
1175 | .select_chip = mxc_nand_select_chip_v1_v3, | ||
1176 | .correct_data = mxc_nand_correct_data_v1, | ||
1177 | .irqpending_quirk = 0, | ||
1178 | .needs_ip = 0, | ||
1179 | .regs_offset = 0xe00, | ||
1180 | .spare0_offset = 0x800, | ||
1181 | .axi_offset = 0, | ||
1182 | .spare_len = 16, | ||
1183 | .eccbytes = 3, | ||
1184 | .eccsize = 1, | ||
1144 | }; | 1185 | }; |
1145 | 1186 | ||
1146 | /* v21: i.MX25, i.MX35 */ | 1187 | /* v21: i.MX25, i.MX35 */ |
@@ -1159,6 +1200,14 @@ static const struct mxc_nand_devtype_data imx25_nand_devtype_data = { | |||
1159 | .ecclayout_4k = &nandv2_hw_eccoob_4k, | 1200 | .ecclayout_4k = &nandv2_hw_eccoob_4k, |
1160 | .select_chip = mxc_nand_select_chip_v2, | 1201 | .select_chip = mxc_nand_select_chip_v2, |
1161 | .correct_data = mxc_nand_correct_data_v2_v3, | 1202 | .correct_data = mxc_nand_correct_data_v2_v3, |
1203 | .irqpending_quirk = 0, | ||
1204 | .needs_ip = 0, | ||
1205 | .regs_offset = 0x1e00, | ||
1206 | .spare0_offset = 0x1000, | ||
1207 | .axi_offset = 0, | ||
1208 | .spare_len = 64, | ||
1209 | .eccbytes = 9, | ||
1210 | .eccsize = 0, | ||
1162 | }; | 1211 | }; |
1163 | 1212 | ||
1164 | /* v3: i.MX51, i.MX53 */ | 1213 | /* v3: i.MX51, i.MX53 */ |
@@ -1177,6 +1226,14 @@ static const struct mxc_nand_devtype_data imx51_nand_devtype_data = { | |||
1177 | .ecclayout_4k = &nandv2_hw_eccoob_smallpage, /* XXX: needs fix */ | 1226 | .ecclayout_4k = &nandv2_hw_eccoob_smallpage, /* XXX: needs fix */ |
1178 | .select_chip = mxc_nand_select_chip_v1_v3, | 1227 | .select_chip = mxc_nand_select_chip_v1_v3, |
1179 | .correct_data = mxc_nand_correct_data_v2_v3, | 1228 | .correct_data = mxc_nand_correct_data_v2_v3, |
1229 | .irqpending_quirk = 0, | ||
1230 | .needs_ip = 1, | ||
1231 | .regs_offset = 0, | ||
1232 | .spare0_offset = 0x1000, | ||
1233 | .axi_offset = 0x1e00, | ||
1234 | .spare_len = 64, | ||
1235 | .eccbytes = 0, | ||
1236 | .eccsize = 0, | ||
1180 | }; | 1237 | }; |
1181 | 1238 | ||
1182 | static int __init mxcnd_probe(struct platform_device *pdev) | 1239 | static int __init mxcnd_probe(struct platform_device *pdev) |
@@ -1241,22 +1298,31 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
1241 | host->main_area0 = host->base; | 1298 | host->main_area0 = host->base; |
1242 | 1299 | ||
1243 | if (nfc_is_v1()) { | 1300 | if (nfc_is_v1()) { |
1244 | host->devtype_data = &imx21_nand_devtype_data; | ||
1245 | if (cpu_is_mx21()) | 1301 | if (cpu_is_mx21()) |
1246 | host->irqpending_quirk = 1; | 1302 | host->devtype_data = &imx21_nand_devtype_data; |
1247 | host->regs = host->base + 0xe00; | 1303 | else |
1248 | host->spare0 = host->base + 0x800; | 1304 | host->devtype_data = &imx27_nand_devtype_data; |
1249 | host->spare_len = 16; | ||
1250 | this->ecc.bytes = 3; | ||
1251 | host->eccsize = 1; | ||
1252 | } else if (nfc_is_v21()) { | 1305 | } else if (nfc_is_v21()) { |
1253 | host->devtype_data = &imx25_nand_devtype_data; | 1306 | host->devtype_data = &imx25_nand_devtype_data; |
1254 | host->regs = host->base + 0x1e00; | ||
1255 | host->spare0 = host->base + 0x1000; | ||
1256 | host->spare_len = 64; | ||
1257 | this->ecc.bytes = 9; | ||
1258 | } else if (nfc_is_v3_2()) { | 1307 | } else if (nfc_is_v3_2()) { |
1259 | host->devtype_data = &imx51_nand_devtype_data; | 1308 | host->devtype_data = &imx51_nand_devtype_data; |
1309 | } else | ||
1310 | BUG(); | ||
1311 | |||
1312 | if (host->devtype_data->regs_offset) | ||
1313 | host->regs = host->base + host->devtype_data->regs_offset; | ||
1314 | host->spare0 = host->base + host->devtype_data->spare0_offset; | ||
1315 | if (host->devtype_data->axi_offset) | ||
1316 | host->regs_axi = host->base + host->devtype_data->axi_offset; | ||
1317 | |||
1318 | this->ecc.bytes = host->devtype_data->eccbytes; | ||
1319 | host->eccsize = host->devtype_data->eccsize; | ||
1320 | |||
1321 | this->select_chip = host->devtype_data->select_chip; | ||
1322 | this->ecc.size = 512; | ||
1323 | this->ecc.layout = host->devtype_data->ecclayout_512; | ||
1324 | |||
1325 | if (host->devtype_data->needs_ip) { | ||
1260 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | 1326 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
1261 | if (!res) { | 1327 | if (!res) { |
1262 | err = -ENODEV; | 1328 | err = -ENODEV; |
@@ -1267,15 +1333,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
1267 | err = -ENOMEM; | 1333 | err = -ENOMEM; |
1268 | goto eirq; | 1334 | goto eirq; |
1269 | } | 1335 | } |
1270 | host->regs_axi = host->base + 0x1e00; | 1336 | } |
1271 | host->spare0 = host->base + 0x1000; | ||
1272 | host->spare_len = 64; | ||
1273 | } else | ||
1274 | BUG(); | ||
1275 | |||
1276 | this->select_chip = host->devtype_data->select_chip; | ||
1277 | this->ecc.size = 512; | ||
1278 | this->ecc.layout = host->devtype_data->ecclayout_512; | ||
1279 | 1337 | ||
1280 | if (pdata->hw_ecc) { | 1338 | if (pdata->hw_ecc) { |
1281 | this->ecc.calculate = mxc_nand_calculate_ecc; | 1339 | this->ecc.calculate = mxc_nand_calculate_ecc; |
@@ -1317,7 +1375,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
1317 | * cleared on i.MX21. Otherwise we can't read the interrupt status bit | 1375 | * cleared on i.MX21. Otherwise we can't read the interrupt status bit |
1318 | * on this machine. | 1376 | * on this machine. |
1319 | */ | 1377 | */ |
1320 | if (host->irqpending_quirk) { | 1378 | if (host->devtype_data->irqpending_quirk) { |
1321 | disable_irq_nosync(host->irq); | 1379 | disable_irq_nosync(host->irq); |
1322 | host->devtype_data->irq_control(host, 1); | 1380 | host->devtype_data->irq_control(host, 1); |
1323 | } | 1381 | } |