Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753549AbcK0Id5 (ORCPT ); Sun, 27 Nov 2016 03:33:57 -0500 Received: from mail-bn3nam01on0046.outbound.protection.outlook.com ([104.47.33.46]:62166 "EHLO NAM01-BN3-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1752509AbcK0Idz (ORCPT ); Sun, 27 Nov 2016 03:33:55 -0500 Authentication-Results: spf=pass (sender IP is 149.199.60.83) smtp.mailfrom=xilinx.com; vger.kernel.org; dkim=none (message not signed) header.d=none;vger.kernel.org; dmarc=bestguesspass action=none header.from=xilinx.com; X-IncomingTopHeaderMarker: OriginalChecksum:;UpperCasedChecksum:;SizeAsReceived:1642;Count:16 From: Naga Sureshkumar Relli To: , , , , CC: , , , Subject: [LINUX RFC v4 3/4] mtd: spi-nor: add stripe support Date: Sun, 27 Nov 2016 14:03:36 +0530 Message-ID: <1480235616-34038-1-git-send-email-nagasure@xilinx.com> X-Mailer: git-send-email 2.1.1 X-RCIS-Action: ALLOW X-TM-AS-Product-Ver: IMSS-7.1.0.1224-8.0.0.1202-22724.006 X-TM-AS-User-Approved-Sender: Yes;Yes X-IncomingHeaderCount: 16 X-EOPAttributedMessage: 0 X-MS-Office365-Filtering-HT: Tenant X-Forefront-Antispam-Report: CIP:149.199.60.83;IPV:NLI;CTRY:US;EFV:NLI;SFV:NSPM;SFS:(10009020)(6009001)(7916002)(2980300002)(438002)(189002)(199003)(81156014)(81166006)(356003)(8676002)(42186005)(6862003)(4326007)(63266004)(47776003)(2906002)(39450400002)(33646002)(7846002)(5001770100001)(45336002)(305945005)(189998001)(39380400001)(52956003)(50226002)(39410400001)(39400400001)(8936002)(36386004)(92566002)(90966002)(5660300001)(36756003)(48376002)(46386002)(5003940100001)(50466002)(38730400001)(103686003)(2201001)(106466001)(575784001)(6636002)(50986999)(626004)(107986001)(217873001);DIR:OUT;SFP:1101;SCL:1;SRVR:CY4PR02MB2390;H:xsj-pvapsmtpgw01;FPR:;SPF:Pass;PTR:unknown-60-83.xilinx.com;MX:1;A:1;LANG:en; X-Microsoft-Exchange-Diagnostics: 1;BL2NAM02FT064;1:RKxE5Av3FzzThTtWYs4UIe6Ht6nQTeF9/85XgPLWOLkt9nowrszQ9IZL49M3WBtA3zz1UzcH2mcbaoV382CFRiulBiWiYRHxdIYoyKed/D4pgPwKToWMWXh9yg4cs201RVboirJKReF+Le+d57roGyiVbQh7TqKnYgHKQRPAVqXSW38jXzFGSNMuu6wpg/wq8z0KHjHqQHuSx8Y8EVjmGNhWNpRfLN+gcHLQJTp7mECLwWVYR3SZvCpLppAP+qEMzKZolwRJY0HJSJxfQj5LlUOZ7cJw/b1Fz/JLbH2I9bpaFCwgPeDr/LtgkMZBOLrfLkM02YO0TjdCV4I/vyO72H52uppkdDOxKNXfsbbVijR/Dgd99fF2YWsCBWOKxC+SNO+Rlu6y6bZFglSAWYPiQlp4AqXMKwL9TCsovL0nuhvCMHuwWpXD5aIhb7HI+rdDgrcMILzyR/pB3rkXhYfz/odlDWdKZhSYIlpcr0p3HHOdb6ajyqzCxmVsjkARsZVp3XBdxveE99/mVmx8bBSxZ5vR84DgpERI9jxmJQzzpkvX55PANj7KJaVbRcjBd5uXYn77REb7MWwV9tYQ3US1STeZ5dXCQyzmQAtCrmSESo8= MIME-Version: 1.0 Content-Type: text/plain X-MS-Office365-Filtering-Correlation-Id: 72c8e5d5-edd9-4bec-1bfa-08d416a01ac0 X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:(22001)(8251501002);SRVR:CY4PR02MB2390; X-Microsoft-Exchange-Diagnostics: 1;CY4PR02MB2390;3:om6sAHfvA7SYe4Gy+Y7SckEeQezorCilZyKhka9K7BRyI2ms9WHXqsuXQ8HgwpAMC8uTka4jzXu2AolTmhwB3Vrj++sa6fnsKn0ZPkXPreV6Q2z9YeG/g3WGbI5UjhaKHm5YfHXmDLF/DOiqnorn9LHe+23cKQSZxk8kGNtOSrLy7XsuOHpzoAIHjd09Fagnm1E8T6/p5vTPYK2yIcbNxcfPaW8T78KlhAXslxsTVBiurblsr7Jk1Wd+Gq1iGOh/+Zk+If/adurcS/fiPM2jz2xHiIi342FuWJ/gpdHqK1woijZqDucRhuu7o8eAPBezwLR6Up+iY91d33k2b/HuehECOs00HvwUaEDjQQQ8gjq3Iux+Rv9JBLsz7x1XNrVGumnvOzjRG/FAlXyXR2y1dA== X-Microsoft-Exchange-Diagnostics: 1;CY4PR02MB2390;25:anhqVExUzWf+6/T9jiPtH5pMA6PzUejUNJaCtlKfrS4nv6P1TujOLZnzi98WQj4mFZPhZwswP1ylhqJerHPSHZnccux6GXHhFRtebcEI3dcAm5kuED2HG7YLD0hmdtbvYY6fyQiizcEIn0vb4aYUlur0upAVFNxcQXtWYDbznFOijW3HipZnV5IPmga23gKpErZv9QFWeGb6dAw1D96wYS6kWIziUo4WUvtqP71wpcJ+9dfle7c//TztS1V504MJCA/XKMffiXrKppShx5Q1I+7rYSkgfH5aaUkDrDEU9ZXvvgU1fpHHpFwwPg4Dsiac9DEn5k7E2ZPSMzjK8XDLfb5NLKq1losqKtLCD1ZB+1PYeOngeqO93WRiIcFOFZggHccCYqIdqcfuEScxsWxiKGdJBnvIoofLQ1xqciL5P1yg//UtuW0wu0yr08WvPAlToLMRw1Qv2QYVyQoDfXQsi2YAUNo3Jmv3LRyxhkolxq+Scm5YcCThORdwrQki/E78r/HChSxpUIeOiYULxDGnbJhvTDZ70ylyb8nkD/n58WyGiJ9DLNQhMgUSmbb0Ze59mns6zQ74qPpzDtzA77IsoolXzV4LRWY/gbdIa2dQYdGGWu5JEHhUCHjRKIsOf7QNU0ohhZFbfd07APT1DbmLMuYOE5u2TmbEn+mCwGIVihOopGBf4mI0j0gUpKb1bkLvv1JqCh7EcEw0gL4gAW4WnteXi9QAnC81wnhXQyzm7odxP7VLh7aBlmQ0AsFm8llnANxZuQPrqt9m+jJSzqP5UrNNHAjZ5IGZUc11iGoONbTT/PQFADO6nhS+YodRsMc4 X-Microsoft-Exchange-Diagnostics: 1;CY4PR02MB2390;31:i+Tv8+l8Xyn9Yloooux0K8CyNHQder7i3bwCLHjLgoRmXjsj/0sqQ9TsfJnO+S0CceS6OOR/ruEWJwrr3jdXJjcjeK+FAQL3X4VXY2mNFIMVZcdmcPzdVXNkdmDcPtixn5YVtvoORCYN1zN66YSfj87lTp90RiSusSEk8MQ5x4YIh+7/iJe+60ejfW+EXE2Vd6+QmuAywJNzNqAQQN1C20aYLiNu0JEKjTzAYKB8GvY8WeQT/MNjhDgC2ey4Z8EQZaJXWhLINrVWs/BMSr7jBOrglISXNjRo6H97KTHz3lQ=;20:KOr5CblT4OQuA1HVMn6eWaNnT4ZuSqiiW4nrIhPHjLVelnkaVPTsU6Af4WrKD6bLIiV/ddzRw/sZC5ikKgff8P/Li1ThmvzakD9bwHpxvyXBA+SQcyPlu+v1KaI3OT5s4YAkCETorbQSGVPoT/zcNLNvJpIOBqqmuo+T+mdpgasmjbezvTrWlY2QRsVkfykFcDO060LlPrWCtbQv2RZgqxoV9L0PxAmYqo07z99nLtTAcoAZ0Qgc6uOKlKPTdjrHbmHUWtp6uwUOShu+nU/f4n1G4G1pq0Ax7IKQz+O8KH8RBK7/QLIiBkBVc8GzXOLJYXMqP9A1gZ0BYYAZppJEI7gDY+O67TDa9rW+RC7sXzMKeMcb0Rdemu+XFLc6bJYDVpLGpLR2Z8TWH3g2NqMVORZIyHpEtYLaNq90UhTz57m5HOLxm4V9oCCcMDyp2yoqQJoOs2WySSyjp8gCNfzAS2qCSADFQ4ZHJ0Lndqcr3/4SeQ66MJ7RM+ARPKZDf7We X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(192813158149592); X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(6045199)(6040361)(6060326)(601004)(2401047)(13015025)(13017025)(13023025)(13024025)(13018025)(5005006)(8121501046)(3002001)(10201501046)(6055026)(6061324)(6041248)(20161123560025)(20161123555025)(20161123564025)(20161123562025);SRVR:CY4PR02MB2390;BCL:0;PCL:0;RULEID:;SRVR:CY4PR02MB2390; X-Microsoft-Exchange-Diagnostics: 1;CY4PR02MB2390;4:Gh4DoejcUy6uD6VyP2LnZwL7Wphr1rRGx/EiHNO4NhmPEg3qQxllxhMyHZ3TVxmsMIs/tHLyBumRq/yi/r7ICqukLrRARuHeK+BO4DdxEkIchsLMOO5XQwmOYU4scihvwSSCoqF07IpO7KsKhk3e0aJG/xrFYGOEDAOIIiOyZL2rIyMTnXz3W3q6N7kRrthlUwS199munCJdifqi4n/0iF8rq9xbx9JIEalzMrstQk9ZwNWt5+ZCbcVbnDs/LGy/vVVeurK1aoHqeUqtQ7D2jPI6YdTKy8TlUFrl2PhW+Lzd1mqQab0SRTKS2Whl9M8nHtBlZU0T0sOQGVeDG69rnM3Rm+ory7siIr8VN/NvAdSAfvdUct8bmR1fUHO3uTNf57vhtpabvWFsktjzBrU2JWoyaRVDG95OSGh7CaIM9mG/ZJSXat77Ruy3YPcc9TSrqySakoCqctj+C9VkwBFgxcGtGYYtNgIAFwIXPLt37r/tpR3fkit7Qfc5QyGpJBP8jUgK5wzGy3NMyq4ebiWAIf8lXPryK0mzhvYDQ6fQSGAMerarnB05pzhpwsyXe2xKy9EnFStORWUp0lo9SsoKRVTHU0cwRD9xd7qf+x2Miexp3cKcBFpiw5XvdfieDUdpaOe2W40fJkXe310XVnkv3NGcoO1SnaSTr1ta9YSQ9JNudeev63Nqdwv4/EVa7TtIh6Eo97tCd+LdH/48FzKYGYzuCJvLUUVYESkNUAHj5+Gc11gZLMOp6ZxFJplYI73x6aUJcc8kONZDWpZdTH0tpw== X-Forefront-PRVS: 0139052FDB X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1;CY4PR02MB2390;23:Kz713dHDP0XpDd6TZbYVB8szf6gM8PqbPNttUCYwk?= =?us-ascii?Q?U2rO9TXkZqBIIeJeY9/pRrU+S76mZ4XfU5mWJfyphns+ZeQVWIPQIpxqmsOx?= =?us-ascii?Q?ppnmSHviw1oNZ9/cjcVjO3AxDjNuPneOjP/vDU0/viWVtBnk1UstDrTz02T0?= =?us-ascii?Q?wHIvP/h2qUjKb3OyHIvJjMcpT71ImlWAcraqJdcGoRD+NgqW8GK6toz0Vipw?= =?us-ascii?Q?KYtr3kAzM8BFjSqFM/Z7Dkxn0GA3M/G8hStvsWBPUGRTj/Pi8RRypiR0KfbP?= =?us-ascii?Q?u0p0wERS8+VxvTBfcvk+ZvyQ90MwjOxa8s7AXkHIv9f/xbXrw7Q0NREvVJY7?= =?us-ascii?Q?UjjL3fE4Ey/45kTeZrrqhJLPXEQRjwXrdllwh9wLbQJVZu96baRt5dMHtJaV?= =?us-ascii?Q?j84R2aFjm+kCsoNMYaaGVeUyC/+pEJvqeTiYO1HhWzFDF7atTaybH1ScRrp3?= =?us-ascii?Q?PoL8SXaWmSPps8TVZt0a+JFybwg2TYkgWqVxyozgXpAd7fliF+VM/uIrPMDn?= =?us-ascii?Q?+o42/zv7Q/4UxMt8XC5HhB3EjxAo9SInqH8Yubz/ST2GB++yCPo09sMG6m6K?= =?us-ascii?Q?9ea9vpvwPWkBOnC8v9OB7NmglcC3xbrbAq99bSXqxAnHb58DSyt2f8IQoiNP?= =?us-ascii?Q?QD9hXuj/12nbgP4Evlx+netrm+MRSGXS9WCuORjssYqYBKaiO3MavLAjOyi9?= =?us-ascii?Q?PEsFkGyuUUEa9eDInMj+WbvW2yyI/y7kP/4JgATuqI2nEzNJJzUz5wKSpfvP?= =?us-ascii?Q?Qvr/3POvmcXi/BiG3KXrwbD++iSmJyEhm1gBQFS/2gZW9mF5pn+KNWIUe6JF?= =?us-ascii?Q?PCe6+jzfu6o8f7OakOmkCFQoMCLk+DTqsDfF5FVhm8rofTKj2ISZdrmPiVjC?= =?us-ascii?Q?AXRs2Em0ejgBuBJYjm1TjSPY5L9zaemvjjU86sL/I7mUwQnPVAwCc2DQ5kQg?= =?us-ascii?Q?jpGJ+tBaydJRrgpPQ9I4ygOqkmyfb9595Hj3rd0p9k4bUJp6qb02jAxXcSNH?= =?us-ascii?Q?zMxe9vvhdNlzP3RpJcxlqAhQ2u4yD9MbtYLSW6wdkq3P1QD7zYHS0ZzFn1oA?= =?us-ascii?Q?ecCUjdJEnyIBALrqClvyqzuOfMRXDDQc4YS3m8WMvUvUISm6QFMtVMwhf92R?= =?us-ascii?Q?Q0IOAP4Y5aWuMpv/o2JqMt6hO5N11wP8dQFgD3C/4XpTy/fXbBFfXhRLLxeo?= =?us-ascii?Q?fZCPgRzP9QmidY=3D?= X-Microsoft-Exchange-Diagnostics: 1;CY4PR02MB2390;6:aeEcVpqv/q76tOOi5wIXyotqFxwueTg//apSzQ0PVXqHl/f600odNlObem81xSjCzt2Blfix5JgcBsYszTe9oQUuDt47kAEFnX2OVcufcweOtD0lhzAi1H7SmL3J6WYNjQVYAhbVxRRRidMQTq508HCIfDA2bYoHI/svYujbwGei5ED51hLHTXS04pHC2m6+cZ/XGkouQFyLoxVKxZgZnLYTsY4MKOF8Jhd1qIerv6+/Beq3QOWt4t0jsPEhU0KMMcy/cZP4ttLpS1n8wxopMZpMfcN1tdMnZEzU66LmnAZzWNKetTNK0+27mHx+ptu4tFaqKtcJrEAhobvAjFHUpNvicRYNnuYt3lanhvVhCyfxNWVPwoaaZaB1HNpVH86B6+4XdO68nmbzJve0ITdITbjazvMZV+/umFUmfHXLOTrjQADi/B2N2aY59KPYX+0W78/ARQeiHlUYvF0tJiGdLnAVOssDd1ashyK29fWubvJ8vRwxj3HnPvHN7dHDonvz;5:ape6n0R9F7LVQ8E4lj1SU0rougL3IryoGNY8Ohg7mf919UCBWf+ocW4ocZndb62LPbF1B3+xNzBWyJtZBE8URzKosJUQTMqrSqbJST7Axtnx0upCLWeTDNpKrjZ25AOtiCzRBgf879cDXY1fdOqnrw==;24:ZiDfPO4TgCNebfA1U6OkGn23Qd79QjTOZCDC2k70ejdHT23Yyk0lCGSH3OyX3Xs9LErCKqCNM4IFyZpey9a5pIX+dqDbUFydaRLmGkXKkaI= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1;CY4PR02MB2390;7:0+n+lhaA0BE08tc0xBwjaZwe8BKAj3vphI17YolrH6xi/u8Hc871/4A8LFMllvsu/aBREJV8cQQrQ7mtarw+aG7r1xWjE7I2WoRacOiQfkrbx4f7hgWnYgrYO86pMvEjhol7OQUF3Lwlj4oFo6dzCxJ2A3AMZt+wNW8+ulDOhqnRxtPL1DcJ1Phg82Sl2AnYBgsrLLqMPwoMeD5HTx+UcKe3Dj8+nC6NGucd401URuygHvf5M8yOCKalmaf6uqwuZ8VtxgWci4kwv+j/dcMY1OhtPhz+Ve1oAikVxb0v2DGPexD4VpL2p3nDUfPHvMLw/CTRjf2itHiO5Dc52D+JpTHTt3vfxQ7WMURXrroMhfBdmMw1asBlFF6J1XvWcGZJGH2l8lau5p0yybL8GbRGWZaFr81hlY2m+w5EekfO7JImZWCaCYUBD/puqqi40NEt1gaYO8PfBzNZUFR6CTzpyQ== X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 27 Nov 2016 08:33:46.2177 (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.83];Helo=[xsj-pvapsmtpgw01] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY4PR02MB2390 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 9929 Lines: 346 This patch adds stripe support and it is needed for GQSPI parallel configuration mode by: - Adding required parameters like stripe and shift to spi_nor structure. - Initializing all added parameters in spi_nor_scan() - Updating read_sr() and read_fsr() for getting status from both flashes - Increasing page_size, sector_size, erase_size and toatal flash size as and when required. - Dividing address by 2 - Updating spi->master->flags for qspi driver to change CS Signed-off-by: Naga Sureshkumar Relli --- Changes for v4: - rename isparallel to stripe Changes for v3: - No change Changes for v2: - Splitted to separate MTD layer changes from SPI core changes --- drivers/mtd/spi-nor/spi-nor.c | 130 ++++++++++++++++++++++++++++++++---------- include/linux/mtd/spi-nor.h | 2 + 2 files changed, 103 insertions(+), 29 deletions(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index d0fc165..4252239 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. */ @@ -89,15 +90,24 @@ static const struct flash_info *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->stripe) { + 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]; } /* @@ -108,15 +118,24 @@ static int read_sr(struct spi_nor *nor) static int read_fsr(struct spi_nor *nor) { int ret; - u8 val; + u8 val[2]; - ret = nor->read_reg(nor, SPINOR_OP_RDFSR, &val, 1); - if (ret < 0) { - pr_err("error %d reading FSR\n", ret); - return ret; + if (nor->stripe) { + ret = nor->read_reg(nor, SPINOR_OP_RDFSR, &val[0], 2); + if (ret < 0) { + pr_err("error %d reading FSR\n", ret); + return ret; + } + val[0] &= val[1]; + } else { + ret = nor->read_reg(nor, SPINOR_OP_RDFSR, &val[0], 1); + if (ret < 0) { + pr_err("error %d reading FSR\n", ret); + return ret; + } } - return val; + return val[0]; } /* @@ -290,9 +309,16 @@ static int spi_nor_wait_till_ready(struct spi_nor *nor) */ static int erase_chip(struct spi_nor *nor) { + u32 ret; + dev_dbg(nor->dev, " %lldKiB\n", (long long)(nor->mtd.size >> 10)); - return nor->write_reg(nor, SPINOR_OP_CHIP_ERASE, NULL, 0); + ret = nor->write_reg(nor, SPINOR_OP_CHIP_ERASE, NULL, 0); + if (ret) + return ret; + + return ret; + } static int spi_nor_lock_and_prep(struct spi_nor *nor, enum spi_nor_ops ops) @@ -349,7 +375,7 @@ static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr) static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) { struct spi_nor *nor = mtd_to_spi_nor(mtd); - u32 addr, len; + u32 addr, len, offset; uint32_t rem; int ret; @@ -399,9 +425,13 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) /* "sector"-at-a-time erase */ } else { while (len) { + write_enable(nor); + offset = addr; + if (nor->stripe) + offset /= 2; - ret = spi_nor_erase_sector(nor, addr); + ret = spi_nor_erase_sector(nor, offset); if (ret) goto erase_err; @@ -525,6 +555,8 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len) bool use_top; int ret; + ofs = ofs >> nor->shift; + status_old = read_sr(nor); if (status_old < 0) return status_old; @@ -610,6 +642,8 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len) bool use_top; int ret; + ofs = ofs >> nor->shift; + status_old = read_sr(nor); if (status_old < 0) return status_old; @@ -709,6 +743,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); @@ -724,6 +760,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); @@ -1018,6 +1056,9 @@ static const struct flash_info *spi_nor_read_id(struct spi_nor *nor) u8 id[SPI_NOR_MAX_ID_LEN]; const struct flash_info *info; + nor->spi->master->flags &= ~(SPI_MASTER_BOTH_CS | + SPI_MASTER_DATA_STRIPE); + tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN); if (tmp < 0) { dev_dbg(nor->dev, "error %d reading JEDEC ID\n", tmp); @@ -1041,6 +1082,7 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, { struct spi_nor *nor = mtd_to_spi_nor(mtd); int ret; + u32 offset = from; dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len); @@ -1049,7 +1091,13 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, return ret; while (len) { - ret = nor->read(nor, from, len, buf); + + offset = from; + + if (nor->stripe) + offset /= 2; + + ret = nor->read(nor, offset, len, buf); if (ret == 0) { /* We shouldn't see 0-length reads */ ret = -EIO; @@ -1161,6 +1209,7 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, struct spi_nor *nor = mtd_to_spi_nor(mtd); size_t page_offset, page_remain, i; ssize_t ret; + u32 offset; dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len); @@ -1178,9 +1227,13 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, /* the size of data remaining on the first page */ page_remain = min_t(size_t, nor->page_size - page_offset, len - i); + offset = (to + i); + + if (nor->stripe) + offset /= 2; write_enable(nor); - ret = nor->write(nor, to + i, page_remain, buf + i); + ret = nor->write(nor, (offset), page_remain, buf + i); if (ret < 0) goto write_err; written = ret; @@ -1302,22 +1355,22 @@ static int spi_nor_check(struct spi_nor *nor) int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) { - const struct flash_info *info = NULL; + struct flash_info *info = NULL; struct device *dev = nor->dev; struct mtd_info *mtd = &nor->mtd; struct device_node *np = spi_nor_get_flash_node(nor); - int ret; - int i; + struct device_node *np_spi; + int ret, i, xlnx_qspi_mode; ret = spi_nor_check(nor); if (ret) return ret; if (name) - info = spi_nor_match_id(name); + info = (struct flash_info *)spi_nor_match_id(name); /* Try to auto-detect if chip name wasn't specified or not found */ if (!info) - info = spi_nor_read_id(nor); + info = (struct flash_info *)spi_nor_read_id(nor); if (IS_ERR_OR_NULL(info)) return -ENOENT; @@ -1341,7 +1394,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) */ dev_warn(dev, "found %s, expected %s\n", jinfo->name, info->name); - info = jinfo; + info = (struct flash_info *)jinfo; } } @@ -1370,6 +1423,27 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) mtd->size = info->sector_size * info->n_sectors; mtd->_erase = spi_nor_erase; mtd->_read = spi_nor_read; +#ifdef CONFIG_OF + np_spi = of_get_next_parent(np); + + if (of_property_read_u32(np_spi, "xlnx,qspi-mode", + &xlnx_qspi_mode) < 0) { + nor->shift = 0; + nor->stripe = 0; + } else if (xlnx_qspi_mode == 2) { + nor->shift = 1; + info->sector_size <<= nor->shift; + info->page_size <<= nor->shift; + mtd->size <<= nor->shift; + nor->stripe = 1; + nor->spi->master->flags |= (SPI_MASTER_BOTH_CS | + SPI_MASTER_DATA_STRIPE); + } +#else + /* Default to single */ + nor->shift = 0; + nor->stripe = 0; +#endif /* NOR protection support for STmicro/Micron chips and similar */ if (JEDEC_MFR(info) == SNOR_MFR_MICRON || @@ -1400,10 +1474,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 { @@ -1508,16 +1582,14 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) dev_info(dev, "%s (%lld Kbytes)\n", info->name, (long long)mtd->size >> 10); - dev_dbg(dev, - "mtd .name = %s, .size = 0x%llx (%lldMiB), " + dev_dbg(dev, "mtd .name = %s, .size = 0x%llx (%lldMiB), " ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n", mtd->name, (long long)mtd->size, (long long)(mtd->size >> 20), mtd->erasesize, mtd->erasesize / 1024, mtd->numeraseregions); if (mtd->numeraseregions) for (i = 0; i < mtd->numeraseregions; i++) - dev_dbg(dev, - "mtd.eraseregions[%d] = { .offset = 0x%llx, " + dev_dbg(dev, "mtd.eraseregions[%d] = { .offset = 0x%llx, " ".erasesize = 0x%.8x (%uKiB), " ".numblocks = %d }\n", i, (long long)mtd->eraseregions[i].offset, diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 84f3ce5..673ec68 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -165,6 +165,8 @@ struct spi_nor { u8 read_dummy; u8 program_opcode; enum read_mode flash_read; + bool shift; + bool stripe; bool sst_write_second; u32 flags; u8 cmd_buf[SPI_NOR_MAX_CMD_SIZE]; -- 2.10.2