Root/target/linux/brcm47xx/patches-3.3/071-bcma-add-functions-to-write-to-nand-flash.patch

1--- a/drivers/bcma/driver_chipcommon_nflash.c
2+++ b/drivers/bcma/driver_chipcommon_nflash.c
3@@ -2,16 +2,23 @@
4  * Broadcom specific AMBA
5  * ChipCommon NAND flash interface
6  *
7+ * Copyright 2011, Tathagata Das <tathagata@alumnux.com>
8+ * Copyright 2010, Broadcom Corporation
9+ *
10  * Licensed under the GNU/GPL. See COPYING for details.
11  */
12 
13+#include <linux/delay.h>
14+#include <linux/mtd/bcm47xx_nand.h>
15+#include <linux/mtd/nand.h>
16 #include <linux/platform_device.h>
17 #include <linux/bcma/bcma.h>
18+#include <linux/bcma/bcma_driver_chipcommon.h>
19 
20 #include "bcma_private.h"
21 
22 struct platform_device bcma_nflash_dev = {
23- .name = "bcma_nflash",
24+ .name = "bcm47xx-nflash",
25     .num_resources = 0,
26 };
27 
28@@ -31,6 +38,11 @@ int bcma_nflash_init(struct bcma_drv_cc
29         return -ENODEV;
30     }
31 
32+ if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
33+ bcma_err(bus, "NAND flash support for BCM4706 not implemented\n");
34+ return -ENOTSUPP;
35+ }
36+
37     cc->nflash.present = true;
38     if (cc->core->id.rev == 38 &&
39         (cc->status & BCMA_CC_CHIPST_5357_NAND_BOOT))
40@@ -42,3 +54,141 @@ int bcma_nflash_init(struct bcma_drv_cc
41 
42     return 0;
43 }
44+
45+/* Issue a nand flash command */
46+static inline void bcma_nflash_cmd(struct bcma_drv_cc *cc, u32 opcode)
47+{
48+ bcma_cc_write32(cc, NAND_CMD_START, opcode);
49+ bcma_cc_read32(cc, NAND_CMD_START);
50+}
51+
52+/* Check offset and length */
53+static int bcma_nflash_offset_is_valid(struct bcma_drv_cc *cc, u32 offset, u32 len, u32 mask)
54+{
55+ if ((offset & mask) != 0 || (len & mask) != 0) {
56+ pr_err("%s(): Address is not aligned. offset: %x, len: %x, mask: %x\n", __func__, offset, len, mask);
57+ return 1;
58+ }
59+
60+ if ((((offset + len) >> 20) >= cc->nflash.size) &&
61+ (((offset + len) & ((1 << 20) - 1)) != 0)) {
62+ pr_err("%s(): Address is outside Flash memory region. offset: %x, len: %x, mask: %x\n", __func__, offset, len, mask);
63+ return 1;
64+ }
65+
66+ return 0;
67+}
68+
69+#define NF_RETRIES 1000000
70+
71+/* Poll for command completion. Returns zero when complete. */
72+int bcma_nflash_poll(struct bcma_drv_cc *cc)
73+{
74+ u32 retries = NF_RETRIES;
75+ u32 pollmask = NIST_CTRL_READY|NIST_FLASH_READY;
76+ u32 mask;
77+
78+ while (retries--) {
79+ mask = bcma_cc_read32(cc, NAND_INTFC_STATUS) & pollmask;
80+ if (mask == pollmask)
81+ return 0;
82+ cpu_relax();
83+ }
84+
85+ if (!retries) {
86+ pr_err("bcma_nflash_poll: not ready\n");
87+ return -1;
88+ }
89+
90+ return 0;
91+}
92+
93+/* Read len bytes starting at offset into buf. Returns number of bytes read. */
94+int bcma_nflash_read(struct bcma_drv_cc *cc, u32 offset, u32 len, u8 *buf)
95+{
96+ u32 mask;
97+ int i;
98+ u32 *to, val, res;
99+
100+ mask = NFL_SECTOR_SIZE - 1;
101+ if (bcma_nflash_offset_is_valid(cc, offset, len, mask))
102+ return 0;
103+
104+ to = (u32 *)buf;
105+ res = len;
106+ while (res > 0) {
107+ bcma_cc_write32(cc, NAND_CMD_ADDR, offset);
108+ bcma_nflash_cmd(cc, NCMD_PAGE_RD);
109+ if (bcma_nflash_poll(cc) < 0)
110+ break;
111+ val = bcma_cc_read32(cc, NAND_INTFC_STATUS);
112+ if ((val & NIST_CACHE_VALID) == 0)
113+ break;
114+ bcma_cc_write32(cc, NAND_CACHE_ADDR, 0);
115+ for (i = 0; i < NFL_SECTOR_SIZE; i += 4, to++) {
116+ *to = bcma_cc_read32(cc, NAND_CACHE_DATA);
117+ }
118+ res -= NFL_SECTOR_SIZE;
119+ offset += NFL_SECTOR_SIZE;
120+ }
121+ return (len - res);
122+}
123+
124+/* Write len bytes starting at offset into buf. Returns success (0) or failure (!0).
125+ * Should poll for completion.
126+ */
127+int bcma_nflash_write(struct bcma_drv_cc *cc, u32 offset, u32 len,
128+ const u8 *buf)
129+{
130+ u32 mask;
131+ int i;
132+ u32 *from, res, reg;
133+
134+ mask = cc->nflash.pagesize - 1;
135+ if (bcma_nflash_offset_is_valid(cc, offset, len, mask))
136+ return 1;
137+
138+ /* disable partial page enable */
139+ reg = bcma_cc_read32(cc, NAND_ACC_CONTROL);
140+ reg &= ~NAC_PARTIAL_PAGE_EN;
141+ bcma_cc_write32(cc, NAND_ACC_CONTROL, reg);
142+
143+ from = (u32 *)buf;
144+ res = len;
145+ while (res > 0) {
146+ bcma_cc_write32(cc, NAND_CACHE_ADDR, 0);
147+ for (i = 0; i < cc->nflash.pagesize; i += 4, from++) {
148+ if (i % 512 == 0)
149+ bcma_cc_write32(cc, NAND_CMD_ADDR, i);
150+ bcma_cc_write32(cc, NAND_CACHE_DATA, *from);
151+ }
152+ bcma_cc_write32(cc, NAND_CMD_ADDR, offset + cc->nflash.pagesize - 512);
153+ bcma_nflash_cmd(cc, NCMD_PAGE_PROG);
154+ if (bcma_nflash_poll(cc) < 0)
155+ break;
156+ res -= cc->nflash.pagesize;
157+ offset += cc->nflash.pagesize;
158+ }
159+
160+ if (res <= 0)
161+ return 0;
162+ else
163+ return (len - res);
164+}
165+
166+/* Erase a region. Returns success (0) or failure (-1).
167+ * Poll for completion.
168+ */
169+int bcma_nflash_erase(struct bcma_drv_cc *cc, u32 offset)
170+{
171+ if ((offset >> 20) >= cc->nflash.size)
172+ return -1;
173+ if ((offset & (cc->nflash.blocksize - 1)) != 0)
174+ return -1;
175+
176+ bcma_cc_write32(cc, NAND_CMD_ADDR, offset);
177+ bcma_nflash_cmd(cc, NCMD_BLOCK_ERASE);
178+ if (bcma_nflash_poll(cc) < 0)
179+ return -1;
180+ return 0;
181+}
182--- a/include/linux/bcma/bcma_driver_chipcommon.h
183+++ b/include/linux/bcma/bcma_driver_chipcommon.h
184@@ -4,6 +4,7 @@
185 #include <linux/platform_device.h>
186 
187 #include <linux/mtd/bcm47xx_sflash.h>
188+#include <linux/mtd/bcm47xx_nand.h>
189 
190 /** ChipCommon core registers. **/
191 #define BCMA_CC_ID 0x0000
192@@ -521,17 +522,6 @@ struct bcma_pflash {
193 };
194 
195 
196-#ifdef CONFIG_BCMA_NFLASH
197-struct mtd_info;
198-
199-struct bcma_nflash {
200- bool present;
201- bool boot; /* This is the flash the SoC boots from */
202-
203- struct mtd_info *mtd;
204-};
205-#endif
206-
207 struct bcma_serial_port {
208     void *regs;
209     unsigned long clockspeed;
210@@ -557,7 +547,7 @@ struct bcma_drv_cc {
211     struct bcm47xx_sflash sflash;
212 #endif
213 #ifdef CONFIG_BCMA_NFLASH
214- struct bcma_nflash nflash;
215+ struct bcm47xx_nflash nflash;
216 #endif
217 
218     int nr_serial_ports;
219@@ -616,4 +606,13 @@ extern void bcma_chipco_regctl_maskset(s
220                        u32 offset, u32 mask, u32 set);
221 extern void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid);
222 
223+#ifdef CONFIG_BCMA_NFLASH
224+/* Chipcommon nflash support. */
225+int bcma_nflash_read(struct bcma_drv_cc *cc, u32 offset, u32 len, u8 *buf);
226+int bcma_nflash_poll(struct bcma_drv_cc *cc);
227+int bcma_nflash_write(struct bcma_drv_cc *cc, u32 offset, u32 len, const u8 *buf);
228+int bcma_nflash_erase(struct bcma_drv_cc *cc, u32 offset);
229+int bcma_nflash_commit(struct bcma_drv_cc *cc, u32 offset, u32 len, const u8 *buf);
230+#endif
231+
232 #endif /* LINUX_BCMA_DRIVER_CC_H_ */
233

Archive Download this file



interactive