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