0041-Add-SMI-NAND-driver.patch 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. From 7c6a797f5ff01d8e968331eb83782ecbf2f13e6d Mon Sep 17 00:00:00 2001
  2. From: Luke Wren <wren6991@gmail.com>
  3. Date: Sat, 5 Sep 2015 01:16:10 +0100
  4. Subject: [PATCH] Add SMI NAND driver
  5. Signed-off-by: Luke Wren <wren6991@gmail.com>
  6. ---
  7. .../bindings/mtd/brcm,bcm2835-smi-nand.txt | 42 ++++
  8. drivers/mtd/nand/Kconfig | 7 +
  9. drivers/mtd/nand/Makefile | 1 +
  10. drivers/mtd/nand/bcm2835_smi_nand.c | 268 +++++++++++++++++++++
  11. 4 files changed, 318 insertions(+)
  12. create mode 100644 Documentation/devicetree/bindings/mtd/brcm,bcm2835-smi-nand.txt
  13. create mode 100644 drivers/mtd/nand/bcm2835_smi_nand.c
  14. --- /dev/null
  15. +++ b/Documentation/devicetree/bindings/mtd/brcm,bcm2835-smi-nand.txt
  16. @@ -0,0 +1,42 @@
  17. +* BCM2835 SMI NAND flash
  18. +
  19. +This driver is a shim between the BCM2835 SMI driver (SMI is a peripheral for
  20. +talking to parallel register interfaces) and Linux's MTD layer.
  21. +
  22. +Required properties:
  23. +- compatible: "brcm,bcm2835-smi-nand"
  24. +- status: "okay"
  25. +
  26. +Optional properties:
  27. +- partition@n, where n is an integer from a consecutive sequence starting at 0
  28. + - Difficult to store partition table on NAND device - normally put it
  29. + in the source code, kernel bootparams, or device tree (the best way!)
  30. + - Sub-properties:
  31. + - label: the partition name, as shown by mtdinfo /dev/mtd*
  32. + - reg: the size and offset of this partition.
  33. + - (optional) read-only: an empty property flagging as read only
  34. +
  35. +Example:
  36. +
  37. +nand: flash@0 {
  38. + compatible = "brcm,bcm2835-smi-nand";
  39. + status = "okay";
  40. +
  41. + partition@0 {
  42. + label = "stage2";
  43. + // 128k
  44. + reg = <0 0x20000>;
  45. + read-only;
  46. + };
  47. + partition@1 {
  48. + label = "firmware";
  49. + // 16M
  50. + reg = <0x20000 0x1000000>;
  51. + read-only;
  52. + };
  53. + partition@2 {
  54. + label = "root";
  55. + // 2G
  56. + reg = <0x1020000 0x80000000>;
  57. + };
  58. +};
  59. \ No newline at end of file
  60. --- a/drivers/mtd/nand/Kconfig
  61. +++ b/drivers/mtd/nand/Kconfig
  62. @@ -41,6 +41,13 @@ config MTD_SM_COMMON
  63. tristate
  64. default n
  65. +config MTD_NAND_BCM2835_SMI
  66. + tristate "Use Broadcom's Secondary Memory Interface as a NAND controller (BCM283x)"
  67. + depends on (MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835) && BCM2835_SMI && MTD_NAND
  68. + default m
  69. + help
  70. + Uses the BCM2835's SMI peripheral as a NAND controller.
  71. +
  72. config MTD_NAND_DENALI
  73. tristate
  74. --- a/drivers/mtd/nand/Makefile
  75. +++ b/drivers/mtd/nand/Makefile
  76. @@ -14,6 +14,7 @@ obj-$(CONFIG_MTD_NAND_DENALI) += denali
  77. obj-$(CONFIG_MTD_NAND_DENALI_PCI) += denali_pci.o
  78. obj-$(CONFIG_MTD_NAND_DENALI_DT) += denali_dt.o
  79. obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o
  80. +obj-$(CONFIG_MTD_NAND_BCM2835_SMI) += bcm2835_smi_nand.o
  81. obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o
  82. obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o
  83. obj-$(CONFIG_MTD_NAND_DAVINCI) += davinci_nand.o
  84. --- /dev/null
  85. +++ b/drivers/mtd/nand/bcm2835_smi_nand.c
  86. @@ -0,0 +1,268 @@
  87. +/**
  88. + * NAND flash driver for Broadcom Secondary Memory Interface
  89. + *
  90. + * Written by Luke Wren <luke@raspberrypi.org>
  91. + * Copyright (c) 2015, Raspberry Pi (Trading) Ltd.
  92. + *
  93. + * Redistribution and use in source and binary forms, with or without
  94. + * modification, are permitted provided that the following conditions
  95. + * are met:
  96. + * 1. Redistributions of source code must retain the above copyright
  97. + * notice, this list of conditions, and the following disclaimer,
  98. + * without modification.
  99. + * 2. Redistributions in binary form must reproduce the above copyright
  100. + * notice, this list of conditions and the following disclaimer in the
  101. + * documentation and/or other materials provided with the distribution.
  102. + * 3. The names of the above-listed copyright holders may not be used
  103. + * to endorse or promote products derived from this software without
  104. + * specific prior written permission.
  105. + *
  106. + * ALTERNATIVELY, this software may be distributed under the terms of the
  107. + * GNU General Public License ("GPL") version 2, as published by the Free
  108. + * Software Foundation.
  109. + *
  110. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  111. + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  112. + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  113. + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  114. + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  115. + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  116. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  117. + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  118. + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  119. + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  120. + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  121. + */
  122. +
  123. +#include <linux/kernel.h>
  124. +#include <linux/module.h>
  125. +#include <linux/of.h>
  126. +#include <linux/platform_device.h>
  127. +#include <linux/slab.h>
  128. +#include <linux/mtd/nand.h>
  129. +#include <linux/mtd/partitions.h>
  130. +
  131. +#include <linux/broadcom/bcm2835_smi.h>
  132. +
  133. +#define DEVICE_NAME "bcm2835-smi-nand"
  134. +#define DRIVER_NAME "smi-nand-bcm2835"
  135. +
  136. +struct bcm2835_smi_nand_host {
  137. + struct bcm2835_smi_instance *smi_inst;
  138. + struct nand_chip nand_chip;
  139. + struct mtd_info mtd;
  140. + struct device *dev;
  141. +};
  142. +
  143. +/****************************************************************************
  144. +*
  145. +* NAND functionality implementation
  146. +*
  147. +****************************************************************************/
  148. +
  149. +#define SMI_NAND_CLE_PIN 0x01
  150. +#define SMI_NAND_ALE_PIN 0x02
  151. +
  152. +static inline void bcm2835_smi_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
  153. + unsigned int ctrl)
  154. +{
  155. + uint32_t cmd32 = cmd;
  156. + uint32_t addr = ~(SMI_NAND_CLE_PIN | SMI_NAND_ALE_PIN);
  157. + struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
  158. + struct bcm2835_smi_instance *inst = host->smi_inst;
  159. +
  160. + if (ctrl & NAND_CLE)
  161. + addr |= SMI_NAND_CLE_PIN;
  162. + if (ctrl & NAND_ALE)
  163. + addr |= SMI_NAND_ALE_PIN;
  164. + /* Lower ALL the CS pins! */
  165. + if (ctrl & NAND_NCE)
  166. + addr &= (SMI_NAND_CLE_PIN | SMI_NAND_ALE_PIN);
  167. +
  168. + bcm2835_smi_set_address(inst, addr);
  169. +
  170. + if (cmd != NAND_CMD_NONE)
  171. + bcm2835_smi_write_buf(inst, &cmd32, 1);
  172. +}
  173. +
  174. +static inline uint8_t bcm2835_smi_nand_read_byte(struct mtd_info *mtd)
  175. +{
  176. + uint8_t byte;
  177. + struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
  178. + struct bcm2835_smi_instance *inst = host->smi_inst;
  179. +
  180. + bcm2835_smi_read_buf(inst, &byte, 1);
  181. + return byte;
  182. +}
  183. +
  184. +static inline void bcm2835_smi_nand_write_byte(struct mtd_info *mtd,
  185. + uint8_t byte)
  186. +{
  187. + struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
  188. + struct bcm2835_smi_instance *inst = host->smi_inst;
  189. +
  190. + bcm2835_smi_write_buf(inst, &byte, 1);
  191. +}
  192. +
  193. +static inline void bcm2835_smi_nand_write_buf(struct mtd_info *mtd,
  194. + const uint8_t *buf, int len)
  195. +{
  196. + struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
  197. + struct bcm2835_smi_instance *inst = host->smi_inst;
  198. +
  199. + bcm2835_smi_write_buf(inst, buf, len);
  200. +}
  201. +
  202. +static inline void bcm2835_smi_nand_read_buf(struct mtd_info *mtd,
  203. + uint8_t *buf, int len)
  204. +{
  205. + struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
  206. + struct bcm2835_smi_instance *inst = host->smi_inst;
  207. +
  208. + bcm2835_smi_read_buf(inst, buf, len);
  209. +}
  210. +
  211. +/****************************************************************************
  212. +*
  213. +* Probe and remove functions
  214. +*
  215. +***************************************************************************/
  216. +
  217. +static int bcm2835_smi_nand_probe(struct platform_device *pdev)
  218. +{
  219. + struct bcm2835_smi_nand_host *host;
  220. + struct nand_chip *this;
  221. + struct mtd_info *mtd;
  222. + struct device *dev = &pdev->dev;
  223. + struct device_node *node = dev->of_node, *smi_node;
  224. + struct mtd_part_parser_data ppdata;
  225. + struct smi_settings *smi_settings;
  226. + struct bcm2835_smi_instance *smi_inst;
  227. + int ret = -ENXIO;
  228. +
  229. + if (!node) {
  230. + dev_err(dev, "No device tree node supplied!");
  231. + return -EINVAL;
  232. + }
  233. +
  234. + smi_node = of_parse_phandle(node, "smi_handle", 0);
  235. +
  236. + /* Request use of SMI peripheral: */
  237. + smi_inst = bcm2835_smi_get(smi_node);
  238. +
  239. + if (!smi_inst) {
  240. + dev_err(dev, "Could not register with SMI.");
  241. + return -EPROBE_DEFER;
  242. + }
  243. +
  244. + /* Set SMI timing and bus width */
  245. +
  246. + smi_settings = bcm2835_smi_get_settings_from_regs(smi_inst);
  247. +
  248. + smi_settings->data_width = SMI_WIDTH_8BIT;
  249. + smi_settings->read_setup_time = 2;
  250. + smi_settings->read_hold_time = 1;
  251. + smi_settings->read_pace_time = 1;
  252. + smi_settings->read_strobe_time = 3;
  253. +
  254. + smi_settings->write_setup_time = 2;
  255. + smi_settings->write_hold_time = 1;
  256. + smi_settings->write_pace_time = 1;
  257. + smi_settings->write_strobe_time = 3;
  258. +
  259. + bcm2835_smi_set_regs_from_settings(smi_inst);
  260. +
  261. + host = devm_kzalloc(dev, sizeof(struct bcm2835_smi_nand_host),
  262. + GFP_KERNEL);
  263. + if (!host)
  264. + return -ENOMEM;
  265. +
  266. + host->dev = dev;
  267. + host->smi_inst = smi_inst;
  268. +
  269. + platform_set_drvdata(pdev, host);
  270. +
  271. + /* Link the structures together */
  272. +
  273. + this = &host->nand_chip;
  274. + mtd = &host->mtd;
  275. + mtd->priv = this;
  276. + mtd->owner = THIS_MODULE;
  277. + mtd->dev.parent = dev;
  278. + mtd->name = DRIVER_NAME;
  279. + ppdata.of_node = node;
  280. +
  281. + /* 20 us command delay time... */
  282. + this->chip_delay = 20;
  283. +
  284. + this->priv = host;
  285. + this->cmd_ctrl = bcm2835_smi_nand_cmd_ctrl;
  286. + this->read_byte = bcm2835_smi_nand_read_byte;
  287. + this->write_byte = bcm2835_smi_nand_write_byte;
  288. + this->write_buf = bcm2835_smi_nand_write_buf;
  289. + this->read_buf = bcm2835_smi_nand_read_buf;
  290. +
  291. + this->ecc.mode = NAND_ECC_SOFT;
  292. +
  293. + /* Should never be accessed directly: */
  294. +
  295. + this->IO_ADDR_R = (void *)0xdeadbeef;
  296. + this->IO_ADDR_W = (void *)0xdeadbeef;
  297. +
  298. + /* First scan to find the device and get the page size */
  299. +
  300. + if (nand_scan_ident(mtd, 1, NULL))
  301. + return -ENXIO;
  302. +
  303. + /* Second phase scan */
  304. +
  305. + if (nand_scan_tail(mtd))
  306. + return -ENXIO;
  307. +
  308. + ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
  309. + if (!ret)
  310. + return 0;
  311. +
  312. + nand_release(mtd);
  313. + return -EINVAL;
  314. +}
  315. +
  316. +static int bcm2835_smi_nand_remove(struct platform_device *pdev)
  317. +{
  318. + struct bcm2835_smi_nand_host *host = platform_get_drvdata(pdev);
  319. +
  320. + nand_release(&host->mtd);
  321. +
  322. + return 0;
  323. +}
  324. +
  325. +/****************************************************************************
  326. +*
  327. +* Register the driver with device tree
  328. +*
  329. +***************************************************************************/
  330. +
  331. +static const struct of_device_id bcm2835_smi_nand_of_match[] = {
  332. + {.compatible = "brcm,bcm2835-smi-nand",},
  333. + { /* sentinel */ }
  334. +};
  335. +
  336. +MODULE_DEVICE_TABLE(of, bcm2835_smi_nand_of_match);
  337. +
  338. +static struct platform_driver bcm2835_smi_nand_driver = {
  339. + .probe = bcm2835_smi_nand_probe,
  340. + .remove = bcm2835_smi_nand_remove,
  341. + .driver = {
  342. + .name = DRIVER_NAME,
  343. + .owner = THIS_MODULE,
  344. + .of_match_table = bcm2835_smi_nand_of_match,
  345. + },
  346. +};
  347. +
  348. +module_platform_driver(bcm2835_smi_nand_driver);
  349. +
  350. +MODULE_ALIAS("platform:smi-nand-bcm2835");
  351. +MODULE_LICENSE("GPL");
  352. +MODULE_DESCRIPTION
  353. + ("Driver for NAND chips using Broadcom Secondary Memory Interface");
  354. +MODULE_AUTHOR("Luke Wren <luke@raspberrypi.org>");