1 // SPDX-License-Identifier: (GPL-2.0+ OR MIT) 2 /* 3 * Copyright (c) 2021 Rockchip Electronics Co., Ltd. 4 */ 5 6 #ifndef __UBOOT__ 7 #include <linux/device.h> 8 #include <linux/kernel.h> 9 #endif 10 #include <linux/mtd/spinand.h> 11 12 #define SPINAND_MFR_ETRON 0xD5 13 14 static SPINAND_OP_VARIANTS(read_cache_variants, 15 SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0), 16 SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), 17 SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), 18 SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), 19 SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), 20 SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); 21 22 static SPINAND_OP_VARIANTS(write_cache_variants, 23 SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), 24 SPINAND_PROG_LOAD(true, 0, NULL, 0)); 25 26 static SPINAND_OP_VARIANTS(update_cache_variants, 27 SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), 28 SPINAND_PROG_LOAD(false, 0, NULL, 0)); 29 30 static int em73c044vcf_oh_ooblayout_ecc(struct mtd_info *mtd, int section, 31 struct mtd_oob_region *region) 32 { 33 if (section > 3) 34 return -ERANGE; 35 36 region->offset = (16 * section) + 8; 37 region->length = 8; 38 39 return 0; 40 } 41 42 static int em73c044vcf_oh_ooblayout_free(struct mtd_info *mtd, int section, 43 struct mtd_oob_region *region) 44 { 45 if (section > 3) 46 return -ERANGE; 47 48 region->offset = (16 * section) + 2; 49 region->length = 6; 50 51 return 0; 52 } 53 54 static const struct mtd_ooblayout_ops em73c044vcf_oh_ooblayout = { 55 .ecc = em73c044vcf_oh_ooblayout_ecc, 56 .rfree = em73c044vcf_oh_ooblayout_free, 57 }; 58 59 static int em73c044vcf_oh_ecc_get_status(struct spinand_device *spinand, 60 u8 status) 61 { 62 struct nand_device *nand = spinand_to_nand(spinand); 63 64 switch (status & STATUS_ECC_MASK) { 65 case STATUS_ECC_NO_BITFLIPS: 66 return 0; 67 68 case STATUS_ECC_UNCOR_ERROR: 69 return -EBADMSG; 70 71 case STATUS_ECC_HAS_BITFLIPS: 72 return 1; 73 74 default: 75 return nand->eccreq.strength; 76 } 77 78 return -EINVAL; 79 } 80 81 static const struct spinand_info etron_spinand_table[] = { 82 SPINAND_INFO("EM73C044VCF-0H", 83 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x36), 84 NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1), 85 NAND_ECCREQ(4, 512), 86 SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 87 &write_cache_variants, 88 &update_cache_variants), 89 SPINAND_HAS_QE_BIT, 90 SPINAND_ECCINFO(&em73c044vcf_oh_ooblayout, 91 em73c044vcf_oh_ecc_get_status)), 92 }; 93 94 static const struct spinand_manufacturer_ops etron_spinand_manuf_ops = { 95 }; 96 97 const struct spinand_manufacturer etron_spinand_manufacturer = { 98 .id = SPINAND_MFR_ETRON, 99 .name = "Etron", 100 .chips = etron_spinand_table, 101 .nchips = ARRAY_SIZE(etron_spinand_table), 102 .ops = &etron_spinand_manuf_ops, 103 }; 104