Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mtd: nand: mxc: Add timing setup for v2 controllers

So far we relied on reset default or the bootloader to configure a
suitable clk rate for the Nand controller. This works but we can
optimize the timing for better performance. This sets the clk rate for
v2 controllers (i.MX25/35) based on the timing mode read from the ONFI
parameter page. This may also enable the symmetric mode (aks EDO mode)
if necessary which reads one word per clock cycle.
Tested on an i.MX25 with a Micron MT29F4G08ABBDAHC attached.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>

authored by

Sascha Hauer and committed by
Boris Brezillon
82830796 4123ea34

+82 -2
+82 -2
drivers/mtd/nand/mxc_nand.c
··· 152 152 void (*select_chip)(struct mtd_info *mtd, int chip); 153 153 int (*correct_data)(struct mtd_info *mtd, u_char *dat, 154 154 u_char *read_ecc, u_char *calc_ecc); 155 + int (*setup_data_interface)(struct mtd_info *mtd, 156 + const struct nand_data_interface *conf, 157 + bool check_only); 155 158 156 159 /* 157 160 * On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked ··· 1015 1012 writew(0x4, NFC_V1_V2_WRPROT); 1016 1013 } 1017 1014 1015 + static int mxc_nand_v2_setup_data_interface(struct mtd_info *mtd, 1016 + const struct nand_data_interface *conf, 1017 + bool check_only) 1018 + { 1019 + struct nand_chip *nand_chip = mtd_to_nand(mtd); 1020 + struct mxc_nand_host *host = nand_get_controller_data(nand_chip); 1021 + int tRC_min_ns, tRC_ps, ret; 1022 + unsigned long rate, rate_round; 1023 + const struct nand_sdr_timings *timings; 1024 + u16 config1; 1025 + 1026 + timings = nand_get_sdr_timings(conf); 1027 + if (IS_ERR(timings)) 1028 + return -ENOTSUPP; 1029 + 1030 + config1 = readw(NFC_V1_V2_CONFIG1); 1031 + 1032 + tRC_min_ns = timings->tRC_min / 1000; 1033 + rate = 1000000000 / tRC_min_ns; 1034 + 1035 + /* 1036 + * For tRC < 30ns we have to use EDO mode. In this case the controller 1037 + * does one access per clock cycle. Otherwise the controller does one 1038 + * access in two clock cycles, thus we have to double the rate to the 1039 + * controller. 1040 + */ 1041 + if (tRC_min_ns < 30) { 1042 + rate_round = clk_round_rate(host->clk, rate); 1043 + config1 |= NFC_V2_CONFIG1_ONE_CYCLE; 1044 + tRC_ps = 1000000000 / (rate_round / 1000); 1045 + } else { 1046 + rate *= 2; 1047 + rate_round = clk_round_rate(host->clk, rate); 1048 + config1 &= ~NFC_V2_CONFIG1_ONE_CYCLE; 1049 + tRC_ps = 1000000000 / (rate_round / 1000 / 2); 1050 + } 1051 + 1052 + /* 1053 + * The timing values compared against are from the i.MX25 Automotive 1054 + * datasheet, Table 50. NFC Timing Parameters 1055 + */ 1056 + if (timings->tCLS_min > tRC_ps - 1000 || 1057 + timings->tCLH_min > tRC_ps - 2000 || 1058 + timings->tCS_min > tRC_ps - 1000 || 1059 + timings->tCH_min > tRC_ps - 2000 || 1060 + timings->tWP_min > tRC_ps - 1500 || 1061 + timings->tALS_min > tRC_ps || 1062 + timings->tALH_min > tRC_ps - 3000 || 1063 + timings->tDS_min > tRC_ps || 1064 + timings->tDH_min > tRC_ps - 5000 || 1065 + timings->tWC_min > 2 * tRC_ps || 1066 + timings->tWH_min > tRC_ps - 2500 || 1067 + timings->tRR_min > 6 * tRC_ps || 1068 + timings->tRP_min > 3 * tRC_ps / 2 || 1069 + timings->tRC_min > 2 * tRC_ps || 1070 + timings->tREH_min > (tRC_ps / 2) - 2500) { 1071 + dev_dbg(host->dev, "Timing out of bounds\n"); 1072 + return -EINVAL; 1073 + } 1074 + 1075 + if (check_only) 1076 + return 0; 1077 + 1078 + ret = clk_set_rate(host->clk, rate); 1079 + if (ret) 1080 + return ret; 1081 + 1082 + writew(config1, NFC_V1_V2_CONFIG1); 1083 + 1084 + dev_dbg(host->dev, "Setting rate to %ldHz, %s mode\n", rate_round, 1085 + config1 & NFC_V2_CONFIG1_ONE_CYCLE ? "One cycle (EDO)" : 1086 + "normal"); 1087 + 1088 + return 0; 1089 + } 1090 + 1018 1091 static void preset_v2(struct mtd_info *mtd) 1019 1092 { 1020 1093 struct nand_chip *nand_chip = mtd_to_nand(mtd); ··· 1357 1278 & ONFI_OPT_CMD_SET_GET_FEATURES)) 1358 1279 return -EINVAL; 1359 1280 1360 - *(uint32_t *)host->main_area0 = 0xdeadbeef; 1361 - 1362 1281 host->devtype_data->send_cmd(host, NAND_CMD_GET_FEATURES, false); 1363 1282 mxc_do_addr_cycle(mtd, addr, -1); 1364 1283 host->devtype_data->send_page(mtd, NFC_OUTPUT); ··· 1457 1380 .ooblayout = &mxc_v2_ooblayout_ops, 1458 1381 .select_chip = mxc_nand_select_chip_v2, 1459 1382 .correct_data = mxc_nand_correct_data_v2_v3, 1383 + .setup_data_interface = mxc_nand_v2_setup_data_interface, 1460 1384 .irqpending_quirk = 0, 1461 1385 .needs_ip = 0, 1462 1386 .regs_offset = 0x1e00, ··· 1665 1587 } 1666 1588 if (err < 0) 1667 1589 return err; 1590 + 1591 + this->setup_data_interface = host->devtype_data->setup_data_interface; 1668 1592 1669 1593 if (host->devtype_data->needs_ip) { 1670 1594 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);