xref: /rk3399_rockchip-uboot/drivers/mtd/nand/spi/fmsh.c (revision 4b3d79dc1b676dfb5774b26fbcdf4c845b0f2f96)
103d86fc3SJon Lin // SPDX-License-Identifier: GPL-2.0
203d86fc3SJon Lin /*
3*4b3d79dcSJon Lin  * Copyright (c) 2020-2021 Rockchip Electronics Co., Ltd
403d86fc3SJon Lin  *
503d86fc3SJon Lin  * Authors:
6*4b3d79dcSJon Lin  *	Dingqiang Lin <jon.lin@rock-chips.com>
703d86fc3SJon Lin  */
803d86fc3SJon Lin 
903d86fc3SJon Lin #ifndef __UBOOT__
1003d86fc3SJon Lin #include <linux/device.h>
1103d86fc3SJon Lin #include <linux/kernel.h>
1203d86fc3SJon Lin #endif
1303d86fc3SJon Lin #include <linux/mtd/spinand.h>
1403d86fc3SJon Lin 
1503d86fc3SJon Lin #define SPINAND_MFR_FMSH		0xA1
1603d86fc3SJon Lin 
1703d86fc3SJon Lin static SPINAND_OP_VARIANTS(read_cache_variants,
1803d86fc3SJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
1903d86fc3SJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
2003d86fc3SJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
2103d86fc3SJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
2203d86fc3SJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
2303d86fc3SJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
2403d86fc3SJon Lin 
2503d86fc3SJon Lin static SPINAND_OP_VARIANTS(write_cache_variants,
2603d86fc3SJon Lin 		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
2703d86fc3SJon Lin 		SPINAND_PROG_LOAD(true, 0, NULL, 0));
2803d86fc3SJon Lin 
2903d86fc3SJon Lin static SPINAND_OP_VARIANTS(update_cache_variants,
3003d86fc3SJon Lin 		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
3103d86fc3SJon Lin 		SPINAND_PROG_LOAD(false, 0, NULL, 0));
3203d86fc3SJon Lin 
3303d86fc3SJon Lin static int fm25s01a_ooblayout_ecc(struct mtd_info *mtd, int section,
3403d86fc3SJon Lin 				  struct mtd_oob_region *region)
3503d86fc3SJon Lin {
3603d86fc3SJon Lin 	return -ERANGE;
3703d86fc3SJon Lin }
3803d86fc3SJon Lin 
3903d86fc3SJon Lin static int fm25s01a_ooblayout_free(struct mtd_info *mtd, int section,
4003d86fc3SJon Lin 				   struct mtd_oob_region *region)
4103d86fc3SJon Lin {
4203d86fc3SJon Lin 	if (section)
4303d86fc3SJon Lin 		return -ERANGE;
4403d86fc3SJon Lin 
4503d86fc3SJon Lin 	region->offset = 2;
4603d86fc3SJon Lin 	region->length = 62;
4703d86fc3SJon Lin 
4803d86fc3SJon Lin 	return 0;
4903d86fc3SJon Lin }
5003d86fc3SJon Lin 
5103d86fc3SJon Lin static const struct mtd_ooblayout_ops fm25s01a_ooblayout = {
5203d86fc3SJon Lin 	.ecc = fm25s01a_ooblayout_ecc,
5303d86fc3SJon Lin 	.rfree = fm25s01a_ooblayout_free,
5403d86fc3SJon Lin };
5503d86fc3SJon Lin 
564cab706eSJon Lin static int fm25s01_ooblayout_ecc(struct mtd_info *mtd, int section,
574cab706eSJon Lin 				 struct mtd_oob_region *region)
584cab706eSJon Lin {
594cab706eSJon Lin 	if (section)
604cab706eSJon Lin 		return -ERANGE;
614cab706eSJon Lin 
624cab706eSJon Lin 	region->offset = 64;
634cab706eSJon Lin 	region->length = 64;
644cab706eSJon Lin 
654cab706eSJon Lin 	return 0;
664cab706eSJon Lin }
674cab706eSJon Lin 
684cab706eSJon Lin static int fm25s01_ooblayout_free(struct mtd_info *mtd, int section,
694cab706eSJon Lin 				  struct mtd_oob_region *region)
704cab706eSJon Lin {
714cab706eSJon Lin 	if (section)
724cab706eSJon Lin 		return -ERANGE;
734cab706eSJon Lin 
744cab706eSJon Lin 	region->offset = 2;
754cab706eSJon Lin 	region->length = 62;
764cab706eSJon Lin 
774cab706eSJon Lin 	return 0;
784cab706eSJon Lin }
794cab706eSJon Lin 
804cab706eSJon Lin static const struct mtd_ooblayout_ops fm25s01_ooblayout = {
814cab706eSJon Lin 	.ecc = fm25s01_ooblayout_ecc,
824cab706eSJon Lin 	.rfree = fm25s01_ooblayout_free,
834cab706eSJon Lin };
844cab706eSJon Lin 
8503d86fc3SJon Lin static const struct spinand_info fmsh_spinand_table[] = {
8603d86fc3SJon Lin 	SPINAND_INFO("FM25S01A", 0xE4,
8703d86fc3SJon Lin 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
8803d86fc3SJon Lin 		     NAND_ECCREQ(1, 512),
8903d86fc3SJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
9003d86fc3SJon Lin 					      &write_cache_variants,
9103d86fc3SJon Lin 					      &update_cache_variants),
9203d86fc3SJon Lin 		     0,
9303d86fc3SJon Lin 		     SPINAND_ECCINFO(&fm25s01a_ooblayout, NULL)),
943ac03e83SJon Lin 	SPINAND_INFO("FM25S02A", 0xE5,
95cc7b616dSJon Lin 		     NAND_MEMORG(1, 2048, 64, 64, 2048, 2, 1, 1),
963ac03e83SJon Lin 		     NAND_ECCREQ(1, 512),
973ac03e83SJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
983ac03e83SJon Lin 					      &write_cache_variants,
993ac03e83SJon Lin 					      &update_cache_variants),
100cc7b616dSJon Lin 		     1,
1013ac03e83SJon Lin 		     SPINAND_ECCINFO(&fm25s01a_ooblayout, NULL)),
1024cab706eSJon Lin 	SPINAND_INFO("FM25S01", 0xA1,
1034cab706eSJon Lin 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
1044cab706eSJon Lin 		     NAND_ECCREQ(1, 512),
1054cab706eSJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
1064cab706eSJon Lin 					      &write_cache_variants,
1074cab706eSJon Lin 					      &update_cache_variants),
1084cab706eSJon Lin 		     0,
1094cab706eSJon Lin 		     SPINAND_ECCINFO(&fm25s01_ooblayout, NULL)),
11003d86fc3SJon Lin };
11103d86fc3SJon Lin 
11203d86fc3SJon Lin /**
11303d86fc3SJon Lin  * fmsh_spinand_detect - initialize device related part in spinand_device
11403d86fc3SJon Lin  * struct if it is a FMSH device.
11503d86fc3SJon Lin  * @spinand: SPI NAND device structure
11603d86fc3SJon Lin  */
11703d86fc3SJon Lin static int fmsh_spinand_detect(struct spinand_device *spinand)
11803d86fc3SJon Lin {
11903d86fc3SJon Lin 	u8 *id = spinand->id.data;
12003d86fc3SJon Lin 	int ret;
12103d86fc3SJon Lin 
12203d86fc3SJon Lin 	/*
12303d86fc3SJon Lin 	 * FMSH SPI NAND read ID need a dummy byte,
12403d86fc3SJon Lin 	 * so the first byte in raw_id is dummy.
12503d86fc3SJon Lin 	 */
12603d86fc3SJon Lin 	if (id[1] != SPINAND_MFR_FMSH)
12703d86fc3SJon Lin 		return 0;
12803d86fc3SJon Lin 
12903d86fc3SJon Lin 	ret = spinand_match_and_init(spinand, fmsh_spinand_table,
13003d86fc3SJon Lin 				     ARRAY_SIZE(fmsh_spinand_table), id[2]);
13103d86fc3SJon Lin 	if (ret)
13203d86fc3SJon Lin 		return ret;
13303d86fc3SJon Lin 
13403d86fc3SJon Lin 	return 1;
13503d86fc3SJon Lin }
13603d86fc3SJon Lin 
13703d86fc3SJon Lin static const struct spinand_manufacturer_ops fmsh_spinand_manuf_ops = {
13803d86fc3SJon Lin 	.detect = fmsh_spinand_detect,
13903d86fc3SJon Lin };
14003d86fc3SJon Lin 
14103d86fc3SJon Lin const struct spinand_manufacturer fmsh_spinand_manufacturer = {
14203d86fc3SJon Lin 	.id = SPINAND_MFR_FMSH,
14303d86fc3SJon Lin 	.name = "FMSH",
14403d86fc3SJon Lin 	.ops = &fmsh_spinand_manuf_ops,
14503d86fc3SJon Lin };
146