11a50e361STakahiro Kuwano // SPDX-License-Identifier: GPL-2.0 21a50e361STakahiro Kuwano /* 31a50e361STakahiro Kuwano * Copyright (c) 2024 SkyHigh Memory Limited 41a50e361STakahiro Kuwano * 51a50e361STakahiro Kuwano * Author: Takahiro Kuwano <takahiro.kuwano@infineon.com> 61a50e361STakahiro Kuwano * Co-Author: KR Kim <kr.kim@skyhighmemory.com> 71a50e361STakahiro Kuwano */ 81a50e361STakahiro Kuwano 91a50e361STakahiro Kuwano #include <linux/device.h> 101a50e361STakahiro Kuwano #include <linux/kernel.h> 111a50e361STakahiro Kuwano #include <linux/mtd/spinand.h> 121a50e361STakahiro Kuwano 131a50e361STakahiro Kuwano #define SPINAND_MFR_SKYHIGH 0x01 141a50e361STakahiro Kuwano #define SKYHIGH_STATUS_ECC_1TO2_BITFLIPS (1 << 4) 151a50e361STakahiro Kuwano #define SKYHIGH_STATUS_ECC_3TO6_BITFLIPS (2 << 4) 161a50e361STakahiro Kuwano #define SKYHIGH_STATUS_ECC_UNCOR_ERROR (3 << 4) 171a50e361STakahiro Kuwano #define SKYHIGH_CONFIG_PROTECT_EN BIT(1) 181a50e361STakahiro Kuwano 191a50e361STakahiro Kuwano static SPINAND_OP_VARIANTS(read_cache_variants, 201a50e361STakahiro Kuwano SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 4, NULL, 0), 211a50e361STakahiro Kuwano SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), 221a50e361STakahiro Kuwano SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 2, NULL, 0), 231a50e361STakahiro Kuwano SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), 24*98b34d52SMiquel Raynal SPINAND_PAGE_READ_FROM_CACHE_FAST_OP(0, 1, NULL, 0), 25*98b34d52SMiquel Raynal SPINAND_PAGE_READ_FROM_CACHE_OP(0, 1, NULL, 0)); 261a50e361STakahiro Kuwano 271a50e361STakahiro Kuwano static SPINAND_OP_VARIANTS(write_cache_variants, 281a50e361STakahiro Kuwano SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), 291a50e361STakahiro Kuwano SPINAND_PROG_LOAD(true, 0, NULL, 0)); 301a50e361STakahiro Kuwano 311a50e361STakahiro Kuwano static SPINAND_OP_VARIANTS(update_cache_variants, 321a50e361STakahiro Kuwano SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), 331a50e361STakahiro Kuwano SPINAND_PROG_LOAD(false, 0, NULL, 0)); 341a50e361STakahiro Kuwano 351a50e361STakahiro Kuwano static int skyhigh_spinand_ooblayout_ecc(struct mtd_info *mtd, int section, 361a50e361STakahiro Kuwano struct mtd_oob_region *region) 371a50e361STakahiro Kuwano { 381a50e361STakahiro Kuwano /* ECC bytes are stored in hidden area. */ 391a50e361STakahiro Kuwano return -ERANGE; 401a50e361STakahiro Kuwano } 411a50e361STakahiro Kuwano 421a50e361STakahiro Kuwano static int skyhigh_spinand_ooblayout_free(struct mtd_info *mtd, int section, 431a50e361STakahiro Kuwano struct mtd_oob_region *region) 441a50e361STakahiro Kuwano { 451a50e361STakahiro Kuwano if (section) 461a50e361STakahiro Kuwano return -ERANGE; 471a50e361STakahiro Kuwano 481a50e361STakahiro Kuwano /* ECC bytes are stored in hidden area. Reserve 2 bytes for the BBM. */ 491a50e361STakahiro Kuwano region->offset = 2; 501a50e361STakahiro Kuwano region->length = mtd->oobsize - 2; 511a50e361STakahiro Kuwano 521a50e361STakahiro Kuwano return 0; 531a50e361STakahiro Kuwano } 541a50e361STakahiro Kuwano 551a50e361STakahiro Kuwano static const struct mtd_ooblayout_ops skyhigh_spinand_ooblayout = { 561a50e361STakahiro Kuwano .ecc = skyhigh_spinand_ooblayout_ecc, 571a50e361STakahiro Kuwano .free = skyhigh_spinand_ooblayout_free, 581a50e361STakahiro Kuwano }; 591a50e361STakahiro Kuwano 601a50e361STakahiro Kuwano static int skyhigh_spinand_ecc_get_status(struct spinand_device *spinand, 611a50e361STakahiro Kuwano u8 status) 621a50e361STakahiro Kuwano { 631a50e361STakahiro Kuwano switch (status & STATUS_ECC_MASK) { 641a50e361STakahiro Kuwano case STATUS_ECC_NO_BITFLIPS: 651a50e361STakahiro Kuwano return 0; 661a50e361STakahiro Kuwano 671a50e361STakahiro Kuwano case SKYHIGH_STATUS_ECC_UNCOR_ERROR: 681a50e361STakahiro Kuwano return -EBADMSG; 691a50e361STakahiro Kuwano 701a50e361STakahiro Kuwano case SKYHIGH_STATUS_ECC_1TO2_BITFLIPS: 711a50e361STakahiro Kuwano return 2; 721a50e361STakahiro Kuwano 731a50e361STakahiro Kuwano case SKYHIGH_STATUS_ECC_3TO6_BITFLIPS: 741a50e361STakahiro Kuwano return 6; 751a50e361STakahiro Kuwano 761a50e361STakahiro Kuwano default: 771a50e361STakahiro Kuwano break; 781a50e361STakahiro Kuwano } 791a50e361STakahiro Kuwano 801a50e361STakahiro Kuwano return -EINVAL; 811a50e361STakahiro Kuwano } 821a50e361STakahiro Kuwano 831a50e361STakahiro Kuwano static const struct spinand_info skyhigh_spinand_table[] = { 841a50e361STakahiro Kuwano SPINAND_INFO("S35ML01G301", 851a50e361STakahiro Kuwano SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x15), 861a50e361STakahiro Kuwano NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), 871a50e361STakahiro Kuwano NAND_ECCREQ(6, 32), 881a50e361STakahiro Kuwano SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 891a50e361STakahiro Kuwano &write_cache_variants, 901a50e361STakahiro Kuwano &update_cache_variants), 911a50e361STakahiro Kuwano SPINAND_NO_RAW_ACCESS, 921a50e361STakahiro Kuwano SPINAND_ECCINFO(&skyhigh_spinand_ooblayout, 931a50e361STakahiro Kuwano skyhigh_spinand_ecc_get_status)), 941a50e361STakahiro Kuwano SPINAND_INFO("S35ML01G300", 951a50e361STakahiro Kuwano SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14), 961a50e361STakahiro Kuwano NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), 971a50e361STakahiro Kuwano NAND_ECCREQ(6, 32), 981a50e361STakahiro Kuwano SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 991a50e361STakahiro Kuwano &write_cache_variants, 1001a50e361STakahiro Kuwano &update_cache_variants), 1011a50e361STakahiro Kuwano SPINAND_NO_RAW_ACCESS, 1021a50e361STakahiro Kuwano SPINAND_ECCINFO(&skyhigh_spinand_ooblayout, 1031a50e361STakahiro Kuwano skyhigh_spinand_ecc_get_status)), 1041a50e361STakahiro Kuwano SPINAND_INFO("S35ML02G300", 1051a50e361STakahiro Kuwano SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x25), 1061a50e361STakahiro Kuwano NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1), 1071a50e361STakahiro Kuwano NAND_ECCREQ(6, 32), 1081a50e361STakahiro Kuwano SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 1091a50e361STakahiro Kuwano &write_cache_variants, 1101a50e361STakahiro Kuwano &update_cache_variants), 1111a50e361STakahiro Kuwano SPINAND_NO_RAW_ACCESS, 1121a50e361STakahiro Kuwano SPINAND_ECCINFO(&skyhigh_spinand_ooblayout, 1131a50e361STakahiro Kuwano skyhigh_spinand_ecc_get_status)), 1141a50e361STakahiro Kuwano SPINAND_INFO("S35ML04G300", 1151a50e361STakahiro Kuwano SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35), 1161a50e361STakahiro Kuwano NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 2, 1, 1), 1171a50e361STakahiro Kuwano NAND_ECCREQ(6, 32), 1181a50e361STakahiro Kuwano SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 1191a50e361STakahiro Kuwano &write_cache_variants, 1201a50e361STakahiro Kuwano &update_cache_variants), 1211a50e361STakahiro Kuwano SPINAND_NO_RAW_ACCESS, 1221a50e361STakahiro Kuwano SPINAND_ECCINFO(&skyhigh_spinand_ooblayout, 1231a50e361STakahiro Kuwano skyhigh_spinand_ecc_get_status)), 1241a50e361STakahiro Kuwano }; 1251a50e361STakahiro Kuwano 1261a50e361STakahiro Kuwano static int skyhigh_spinand_init(struct spinand_device *spinand) 1271a50e361STakahiro Kuwano { 1281a50e361STakahiro Kuwano /* 1291a50e361STakahiro Kuwano * Config_Protect_En (bit 1 in Block Lock register) must be set to 1 1301a50e361STakahiro Kuwano * before writing other bits. Do it here before core unlocks all blocks 1311a50e361STakahiro Kuwano * by writing block protection bits. 1321a50e361STakahiro Kuwano */ 1331a50e361STakahiro Kuwano return spinand_write_reg_op(spinand, REG_BLOCK_LOCK, 1341a50e361STakahiro Kuwano SKYHIGH_CONFIG_PROTECT_EN); 1351a50e361STakahiro Kuwano } 1361a50e361STakahiro Kuwano 1371a50e361STakahiro Kuwano static const struct spinand_manufacturer_ops skyhigh_spinand_manuf_ops = { 1381a50e361STakahiro Kuwano .init = skyhigh_spinand_init, 1391a50e361STakahiro Kuwano }; 1401a50e361STakahiro Kuwano 1411a50e361STakahiro Kuwano const struct spinand_manufacturer skyhigh_spinand_manufacturer = { 1421a50e361STakahiro Kuwano .id = SPINAND_MFR_SKYHIGH, 1431a50e361STakahiro Kuwano .name = "SkyHigh", 1441a50e361STakahiro Kuwano .chips = skyhigh_spinand_table, 1451a50e361STakahiro Kuwano .nchips = ARRAY_SIZE(skyhigh_spinand_table), 1461a50e361STakahiro Kuwano .ops = &skyhigh_spinand_manuf_ops, 1471a50e361STakahiro Kuwano }; 148