brcm47xx: deactivate mips wait instruction only for BCM4706
[openwrt.git] / target / linux / brcm47xx / patches-3.10 / 053-mtd_bcm47xxsflash_writing_support.patch
1 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
2 Subject: [RFC][PATCH] mtd: bcm47xxsflash: writing support
3 Date: Wed, 22 May 2013 14:39:02 +0200
4
5 ---
6  drivers/mtd/devices/bcm47xxsflash.c |  130 +++++++++++++++++++++++++++++++++--
7  1 file changed, 126 insertions(+), 4 deletions(-)
8
9 --- a/drivers/mtd/devices/bcm47xxsflash.c
10 +++ b/drivers/mtd/devices/bcm47xxsflash.c
11 @@ -116,6 +116,127 @@ static int bcm47xxsflash_read(struct mtd
12         return len;
13  }
14  
15 +static int bcm47xxsflash_write_st(struct mtd_info *mtd, u32 offset, size_t len,
16 +                                 const u_char *buf)
17 +{
18 +       struct bcm47xxsflash *b47s = mtd->priv;
19 +       int written = 0;
20 +
21 +       /* Enable writes */
22 +       bcm47xxsflash_cmd(b47s, OPCODE_ST_WREN);
23 +
24 +       /* Write first byte */
25 +       b47s->cc_write(b47s, BCMA_CC_FLASHADDR, offset);
26 +       b47s->cc_write(b47s, BCMA_CC_FLASHDATA, *buf++);
27 +
28 +       /* Program page */
29 +       if (b47s->bcma_cc->core->id.rev < 20) {
30 +               bcm47xxsflash_cmd(b47s, OPCODE_ST_PP);
31 +               return 1; /* 1B written */
32 +       }
33 +
34 +       /* Program page and set CSA (on newer chips we can continue writing) */
35 +       bcm47xxsflash_cmd(b47s, OPCODE_ST_CSA | OPCODE_ST_PP);
36 +       offset++;
37 +       len--;
38 +       written++;
39 +
40 +       while (len > 0) {
41 +               /* Page boundary, another function call is needed */
42 +               if ((offset & 0xFF) == 0)
43 +                       break;
44 +
45 +               bcm47xxsflash_cmd(b47s, OPCODE_ST_CSA | *buf++);
46 +               offset++;
47 +               len--;
48 +               written++;
49 +       }
50 +
51 +       /* All done, drop CSA & poll */
52 +       b47s->cc_write(b47s, BCMA_CC_FLASHCTL, 0);
53 +       udelay(1);
54 +       if (bcm47xxsflash_poll(b47s, HZ / 10))
55 +               pr_err("Flash rejected dropping CSA\n");
56 +
57 +       return written;
58 +}
59 +
60 +static int bcm47xxsflash_write_at(struct mtd_info *mtd, u32 offset, size_t len,
61 +                                 const u_char *buf)
62 +{
63 +       struct bcm47xxsflash *b47s = mtd->priv;
64 +       u32 mask = b47s->blocksize - 1;
65 +       u32 page = (offset & ~mask) << 1;
66 +       u32 byte = offset & mask;
67 +       int written = 0;
68 +
69 +       /* If we don't overwrite whole page, read it to the buffer first */
70 +       if (byte || (len < b47s->blocksize)) {
71 +               int err;
72 +
73 +               b47s->cc_write(b47s, BCMA_CC_FLASHADDR, page);
74 +               bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_LOAD);
75 +               /* 250 us for AT45DB321B */
76 +               err = bcm47xxsflash_poll(b47s, HZ / 1000);
77 +               if (err) {
78 +                       pr_err("Timeout reading page 0x%X info buffer\n", page);
79 +                       return err;
80 +               }
81 +       }
82 +
83 +       /* Change buffer content with our data */
84 +       while (len > 0) {
85 +               /* Page boundary, another function call is needed */
86 +               if (byte == b47s->blocksize)
87 +                       break;
88 +
89 +               b47s->cc_write(b47s, BCMA_CC_FLASHADDR, byte++);
90 +               b47s->cc_write(b47s, BCMA_CC_FLASHDATA, *buf++);
91 +               bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_WRITE);
92 +               len--;
93 +               written++;
94 +       }
95 +
96 +       /* Program page with the buffer content */
97 +       b47s->cc_write(b47s, BCMA_CC_FLASHADDR, page);
98 +       bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_PROGRAM);
99 +
100 +       return written;
101 +}
102 +
103 +static int bcm47xxsflash_write(struct mtd_info *mtd, loff_t to, size_t len,
104 +                              size_t *retlen, const u_char *buf)
105 +{
106 +       struct bcm47xxsflash *b47s = mtd->priv;
107 +       int written;
108 +
109 +       /* Writing functions can return without writing all passed data, for
110 +        * example when the hardware is too old or when we git page boundary.
111 +        */
112 +       while (len > 0) {
113 +               switch (b47s->type) {
114 +               case BCM47XXSFLASH_TYPE_ST:
115 +                       written = bcm47xxsflash_write_st(mtd, to, len, buf);
116 +                       break;
117 +               case BCM47XXSFLASH_TYPE_ATMEL:
118 +                       written = bcm47xxsflash_write_at(mtd, to, len, buf);
119 +                       break;
120 +               default:
121 +                       BUG_ON(1);
122 +               }
123 +               if (written < 0) {
124 +                       pr_err("Error writing at offset 0x%llX\n", to);
125 +                       return written;
126 +               }
127 +               to += (loff_t)written;
128 +               len -= written;
129 +               *retlen += written;
130 +               buf += written;
131 +       }
132 +
133 +       return 0;
134 +}
135 +
136  static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s)
137  {
138         struct mtd_info *mtd = &b47s->mtd;
139 @@ -123,16 +244,17 @@ static void bcm47xxsflash_fill_mtd(struc
140         mtd->priv = b47s;
141         mtd->name = "bcm47xxsflash";
142         mtd->owner = THIS_MODULE;
143 -       mtd->type = MTD_ROM;
144  
145 -       /* TODO: implement writing support and verify/change following code */
146 -       mtd->flags = MTD_CAP_ROM;
147 +       mtd->type = MTD_NORFLASH;
148 +       mtd->flags = MTD_CAP_NORFLASH;
149         mtd->size = b47s->size;
150         mtd->erasesize = b47s->blocksize;
151 -       mtd->writebufsize = mtd->writesize = 1;
152 +       mtd->writesize = 1;
153 +       mtd->writebufsize = 1;
154  
155         mtd->_erase = bcm47xxsflash_erase;
156         mtd->_read = bcm47xxsflash_read;
157 +       mtd->_write = bcm47xxsflash_write;
158  }
159  
160  /**************************************************