1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2020 Rockchip Electronics Co., Ltd 4 * 5 * Authors: 6 * Dingqiang Lin <jon.lin@rock-chips.com> 7 */ 8 9 #ifndef __UBOOT__ 10 #include <linux/device.h> 11 #include <linux/kernel.h> 12 #endif 13 #include <linux/mtd/spinand.h> 14 15 #define SPINAND_MFR_DOSILICON 0xE5 16 17 #define DOSICON_STATUS_ECC_MASK GENMASK(7, 4) 18 #define DOSICON_STATUS_ECC_NO_BITFLIPS (0 << 4) 19 #define DOSICON_STATUS_ECC_1TO3_BITFLIPS (1 << 4) 20 #define DOSICON_STATUS_ECC_4TO6_BITFLIPS (3 << 4) 21 #define DOSICON_STATUS_ECC_7TO8_BITFLIPS (5 << 4) 22 23 static SPINAND_OP_VARIANTS(read_cache_variants, 24 SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0), 25 SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), 26 SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), 27 SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), 28 SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), 29 SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); 30 31 static SPINAND_OP_VARIANTS(write_cache_variants, 32 SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), 33 SPINAND_PROG_LOAD(true, 0, NULL, 0)); 34 35 static SPINAND_OP_VARIANTS(update_cache_variants, 36 SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), 37 SPINAND_PROG_LOAD(false, 0, NULL, 0)); 38 39 static int ds35xxga_ooblayout_ecc(struct mtd_info *mtd, int section, 40 struct mtd_oob_region *region) 41 { 42 if (section > 3) 43 return -ERANGE; 44 45 region->offset = (16 * section) + 8; 46 region->length = 8; 47 48 return 0; 49 } 50 51 static int ds35xxga_ooblayout_free(struct mtd_info *mtd, int section, 52 struct mtd_oob_region *region) 53 { 54 if (section > 3) 55 return -ERANGE; 56 57 region->offset = (16 * section) + 2; 58 region->length = 6; 59 60 return 0; 61 } 62 63 static const struct mtd_ooblayout_ops ds35xxga_ooblayout = { 64 .ecc = ds35xxga_ooblayout_ecc, 65 .rfree = ds35xxga_ooblayout_free, 66 }; 67 68 static int ds35xxgb_ooblayout_ecc(struct mtd_info *mtd, int section, 69 struct mtd_oob_region *region) 70 { 71 if (section) 72 return -ERANGE; 73 74 region->offset = 64; 75 region->length = 64; 76 77 return 0; 78 } 79 80 static int ds35xxgb_ooblayout_free(struct mtd_info *mtd, int section, 81 struct mtd_oob_region *region) 82 { 83 if (section) 84 return -ERANGE; 85 86 /* Reserve 1 bytes for the BBM. */ 87 region->offset = 1; 88 region->length = 63; 89 90 return 0; 91 } 92 93 static const struct mtd_ooblayout_ops ds35xxgb_ooblayout = { 94 .ecc = ds35xxgb_ooblayout_ecc, 95 .rfree = ds35xxgb_ooblayout_free, 96 }; 97 98 static int ds35xxgb_ecc_get_status(struct spinand_device *spinand, 99 u8 status) 100 { 101 switch (status & DOSICON_STATUS_ECC_MASK) { 102 case STATUS_ECC_NO_BITFLIPS: 103 return 0; 104 105 case STATUS_ECC_UNCOR_ERROR: 106 return -EBADMSG; 107 108 case DOSICON_STATUS_ECC_1TO3_BITFLIPS: 109 return 3; 110 111 case DOSICON_STATUS_ECC_4TO6_BITFLIPS: 112 return 6; 113 114 case DOSICON_STATUS_ECC_7TO8_BITFLIPS: 115 return 8; 116 117 default: 118 break; 119 } 120 121 return -EINVAL; 122 } 123 124 static const struct spinand_info dosilicon_spinand_table[] = { 125 SPINAND_INFO("DS35X1GA", 126 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x71), 127 NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1), 128 NAND_ECCREQ(4, 512), 129 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 130 &write_cache_variants, 131 &update_cache_variants), 132 SPINAND_HAS_QE_BIT, 133 SPINAND_ECCINFO(&ds35xxga_ooblayout, NULL)), 134 SPINAND_INFO("DS35Q2GA", 135 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x72), 136 NAND_MEMORG(1, 2048, 64, 64, 2048, 2, 1, 1), 137 NAND_ECCREQ(4, 512), 138 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 139 &write_cache_variants, 140 &update_cache_variants), 141 SPINAND_HAS_QE_BIT, 142 SPINAND_ECCINFO(&ds35xxga_ooblayout, NULL)), 143 SPINAND_INFO("DS35M1GA", 144 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x21), 145 NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1), 146 NAND_ECCREQ(4, 512), 147 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 148 &write_cache_variants, 149 &update_cache_variants), 150 SPINAND_HAS_QE_BIT, 151 SPINAND_ECCINFO(&ds35xxga_ooblayout, NULL)), 152 SPINAND_INFO("DS35M2GA", 153 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x22), 154 NAND_MEMORG(1, 2048, 64, 64, 2048, 2, 1, 1), 155 NAND_ECCREQ(4, 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(&ds35xxga_ooblayout, NULL)), 161 SPINAND_INFO("DS35Q2GB", 162 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xF2), 163 NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 1), 164 NAND_ECCREQ(8, 512), 165 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 166 &write_cache_variants, 167 &update_cache_variants), 168 SPINAND_HAS_QE_BIT, 169 SPINAND_ECCINFO(&ds35xxgb_ooblayout, 170 ds35xxgb_ecc_get_status)), 171 SPINAND_INFO("DS35M1GB", 172 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xA1), 173 NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1), 174 NAND_ECCREQ(8, 512), 175 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 176 &write_cache_variants, 177 &update_cache_variants), 178 SPINAND_HAS_QE_BIT, 179 SPINAND_ECCINFO(&ds35xxgb_ooblayout, 180 ds35xxgb_ecc_get_status)), 181 SPINAND_INFO("DS35Q1GB", 182 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xF1), 183 NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1), 184 NAND_ECCREQ(8, 512), 185 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 186 &write_cache_variants, 187 &update_cache_variants), 188 SPINAND_HAS_QE_BIT, 189 SPINAND_ECCINFO(&ds35xxgb_ooblayout, 190 ds35xxgb_ecc_get_status)), 191 SPINAND_INFO("DS35Q4GM", 192 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xF4), 193 NAND_MEMORG(1, 2048, 128, 64, 4096, 2, 1, 1), 194 NAND_ECCREQ(8, 512), 195 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 196 &write_cache_variants, 197 &update_cache_variants), 198 SPINAND_HAS_QE_BIT, 199 SPINAND_ECCINFO(&ds35xxgb_ooblayout, 200 ds35xxgb_ecc_get_status)), 201 SPINAND_INFO("DS35Q12B", 202 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xF5), 203 NAND_MEMORG(1, 2048, 128, 64, 512, 1, 1, 1), 204 NAND_ECCREQ(8, 512), 205 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 206 &write_cache_variants, 207 &update_cache_variants), 208 SPINAND_HAS_QE_BIT, 209 SPINAND_ECCINFO(&ds35xxgb_ooblayout, 210 ds35xxgb_ecc_get_status)), 211 SPINAND_INFO("DS35M12B", 212 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xA5), 213 NAND_MEMORG(1, 2048, 128, 64, 512, 1, 1, 1), 214 NAND_ECCREQ(8, 512), 215 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 216 &write_cache_variants, 217 &update_cache_variants), 218 SPINAND_HAS_QE_BIT, 219 SPINAND_ECCINFO(&ds35xxgb_ooblayout, 220 ds35xxgb_ecc_get_status)), 221 }; 222 223 static const struct spinand_manufacturer_ops dosilicon_spinand_manuf_ops = { 224 }; 225 226 const struct spinand_manufacturer dosilicon_spinand_manufacturer = { 227 .id = SPINAND_MFR_DOSILICON, 228 .name = "dosilicon", 229 .chips = dosilicon_spinand_table, 230 .nchips = ARRAY_SIZE(dosilicon_spinand_table), 231 .ops = &dosilicon_spinand_manuf_ops, 232 }; 233