152b00601SJon Lin // SPDX-License-Identifier: GPL-2.0
252b00601SJon Lin /*
352b00601SJon Lin * Copyright (c) 2020 Grandstream Networks, Inc
452b00601SJon Lin *
552b00601SJon Lin * Authors:
652b00601SJon Lin * Carl <xjxia@grandstream.cn>
752b00601SJon Lin */
852b00601SJon Lin
952b00601SJon Lin #ifndef __UBOOT__
1052b00601SJon Lin #include <linux/device.h>
1152b00601SJon Lin #include <linux/kernel.h>
1252b00601SJon Lin #endif
1352b00601SJon Lin #include <linux/mtd/spinand.h>
1452b00601SJon Lin
1552b00601SJon Lin #define SPINAND_MFR_ESMT 0xC8
1652b00601SJon Lin
1752b00601SJon Lin static SPINAND_OP_VARIANTS(read_cache_variants,
1852b00601SJon Lin SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
1952b00601SJon Lin SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
2052b00601SJon Lin SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
2152b00601SJon Lin SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
2252b00601SJon Lin SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
2352b00601SJon Lin SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
2452b00601SJon Lin
2552b00601SJon Lin static SPINAND_OP_VARIANTS(write_cache_variants,
2652b00601SJon Lin SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
2752b00601SJon Lin SPINAND_PROG_LOAD(true, 0, NULL, 0));
2852b00601SJon Lin
2952b00601SJon Lin static SPINAND_OP_VARIANTS(update_cache_variants,
3052b00601SJon Lin SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
3152b00601SJon Lin SPINAND_PROG_LOAD(false, 0, NULL, 0));
3252b00601SJon Lin
f50lxx41x_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)3352b00601SJon Lin static int f50lxx41x_ooblayout_ecc(struct mtd_info *mtd, int section,
3452b00601SJon Lin struct mtd_oob_region *region)
3552b00601SJon Lin {
3652b00601SJon Lin if (section > 3)
3752b00601SJon Lin return -ERANGE;
3852b00601SJon Lin
3952b00601SJon Lin region->offset = (16 * section) + 8;
4052b00601SJon Lin region->length = 8;
4152b00601SJon Lin
4252b00601SJon Lin return 0;
4352b00601SJon Lin }
4452b00601SJon Lin
f50lxx41x_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)4552b00601SJon Lin static int f50lxx41x_ooblayout_free(struct mtd_info *mtd, int section,
4652b00601SJon Lin struct mtd_oob_region *region)
4752b00601SJon Lin {
4852b00601SJon Lin if (section > 3)
4952b00601SJon Lin return -ERANGE;
5052b00601SJon Lin
5152b00601SJon Lin region->offset = (16 * section) + 2;
5252b00601SJon Lin region->length = 6;
5352b00601SJon Lin
5452b00601SJon Lin return 0;
5552b00601SJon Lin }
5652b00601SJon Lin
5752b00601SJon Lin static const struct mtd_ooblayout_ops f50lxx41x_ooblayout = {
5852b00601SJon Lin .ecc = f50lxx41x_ooblayout_ecc,
5952b00601SJon Lin .rfree = f50lxx41x_ooblayout_free,
6052b00601SJon Lin };
6152b00601SJon Lin
f50l2g41ka_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)62*fb6306edSJon Lin static int f50l2g41ka_ooblayout_ecc(struct mtd_info *mtd, int section,
63*fb6306edSJon Lin struct mtd_oob_region *region)
64*fb6306edSJon Lin {
65*fb6306edSJon Lin if (section)
66*fb6306edSJon Lin return -ERANGE;
67*fb6306edSJon Lin
68*fb6306edSJon Lin region->offset = mtd->oobsize / 2;
69*fb6306edSJon Lin region->length = mtd->oobsize / 2;
70*fb6306edSJon Lin
71*fb6306edSJon Lin return 0;
72*fb6306edSJon Lin }
73*fb6306edSJon Lin
f50l2g41ka_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)74*fb6306edSJon Lin static int f50l2g41ka_ooblayout_free(struct mtd_info *mtd, int section,
75*fb6306edSJon Lin struct mtd_oob_region *region)
76*fb6306edSJon Lin {
77*fb6306edSJon Lin if (section)
78*fb6306edSJon Lin return -ERANGE;
79*fb6306edSJon Lin
80*fb6306edSJon Lin region->offset = 2;
81*fb6306edSJon Lin region->length = mtd->oobsize / 2 - 2;
82*fb6306edSJon Lin
83*fb6306edSJon Lin return 0;
84*fb6306edSJon Lin }
85*fb6306edSJon Lin
86*fb6306edSJon Lin static const struct mtd_ooblayout_ops f50l2g41ka_ooblayout = {
87*fb6306edSJon Lin .ecc = f50l2g41ka_ooblayout_ecc,
88*fb6306edSJon Lin .rfree = f50l2g41ka_ooblayout_free,
89*fb6306edSJon Lin };
90*fb6306edSJon Lin
91*fb6306edSJon Lin /*
92*fb6306edSJon Lin * ecc bits: 0xC0[4,6]
93*fb6306edSJon Lin * [0b000], No bit errors were detected;
94*fb6306edSJon Lin * [0b001] and [0b011], 1~6 Bit errors were detected and corrected. Not
95*fb6306edSJon Lin * reach Flipping Bits;
96*fb6306edSJon Lin * [0b101], Bit error count equals the bit flip
97*fb6306edSJon Lin * detection threshold
98*fb6306edSJon Lin * [0b010], Multiple bit errors were detected and
99*fb6306edSJon Lin * not corrected.
100*fb6306edSJon Lin * others, Reserved.
101*fb6306edSJon Lin */
f50l2g41ka_ecc_ecc_get_status(struct spinand_device * spinand,u8 status)102*fb6306edSJon Lin static int f50l2g41ka_ecc_ecc_get_status(struct spinand_device *spinand,
103*fb6306edSJon Lin u8 status)
104*fb6306edSJon Lin {
105*fb6306edSJon Lin struct nand_device *nand = spinand_to_nand(spinand);
106*fb6306edSJon Lin u8 eccsr = (status & GENMASK(6, 4)) >> 4;
107*fb6306edSJon Lin
108*fb6306edSJon Lin if (eccsr <= 1 || eccsr == 3)
109*fb6306edSJon Lin return eccsr;
110*fb6306edSJon Lin else if (eccsr == 5)
111*fb6306edSJon Lin return nand->eccreq.strength;
112*fb6306edSJon Lin else
113*fb6306edSJon Lin return -EBADMSG;
114*fb6306edSJon Lin }
115*fb6306edSJon Lin
11652b00601SJon Lin static const struct spinand_info esmt_spinand_table[] = {
11781afcfe1SJon Lin SPINAND_INFO("F50L1G41LB",
11881afcfe1SJon Lin SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x01),
11952b00601SJon Lin NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
12052b00601SJon Lin NAND_ECCREQ(1, 512),
12152b00601SJon Lin SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
12252b00601SJon Lin &write_cache_variants,
12352b00601SJon Lin &update_cache_variants),
12452b00601SJon Lin 0,
12552b00601SJon Lin SPINAND_ECCINFO(&f50lxx41x_ooblayout, NULL)),
126*fb6306edSJon Lin SPINAND_INFO("F50L2G41KA",
127*fb6306edSJon Lin SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x41, 0x7F),
128*fb6306edSJon Lin NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
129*fb6306edSJon Lin NAND_ECCREQ(8, 512),
130*fb6306edSJon Lin SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
131*fb6306edSJon Lin &write_cache_variants,
132*fb6306edSJon Lin &update_cache_variants),
133*fb6306edSJon Lin 0,
134*fb6306edSJon Lin SPINAND_ECCINFO(&f50l2g41ka_ooblayout, f50l2g41ka_ecc_ecc_get_status)),
13552b00601SJon Lin };
13652b00601SJon Lin
13752b00601SJon Lin static const struct spinand_manufacturer_ops esmt_spinand_manuf_ops = {
13852b00601SJon Lin };
13952b00601SJon Lin
14052b00601SJon Lin const struct spinand_manufacturer esmt_spinand_manufacturer = {
14152b00601SJon Lin .id = SPINAND_MFR_ESMT,
14252b00601SJon Lin .name = "esmt",
14381afcfe1SJon Lin .chips = esmt_spinand_table,
14481afcfe1SJon Lin .nchips = ARRAY_SIZE(esmt_spinand_table),
14552b00601SJon Lin .ops = &esmt_spinand_manuf_ops,
14652b00601SJon Lin };
147