1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2022 Aidan MacDonald
4 *
5 * Author: Aidan MacDonald <aidanmacdonald.0x0@gmail.com>
6 */
7
8#include <linux/device.h>
9#include <linux/kernel.h>
10#include <linux/mtd/spinand.h>
11
12
13#define SPINAND_MFR_ATO		0x9b
14
15
16static SPINAND_OP_VARIANTS(read_cache_variants,
17		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
18		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
19		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
20
21static SPINAND_OP_VARIANTS(write_cache_variants,
22		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
23		SPINAND_PROG_LOAD(true, 0, NULL, 0));
24
25static SPINAND_OP_VARIANTS(update_cache_variants,
26		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
27		SPINAND_PROG_LOAD(false, 0, NULL, 0));
28
29
30static int ato25d1ga_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	return 0;
39}
40
41static int ato25d1ga_ooblayout_free(struct mtd_info *mtd, int section,
42				   struct mtd_oob_region *region)
43{
44	if (section > 3)
45		return -ERANGE;
46
47	if (section) {
48		region->offset = (16 * section);
49		region->length = 8;
50	} else {
51		/* first byte of section 0 is reserved for the BBM */
52		region->offset = 1;
53		region->length = 7;
54	}
55
56	return 0;
57}
58
59static const struct mtd_ooblayout_ops ato25d1ga_ooblayout = {
60	.ecc = ato25d1ga_ooblayout_ecc,
61	.free = ato25d1ga_ooblayout_free,
62};
63
64
65static const struct spinand_info ato_spinand_table[] = {
66	SPINAND_INFO("ATO25D1GA",
67		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x12),
68		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
69		     NAND_ECCREQ(1, 512),
70		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
71					      &write_cache_variants,
72					      &update_cache_variants),
73		     SPINAND_HAS_QE_BIT,
74		     SPINAND_ECCINFO(&ato25d1ga_ooblayout, NULL)),
75};
76
77static const struct spinand_manufacturer_ops ato_spinand_manuf_ops = {
78};
79
80const struct spinand_manufacturer ato_spinand_manufacturer = {
81	.id = SPINAND_MFR_ATO,
82	.name = "ATO",
83	.chips = ato_spinand_table,
84	.nchips = ARRAY_SIZE(ato_spinand_table),
85	.ops = &ato_spinand_manuf_ops,
86};
87