aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand/atmel_nand.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/nand/atmel_nand.c')
-rw-r--r--drivers/mtd/nand/atmel_nand.c141
1 files changed, 117 insertions, 24 deletions
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index c516a9408087..ffcbcca2fd2d 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -101,6 +101,8 @@ struct atmel_nand_host {
101 u8 pmecc_corr_cap; 101 u8 pmecc_corr_cap;
102 u16 pmecc_sector_size; 102 u16 pmecc_sector_size;
103 u32 pmecc_lookup_table_offset; 103 u32 pmecc_lookup_table_offset;
104 u32 pmecc_lookup_table_offset_512;
105 u32 pmecc_lookup_table_offset_1024;
104 106
105 int pmecc_bytes_per_sector; 107 int pmecc_bytes_per_sector;
106 int pmecc_sector_number; 108 int pmecc_sector_number;
@@ -908,6 +910,84 @@ static void atmel_pmecc_core_init(struct mtd_info *mtd)
908 pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE); 910 pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
909} 911}
910 912
913/*
914 * Get ECC requirement in ONFI parameters, returns -1 if ONFI
915 * parameters is not supported.
916 * return 0 if success to get the ECC requirement.
917 */
918static int get_onfi_ecc_param(struct nand_chip *chip,
919 int *ecc_bits, int *sector_size)
920{
921 *ecc_bits = *sector_size = 0;
922
923 if (chip->onfi_params.ecc_bits == 0xff)
924 /* TODO: the sector_size and ecc_bits need to be find in
925 * extended ecc parameter, currently we don't support it.
926 */
927 return -1;
928
929 *ecc_bits = chip->onfi_params.ecc_bits;
930
931 /* The default sector size (ecc codeword size) is 512 */
932 *sector_size = 512;
933
934 return 0;
935}
936
937/*
938 * Get ecc requirement from ONFI parameters ecc requirement.
939 * If pmecc-cap, pmecc-sector-size in DTS are not specified, this function
940 * will set them according to ONFI ecc requirement. Otherwise, use the
941 * value in DTS file.
942 * return 0 if success. otherwise return error code.
943 */
944static int pmecc_choose_ecc(struct atmel_nand_host *host,
945 int *cap, int *sector_size)
946{
947 /* Get ECC requirement from ONFI parameters */
948 *cap = *sector_size = 0;
949 if (host->nand_chip.onfi_version) {
950 if (!get_onfi_ecc_param(&host->nand_chip, cap, sector_size))
951 dev_info(host->dev, "ONFI params, minimum required ECC: %d bits in %d bytes\n",
952 *cap, *sector_size);
953 else
954 dev_info(host->dev, "NAND chip ECC reqirement is in Extended ONFI parameter, we don't support yet.\n");
955 } else {
956 dev_info(host->dev, "NAND chip is not ONFI compliant, assume ecc_bits is 2 in 512 bytes");
957 }
958 if (*cap == 0 && *sector_size == 0) {
959 *cap = 2;
960 *sector_size = 512;
961 }
962
963 /* If dts file doesn't specify then use the one in ONFI parameters */
964 if (host->pmecc_corr_cap == 0) {
965 /* use the most fitable ecc bits (the near bigger one ) */
966 if (*cap <= 2)
967 host->pmecc_corr_cap = 2;
968 else if (*cap <= 4)
969 host->pmecc_corr_cap = 4;
970 else if (*cap < 8)
971 host->pmecc_corr_cap = 8;
972 else if (*cap < 12)
973 host->pmecc_corr_cap = 12;
974 else if (*cap < 24)
975 host->pmecc_corr_cap = 24;
976 else
977 return -EINVAL;
978 }
979 if (host->pmecc_sector_size == 0) {
980 /* use the most fitable sector size (the near smaller one ) */
981 if (*sector_size >= 1024)
982 host->pmecc_sector_size = 1024;
983 else if (*sector_size >= 512)
984 host->pmecc_sector_size = 512;
985 else
986 return -EINVAL;
987 }
988 return 0;
989}
990
911static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev, 991static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
912 struct atmel_nand_host *host) 992 struct atmel_nand_host *host)
913{ 993{
@@ -916,8 +996,22 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
916 struct resource *regs, *regs_pmerr, *regs_rom; 996 struct resource *regs, *regs_pmerr, *regs_rom;
917 int cap, sector_size, err_no; 997 int cap, sector_size, err_no;
918 998
999 err_no = pmecc_choose_ecc(host, &cap, &sector_size);
1000 if (err_no) {
1001 dev_err(host->dev, "The NAND flash's ECC requirement are not support!");
1002 return err_no;
1003 }
1004
1005 if (cap != host->pmecc_corr_cap ||
1006 sector_size != host->pmecc_sector_size)
1007 dev_info(host->dev, "WARNING: Be Caution! Using different PMECC parameters from Nand ONFI ECC reqirement.\n");
1008
919 cap = host->pmecc_corr_cap; 1009 cap = host->pmecc_corr_cap;
920 sector_size = host->pmecc_sector_size; 1010 sector_size = host->pmecc_sector_size;
1011 host->pmecc_lookup_table_offset = (sector_size == 512) ?
1012 host->pmecc_lookup_table_offset_512 :
1013 host->pmecc_lookup_table_offset_1024;
1014
921 dev_info(host->dev, "Initialize PMECC params, cap: %d, sector: %d\n", 1015 dev_info(host->dev, "Initialize PMECC params, cap: %d, sector: %d\n",
922 cap, sector_size); 1016 cap, sector_size);
923 1017
@@ -1215,7 +1309,7 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
1215static int atmel_of_init_port(struct atmel_nand_host *host, 1309static int atmel_of_init_port(struct atmel_nand_host *host,
1216 struct device_node *np) 1310 struct device_node *np)
1217{ 1311{
1218 u32 val, table_offset; 1312 u32 val;
1219 u32 offset[2]; 1313 u32 offset[2];
1220 int ecc_mode; 1314 int ecc_mode;
1221 struct atmel_nand_data *board = &host->board; 1315 struct atmel_nand_data *board = &host->board;
@@ -1259,42 +1353,41 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
1259 1353
1260 /* use PMECC, get correction capability, sector size and lookup 1354 /* use PMECC, get correction capability, sector size and lookup
1261 * table offset. 1355 * table offset.
1356 * If correction bits and sector size are not specified, then find
1357 * them from NAND ONFI parameters.
1262 */ 1358 */
1263 if (of_property_read_u32(np, "atmel,pmecc-cap", &val) != 0) { 1359 if (of_property_read_u32(np, "atmel,pmecc-cap", &val) == 0) {
1264 dev_err(host->dev, "Cannot decide PMECC Capability\n"); 1360 if ((val != 2) && (val != 4) && (val != 8) && (val != 12) &&
1265 return -EINVAL; 1361 (val != 24)) {
1266 } else if ((val != 2) && (val != 4) && (val != 8) && (val != 12) && 1362 dev_err(host->dev,
1267 (val != 24)) { 1363 "Unsupported PMECC correction capability: %d; should be 2, 4, 8, 12 or 24\n",
1268 dev_err(host->dev, 1364 val);
1269 "Unsupported PMECC correction capability: %d; should be 2, 4, 8, 12 or 24\n", 1365 return -EINVAL;
1270 val); 1366 }
1271 return -EINVAL; 1367 host->pmecc_corr_cap = (u8)val;
1272 } 1368 }
1273 host->pmecc_corr_cap = (u8)val;
1274 1369
1275 if (of_property_read_u32(np, "atmel,pmecc-sector-size", &val) != 0) { 1370 if (of_property_read_u32(np, "atmel,pmecc-sector-size", &val) == 0) {
1276 dev_err(host->dev, "Cannot decide PMECC Sector Size\n"); 1371 if ((val != 512) && (val != 1024)) {
1277 return -EINVAL; 1372 dev_err(host->dev,
1278 } else if ((val != 512) && (val != 1024)) { 1373 "Unsupported PMECC sector size: %d; should be 512 or 1024 bytes\n",
1279 dev_err(host->dev, 1374 val);
1280 "Unsupported PMECC sector size: %d; should be 512 or 1024 bytes\n", 1375 return -EINVAL;
1281 val); 1376 }
1282 return -EINVAL; 1377 host->pmecc_sector_size = (u16)val;
1283 } 1378 }
1284 host->pmecc_sector_size = (u16)val;
1285 1379
1286 if (of_property_read_u32_array(np, "atmel,pmecc-lookup-table-offset", 1380 if (of_property_read_u32_array(np, "atmel,pmecc-lookup-table-offset",
1287 offset, 2) != 0) { 1381 offset, 2) != 0) {
1288 dev_err(host->dev, "Cannot get PMECC lookup table offset\n"); 1382 dev_err(host->dev, "Cannot get PMECC lookup table offset\n");
1289 return -EINVAL; 1383 return -EINVAL;
1290 } 1384 }
1291 table_offset = host->pmecc_sector_size == 512 ? offset[0] : offset[1]; 1385 if (!offset[0] && !offset[1]) {
1292
1293 if (!table_offset) {
1294 dev_err(host->dev, "Invalid PMECC lookup table offset\n"); 1386 dev_err(host->dev, "Invalid PMECC lookup table offset\n");
1295 return -EINVAL; 1387 return -EINVAL;
1296 } 1388 }
1297 host->pmecc_lookup_table_offset = table_offset; 1389 host->pmecc_lookup_table_offset_512 = offset[0];
1390 host->pmecc_lookup_table_offset_1024 = offset[1];
1298 1391
1299 return 0; 1392 return 0;
1300} 1393}