File Index
Files and directories
Sign in
FILE

skyhigh.c

File preview with syntax highlighting.

linux-6.19.14/drivers/mtd/nand/spi/skyhigh.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (c) 2024 SkyHigh Memory Limited
  4 *
  5 * Author: Takahiro Kuwano <takahiro.kuwano@infineon.com>
  6 * Co-Author: KR Kim <kr.kim@skyhighmemory.com>
  7 */
  8
  9#include <linux/device.h>
 10#include <linux/kernel.h>
 11#include <linux/mtd/spinand.h>
 12
 13#define SPINAND_MFR_SKYHIGH			0x01
 14#define SKYHIGH_STATUS_ECC_1TO2_BITFLIPS	(1 << 4)
 15#define SKYHIGH_STATUS_ECC_3TO6_BITFLIPS	(2 << 4)
 16#define SKYHIGH_STATUS_ECC_UNCOR_ERROR		(3 << 4)
 17#define SKYHIGH_CONFIG_PROTECT_EN		BIT(1)
 18
 19static SPINAND_OP_VARIANTS(read_cache_variants,
 20		SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 4, NULL, 0, 0),
 21		SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
 22		SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 2, NULL, 0, 0),
 23		SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
 24		SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
 25		SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
 26
 27static SPINAND_OP_VARIANTS(write_cache_variants,
 28		SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
 29		SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
 30
 31static SPINAND_OP_VARIANTS(update_cache_variants,
 32		SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
 33		SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
 34
 35static int skyhigh_spinand_ooblayout_ecc(struct mtd_info *mtd, int section,
 36					 struct mtd_oob_region *region)
 37{
 38	/* ECC bytes are stored in hidden area. */
 39	return -ERANGE;
 40}
 41
 42static int skyhigh_spinand_ooblayout_free(struct mtd_info *mtd, int section,
 43					  struct mtd_oob_region *region)
 44{
 45	if (section)
 46		return -ERANGE;
 47
 48	/* ECC bytes are stored in hidden area. Reserve 2 bytes for the BBM. */
 49	region->offset = 2;
 50	region->length = mtd->oobsize - 2;
 51
 52	return 0;
 53}
 54
 55static const struct mtd_ooblayout_ops skyhigh_spinand_ooblayout = {
 56	.ecc = skyhigh_spinand_ooblayout_ecc,
 57	.free = skyhigh_spinand_ooblayout_free,
 58};
 59
 60static int skyhigh_spinand_ecc_get_status(struct spinand_device *spinand,
 61					  u8 status)
 62{
 63	switch (status & STATUS_ECC_MASK) {
 64	case STATUS_ECC_NO_BITFLIPS:
 65		return 0;
 66
 67	case SKYHIGH_STATUS_ECC_UNCOR_ERROR:
 68		return -EBADMSG;
 69
 70	case SKYHIGH_STATUS_ECC_1TO2_BITFLIPS:
 71		return 2;
 72
 73	case SKYHIGH_STATUS_ECC_3TO6_BITFLIPS:
 74		return 6;
 75
 76	default:
 77		break;
 78	}
 79
 80	return -EINVAL;
 81}
 82
 83static const struct spinand_info skyhigh_spinand_table[] = {
 84	SPINAND_INFO("S35ML01G301",
 85		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x15),
 86		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
 87		     NAND_ECCREQ(6, 32),
 88		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 89					      &write_cache_variants,
 90					      &update_cache_variants),
 91		     SPINAND_NO_RAW_ACCESS,
 92		     SPINAND_ECCINFO(&skyhigh_spinand_ooblayout,
 93				     skyhigh_spinand_ecc_get_status)),
 94	SPINAND_INFO("S35ML01G300",
 95		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14),
 96		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
 97		     NAND_ECCREQ(6, 32),
 98		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 99					      &write_cache_variants,
100					      &update_cache_variants),
101		     SPINAND_NO_RAW_ACCESS,
102		     SPINAND_ECCINFO(&skyhigh_spinand_ooblayout,
103				     skyhigh_spinand_ecc_get_status)),
104	SPINAND_INFO("S35ML02G300",
105		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x25),
106		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
107		     NAND_ECCREQ(6, 32),
108		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
109					      &write_cache_variants,
110					      &update_cache_variants),
111		     SPINAND_NO_RAW_ACCESS,
112		     SPINAND_ECCINFO(&skyhigh_spinand_ooblayout,
113				     skyhigh_spinand_ecc_get_status)),
114	SPINAND_INFO("S35ML04G300",
115		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
116		     NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 2, 1, 1),
117		     NAND_ECCREQ(6, 32),
118		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
119					      &write_cache_variants,
120					      &update_cache_variants),
121		     SPINAND_NO_RAW_ACCESS,
122		     SPINAND_ECCINFO(&skyhigh_spinand_ooblayout,
123				     skyhigh_spinand_ecc_get_status)),
124};
125
126static int skyhigh_spinand_init(struct spinand_device *spinand)
127{
128	/*
129	 * Config_Protect_En (bit 1 in Block Lock register) must be set to 1
130	 * before writing other bits. Do it here before core unlocks all blocks
131	 * by writing block protection bits.
132	 */
133	return spinand_write_reg_op(spinand, REG_BLOCK_LOCK,
134				    SKYHIGH_CONFIG_PROTECT_EN);
135}
136
137static const struct spinand_manufacturer_ops skyhigh_spinand_manuf_ops = {
138	.init = skyhigh_spinand_init,
139};
140
141const struct spinand_manufacturer skyhigh_spinand_manufacturer = {
142	.id = SPINAND_MFR_SKYHIGH,
143	.name = "SkyHigh",
144	.chips = skyhigh_spinand_table,
145	.nchips = ARRAY_SIZE(skyhigh_spinand_table),
146	.ops = &skyhigh_spinand_manuf_ops,
147};
~/ Read-only file preview.