1da9bb89bSJon Lin // SPDX-License-Identifier: GPL-2.0
2da9bb89bSJon Lin /*
3da9bb89bSJon Lin * Copyright (c) 2021 Rockchip Electronics Co., Ltd
4da9bb89bSJon Lin *
5da9bb89bSJon Lin * Authors:
6da9bb89bSJon Lin * Dingqiang Lin <jon.lin@rock-chips.com>
7da9bb89bSJon Lin */
8da9bb89bSJon Lin
9da9bb89bSJon Lin #ifndef __UBOOT__
10da9bb89bSJon Lin #include <linux/device.h>
11da9bb89bSJon Lin #include <linux/kernel.h>
12da9bb89bSJon Lin #endif
13da9bb89bSJon Lin #include <linux/mtd/spinand.h>
14da9bb89bSJon Lin
15da9bb89bSJon Lin #define SPINAND_MFR_JSC 0xBF
16da9bb89bSJon Lin
17da9bb89bSJon Lin static SPINAND_OP_VARIANTS(read_cache_variants,
18da9bb89bSJon Lin SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
19da9bb89bSJon Lin SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
20da9bb89bSJon Lin SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
21da9bb89bSJon Lin SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
22da9bb89bSJon Lin SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
23da9bb89bSJon Lin SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
24da9bb89bSJon Lin
25da9bb89bSJon Lin static SPINAND_OP_VARIANTS(write_cache_variants,
26da9bb89bSJon Lin SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
27da9bb89bSJon Lin SPINAND_PROG_LOAD(true, 0, NULL, 0));
28da9bb89bSJon Lin
29da9bb89bSJon Lin static SPINAND_OP_VARIANTS(update_cache_variants,
30da9bb89bSJon Lin SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
31da9bb89bSJon Lin SPINAND_PROG_LOAD(false, 0, NULL, 0));
32da9bb89bSJon Lin
js28u1gqscahg_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)33da9bb89bSJon Lin static int js28u1gqscahg_ooblayout_ecc(struct mtd_info *mtd, int section,
34da9bb89bSJon Lin struct mtd_oob_region *region)
35da9bb89bSJon Lin {
36da9bb89bSJon Lin if (section)
37da9bb89bSJon Lin return -ERANGE;
38da9bb89bSJon Lin
39da9bb89bSJon Lin region->offset = mtd->oobsize / 2;
40da9bb89bSJon Lin region->length = mtd->oobsize / 2;
41da9bb89bSJon Lin
42da9bb89bSJon Lin return 0;
43da9bb89bSJon Lin }
44da9bb89bSJon Lin
js28u1gqscahg_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)45da9bb89bSJon Lin static int js28u1gqscahg_ooblayout_free(struct mtd_info *mtd, int section,
46da9bb89bSJon Lin struct mtd_oob_region *region)
47da9bb89bSJon Lin {
48da9bb89bSJon Lin if (section)
49da9bb89bSJon Lin return -ERANGE;
50da9bb89bSJon Lin
51da9bb89bSJon Lin /* Reserve 2 bytes for the BBM. */
52da9bb89bSJon Lin region->offset = 2;
53da9bb89bSJon Lin region->length = mtd->oobsize / 2 - 2;
54da9bb89bSJon Lin
55da9bb89bSJon Lin return 0;
56da9bb89bSJon Lin }
57da9bb89bSJon Lin
58da9bb89bSJon Lin static const struct mtd_ooblayout_ops js28u1gqscahg_ooblayout = {
59da9bb89bSJon Lin .ecc = js28u1gqscahg_ooblayout_ecc,
60da9bb89bSJon Lin .rfree = js28u1gqscahg_ooblayout_free,
61da9bb89bSJon Lin };
62da9bb89bSJon Lin
63da9bb89bSJon Lin /*
64da9bb89bSJon Lin * ecc bits: 0xC0[4,6]
65da9bb89bSJon Lin * [0b000], No bit errors were detected;
66da9bb89bSJon Lin * [0b001, 0b011], 1~3 Bit errors were detected and corrected. Not
67da9bb89bSJon Lin * reach Flipping Bits;
68da9bb89bSJon Lin * [0b100], Bit error count equals the bit flip
69da9bb89bSJon Lin * detection threshold
70da9bb89bSJon Lin * others, Reserved.
71da9bb89bSJon Lin */
js28u1gqscahg_ecc_get_status(struct spinand_device * spinand,u8 status)72da9bb89bSJon Lin static int js28u1gqscahg_ecc_get_status(struct spinand_device *spinand,
73da9bb89bSJon Lin u8 status)
74da9bb89bSJon Lin {
75*ed68cf16SJon Lin struct nand_device *nand = spinand_to_nand(spinand);
76*ed68cf16SJon Lin u8 eccsr = (status & GENMASK(6, 4)) >> 4;
77da9bb89bSJon Lin
78*ed68cf16SJon Lin if (eccsr < 4)
79da9bb89bSJon Lin return eccsr;
80*ed68cf16SJon Lin else if (eccsr == 4)
81*ed68cf16SJon Lin return nand->eccreq.strength;
82da9bb89bSJon Lin else
83da9bb89bSJon Lin return -EBADMSG;
84da9bb89bSJon Lin }
85da9bb89bSJon Lin
86da9bb89bSJon Lin static const struct spinand_info jsc_spinand_table[] = {
8781afcfe1SJon Lin SPINAND_INFO("JS28U1GQSCAHG-83",
8881afcfe1SJon Lin SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x21),
89da9bb89bSJon Lin NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
90da9bb89bSJon Lin NAND_ECCREQ(4, 512),
91da9bb89bSJon Lin SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
92da9bb89bSJon Lin &write_cache_variants,
93da9bb89bSJon Lin &update_cache_variants),
94da9bb89bSJon Lin SPINAND_HAS_QE_BIT,
95da9bb89bSJon Lin SPINAND_ECCINFO(&js28u1gqscahg_ooblayout, js28u1gqscahg_ecc_get_status)),
96da9bb89bSJon Lin };
97da9bb89bSJon Lin
98da9bb89bSJon Lin static const struct spinand_manufacturer_ops jsc_spinand_manuf_ops = {
99da9bb89bSJon Lin };
100da9bb89bSJon Lin
101da9bb89bSJon Lin const struct spinand_manufacturer jsc_spinand_manufacturer = {
102da9bb89bSJon Lin .id = SPINAND_MFR_JSC,
103da9bb89bSJon Lin .name = "JSC",
10481afcfe1SJon Lin .chips = jsc_spinand_table,
10581afcfe1SJon Lin .nchips = ARRAY_SIZE(jsc_spinand_table),
106da9bb89bSJon Lin .ops = &jsc_spinand_manuf_ops,
107da9bb89bSJon Lin };
108