Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752816AbbHCJF6 (ORCPT ); Mon, 3 Aug 2015 05:05:58 -0400 Received: from mail-bn1bon0069.outbound.protection.outlook.com ([157.56.111.69]:6555 "EHLO na01-bn1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751756AbbHCJF1 (ORCPT ); Mon, 3 Aug 2015 05:05:27 -0400 Authentication-Results: spf=pass (sender IP is 149.199.60.100) smtp.mailfrom=xilinx.com; vger.kernel.org; dkim=none (message not signed) header.d=none; From: Ranjit Waghmode To: , , , , , , , , , , , CC: , , , , , , , , Ranjit Waghmode Subject: [LINUX RFC 1/2] mtd: spi-nor: add dual parallel mode support Date: Mon, 3 Aug 2015 14:35:06 +0530 Message-ID: <1438592707-30713-2-git-send-email-ranjit.waghmode@xilinx.com> X-Mailer: git-send-email 2.1.2 In-Reply-To: <1438592707-30713-1-git-send-email-ranjit.waghmode@xilinx.com> References: <1438592707-30713-1-git-send-email-ranjit.waghmode@xilinx.com> X-RCIS-Action: ALLOW X-TM-AS-Product-Ver: IMSS-7.1.0.1224-8.0.0.1202-21720.004 X-TM-AS-User-Approved-Sender: Yes;Yes X-EOPAttributedMessage: 0 X-Microsoft-Exchange-Diagnostics: 1;BN1BFFO11FD033;1:NoNwmid7il89uCTWQfVgP35G++HpjorOgKb/p0MIcp9R/em2SDO8SBmyGv8/EodxNyN9GkAxRUQ/WvaQBeuy2PjDldPSeWFGjRnLhJL+29S6dEUmRGOVtsh6ZmNDoCFUhlz0ohop0S4nzaZej4mpycaRzw0y8VUimkNdbMyUj0rF8vVrndk1mfdzvCGPB52N+rilaVTV8FprHhwNdCIo/PExuHHzUF2jZs17chp6C262939y/m93lhn6KI0GyvuHa/gSB4e858xRNSnjft4hJS4lRwcMfotECdSCJ6kAo2zcbjuCJoib2bbNWEzxn/i/byEbl7F9VtDphQiar90tvw== X-Forefront-Antispam-Report: CIP:149.199.60.100;CTRY:US;IPV:NLI;EFV:NLI;SFV:NSPM;SFS:(10009020)(6009001)(2980300002)(438002)(199003)(189002)(50226001)(50466002)(189998001)(47776003)(87936001)(52956003)(19580395003)(2201001)(86362001)(19580405001)(6806004)(575784001)(77156002)(62966003)(42186005)(63266004)(48376002)(46102003)(76176999)(33646002)(50986999)(2950100001)(36756003)(106466001)(107886002)(36386004)(5001770100001)(46386002)(45336002)(5001960100002)(92566002)(229853001)(7059030)(107986001)(921003)(4001430100001)(1121003)(90966001)(217873001);DIR:OUT;SFP:1101;SCL:1;SRVR:BN1BFFO11HUB056;H:xsj-pvapsmtpgw02;FPR:;SPF:Pass;MLV:sfv;A:1;MX:1;LANG:en; MIME-Version: 1.0 Content-Type: text/plain X-Microsoft-Exchange-Diagnostics: 1;BN1BFFO11HUB056;2:V9m5jZ2Tf50M6GUv631I1zWjlGsb050NUDtqgj45JRVAkRQEAAWU1O5aIBHvtCHRfapMwKNjxHXtNFTUQrA6/zE4LavdUUGl2WgPjsgF6kfIT//pTc1bAuiDwarXWX8TnHK8E8kIUJz799YBXZEkRMBaKXXwSzL6VHbT33RVvc0=;3:jevZEj9QmSsJJxalFfQijpCryZClP6DZueRlHxezYjlWO4+3oN6Mls4uiuSrUfr1Eob+XRplA+cNVMxklWmjQ39J3RuK79JHtcEEFTh1qZyLtnpv1fT5RGepCwIVdvnpP0OfmId7YVPSDm2rSvoRe42MIJQfpO4eB1IdV9HVA9+lsZFerPRS0Sw+LcXGdwNHsFRyTxC5Rt0fcquLS7TMPeNWMLtdv0owBKuYmw83YbFuG4drkiCaBCMqYLKco6tr;25:u+hVb/kl9P3slNbL2IGMw160pNQfF6MlV1l5IRubVAH4fHtK27k8H7z7lSiT3sKhNo+YlhtKeBVcKb8bImCNzQAY3MzFhpY2AyQwA8wA5SZc9ObfRIHD1JoS8LMoVplwtq/sy+Ap4TjIkKY/kNIU6MW36WXYMWcxy1MvZqauWUPCC8RU+nzgKa/HZMSX2auj7MhPwwJRLL29bY0Bbi2dlZQhlKaxHGtD5pjmvBV72V/8E5Rma26ZHIuGdXAMQp+6 X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:BN1BFFO11HUB056; X-Microsoft-Exchange-Diagnostics: 1;BN1BFFO11HUB056;20:uA/o/tX41CZT7P3FKXj5Z3wvYi8yYtHOtprtPOuLfR+aCD/jfJ0pAVepDqyz68e//RBEI2d8X60BVnO18+uPJgG+iYGaaRkJCD6M56nezEmMORGVXevZAZ3fR+lZt6aO4iMsRPP7sTDsR9IGnMAzsGjCXehpbqm5Tg7kOAoOnFHNcqId749+3u7XGK9R60HCJjdPrvxxN7s03MonSbb04vSX+rWyHS8gU6c9S+AW2iSRorz7Po4qjAu20WHoiJLRHzHwpCre/Gsl4YmbTweJTBZRLpAXsWZMQwFk7U0YJtmRz48BdtGCRb+94eAyJmJZFBDpEzr5+dvN/nSYgb95+vYs2ZibQWNcxWYMeXS5R0XEuz486jilPsvTM3p9T1pFGAiVsTuIDI/wqZp1MCXuIU8QA6/lBa0ozE4MDkEJX2o2Rh7ux0ZXPWhFsrn0pdCSFP007HGDLRDhdx3Hk4TJxLFYKjERWq4hR6LiH7sNSWnvmwURz1z+JrbiyJuug7CD;4:BYL0KSIsEeBTaihLVAb+dGEU0VbPYVqhesKhj7UpNxJc7Px4V6sE/8SHDDs0cmmNKf5TOEbtoVyRl3VwqLBYyUTXINmoqpV3euIKHKoY3OnXnD3WcSAfDW9sTaAJmtPT7XWZYm4+4SltP0kB2KdD7QFsMbAIzpWb61Z0XS5eBgqNf9AoW2Mw9tXvYhAJH1WGAS0oVyxc0KurOqKs45ExU6v/UX/6TcQ6RahD16NJLYsBI/AZnx+okMeEm3Ch16DDyYVXGZkT3lkGiF3MGKyk2jGaYTmfhFkaocxk2g0wQGU= BN1BFFO11HUB056: X-MS-Exchange-Organization-RulesExecuted X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(601004)(5005006)(3002001);SRVR:BN1BFFO11HUB056;BCL:0;PCL:0;RULEID:;SRVR:BN1BFFO11HUB056; X-Forefront-PRVS: 0657D528EC X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1;BN1BFFO11HUB056;23:AwXHBAg8tHzht79fSE/X6AatifcTK82UlxdTB5t?= =?us-ascii?Q?zKICsyZqDyEN+mO+4I29UOuhg0QYB/cxhe0m+sRAeBd0XS4KeyNbjZTAmCpl?= =?us-ascii?Q?JlW1A+ioQgccwMQmKaI4CrFOOWRYiRC5RGsqt+PA0U4gWdBZ8A3E8duQHCoP?= =?us-ascii?Q?4M3yJ+DRP5gwUzDcGFxSfJPoakMNZdf7Q9U6ZTDh4ocqhnkIoBwS/VOLCuYd?= =?us-ascii?Q?HW/mkOBv8RKpFvTEeYzSXedT0uzVl9k+IUyojE44x90fuAoHnpJML2euCpWG?= =?us-ascii?Q?dtLrIQ55Is2SNFAMcH5A61YIxiiCWMxhwygcoUrhEH8vrNR04XR5rTZ2TSb+?= =?us-ascii?Q?pcdDKIz72olbZ7ivxPTkBc7WuL8ClCEwM77uCcDVpkWXIf3CClSugixwhkWW?= =?us-ascii?Q?HPp/hkcdoS4x9kVvGaijT0v62tYzjHemWVf9g4c6itCv+qUCxT+9ykjzcAm1?= =?us-ascii?Q?E6spom6cmqITOjDEjuCFVOxQt88gLw/lr4Wc3l7HcdwKMeA/Bh0KB33cm9fl?= =?us-ascii?Q?OUslV2zNwPn7FQQFc6s+XILJTpKwagf4I7NcFhPTYICYhN/CK3mex6UbHcM6?= =?us-ascii?Q?vJayjRwQCtFSvRKfTcLfq8mOSdr3/uWkIliLctMWzmt08KuMytLuckZtaR3v?= =?us-ascii?Q?5622qsVZMHJ2x5AiZGktYNXruM0oPgJcI0/dTYu44+PC4SYJT/FBWKviZkh2?= =?us-ascii?Q?KN9qJU84FkEx5XeCLsimuKCeoBvzY3r3/NLjg1mZ1IR1qu+K35LqxjdQsAPJ?= =?us-ascii?Q?i0cmaNbOIdtkVEqp28VHcc6CEAbcsqBE5iZfEwIQOzyxng5helIOVs6YUyO/?= =?us-ascii?Q?nXadco5KacPSXXZ0jGWZeCnUM44ehlx9hgoRTaK2IgiI4aVUGxmdtEZwfSjP?= =?us-ascii?Q?JUgeXXeFP9go+CcxdGVZbTugFs2EoZ37DuF2UnSL5LfdIpk4qak7bylBmA3s?= =?us-ascii?Q?01p746bNGjXySiTljzWxD29s87D6jo2e4FrncoZ7Wseg/z99rNfnB+AYIQ33?= =?us-ascii?Q?UyBivt2Hh60Ge5ZgeecLR/ZkVkD2TzgZ4FifYseTjrfz6O2pCtOcaFUhC9ZO?= =?us-ascii?Q?/+UcWK0w18Tpdnw5ppDwGSIQEbeRZKbtkVX8aRYkWyw8z6vEiIYx6s+Qkury?= =?us-ascii?Q?9BTX4bHhEhsoOSw1grlxXmaGBduglSbfa?= X-Microsoft-Exchange-Diagnostics: 1;BN1BFFO11HUB056;5:m7V9hZnSMD+g1Y9UjUsJl00PgSRr4WZSPutXHVzDgZiTmyM9f8+GTMhVOQhQWlG7Ihg1RXgvAFCS3zhN2w9ucFB30LHGVXoL2JQi7K9jVcSYaFIduDZvXDp156L97KBNv2PBytfzil93bLVBipNbhw==;24:KDxqD2+SdwCiYY6w0L0lO9Ee6qgEag/Olwhb7hxqarK+ANxaz2ECaEuRy+AbW69wCKEkvR/MHB7rndD4cluBK6YuqkLaavVKqN//T4M0Bmk= X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 03 Aug 2015 09:05:25.2775 (UTC) X-MS-Exchange-CrossTenant-Id: 657af505-d5df-48d0-8300-c31994686c5c X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=657af505-d5df-48d0-8300-c31994686c5c;Ip=[149.199.60.100];Helo=[xsj-pvapsmtpgw02] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BN1BFFO11HUB056 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 9206 Lines: 308 This patch adds support for dual parallel configuration. - Added required parameters to spi_nor structure. Initialized all added parameters in spi_nor_scan() - Updated read_sr() and read_fsr() for getting status of both flashes - Added support for dual parallel in spi_nor_read/write/erase functions by: a) Increasing page_size, sector_size, erase_size and toatal flash size as and when required. b) Dividing address by 2 c) Updating spi->master->flags for qspi driver to change CS - Added defines for data stripe and two flash support Signed-off-by: Ranjit Waghmode --- drivers/mtd/devices/m25p80.c | 1 + drivers/mtd/spi-nor/spi-nor.c | 92 ++++++++++++++++++++++++++++++++++--------- include/linux/mtd/spi-nor.h | 3 ++ include/linux/spi/spi.h | 2 + 4 files changed, 79 insertions(+), 19 deletions(-) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index d313f948b..174ed0f 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -207,6 +207,7 @@ static int m25p_probe(struct spi_device *spi) spi_set_drvdata(spi, flash); flash->mtd.priv = nor; flash->spi = spi; + nor->spi = spi; if (spi->mode & SPI_RX_QUAD) mode = SPI_NOR_QUAD; diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index d78831b..9818a76 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -22,6 +22,7 @@ #include #include #include +#include /* Define max times to check status register before we give up. */ #define MAX_READY_WAIT_JIFFIES (40 * HZ) /* M25P16 specs 40s max chip erase */ @@ -69,15 +70,24 @@ static const struct spi_device_id *spi_nor_match_id(const char *name); static int read_sr(struct spi_nor *nor) { int ret; - u8 val; + u8 val[2]; - ret = nor->read_reg(nor, SPINOR_OP_RDSR, &val, 1); - if (ret < 0) { - pr_err("error %d reading SR\n", (int) ret); - return ret; + if (nor->isparallel) { + ret = nor->read_reg(nor, SPINOR_OP_RDSR, &val[0], 2); + if (ret < 0) { + pr_err("error %d reading SR\n", (int) ret); + return ret; + } + val[0] |= val[1]; + } else { + ret = nor->read_reg(nor, SPINOR_OP_RDSR, &val[0], 1); + if (ret < 0) { + pr_err("error %d reading SR\n", (int) ret); + return ret; + } } - return val; + return val[0]; } /* @@ -87,16 +97,24 @@ static int read_sr(struct spi_nor *nor) */ static int read_fsr(struct spi_nor *nor) { - int ret; - u8 val; + int ret, size; + u8 val[2]; + + size = 1; + val[1] = 0xff; + + if (nor->isparallel) + size = 2; - ret = nor->read_reg(nor, SPINOR_OP_RDFSR, &val, 1); + ret = nor->read_reg(nor, SPINOR_OP_RDFSR, &val[0], size); if (ret < 0) { pr_err("error %d reading FSR\n", ret); return ret; } - return val; + val[0] &= val[1]; + + return val[0]; } /* @@ -317,6 +335,9 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) if (ret) return ret; + if (nor->isparallel) + nor->spi->master->flags |= SPI_MASTER_DATA_STRIPE; + /* whole-chip erase? */ if (len == mtd->size) { write_enable(nor); @@ -340,6 +361,8 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) while (len) { write_enable(nor); + addr = addr >> nor->shift; + if (nor->erase(nor, addr)) { ret = -EIO; goto erase_err; @@ -360,19 +383,22 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); - + if (nor->isparallel) + nor->spi->master->flags &= ~SPI_MASTER_DATA_STRIPE; return ret; erase_err: spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE); instr->state = MTD_ERASE_FAILED; + if (nor->isparallel) + nor->spi->master->flags &= ~SPI_MASTER_DATA_STRIPE; return ret; } static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len) { struct mtd_info *mtd = nor->mtd; - uint32_t offset = ofs; + uint32_t offset = ofs >> nor->shift; uint8_t status_old, status_new; int ret = 0; @@ -406,7 +432,7 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len) static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len) { struct mtd_info *mtd = nor->mtd; - uint32_t offset = ofs; + uint32_t offset = ofs >> nor->shift; uint8_t status_old, status_new; int ret = 0; @@ -446,6 +472,8 @@ static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) if (ret) return ret; + ofs = ofs >> nor->shift; + ret = nor->flash_lock(nor, ofs, len); spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_UNLOCK); @@ -461,6 +489,8 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) if (ret) return ret; + ofs = ofs >> nor->shift; + ret = nor->flash_unlock(nor, ofs, len); spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK); @@ -707,6 +737,7 @@ static const struct spi_device_id *spi_nor_read_id(struct spi_nor *nor) int tmp; u8 id[SPI_NOR_MAX_ID_LEN]; struct flash_info *info; + nor->spi->master->flags &= ~SPI_MASTER_BOTH_CS; tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN); if (tmp < 0) { @@ -738,7 +769,13 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, if (ret) return ret; - ret = nor->read(nor, from, len, retlen, buf); + if (nor->isparallel) + nor->spi->master->flags |= SPI_MASTER_DATA_STRIPE; + + ret = nor->read(nor, from >> nor->shift, len, retlen, buf); + + if (nor->isparallel) + nor->spi->master->flags &= ~SPI_MASTER_DATA_STRIPE; spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_READ); return ret; @@ -834,11 +871,11 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, /* do all the bytes fit onto one page? */ if (page_offset + len <= nor->page_size) { - nor->write(nor, to, len, retlen, buf); + nor->write(nor, to >> nor->shift, len, retlen, buf); } else { /* the size of data remaining on the first page */ page_size = nor->page_size - page_offset; - nor->write(nor, to, page_size, retlen, buf); + nor->write(nor, to >> nor->shift, page_size, retlen, buf); /* write everything in nor->page_size chunks */ for (i = page_size; i < len; i += page_size) { @@ -852,12 +889,15 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, write_enable(nor); - nor->write(nor, to + i, page_size, retlen, buf + i); + nor->write(nor, (to + i) >> nor->shift, page_size, + retlen, buf + i); } } ret = spi_nor_wait_till_ready(nor); write_err: + if (nor->isparallel) + nor->spi->master->flags &= ~SPI_MASTER_DATA_STRIPE; spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE); return ret; } @@ -1073,6 +1113,20 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) mtd->_erase = spi_nor_erase; mtd->_read = spi_nor_read; +#ifdef CONFIG_OF + struct device_node *np_spi = of_get_next_parent(np); + u32 is_dual; + + if (of_property_read_u32(np_spi, "is-dual", &is_dual) > 0) { + nor->shift = 1; + info->sector_size <<= nor->shift; + info->page_size <<= nor->shift; + mtd->size <<= nor->shift; + nor->isparallel = 1; + nor->spi->master->flags |= SPI_MASTER_BOTH_CS; + } +#endif + /* nor protection support for STmicro chips */ if (JEDEC_MFR(info) == CFI_MFR_ST) { nor->flash_lock = stm_lock; @@ -1097,10 +1151,10 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) /* prefer "small sector" erase if possible */ if (info->flags & SECT_4K) { nor->erase_opcode = SPINOR_OP_BE_4K; - mtd->erasesize = 4096; + mtd->erasesize = 4096 << nor->shift; } else if (info->flags & SECT_4K_PMC) { nor->erase_opcode = SPINOR_OP_BE_4K_PMC; - mtd->erasesize = 4096; + mtd->erasesize = 4096 << nor->shift; } else #endif { diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index e540952..6ef25a8 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -163,6 +163,7 @@ struct spi_nor { struct mtd_info *mtd; struct mutex lock; struct device *dev; + struct spi_device *spi; u32 page_size; u8 addr_width; u8 erase_opcode; @@ -170,6 +171,8 @@ struct spi_nor { u8 read_dummy; u8 program_opcode; enum read_mode flash_read; + bool shift; + bool isparallel; bool sst_write_second; u32 flags; struct spi_nor_xfer_cfg cfg; diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index d673072..8dec349 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -355,6 +355,8 @@ struct spi_master { #define SPI_MASTER_NO_TX BIT(2) /* can't do buffer write */ #define SPI_MASTER_MUST_RX BIT(3) /* requires rx */ #define SPI_MASTER_MUST_TX BIT(4) /* requires tx */ +#define SPI_MASTER_DATA_STRIPE BIT(7) /* support data stripe */ +#define SPI_MASTER_BOTH_CS BIT(8) /* enable both chips */ /* lock and mutex for SPI bus locking */ spinlock_t bus_lock_spinlock; -- 2.1.2 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/