1*03d86fc3SJon Lin // SPDX-License-Identifier: GPL-2.0 2*03d86fc3SJon Lin /* 3*03d86fc3SJon Lin * Copyright (c) 2020 exceet electronics GmbH 4*03d86fc3SJon Lin * 5*03d86fc3SJon Lin * Authors: 6*03d86fc3SJon Lin * Frieder Schrempf <frieder.schrempf@exceet.de> 7*03d86fc3SJon Lin * Boris Brezillon <boris.brezillon@bootlin.com> 8*03d86fc3SJon Lin */ 9*03d86fc3SJon Lin 10*03d86fc3SJon Lin #ifndef __UBOOT__ 11*03d86fc3SJon Lin #include <linux/device.h> 12*03d86fc3SJon Lin #include <linux/kernel.h> 13*03d86fc3SJon Lin #endif 14*03d86fc3SJon Lin #include <linux/mtd/spinand.h> 15*03d86fc3SJon Lin 16*03d86fc3SJon Lin #define SPINAND_MFR_FMSH 0xA1 17*03d86fc3SJon Lin 18*03d86fc3SJon Lin static SPINAND_OP_VARIANTS(read_cache_variants, 19*03d86fc3SJon Lin SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0), 20*03d86fc3SJon Lin SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), 21*03d86fc3SJon Lin SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), 22*03d86fc3SJon Lin SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), 23*03d86fc3SJon Lin SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), 24*03d86fc3SJon Lin SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); 25*03d86fc3SJon Lin 26*03d86fc3SJon Lin static SPINAND_OP_VARIANTS(write_cache_variants, 27*03d86fc3SJon Lin SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), 28*03d86fc3SJon Lin SPINAND_PROG_LOAD(true, 0, NULL, 0)); 29*03d86fc3SJon Lin 30*03d86fc3SJon Lin static SPINAND_OP_VARIANTS(update_cache_variants, 31*03d86fc3SJon Lin SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), 32*03d86fc3SJon Lin SPINAND_PROG_LOAD(false, 0, NULL, 0)); 33*03d86fc3SJon Lin 34*03d86fc3SJon Lin static int fm25s01a_ooblayout_ecc(struct mtd_info *mtd, int section, 35*03d86fc3SJon Lin struct mtd_oob_region *region) 36*03d86fc3SJon Lin { 37*03d86fc3SJon Lin return -ERANGE; 38*03d86fc3SJon Lin } 39*03d86fc3SJon Lin 40*03d86fc3SJon Lin static int fm25s01a_ooblayout_free(struct mtd_info *mtd, int section, 41*03d86fc3SJon Lin struct mtd_oob_region *region) 42*03d86fc3SJon Lin { 43*03d86fc3SJon Lin if (section) 44*03d86fc3SJon Lin return -ERANGE; 45*03d86fc3SJon Lin 46*03d86fc3SJon Lin region->offset = 2; 47*03d86fc3SJon Lin region->length = 62; 48*03d86fc3SJon Lin 49*03d86fc3SJon Lin return 0; 50*03d86fc3SJon Lin } 51*03d86fc3SJon Lin 52*03d86fc3SJon Lin static const struct mtd_ooblayout_ops fm25s01a_ooblayout = { 53*03d86fc3SJon Lin .ecc = fm25s01a_ooblayout_ecc, 54*03d86fc3SJon Lin .rfree = fm25s01a_ooblayout_free, 55*03d86fc3SJon Lin }; 56*03d86fc3SJon Lin 57*03d86fc3SJon Lin static const struct spinand_info fmsh_spinand_table[] = { 58*03d86fc3SJon Lin SPINAND_INFO("FM25S01A", 0xE4, 59*03d86fc3SJon Lin NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1), 60*03d86fc3SJon Lin NAND_ECCREQ(1, 512), 61*03d86fc3SJon Lin SPINAND_INFO_OP_VARIANTS(&read_cache_variants, 62*03d86fc3SJon Lin &write_cache_variants, 63*03d86fc3SJon Lin &update_cache_variants), 64*03d86fc3SJon Lin 0, 65*03d86fc3SJon Lin SPINAND_ECCINFO(&fm25s01a_ooblayout, NULL)), 66*03d86fc3SJon Lin }; 67*03d86fc3SJon Lin 68*03d86fc3SJon Lin /** 69*03d86fc3SJon Lin * fmsh_spinand_detect - initialize device related part in spinand_device 70*03d86fc3SJon Lin * struct if it is a FMSH device. 71*03d86fc3SJon Lin * @spinand: SPI NAND device structure 72*03d86fc3SJon Lin */ 73*03d86fc3SJon Lin static int fmsh_spinand_detect(struct spinand_device *spinand) 74*03d86fc3SJon Lin { 75*03d86fc3SJon Lin u8 *id = spinand->id.data; 76*03d86fc3SJon Lin int ret; 77*03d86fc3SJon Lin 78*03d86fc3SJon Lin /* 79*03d86fc3SJon Lin * FMSH SPI NAND read ID need a dummy byte, 80*03d86fc3SJon Lin * so the first byte in raw_id is dummy. 81*03d86fc3SJon Lin */ 82*03d86fc3SJon Lin if (id[1] != SPINAND_MFR_FMSH) 83*03d86fc3SJon Lin return 0; 84*03d86fc3SJon Lin 85*03d86fc3SJon Lin ret = spinand_match_and_init(spinand, fmsh_spinand_table, 86*03d86fc3SJon Lin ARRAY_SIZE(fmsh_spinand_table), id[2]); 87*03d86fc3SJon Lin if (ret) 88*03d86fc3SJon Lin return ret; 89*03d86fc3SJon Lin 90*03d86fc3SJon Lin return 1; 91*03d86fc3SJon Lin } 92*03d86fc3SJon Lin 93*03d86fc3SJon Lin static const struct spinand_manufacturer_ops fmsh_spinand_manuf_ops = { 94*03d86fc3SJon Lin .detect = fmsh_spinand_detect, 95*03d86fc3SJon Lin }; 96*03d86fc3SJon Lin 97*03d86fc3SJon Lin const struct spinand_manufacturer fmsh_spinand_manufacturer = { 98*03d86fc3SJon Lin .id = SPINAND_MFR_FMSH, 99*03d86fc3SJon Lin .name = "FMSH", 100*03d86fc3SJon Lin .ops = &fmsh_spinand_manuf_ops, 101*03d86fc3SJon Lin }; 102