| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (C) 2016 Sigma Designs |
|---|
| 3 | | - * |
|---|
| 4 | | - * This program is free software; you can redistribute it and/or |
|---|
| 5 | | - * modify it under the terms of the GNU General Public License |
|---|
| 6 | | - * version 2 as published by the Free Software Foundation. |
|---|
| 7 | 4 | */ |
|---|
| 8 | 5 | |
|---|
| 9 | 6 | #include <linux/io.h> |
|---|
| .. | .. |
|---|
| 116 | 113 | |
|---|
| 117 | 114 | #define TIMING(t0, t1, t2, t3) ((t0) << 24 | (t1) << 16 | (t2) << 8 | (t3)) |
|---|
| 118 | 115 | |
|---|
| 119 | | -static void tango_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) |
|---|
| 116 | +static void tango_select_target(struct nand_chip *chip, unsigned int cs) |
|---|
| 120 | 117 | { |
|---|
| 121 | | - struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd)); |
|---|
| 122 | | - |
|---|
| 123 | | - if (ctrl & NAND_CLE) |
|---|
| 124 | | - writeb_relaxed(dat, tchip->base + PBUS_CMD); |
|---|
| 125 | | - |
|---|
| 126 | | - if (ctrl & NAND_ALE) |
|---|
| 127 | | - writeb_relaxed(dat, tchip->base + PBUS_ADDR); |
|---|
| 128 | | -} |
|---|
| 129 | | - |
|---|
| 130 | | -static int tango_dev_ready(struct mtd_info *mtd) |
|---|
| 131 | | -{ |
|---|
| 132 | | - struct nand_chip *chip = mtd_to_nand(mtd); |
|---|
| 133 | | - struct tango_nfc *nfc = to_tango_nfc(chip->controller); |
|---|
| 134 | | - |
|---|
| 135 | | - return readl_relaxed(nfc->pbus_base + PBUS_CS_CTRL) & PBUS_IORDY; |
|---|
| 136 | | -} |
|---|
| 137 | | - |
|---|
| 138 | | -static u8 tango_read_byte(struct mtd_info *mtd) |
|---|
| 139 | | -{ |
|---|
| 140 | | - struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd)); |
|---|
| 141 | | - |
|---|
| 142 | | - return readb_relaxed(tchip->base + PBUS_DATA); |
|---|
| 143 | | -} |
|---|
| 144 | | - |
|---|
| 145 | | -static void tango_read_buf(struct mtd_info *mtd, u8 *buf, int len) |
|---|
| 146 | | -{ |
|---|
| 147 | | - struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd)); |
|---|
| 148 | | - |
|---|
| 149 | | - ioread8_rep(tchip->base + PBUS_DATA, buf, len); |
|---|
| 150 | | -} |
|---|
| 151 | | - |
|---|
| 152 | | -static void tango_write_buf(struct mtd_info *mtd, const u8 *buf, int len) |
|---|
| 153 | | -{ |
|---|
| 154 | | - struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd)); |
|---|
| 155 | | - |
|---|
| 156 | | - iowrite8_rep(tchip->base + PBUS_DATA, buf, len); |
|---|
| 157 | | -} |
|---|
| 158 | | - |
|---|
| 159 | | -static void tango_select_chip(struct mtd_info *mtd, int idx) |
|---|
| 160 | | -{ |
|---|
| 161 | | - struct nand_chip *chip = mtd_to_nand(mtd); |
|---|
| 162 | 118 | struct tango_nfc *nfc = to_tango_nfc(chip->controller); |
|---|
| 163 | 119 | struct tango_chip *tchip = to_tango_chip(chip); |
|---|
| 164 | | - |
|---|
| 165 | | - if (idx < 0) |
|---|
| 166 | | - return; /* No "chip unselect" function */ |
|---|
| 167 | 120 | |
|---|
| 168 | 121 | writel_relaxed(tchip->timing1, nfc->reg_base + NFC_TIMING1); |
|---|
| 169 | 122 | writel_relaxed(tchip->timing2, nfc->reg_base + NFC_TIMING2); |
|---|
| .. | .. |
|---|
| 171 | 124 | writel_relaxed(tchip->pkt_0_cfg, nfc->reg_base + NFC_PKT_0_CFG); |
|---|
| 172 | 125 | writel_relaxed(tchip->pkt_n_cfg, nfc->reg_base + NFC_PKT_N_CFG); |
|---|
| 173 | 126 | writel_relaxed(tchip->bb_cfg, nfc->reg_base + NFC_BB_CFG); |
|---|
| 127 | +} |
|---|
| 128 | + |
|---|
| 129 | +static int tango_waitrdy(struct nand_chip *chip, unsigned int timeout_ms) |
|---|
| 130 | +{ |
|---|
| 131 | + struct tango_nfc *nfc = to_tango_nfc(chip->controller); |
|---|
| 132 | + u32 status; |
|---|
| 133 | + |
|---|
| 134 | + return readl_relaxed_poll_timeout(nfc->pbus_base + PBUS_CS_CTRL, |
|---|
| 135 | + status, status & PBUS_IORDY, 20, |
|---|
| 136 | + timeout_ms); |
|---|
| 137 | +} |
|---|
| 138 | + |
|---|
| 139 | +static int tango_exec_instr(struct nand_chip *chip, |
|---|
| 140 | + const struct nand_op_instr *instr) |
|---|
| 141 | +{ |
|---|
| 142 | + struct tango_chip *tchip = to_tango_chip(chip); |
|---|
| 143 | + unsigned int i; |
|---|
| 144 | + |
|---|
| 145 | + switch (instr->type) { |
|---|
| 146 | + case NAND_OP_CMD_INSTR: |
|---|
| 147 | + writeb_relaxed(instr->ctx.cmd.opcode, tchip->base + PBUS_CMD); |
|---|
| 148 | + return 0; |
|---|
| 149 | + case NAND_OP_ADDR_INSTR: |
|---|
| 150 | + for (i = 0; i < instr->ctx.addr.naddrs; i++) |
|---|
| 151 | + writeb_relaxed(instr->ctx.addr.addrs[i], |
|---|
| 152 | + tchip->base + PBUS_ADDR); |
|---|
| 153 | + return 0; |
|---|
| 154 | + case NAND_OP_DATA_IN_INSTR: |
|---|
| 155 | + ioread8_rep(tchip->base + PBUS_DATA, instr->ctx.data.buf.in, |
|---|
| 156 | + instr->ctx.data.len); |
|---|
| 157 | + return 0; |
|---|
| 158 | + case NAND_OP_DATA_OUT_INSTR: |
|---|
| 159 | + iowrite8_rep(tchip->base + PBUS_DATA, instr->ctx.data.buf.out, |
|---|
| 160 | + instr->ctx.data.len); |
|---|
| 161 | + return 0; |
|---|
| 162 | + case NAND_OP_WAITRDY_INSTR: |
|---|
| 163 | + return tango_waitrdy(chip, |
|---|
| 164 | + instr->ctx.waitrdy.timeout_ms); |
|---|
| 165 | + default: |
|---|
| 166 | + break; |
|---|
| 167 | + } |
|---|
| 168 | + |
|---|
| 169 | + return -EINVAL; |
|---|
| 170 | +} |
|---|
| 171 | + |
|---|
| 172 | +static int tango_exec_op(struct nand_chip *chip, |
|---|
| 173 | + const struct nand_operation *op, |
|---|
| 174 | + bool check_only) |
|---|
| 175 | +{ |
|---|
| 176 | + unsigned int i; |
|---|
| 177 | + int ret = 0; |
|---|
| 178 | + |
|---|
| 179 | + if (check_only) |
|---|
| 180 | + return 0; |
|---|
| 181 | + |
|---|
| 182 | + tango_select_target(chip, op->cs); |
|---|
| 183 | + for (i = 0; i < op->ninstrs; i++) { |
|---|
| 184 | + ret = tango_exec_instr(chip, &op->instrs[i]); |
|---|
| 185 | + if (ret) |
|---|
| 186 | + break; |
|---|
| 187 | + } |
|---|
| 188 | + |
|---|
| 189 | + return ret; |
|---|
| 174 | 190 | } |
|---|
| 175 | 191 | |
|---|
| 176 | 192 | /* |
|---|
| .. | .. |
|---|
| 277 | 293 | return err; |
|---|
| 278 | 294 | } |
|---|
| 279 | 295 | |
|---|
| 280 | | -static int tango_read_page(struct mtd_info *mtd, struct nand_chip *chip, |
|---|
| 281 | | - u8 *buf, int oob_required, int page) |
|---|
| 296 | +static int tango_read_page(struct nand_chip *chip, u8 *buf, |
|---|
| 297 | + int oob_required, int page) |
|---|
| 282 | 298 | { |
|---|
| 299 | + struct mtd_info *mtd = nand_to_mtd(chip); |
|---|
| 283 | 300 | struct tango_nfc *nfc = to_tango_nfc(chip->controller); |
|---|
| 284 | 301 | int err, res, len = mtd->writesize; |
|---|
| 285 | 302 | |
|---|
| 303 | + tango_select_target(chip, chip->cur_cs); |
|---|
| 286 | 304 | if (oob_required) |
|---|
| 287 | | - chip->ecc.read_oob(mtd, chip, page); |
|---|
| 305 | + chip->ecc.read_oob(chip, page); |
|---|
| 288 | 306 | |
|---|
| 289 | 307 | err = do_dma(nfc, DMA_FROM_DEVICE, NFC_READ, buf, len, page); |
|---|
| 290 | 308 | if (err) |
|---|
| .. | .. |
|---|
| 292 | 310 | |
|---|
| 293 | 311 | res = decode_error_report(chip); |
|---|
| 294 | 312 | if (res < 0) { |
|---|
| 295 | | - chip->ecc.read_oob_raw(mtd, chip, page); |
|---|
| 313 | + chip->ecc.read_oob_raw(chip, page); |
|---|
| 296 | 314 | res = check_erased_page(chip, buf); |
|---|
| 297 | 315 | } |
|---|
| 298 | 316 | |
|---|
| 299 | 317 | return res; |
|---|
| 300 | 318 | } |
|---|
| 301 | 319 | |
|---|
| 302 | | -static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip, |
|---|
| 303 | | - const u8 *buf, int oob_required, int page) |
|---|
| 320 | +static int tango_write_page(struct nand_chip *chip, const u8 *buf, |
|---|
| 321 | + int oob_required, int page) |
|---|
| 304 | 322 | { |
|---|
| 323 | + struct mtd_info *mtd = nand_to_mtd(chip); |
|---|
| 305 | 324 | struct tango_nfc *nfc = to_tango_nfc(chip->controller); |
|---|
| 306 | | - int err, status, len = mtd->writesize; |
|---|
| 325 | + const struct nand_sdr_timings *timings; |
|---|
| 326 | + int err, len = mtd->writesize; |
|---|
| 327 | + u8 status; |
|---|
| 307 | 328 | |
|---|
| 308 | 329 | /* Calling tango_write_oob() would send PAGEPROG twice */ |
|---|
| 309 | 330 | if (oob_required) |
|---|
| 310 | 331 | return -ENOTSUPP; |
|---|
| 311 | 332 | |
|---|
| 333 | + tango_select_target(chip, chip->cur_cs); |
|---|
| 312 | 334 | writel_relaxed(0xffffffff, nfc->mem_base + METADATA); |
|---|
| 313 | 335 | err = do_dma(nfc, DMA_TO_DEVICE, NFC_WRITE, buf, len, page); |
|---|
| 314 | 336 | if (err) |
|---|
| 315 | 337 | return err; |
|---|
| 316 | 338 | |
|---|
| 317 | | - status = chip->waitfunc(mtd, chip); |
|---|
| 318 | | - if (status & NAND_STATUS_FAIL) |
|---|
| 319 | | - return -EIO; |
|---|
| 339 | + timings = nand_get_sdr_timings(nand_get_interface_config(chip)); |
|---|
| 340 | + err = tango_waitrdy(chip, PSEC_TO_MSEC(timings->tR_max)); |
|---|
| 341 | + if (err) |
|---|
| 342 | + return err; |
|---|
| 320 | 343 | |
|---|
| 321 | | - return 0; |
|---|
| 344 | + err = nand_status_op(chip, &status); |
|---|
| 345 | + if (err) |
|---|
| 346 | + return err; |
|---|
| 347 | + |
|---|
| 348 | + return (status & NAND_STATUS_FAIL) ? -EIO : 0; |
|---|
| 322 | 349 | } |
|---|
| 323 | 350 | |
|---|
| 324 | 351 | static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos) |
|---|
| 325 | 352 | { |
|---|
| 326 | | - struct mtd_info *mtd = nand_to_mtd(chip); |
|---|
| 327 | | - |
|---|
| 328 | 353 | *pos += len; |
|---|
| 329 | 354 | |
|---|
| 330 | 355 | if (!*buf) { |
|---|
| 331 | 356 | /* skip over "len" bytes */ |
|---|
| 332 | 357 | nand_change_read_column_op(chip, *pos, NULL, 0, false); |
|---|
| 333 | 358 | } else { |
|---|
| 334 | | - tango_read_buf(mtd, *buf, len); |
|---|
| 359 | + struct tango_chip *tchip = to_tango_chip(chip); |
|---|
| 360 | + |
|---|
| 361 | + ioread8_rep(tchip->base + PBUS_DATA, *buf, len); |
|---|
| 335 | 362 | *buf += len; |
|---|
| 336 | 363 | } |
|---|
| 337 | 364 | } |
|---|
| 338 | 365 | |
|---|
| 339 | 366 | static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos) |
|---|
| 340 | 367 | { |
|---|
| 341 | | - struct mtd_info *mtd = nand_to_mtd(chip); |
|---|
| 342 | | - |
|---|
| 343 | 368 | *pos += len; |
|---|
| 344 | 369 | |
|---|
| 345 | 370 | if (!*buf) { |
|---|
| 346 | 371 | /* skip over "len" bytes */ |
|---|
| 347 | 372 | nand_change_write_column_op(chip, *pos, NULL, 0, false); |
|---|
| 348 | 373 | } else { |
|---|
| 349 | | - tango_write_buf(mtd, *buf, len); |
|---|
| 374 | + struct tango_chip *tchip = to_tango_chip(chip); |
|---|
| 375 | + |
|---|
| 376 | + iowrite8_rep(tchip->base + PBUS_DATA, *buf, len); |
|---|
| 350 | 377 | *buf += len; |
|---|
| 351 | 378 | } |
|---|
| 352 | 379 | } |
|---|
| .. | .. |
|---|
| 424 | 451 | aux_write(chip, &oob, ecc_size, &pos); |
|---|
| 425 | 452 | } |
|---|
| 426 | 453 | |
|---|
| 427 | | -static int tango_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, |
|---|
| 428 | | - u8 *buf, int oob_required, int page) |
|---|
| 454 | +static int tango_read_page_raw(struct nand_chip *chip, u8 *buf, |
|---|
| 455 | + int oob_required, int page) |
|---|
| 429 | 456 | { |
|---|
| 457 | + tango_select_target(chip, chip->cur_cs); |
|---|
| 430 | 458 | nand_read_page_op(chip, page, 0, NULL, 0); |
|---|
| 431 | 459 | raw_read(chip, buf, chip->oob_poi); |
|---|
| 432 | 460 | return 0; |
|---|
| 433 | 461 | } |
|---|
| 434 | 462 | |
|---|
| 435 | | -static int tango_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, |
|---|
| 436 | | - const u8 *buf, int oob_required, int page) |
|---|
| 463 | +static int tango_write_page_raw(struct nand_chip *chip, const u8 *buf, |
|---|
| 464 | + int oob_required, int page) |
|---|
| 437 | 465 | { |
|---|
| 466 | + tango_select_target(chip, chip->cur_cs); |
|---|
| 438 | 467 | nand_prog_page_begin_op(chip, page, 0, NULL, 0); |
|---|
| 439 | 468 | raw_write(chip, buf, chip->oob_poi); |
|---|
| 440 | 469 | return nand_prog_page_end_op(chip); |
|---|
| 441 | 470 | } |
|---|
| 442 | 471 | |
|---|
| 443 | | -static int tango_read_oob(struct mtd_info *mtd, struct nand_chip *chip, |
|---|
| 444 | | - int page) |
|---|
| 472 | +static int tango_read_oob(struct nand_chip *chip, int page) |
|---|
| 445 | 473 | { |
|---|
| 474 | + tango_select_target(chip, chip->cur_cs); |
|---|
| 446 | 475 | nand_read_page_op(chip, page, 0, NULL, 0); |
|---|
| 447 | 476 | raw_read(chip, NULL, chip->oob_poi); |
|---|
| 448 | 477 | return 0; |
|---|
| 449 | 478 | } |
|---|
| 450 | 479 | |
|---|
| 451 | | -static int tango_write_oob(struct mtd_info *mtd, struct nand_chip *chip, |
|---|
| 452 | | - int page) |
|---|
| 480 | +static int tango_write_oob(struct nand_chip *chip, int page) |
|---|
| 453 | 481 | { |
|---|
| 482 | + tango_select_target(chip, chip->cur_cs); |
|---|
| 454 | 483 | nand_prog_page_begin_op(chip, page, 0, NULL, 0); |
|---|
| 455 | 484 | raw_write(chip, NULL, chip->oob_poi); |
|---|
| 456 | 485 | return nand_prog_page_end_op(chip); |
|---|
| .. | .. |
|---|
| 485 | 514 | return DIV_ROUND_UP_ULL((u64)kHz * ps, NSEC_PER_SEC); |
|---|
| 486 | 515 | } |
|---|
| 487 | 516 | |
|---|
| 488 | | -static int tango_set_timings(struct mtd_info *mtd, int csline, |
|---|
| 489 | | - const struct nand_data_interface *conf) |
|---|
| 517 | +static int tango_set_timings(struct nand_chip *chip, int csline, |
|---|
| 518 | + const struct nand_interface_config *conf) |
|---|
| 490 | 519 | { |
|---|
| 491 | 520 | const struct nand_sdr_timings *sdr = nand_get_sdr_timings(conf); |
|---|
| 492 | | - struct nand_chip *chip = mtd_to_nand(mtd); |
|---|
| 493 | 521 | struct tango_nfc *nfc = to_tango_nfc(chip->controller); |
|---|
| 494 | 522 | struct tango_chip *tchip = to_tango_chip(chip); |
|---|
| 495 | 523 | u32 Trdy, Textw, Twc, Twpw, Tacc, Thold, Trpw, Textr; |
|---|
| .. | .. |
|---|
| 521 | 549 | { |
|---|
| 522 | 550 | struct nand_ecc_ctrl *ecc = &chip->ecc; |
|---|
| 523 | 551 | |
|---|
| 524 | | - ecc->mode = NAND_ECC_HW; |
|---|
| 525 | | - ecc->algo = NAND_ECC_BCH; |
|---|
| 552 | + ecc->engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST; |
|---|
| 553 | + ecc->algo = NAND_ECC_ALGO_BCH; |
|---|
| 526 | 554 | ecc->bytes = DIV_ROUND_UP(ecc->strength * FIELD_ORDER, BITS_PER_BYTE); |
|---|
| 527 | 555 | |
|---|
| 528 | 556 | ecc->read_page_raw = tango_read_page_raw; |
|---|
| .. | .. |
|---|
| 537 | 565 | |
|---|
| 538 | 566 | static const struct nand_controller_ops tango_controller_ops = { |
|---|
| 539 | 567 | .attach_chip = tango_attach_chip, |
|---|
| 568 | + .setup_interface = tango_set_timings, |
|---|
| 569 | + .exec_op = tango_exec_op, |
|---|
| 540 | 570 | }; |
|---|
| 541 | 571 | |
|---|
| 542 | 572 | static int chip_init(struct device *dev, struct device_node *np) |
|---|
| .. | .. |
|---|
| 571 | 601 | ecc = &chip->ecc; |
|---|
| 572 | 602 | mtd = nand_to_mtd(chip); |
|---|
| 573 | 603 | |
|---|
| 574 | | - chip->read_byte = tango_read_byte; |
|---|
| 575 | | - chip->write_buf = tango_write_buf; |
|---|
| 576 | | - chip->read_buf = tango_read_buf; |
|---|
| 577 | | - chip->select_chip = tango_select_chip; |
|---|
| 578 | | - chip->cmd_ctrl = tango_cmd_ctrl; |
|---|
| 579 | | - chip->dev_ready = tango_dev_ready; |
|---|
| 580 | | - chip->setup_data_interface = tango_set_timings; |
|---|
| 581 | | - chip->options = NAND_USE_BOUNCE_BUFFER | |
|---|
| 604 | + chip->options = NAND_USES_DMA | |
|---|
| 582 | 605 | NAND_NO_SUBPAGE_WRITE | |
|---|
| 583 | 606 | NAND_WAIT_TCCS; |
|---|
| 584 | 607 | chip->controller = &nfc->hw; |
|---|
| .. | .. |
|---|
| 610 | 633 | |
|---|
| 611 | 634 | static int tango_nand_remove(struct platform_device *pdev) |
|---|
| 612 | 635 | { |
|---|
| 613 | | - int cs; |
|---|
| 614 | 636 | struct tango_nfc *nfc = platform_get_drvdata(pdev); |
|---|
| 637 | + struct nand_chip *chip; |
|---|
| 638 | + int cs, ret; |
|---|
| 615 | 639 | |
|---|
| 616 | 640 | dma_release_channel(nfc->chan); |
|---|
| 617 | 641 | |
|---|
| 618 | 642 | for (cs = 0; cs < MAX_CS; ++cs) { |
|---|
| 619 | | - if (nfc->chips[cs]) |
|---|
| 620 | | - nand_release(&nfc->chips[cs]->nand_chip); |
|---|
| 643 | + if (nfc->chips[cs]) { |
|---|
| 644 | + chip = &nfc->chips[cs]->nand_chip; |
|---|
| 645 | + ret = mtd_device_unregister(nand_to_mtd(chip)); |
|---|
| 646 | + WARN_ON(ret); |
|---|
| 647 | + nand_cleanup(chip); |
|---|
| 648 | + } |
|---|
| 621 | 649 | } |
|---|
| 622 | 650 | |
|---|
| 623 | 651 | return 0; |
|---|
| .. | .. |
|---|
| 669 | 697 | err = chip_init(&pdev->dev, np); |
|---|
| 670 | 698 | if (err) { |
|---|
| 671 | 699 | tango_nand_remove(pdev); |
|---|
| 700 | + of_node_put(np); |
|---|
| 672 | 701 | return err; |
|---|
| 673 | 702 | } |
|---|
| 674 | 703 | } |
|---|