Received: by 2002:a25:ab43:0:0:0:0:0 with SMTP id u61csp7280804ybi; Wed, 5 Jun 2019 14:37:06 -0700 (PDT) X-Google-Smtp-Source: APXvYqw1azeDMy4cJcm2xawAJWcGevmXhA2gOfOFwL7qy9i0FHgb2dWIdORZOq8turlQV2sBs0GI X-Received: by 2002:aa7:8d89:: with SMTP id i9mr11412106pfr.77.1559770625971; Wed, 05 Jun 2019 14:37:05 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1559770625; cv=none; d=google.com; s=arc-20160816; b=YYOme2Y9w7p3DzRcpXqdb1Q0fNz/k01mrxw3HVgsDgcBZ8vYmbwihuG2eaeDsBlYzJ 0kD9Jr2s2H87dgCXRPZ3YCh4LLD2JZT93AbjW/SA9J5bhmCviIpT7TqUy1wrCGN7vCOR PGmh/8KUTjpxwgsGT1jWH0OPa48P+cLmmDzYlVxonTsVAMG0ro003Y/FmUm9kp9tx16+ 1nPZAhmhHZ5BNCUIHV3G/Hsg4X5/9X7UckY4bLhmxDYSdRTrgfQv4x4zpdlruY5Gut0E /IUesCPhx36xwj/xb2KGZUV3gaEJsV8jarzopK9wvyKbrFrR/yPvuABDKUCN/jK5JDK8 oW2g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from; bh=b/Ck3bTVIRMY9WkWfO1ksZLZdudBHohdBIp1nYipV/U=; b=mwUQjQ65yg2AbLWRIhfzR7/QgNnUYTX6SQOjAU3q4vXKUjOrePdSuv2XbEtvrSNCeu 5kAJyyaplHZRbmD2JuRkzLrmt1ZahfeqSLVznGs2HdRHB0SJ/Y5K2jQrNWwGskXNhYJA KarpvjS4rjgAHlXlhIDGbam9A8A4326pbuLsg5lBvLK52GHB9574VCRYAvTkbr8CF/P1 8MPEs57VVG+kpwmOQeQX9uvju3IVnfTPfnxhqGUuh3viFmBgsg05+EB9hUX7AxCfFijt M+9uOOE6spmHg0zK/exNXhy0HojaRa+TGySKNs7aeHoKAatyy6DJDtm7jxBFUwwcqQVb xGew== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 68si30447079plc.160.2019.06.05.14.36.48; Wed, 05 Jun 2019 14:37:05 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726597AbfFEVff (ORCPT + 99 others); Wed, 5 Jun 2019 17:35:35 -0400 Received: from mx.allycomm.com ([138.68.30.55]:10524 "EHLO mx.allycomm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726532AbfFEVff (ORCPT ); Wed, 5 Jun 2019 17:35:35 -0400 Received: from allycomm.com (unknown [IPv6:2601:647:5401:2210::49]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx.allycomm.com (Postfix) with ESMTPSA id 0998D22214; Wed, 5 Jun 2019 14:35:33 -0700 (PDT) From: Jeff Kletsky To: Miquel Raynal , Richard Weinberger , David Woodhouse , Brian Norris , Marek Vasut , Vignesh Raghavendra Cc: Schrempf Frieder , Jeff Kletsky , linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org Subject: [PATCH] mtd: spinand: Support Paragon PN26G01A and PN26G02A Date: Wed, 5 Jun 2019 14:35:15 -0700 Message-Id: <20190605213516.13516-1-lede@allycomm.com> X-Mailer: git-send-email 2.20.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Jeff Kletsky These Paragon chips are very similar to other 1Gb/2Gb chips in terms of their layout and command timings. One notable difference is that "Minimum number of valid blocks" (Nvb) is 1003 per Gb, rather than the common 1004. As a result, the bad-block reservation is 21 per Gb, rather than 20 per Gb. Datasheets available at http://www.xtxtech.com/upfile/2016082517274590.pdf http://www.xtxtech.com/upfile/2016082517282329.pdf Signed-off-by: Jeff Kletsky --- drivers/mtd/nand/spi/Makefile | 2 +- drivers/mtd/nand/spi/core.c | 1 + drivers/mtd/nand/spi/paragon.c | 142 +++++++++++++++++++++++++++++++++ include/linux/mtd/spinand.h | 1 + 4 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 drivers/mtd/nand/spi/paragon.c diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile index 753125082640..9662b9c1d5a9 100644 --- a/drivers/mtd/nand/spi/Makefile +++ b/drivers/mtd/nand/spi/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 -spinand-objs := core.o gigadevice.o macronix.o micron.o toshiba.o winbond.o +spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o obj-$(CONFIG_MTD_SPI_NAND) += spinand.o diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 556bfdb34455..f0f3528aab8f 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -757,6 +757,7 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = { &gigadevice_spinand_manufacturer, ¯onix_spinand_manufacturer, µn_spinand_manufacturer, + ¶gon_spinand_manufacturer, &toshiba_spinand_manufacturer, &winbond_spinand_manufacturer, }; diff --git a/drivers/mtd/nand/spi/paragon.c b/drivers/mtd/nand/spi/paragon.c new file mode 100644 index 000000000000..dd863dbc593a --- /dev/null +++ b/drivers/mtd/nand/spi/paragon.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Jeff Kletsky + * + * Author: Jeff Kletsky + */ + +#include +#include +#include + + +#define SPINAND_MFR_PARAGON 0xa1 + + +#define PN26G0XA_STATUS_ECC_BITMASK (3 << 4) + +#define PN26G0XA_STATUS_ECC_NONE_DETECTED (0 << 4) +#define PN26G0XA_STATUS_ECC_1_7_CORRECTED (1 << 4) +#define PN26G0XA_STATUS_ECC_ERRORED (2 << 4) +#define PN26G0XA_STATUS_ECC_8_CORRECTED (3 << 4) + + +static SPINAND_OP_VARIANTS(read_cache_variants, + SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); + +static SPINAND_OP_VARIANTS(write_cache_variants, + SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), + SPINAND_PROG_LOAD(true, 0, NULL, 0)); + +static SPINAND_OP_VARIANTS(update_cache_variants, + SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), + SPINAND_PROG_LOAD(false, 0, NULL, 0)); + + +static int pn26g0xa_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section) + return -ERANGE; + + region->offset = 64; + region->length = 64; + + return 0; +} + +static int pn26g0xa_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section) + return -ERANGE; + + region->offset = 1; /* Reserved byte for BBM */ + region->length = 63; + + return 0; +} + +static int pn26g0xa_ecc_get_status(struct spinand_device *spinand, + u8 status) +{ + switch (status & PN26G0XA_STATUS_ECC_BITMASK) { + case PN26G0XA_STATUS_ECC_NONE_DETECTED: + return 0; + + case PN26G0XA_STATUS_ECC_1_7_CORRECTED: + return 7; /* Return upper limit by convention */ + + case PN26G0XA_STATUS_ECC_8_CORRECTED: + return 8; + + case PN26G0XA_STATUS_ECC_ERRORED: + return -EBADMSG; + + default: + break; + } + + return -EINVAL; +} + +static const struct mtd_ooblayout_ops pn26g0xa_ooblayout = { + .ecc = pn26g0xa_ooblayout_ecc, + .free = pn26g0xa_ooblayout_free, +}; + + +static const struct spinand_info paragon_spinand_table[] = { + SPINAND_INFO("PN26G01A", 0xe1, + NAND_MEMORG(1, 2048, 128, 64, 1024, 21, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + 0, + SPINAND_ECCINFO(&pn26g0xa_ooblayout, + pn26g0xa_ecc_get_status)), + SPINAND_INFO("PN26G02A", 0xe2, + NAND_MEMORG(1, 2048, 128, 64, 1024, 21, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + 0, + SPINAND_ECCINFO(&pn26g0xa_ooblayout, + pn26g0xa_ecc_get_status)), +}; + +static int paragon_spinand_detect(struct spinand_device *spinand) +{ + u8 *id = spinand->id.data; + int ret; + + /* Read ID returns [0][MID][DID] */ + + if (id[1] != SPINAND_MFR_PARAGON) + return 0; + + ret = spinand_match_and_init(spinand, paragon_spinand_table, + ARRAY_SIZE(paragon_spinand_table), + id[2]); + if (ret) + return ret; + + return 1; +} + +static const struct spinand_manufacturer_ops paragon_spinand_manuf_ops = { + .detect = paragon_spinand_detect, +}; + +const struct spinand_manufacturer paragon_spinand_manufacturer = { + .id = SPINAND_MFR_PARAGON, + .name = "Paragon", + .ops = ¶gon_spinand_manuf_ops, +}; diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h index fbc0423bb4ae..4ea558bd3c46 100644 --- a/include/linux/mtd/spinand.h +++ b/include/linux/mtd/spinand.h @@ -227,6 +227,7 @@ struct spinand_manufacturer { extern const struct spinand_manufacturer gigadevice_spinand_manufacturer; extern const struct spinand_manufacturer macronix_spinand_manufacturer; extern const struct spinand_manufacturer micron_spinand_manufacturer; +extern const struct spinand_manufacturer paragon_spinand_manufacturer; extern const struct spinand_manufacturer toshiba_spinand_manufacturer; extern const struct spinand_manufacturer winbond_spinand_manufacturer; -- 2.20.1