xref: /kernel/linux/linux-6.6/drivers/mtd/nand/spi/xtx.c (revision 62306a36)
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Author:
4 * Felix Matouschek <felix@matouschek.org>
5 */
6
7#include <linux/device.h>
8#include <linux/kernel.h>
9#include <linux/mtd/spinand.h>
10
11#define SPINAND_MFR_XTX	0x0B
12
13#define XT26G0XA_STATUS_ECC_MASK	GENMASK(5, 2)
14#define XT26G0XA_STATUS_ECC_NO_DETECTED	(0 << 2)
15#define XT26G0XA_STATUS_ECC_8_CORRECTED	(3 << 4)
16#define XT26G0XA_STATUS_ECC_UNCOR_ERROR	(2 << 4)
17
18static SPINAND_OP_VARIANTS(read_cache_variants,
19		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
20		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
21		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
22		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
23		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
24		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
25
26static SPINAND_OP_VARIANTS(write_cache_variants,
27		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
28		SPINAND_PROG_LOAD(true, 0, NULL, 0));
29
30static SPINAND_OP_VARIANTS(update_cache_variants,
31		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
32		SPINAND_PROG_LOAD(false, 0, NULL, 0));
33
34static int xt26g0xa_ooblayout_ecc(struct mtd_info *mtd, int section,
35				   struct mtd_oob_region *region)
36{
37	if (section)
38		return -ERANGE;
39
40	region->offset = 48;
41	region->length = 16;
42
43	return 0;
44}
45
46static int xt26g0xa_ooblayout_free(struct mtd_info *mtd, int section,
47				   struct mtd_oob_region *region)
48{
49	if (section)
50		return -ERANGE;
51
52	region->offset = 1;
53	region->length = 47;
54
55	return 0;
56}
57
58static const struct mtd_ooblayout_ops xt26g0xa_ooblayout = {
59	.ecc = xt26g0xa_ooblayout_ecc,
60	.free = xt26g0xa_ooblayout_free,
61};
62
63static int xt26g0xa_ecc_get_status(struct spinand_device *spinand,
64					 u8 status)
65{
66	status = status & XT26G0XA_STATUS_ECC_MASK;
67
68	switch (status) {
69	case XT26G0XA_STATUS_ECC_NO_DETECTED:
70		return 0;
71	case XT26G0XA_STATUS_ECC_8_CORRECTED:
72		return 8;
73	case XT26G0XA_STATUS_ECC_UNCOR_ERROR:
74		return -EBADMSG;
75	default:
76		break;
77	}
78
79	/* At this point values greater than (2 << 4) are invalid  */
80	if (status > XT26G0XA_STATUS_ECC_UNCOR_ERROR)
81		return -EINVAL;
82
83	/* (1 << 2) through (7 << 2) are 1-7 corrected errors */
84	return status >> 2;
85}
86
87static const struct spinand_info xtx_spinand_table[] = {
88	SPINAND_INFO("XT26G01A",
89		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xE1),
90		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
91		     NAND_ECCREQ(8, 512),
92		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
93					      &write_cache_variants,
94					      &update_cache_variants),
95		     SPINAND_HAS_QE_BIT,
96		     SPINAND_ECCINFO(&xt26g0xa_ooblayout,
97				     xt26g0xa_ecc_get_status)),
98	SPINAND_INFO("XT26G02A",
99		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xE2),
100		     NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
101		     NAND_ECCREQ(8, 512),
102		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
103					      &write_cache_variants,
104					      &update_cache_variants),
105		     SPINAND_HAS_QE_BIT,
106		     SPINAND_ECCINFO(&xt26g0xa_ooblayout,
107				     xt26g0xa_ecc_get_status)),
108	SPINAND_INFO("XT26G04A",
109		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xE3),
110		     NAND_MEMORG(1, 2048, 64, 128, 2048, 40, 1, 1, 1),
111		     NAND_ECCREQ(8, 512),
112		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
113					      &write_cache_variants,
114					      &update_cache_variants),
115		     SPINAND_HAS_QE_BIT,
116		     SPINAND_ECCINFO(&xt26g0xa_ooblayout,
117				     xt26g0xa_ecc_get_status)),
118};
119
120static const struct spinand_manufacturer_ops xtx_spinand_manuf_ops = {
121};
122
123const struct spinand_manufacturer xtx_spinand_manufacturer = {
124	.id = SPINAND_MFR_XTX,
125	.name = "XTX",
126	.chips = xtx_spinand_table,
127	.nchips = ARRAY_SIZE(xtx_spinand_table),
128	.ops = &xtx_spinand_manuf_ops,
129};
130