.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) 2017 Free Electrons |
---|
3 | 4 | * Copyright (C) 2017 NextThing Co |
---|
4 | 5 | * |
---|
5 | 6 | * Author: Boris Brezillon <boris.brezillon@free-electrons.com> |
---|
6 | | - * |
---|
7 | | - * This program is free software; you can redistribute it and/or modify |
---|
8 | | - * it under the terms of the GNU General Public License as published by |
---|
9 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
10 | | - * (at your option) any later version. |
---|
11 | | - * |
---|
12 | | - * This program is distributed in the hope that it will be useful, |
---|
13 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
14 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
15 | | - * GNU General Public License for more details. |
---|
16 | 7 | */ |
---|
17 | 8 | |
---|
18 | | -#include <linux/mtd/rawnand.h> |
---|
19 | 9 | #include <linux/sizes.h> |
---|
20 | 10 | #include <linux/slab.h> |
---|
| 11 | + |
---|
| 12 | +#include "internals.h" |
---|
21 | 13 | |
---|
22 | 14 | #define NAND_HYNIX_CMD_SET_PARAMS 0x36 |
---|
23 | 15 | #define NAND_HYNIX_CMD_APPLY_PARAMS 0x16 |
---|
.. | .. |
---|
34 | 26 | struct hynix_read_retry { |
---|
35 | 27 | int nregs; |
---|
36 | 28 | const u8 *regs; |
---|
37 | | - u8 values[0]; |
---|
| 29 | + u8 values[]; |
---|
38 | 30 | }; |
---|
39 | 31 | |
---|
40 | 32 | /** |
---|
.. | .. |
---|
79 | 71 | |
---|
80 | 72 | static int hynix_nand_cmd_op(struct nand_chip *chip, u8 cmd) |
---|
81 | 73 | { |
---|
82 | | - struct mtd_info *mtd = nand_to_mtd(chip); |
---|
83 | | - |
---|
84 | | - if (chip->exec_op) { |
---|
| 74 | + if (nand_has_exec_op(chip)) { |
---|
85 | 75 | struct nand_op_instr instrs[] = { |
---|
86 | 76 | NAND_OP_CMD(cmd, 0), |
---|
87 | 77 | }; |
---|
88 | | - struct nand_operation op = NAND_OPERATION(instrs); |
---|
| 78 | + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); |
---|
89 | 79 | |
---|
90 | 80 | return nand_exec_op(chip, &op); |
---|
91 | 81 | } |
---|
92 | 82 | |
---|
93 | | - chip->cmdfunc(mtd, cmd, -1, -1); |
---|
| 83 | + chip->legacy.cmdfunc(chip, cmd, -1, -1); |
---|
94 | 84 | |
---|
95 | 85 | return 0; |
---|
96 | 86 | } |
---|
97 | 87 | |
---|
98 | 88 | static int hynix_nand_reg_write_op(struct nand_chip *chip, u8 addr, u8 val) |
---|
99 | 89 | { |
---|
100 | | - struct mtd_info *mtd = nand_to_mtd(chip); |
---|
101 | 90 | u16 column = ((u16)addr << 8) | addr; |
---|
102 | 91 | |
---|
103 | | - if (chip->exec_op) { |
---|
| 92 | + if (nand_has_exec_op(chip)) { |
---|
104 | 93 | struct nand_op_instr instrs[] = { |
---|
105 | 94 | NAND_OP_ADDR(1, &addr, 0), |
---|
106 | 95 | NAND_OP_8BIT_DATA_OUT(1, &val, 0), |
---|
107 | 96 | }; |
---|
108 | | - struct nand_operation op = NAND_OPERATION(instrs); |
---|
| 97 | + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); |
---|
109 | 98 | |
---|
110 | 99 | return nand_exec_op(chip, &op); |
---|
111 | 100 | } |
---|
112 | 101 | |
---|
113 | | - chip->cmdfunc(mtd, NAND_CMD_NONE, column, -1); |
---|
114 | | - chip->write_byte(mtd, val); |
---|
| 102 | + chip->legacy.cmdfunc(chip, NAND_CMD_NONE, column, -1); |
---|
| 103 | + chip->legacy.write_byte(chip, val); |
---|
115 | 104 | |
---|
116 | 105 | return 0; |
---|
117 | 106 | } |
---|
118 | 107 | |
---|
119 | | -static int hynix_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode) |
---|
| 108 | +static int hynix_nand_setup_read_retry(struct nand_chip *chip, int retry_mode) |
---|
120 | 109 | { |
---|
121 | | - struct nand_chip *chip = mtd_to_nand(mtd); |
---|
122 | 110 | struct hynix_nand *hynix = nand_get_manufacturer_data(chip); |
---|
123 | 111 | const u8 *values; |
---|
124 | 112 | int i, ret; |
---|
.. | .. |
---|
349 | 337 | rr->nregs = nregs; |
---|
350 | 338 | rr->regs = hynix_1xnm_mlc_read_retry_regs; |
---|
351 | 339 | hynix->read_retry = rr; |
---|
352 | | - chip->setup_read_retry = hynix_nand_setup_read_retry; |
---|
| 340 | + chip->ops.setup_read_retry = hynix_nand_setup_read_retry; |
---|
353 | 341 | chip->read_retries = nmodes; |
---|
354 | 342 | |
---|
355 | 343 | out: |
---|
.. | .. |
---|
421 | 409 | bool valid_jedecid) |
---|
422 | 410 | { |
---|
423 | 411 | struct mtd_info *mtd = nand_to_mtd(chip); |
---|
| 412 | + struct nand_memory_organization *memorg; |
---|
424 | 413 | u8 oobsize; |
---|
| 414 | + |
---|
| 415 | + memorg = nanddev_get_memorg(&chip->base); |
---|
425 | 416 | |
---|
426 | 417 | oobsize = ((chip->id.data[3] >> 2) & 0x3) | |
---|
427 | 418 | ((chip->id.data[3] >> 4) & 0x4); |
---|
.. | .. |
---|
429 | 420 | if (valid_jedecid) { |
---|
430 | 421 | switch (oobsize) { |
---|
431 | 422 | case 0: |
---|
432 | | - mtd->oobsize = 2048; |
---|
| 423 | + memorg->oobsize = 2048; |
---|
433 | 424 | break; |
---|
434 | 425 | case 1: |
---|
435 | | - mtd->oobsize = 1664; |
---|
| 426 | + memorg->oobsize = 1664; |
---|
436 | 427 | break; |
---|
437 | 428 | case 2: |
---|
438 | | - mtd->oobsize = 1024; |
---|
| 429 | + memorg->oobsize = 1024; |
---|
439 | 430 | break; |
---|
440 | 431 | case 3: |
---|
441 | | - mtd->oobsize = 640; |
---|
| 432 | + memorg->oobsize = 640; |
---|
442 | 433 | break; |
---|
443 | 434 | default: |
---|
444 | 435 | /* |
---|
.. | .. |
---|
453 | 444 | } else { |
---|
454 | 445 | switch (oobsize) { |
---|
455 | 446 | case 0: |
---|
456 | | - mtd->oobsize = 128; |
---|
| 447 | + memorg->oobsize = 128; |
---|
457 | 448 | break; |
---|
458 | 449 | case 1: |
---|
459 | | - mtd->oobsize = 224; |
---|
| 450 | + memorg->oobsize = 224; |
---|
460 | 451 | break; |
---|
461 | 452 | case 2: |
---|
462 | | - mtd->oobsize = 448; |
---|
| 453 | + memorg->oobsize = 448; |
---|
463 | 454 | break; |
---|
464 | 455 | case 3: |
---|
465 | | - mtd->oobsize = 64; |
---|
| 456 | + memorg->oobsize = 64; |
---|
466 | 457 | break; |
---|
467 | 458 | case 4: |
---|
468 | | - mtd->oobsize = 32; |
---|
| 459 | + memorg->oobsize = 32; |
---|
469 | 460 | break; |
---|
470 | 461 | case 5: |
---|
471 | | - mtd->oobsize = 16; |
---|
| 462 | + memorg->oobsize = 16; |
---|
472 | 463 | break; |
---|
473 | 464 | case 6: |
---|
474 | | - mtd->oobsize = 640; |
---|
| 465 | + memorg->oobsize = 640; |
---|
475 | 466 | break; |
---|
476 | 467 | default: |
---|
477 | 468 | /* |
---|
.. | .. |
---|
495 | 486 | * the actual OOB size for this chip is: 640 * 16k / 8k). |
---|
496 | 487 | */ |
---|
497 | 488 | if (chip->id.data[1] == 0xde) |
---|
498 | | - mtd->oobsize *= mtd->writesize / SZ_8K; |
---|
| 489 | + memorg->oobsize *= memorg->pagesize / SZ_8K; |
---|
499 | 490 | } |
---|
| 491 | + |
---|
| 492 | + mtd->oobsize = memorg->oobsize; |
---|
500 | 493 | } |
---|
501 | 494 | |
---|
502 | 495 | static void hynix_nand_extract_ecc_requirements(struct nand_chip *chip, |
---|
503 | 496 | bool valid_jedecid) |
---|
504 | 497 | { |
---|
| 498 | + struct nand_device *base = &chip->base; |
---|
| 499 | + struct nand_ecc_props requirements = {}; |
---|
505 | 500 | u8 ecc_level = (chip->id.data[4] >> 4) & 0x7; |
---|
506 | 501 | |
---|
507 | 502 | if (valid_jedecid) { |
---|
508 | 503 | /* Reference: H27UCG8T2E datasheet */ |
---|
509 | | - chip->ecc_step_ds = 1024; |
---|
| 504 | + requirements.step_size = 1024; |
---|
510 | 505 | |
---|
511 | 506 | switch (ecc_level) { |
---|
512 | 507 | case 0: |
---|
513 | | - chip->ecc_step_ds = 0; |
---|
514 | | - chip->ecc_strength_ds = 0; |
---|
| 508 | + requirements.step_size = 0; |
---|
| 509 | + requirements.strength = 0; |
---|
515 | 510 | break; |
---|
516 | 511 | case 1: |
---|
517 | | - chip->ecc_strength_ds = 4; |
---|
| 512 | + requirements.strength = 4; |
---|
518 | 513 | break; |
---|
519 | 514 | case 2: |
---|
520 | | - chip->ecc_strength_ds = 24; |
---|
| 515 | + requirements.strength = 24; |
---|
521 | 516 | break; |
---|
522 | 517 | case 3: |
---|
523 | | - chip->ecc_strength_ds = 32; |
---|
| 518 | + requirements.strength = 32; |
---|
524 | 519 | break; |
---|
525 | 520 | case 4: |
---|
526 | | - chip->ecc_strength_ds = 40; |
---|
| 521 | + requirements.strength = 40; |
---|
527 | 522 | break; |
---|
528 | 523 | case 5: |
---|
529 | | - chip->ecc_strength_ds = 50; |
---|
| 524 | + requirements.strength = 50; |
---|
530 | 525 | break; |
---|
531 | 526 | case 6: |
---|
532 | | - chip->ecc_strength_ds = 60; |
---|
| 527 | + requirements.strength = 60; |
---|
533 | 528 | break; |
---|
534 | 529 | default: |
---|
535 | 530 | /* |
---|
.. | .. |
---|
550 | 545 | if (nand_tech < 3) { |
---|
551 | 546 | /* > 26nm, reference: H27UBG8T2A datasheet */ |
---|
552 | 547 | if (ecc_level < 5) { |
---|
553 | | - chip->ecc_step_ds = 512; |
---|
554 | | - chip->ecc_strength_ds = 1 << ecc_level; |
---|
| 548 | + requirements.step_size = 512; |
---|
| 549 | + requirements.strength = 1 << ecc_level; |
---|
555 | 550 | } else if (ecc_level < 7) { |
---|
556 | 551 | if (ecc_level == 5) |
---|
557 | | - chip->ecc_step_ds = 2048; |
---|
| 552 | + requirements.step_size = 2048; |
---|
558 | 553 | else |
---|
559 | | - chip->ecc_step_ds = 1024; |
---|
560 | | - chip->ecc_strength_ds = 24; |
---|
| 554 | + requirements.step_size = 1024; |
---|
| 555 | + requirements.strength = 24; |
---|
561 | 556 | } else { |
---|
562 | 557 | /* |
---|
563 | 558 | * We should never reach this case, but if that |
---|
.. | .. |
---|
570 | 565 | } else { |
---|
571 | 566 | /* <= 26nm, reference: H27UBG8T2B datasheet */ |
---|
572 | 567 | if (!ecc_level) { |
---|
573 | | - chip->ecc_step_ds = 0; |
---|
574 | | - chip->ecc_strength_ds = 0; |
---|
| 568 | + requirements.step_size = 0; |
---|
| 569 | + requirements.strength = 0; |
---|
575 | 570 | } else if (ecc_level < 5) { |
---|
576 | | - chip->ecc_step_ds = 512; |
---|
577 | | - chip->ecc_strength_ds = 1 << (ecc_level - 1); |
---|
| 571 | + requirements.step_size = 512; |
---|
| 572 | + requirements.strength = 1 << (ecc_level - 1); |
---|
578 | 573 | } else { |
---|
579 | | - chip->ecc_step_ds = 1024; |
---|
580 | | - chip->ecc_strength_ds = 24 + |
---|
| 574 | + requirements.step_size = 1024; |
---|
| 575 | + requirements.strength = 24 + |
---|
581 | 576 | (8 * (ecc_level - 5)); |
---|
582 | 577 | } |
---|
583 | 578 | } |
---|
584 | 579 | } |
---|
| 580 | + |
---|
| 581 | + nanddev_set_ecc_requirements(base, &requirements); |
---|
585 | 582 | } |
---|
586 | 583 | |
---|
587 | 584 | static void hynix_nand_extract_scrambling_requirements(struct nand_chip *chip, |
---|
.. | .. |
---|
590 | 587 | u8 nand_tech; |
---|
591 | 588 | |
---|
592 | 589 | /* We need scrambling on all TLC NANDs*/ |
---|
593 | | - if (chip->bits_per_cell > 2) |
---|
| 590 | + if (nanddev_bits_per_cell(&chip->base) > 2) |
---|
594 | 591 | chip->options |= NAND_NEED_SCRAMBLING; |
---|
595 | 592 | |
---|
596 | 593 | /* And on MLC NANDs with sub-3xnm process */ |
---|
.. | .. |
---|
612 | 609 | static void hynix_nand_decode_id(struct nand_chip *chip) |
---|
613 | 610 | { |
---|
614 | 611 | struct mtd_info *mtd = nand_to_mtd(chip); |
---|
| 612 | + struct nand_memory_organization *memorg; |
---|
615 | 613 | bool valid_jedecid; |
---|
616 | 614 | u8 tmp; |
---|
| 615 | + |
---|
| 616 | + memorg = nanddev_get_memorg(&chip->base); |
---|
617 | 617 | |
---|
618 | 618 | /* |
---|
619 | 619 | * Exclude all SLC NANDs from this advanced detection scheme. |
---|
.. | .. |
---|
628 | 628 | } |
---|
629 | 629 | |
---|
630 | 630 | /* Extract pagesize */ |
---|
631 | | - mtd->writesize = 2048 << (chip->id.data[3] & 0x03); |
---|
| 631 | + memorg->pagesize = 2048 << (chip->id.data[3] & 0x03); |
---|
| 632 | + mtd->writesize = memorg->pagesize; |
---|
632 | 633 | |
---|
633 | 634 | tmp = (chip->id.data[3] >> 4) & 0x3; |
---|
634 | 635 | /* |
---|
.. | .. |
---|
638 | 639 | * The only exception is when ID[3][4:5] == 3 and ID[3][7] == 0, in |
---|
639 | 640 | * this case the erasesize is set to 768KiB. |
---|
640 | 641 | */ |
---|
641 | | - if (chip->id.data[3] & 0x80) |
---|
| 642 | + if (chip->id.data[3] & 0x80) { |
---|
| 643 | + memorg->pages_per_eraseblock = (SZ_1M << tmp) / |
---|
| 644 | + memorg->pagesize; |
---|
642 | 645 | mtd->erasesize = SZ_1M << tmp; |
---|
643 | | - else if (tmp == 3) |
---|
| 646 | + } else if (tmp == 3) { |
---|
| 647 | + memorg->pages_per_eraseblock = (SZ_512K + SZ_256K) / |
---|
| 648 | + memorg->pagesize; |
---|
644 | 649 | mtd->erasesize = SZ_512K + SZ_256K; |
---|
645 | | - else |
---|
| 650 | + } else { |
---|
| 651 | + memorg->pages_per_eraseblock = (SZ_128K << tmp) / |
---|
| 652 | + memorg->pagesize; |
---|
646 | 653 | mtd->erasesize = SZ_128K << tmp; |
---|
| 654 | + } |
---|
647 | 655 | |
---|
648 | 656 | /* |
---|
649 | 657 | * Modern Toggle DDR NANDs have a valid JEDECID even though they are |
---|
.. | .. |
---|
669 | 677 | nand_set_manufacturer_data(chip, NULL); |
---|
670 | 678 | } |
---|
671 | 679 | |
---|
| 680 | +static int |
---|
| 681 | +h27ucg8t2atrbc_choose_interface_config(struct nand_chip *chip, |
---|
| 682 | + struct nand_interface_config *iface) |
---|
| 683 | +{ |
---|
| 684 | + onfi_fill_interface_config(chip, iface, NAND_SDR_IFACE, 4); |
---|
| 685 | + |
---|
| 686 | + return nand_choose_best_sdr_timings(chip, iface, NULL); |
---|
| 687 | +} |
---|
| 688 | + |
---|
672 | 689 | static int hynix_nand_init(struct nand_chip *chip) |
---|
673 | 690 | { |
---|
674 | 691 | struct hynix_nand *hynix; |
---|
675 | 692 | int ret; |
---|
676 | 693 | |
---|
677 | 694 | if (!nand_is_slc(chip)) |
---|
678 | | - chip->bbt_options |= NAND_BBT_SCANLASTPAGE; |
---|
| 695 | + chip->options |= NAND_BBM_LASTPAGE; |
---|
679 | 696 | else |
---|
680 | | - chip->bbt_options |= NAND_BBT_SCAN2NDPAGE; |
---|
| 697 | + chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE; |
---|
681 | 698 | |
---|
682 | 699 | hynix = kzalloc(sizeof(*hynix), GFP_KERNEL); |
---|
683 | 700 | if (!hynix) |
---|
.. | .. |
---|
685 | 702 | |
---|
686 | 703 | nand_set_manufacturer_data(chip, hynix); |
---|
687 | 704 | |
---|
| 705 | + if (!strncmp("H27UCG8T2ATR-BC", chip->parameters.model, |
---|
| 706 | + sizeof("H27UCG8T2ATR-BC") - 1)) |
---|
| 707 | + chip->ops.choose_interface_config = |
---|
| 708 | + h27ucg8t2atrbc_choose_interface_config; |
---|
| 709 | + |
---|
688 | 710 | ret = hynix_nand_rr_init(chip); |
---|
689 | 711 | if (ret) |
---|
690 | 712 | hynix_nand_cleanup(chip); |
---|