264 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Author:4 * Felix Matouschek <felix@matouschek.org>5 */6 7#include <linux/bitfield.h>8#include <linux/device.h>9#include <linux/kernel.h>10#include <linux/mtd/spinand.h>11 12#define SPINAND_MFR_XTX 0x0B13 14#define XT26G0XA_STATUS_ECC_MASK GENMASK(5, 2)15#define XT26G0XA_STATUS_ECC_NO_DETECTED (0 << 2)16#define XT26G0XA_STATUS_ECC_8_CORRECTED (3 << 4)17#define XT26G0XA_STATUS_ECC_UNCOR_ERROR (2 << 4)18 19#define XT26XXXD_STATUS_ECC3_ECC2_MASK GENMASK(7, 6)20#define XT26XXXD_STATUS_ECC_NO_DETECTED (0)21#define XT26XXXD_STATUS_ECC_1_7_CORRECTED (1)22#define XT26XXXD_STATUS_ECC_8_CORRECTED (3)23#define XT26XXXD_STATUS_ECC_UNCOR_ERROR (2)24 25static SPINAND_OP_VARIANTS(read_cache_variants,26 SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),27 SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),28 SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),29 SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),30 SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),31 SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));32 33static SPINAND_OP_VARIANTS(write_cache_variants,34 SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),35 SPINAND_PROG_LOAD(true, 0, NULL, 0));36 37static SPINAND_OP_VARIANTS(update_cache_variants,38 SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),39 SPINAND_PROG_LOAD(false, 0, NULL, 0));40 41static int xt26g0xa_ooblayout_ecc(struct mtd_info *mtd, int section,42 struct mtd_oob_region *region)43{44 if (section)45 return -ERANGE;46 47 region->offset = 48;48 region->length = 16;49 50 return 0;51}52 53static int xt26g0xa_ooblayout_free(struct mtd_info *mtd, int section,54 struct mtd_oob_region *region)55{56 if (section)57 return -ERANGE;58 59 region->offset = 1;60 region->length = 47;61 62 return 0;63}64 65static const struct mtd_ooblayout_ops xt26g0xa_ooblayout = {66 .ecc = xt26g0xa_ooblayout_ecc,67 .free = xt26g0xa_ooblayout_free,68};69 70static int xt26g0xa_ecc_get_status(struct spinand_device *spinand,71 u8 status)72{73 status = status & XT26G0XA_STATUS_ECC_MASK;74 75 switch (status) {76 case XT26G0XA_STATUS_ECC_NO_DETECTED:77 return 0;78 case XT26G0XA_STATUS_ECC_8_CORRECTED:79 return 8;80 case XT26G0XA_STATUS_ECC_UNCOR_ERROR:81 return -EBADMSG;82 default:83 break;84 }85 86 /* At this point values greater than (2 << 4) are invalid */87 if (status > XT26G0XA_STATUS_ECC_UNCOR_ERROR)88 return -EINVAL;89 90 /* (1 << 2) through (7 << 2) are 1-7 corrected errors */91 return status >> 2;92}93 94static int xt26xxxd_ooblayout_ecc(struct mtd_info *mtd, int section,95 struct mtd_oob_region *region)96{97 if (section)98 return -ERANGE;99 100 region->offset = mtd->oobsize / 2;101 region->length = mtd->oobsize / 2;102 103 return 0;104}105 106static int xt26xxxd_ooblayout_free(struct mtd_info *mtd, int section,107 struct mtd_oob_region *region)108{109 if (section)110 return -ERANGE;111 112 region->offset = 2;113 region->length = mtd->oobsize / 2 - 2;114 115 return 0;116}117 118static const struct mtd_ooblayout_ops xt26xxxd_ooblayout = {119 .ecc = xt26xxxd_ooblayout_ecc,120 .free = xt26xxxd_ooblayout_free,121};122 123static int xt26xxxd_ecc_get_status(struct spinand_device *spinand,124 u8 status)125{126 switch (FIELD_GET(STATUS_ECC_MASK, status)) {127 case XT26XXXD_STATUS_ECC_NO_DETECTED:128 return 0;129 case XT26XXXD_STATUS_ECC_UNCOR_ERROR:130 return -EBADMSG;131 case XT26XXXD_STATUS_ECC_1_7_CORRECTED:132 return 4 + FIELD_GET(XT26XXXD_STATUS_ECC3_ECC2_MASK, status);133 case XT26XXXD_STATUS_ECC_8_CORRECTED:134 return 8;135 default:136 break;137 }138 139 return -EINVAL;140}141static const struct spinand_info xtx_spinand_table[] = {142 SPINAND_INFO("XT26G01A",143 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xE1),144 NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),145 NAND_ECCREQ(8, 512),146 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,147 &write_cache_variants,148 &update_cache_variants),149 SPINAND_HAS_QE_BIT,150 SPINAND_ECCINFO(&xt26g0xa_ooblayout,151 xt26g0xa_ecc_get_status)),152 SPINAND_INFO("XT26G02A",153 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xE2),154 NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),155 NAND_ECCREQ(8, 512),156 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,157 &write_cache_variants,158 &update_cache_variants),159 SPINAND_HAS_QE_BIT,160 SPINAND_ECCINFO(&xt26g0xa_ooblayout,161 xt26g0xa_ecc_get_status)),162 SPINAND_INFO("XT26G04A",163 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xE3),164 NAND_MEMORG(1, 2048, 64, 128, 2048, 40, 1, 1, 1),165 NAND_ECCREQ(8, 512),166 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,167 &write_cache_variants,168 &update_cache_variants),169 SPINAND_HAS_QE_BIT,170 SPINAND_ECCINFO(&xt26g0xa_ooblayout,171 xt26g0xa_ecc_get_status)),172 SPINAND_INFO("XT26G01D",173 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x31),174 NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),175 NAND_ECCREQ(8, 512),176 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,177 &write_cache_variants,178 &update_cache_variants),179 0,180 SPINAND_ECCINFO(&xt26xxxd_ooblayout,181 xt26xxxd_ecc_get_status)),182 SPINAND_INFO("XT26G11D",183 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x34),184 NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),185 NAND_ECCREQ(8, 512),186 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,187 &write_cache_variants,188 &update_cache_variants),189 0,190 SPINAND_ECCINFO(&xt26xxxd_ooblayout,191 xt26xxxd_ecc_get_status)),192 SPINAND_INFO("XT26Q01D",193 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x51),194 NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),195 NAND_ECCREQ(8, 512),196 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,197 &write_cache_variants,198 &update_cache_variants),199 0,200 SPINAND_ECCINFO(&xt26xxxd_ooblayout,201 xt26xxxd_ecc_get_status)),202 SPINAND_INFO("XT26G02D",203 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x32),204 NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),205 NAND_ECCREQ(8, 512),206 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,207 &write_cache_variants,208 &update_cache_variants),209 0,210 SPINAND_ECCINFO(&xt26xxxd_ooblayout,211 xt26xxxd_ecc_get_status)),212 SPINAND_INFO("XT26G12D",213 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x35),214 NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),215 NAND_ECCREQ(8, 512),216 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,217 &write_cache_variants,218 &update_cache_variants),219 0,220 SPINAND_ECCINFO(&xt26xxxd_ooblayout,221 xt26xxxd_ecc_get_status)),222 SPINAND_INFO("XT26Q02D",223 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x52),224 NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),225 NAND_ECCREQ(8, 512),226 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,227 &write_cache_variants,228 &update_cache_variants),229 0,230 SPINAND_ECCINFO(&xt26xxxd_ooblayout,231 xt26xxxd_ecc_get_status)),232 SPINAND_INFO("XT26G04D",233 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x33),234 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),235 NAND_ECCREQ(8, 512),236 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,237 &write_cache_variants,238 &update_cache_variants),239 0,240 SPINAND_ECCINFO(&xt26xxxd_ooblayout,241 xt26xxxd_ecc_get_status)),242 SPINAND_INFO("XT26Q04D",243 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x53),244 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),245 NAND_ECCREQ(8, 512),246 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,247 &write_cache_variants,248 &update_cache_variants),249 0,250 SPINAND_ECCINFO(&xt26xxxd_ooblayout,251 xt26xxxd_ecc_get_status)),252};253 254static const struct spinand_manufacturer_ops xtx_spinand_manuf_ops = {255};256 257const struct spinand_manufacturer xtx_spinand_manufacturer = {258 .id = SPINAND_MFR_XTX,259 .name = "XTX",260 .chips = xtx_spinand_table,261 .nchips = ARRAY_SIZE(xtx_spinand_table),262 .ops = &xtx_spinand_manuf_ops,263};264