|
@@ -152,6 +152,9 @@ struct mxc_nand_devtype_data {
|
|
|
void (*select_chip)(struct mtd_info *mtd, int chip);
|
|
|
int (*correct_data)(struct mtd_info *mtd, u_char *dat,
|
|
|
u_char *read_ecc, u_char *calc_ecc);
|
|
|
+ int (*setup_data_interface)(struct mtd_info *mtd,
|
|
|
+ const struct nand_data_interface *conf,
|
|
|
+ bool check_only);
|
|
|
|
|
|
/*
|
|
|
* On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked
|
|
@@ -1012,6 +1015,82 @@ static void preset_v1(struct mtd_info *mtd)
|
|
|
writew(0x4, NFC_V1_V2_WRPROT);
|
|
|
}
|
|
|
|
|
|
+static int mxc_nand_v2_setup_data_interface(struct mtd_info *mtd,
|
|
|
+ const struct nand_data_interface *conf,
|
|
|
+ bool check_only)
|
|
|
+{
|
|
|
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
|
|
+ struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
|
|
|
+ int tRC_min_ns, tRC_ps, ret;
|
|
|
+ unsigned long rate, rate_round;
|
|
|
+ const struct nand_sdr_timings *timings;
|
|
|
+ u16 config1;
|
|
|
+
|
|
|
+ timings = nand_get_sdr_timings(conf);
|
|
|
+ if (IS_ERR(timings))
|
|
|
+ return -ENOTSUPP;
|
|
|
+
|
|
|
+ config1 = readw(NFC_V1_V2_CONFIG1);
|
|
|
+
|
|
|
+ tRC_min_ns = timings->tRC_min / 1000;
|
|
|
+ rate = 1000000000 / tRC_min_ns;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * For tRC < 30ns we have to use EDO mode. In this case the controller
|
|
|
+ * does one access per clock cycle. Otherwise the controller does one
|
|
|
+ * access in two clock cycles, thus we have to double the rate to the
|
|
|
+ * controller.
|
|
|
+ */
|
|
|
+ if (tRC_min_ns < 30) {
|
|
|
+ rate_round = clk_round_rate(host->clk, rate);
|
|
|
+ config1 |= NFC_V2_CONFIG1_ONE_CYCLE;
|
|
|
+ tRC_ps = 1000000000 / (rate_round / 1000);
|
|
|
+ } else {
|
|
|
+ rate *= 2;
|
|
|
+ rate_round = clk_round_rate(host->clk, rate);
|
|
|
+ config1 &= ~NFC_V2_CONFIG1_ONE_CYCLE;
|
|
|
+ tRC_ps = 1000000000 / (rate_round / 1000 / 2);
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * The timing values compared against are from the i.MX25 Automotive
|
|
|
+ * datasheet, Table 50. NFC Timing Parameters
|
|
|
+ */
|
|
|
+ if (timings->tCLS_min > tRC_ps - 1000 ||
|
|
|
+ timings->tCLH_min > tRC_ps - 2000 ||
|
|
|
+ timings->tCS_min > tRC_ps - 1000 ||
|
|
|
+ timings->tCH_min > tRC_ps - 2000 ||
|
|
|
+ timings->tWP_min > tRC_ps - 1500 ||
|
|
|
+ timings->tALS_min > tRC_ps ||
|
|
|
+ timings->tALH_min > tRC_ps - 3000 ||
|
|
|
+ timings->tDS_min > tRC_ps ||
|
|
|
+ timings->tDH_min > tRC_ps - 5000 ||
|
|
|
+ timings->tWC_min > 2 * tRC_ps ||
|
|
|
+ timings->tWH_min > tRC_ps - 2500 ||
|
|
|
+ timings->tRR_min > 6 * tRC_ps ||
|
|
|
+ timings->tRP_min > 3 * tRC_ps / 2 ||
|
|
|
+ timings->tRC_min > 2 * tRC_ps ||
|
|
|
+ timings->tREH_min > (tRC_ps / 2) - 2500) {
|
|
|
+ dev_dbg(host->dev, "Timing out of bounds\n");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (check_only)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ ret = clk_set_rate(host->clk, rate);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ writew(config1, NFC_V1_V2_CONFIG1);
|
|
|
+
|
|
|
+ dev_dbg(host->dev, "Setting rate to %ldHz, %s mode\n", rate_round,
|
|
|
+ config1 & NFC_V2_CONFIG1_ONE_CYCLE ? "One cycle (EDO)" :
|
|
|
+ "normal");
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static void preset_v2(struct mtd_info *mtd)
|
|
|
{
|
|
|
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
|
@@ -1278,8 +1357,6 @@ static int mxc_nand_onfi_get_features(struct mtd_info *mtd,
|
|
|
& ONFI_OPT_CMD_SET_GET_FEATURES))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- *(uint32_t *)host->main_area0 = 0xdeadbeef;
|
|
|
-
|
|
|
host->devtype_data->send_cmd(host, NAND_CMD_GET_FEATURES, false);
|
|
|
mxc_do_addr_cycle(mtd, addr, -1);
|
|
|
host->devtype_data->send_page(mtd, NFC_OUTPUT);
|
|
@@ -1380,6 +1457,7 @@ static const struct mxc_nand_devtype_data imx25_nand_devtype_data = {
|
|
|
.ooblayout = &mxc_v2_ooblayout_ops,
|
|
|
.select_chip = mxc_nand_select_chip_v2,
|
|
|
.correct_data = mxc_nand_correct_data_v2_v3,
|
|
|
+ .setup_data_interface = mxc_nand_v2_setup_data_interface,
|
|
|
.irqpending_quirk = 0,
|
|
|
.needs_ip = 0,
|
|
|
.regs_offset = 0x1e00,
|
|
@@ -1588,6 +1666,8 @@ static int mxcnd_probe(struct platform_device *pdev)
|
|
|
if (err < 0)
|
|
|
return err;
|
|
|
|
|
|
+ this->setup_data_interface = host->devtype_data->setup_data_interface;
|
|
|
+
|
|
|
if (host->devtype_data->needs_ip) {
|
|
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
|
host->regs_ip = devm_ioremap_resource(&pdev->dev, res);
|