sunxi: add support for 4.1
[openwrt.git] / target / linux / sunxi / patches-4.1 / 129-nand-sunxi-fix-write-to-USER_DATA-a13.patch
1 From b1488f1a55da6a297ac4e8e9140922f35b7583c5 Mon Sep 17 00:00:00 2001
2 From: Boris Brezillon <boris.brezillon@free-electrons.com>
3 Date: Mon, 15 Jun 2015 11:09:58 +0200
4 Subject: [PATCH] nand: sunxi: fix write to USER_DATA reg
5
6 The USER_DATA register cannot be updated with readb on A13 SoCs, thus
7 triggering a bug when using memcpy_toio on this register.
8 Use writel (plus a temporary variable to old the USER_DATA value) to
9 address that problem.
10
11 Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
12 ---
13  drivers/mtd/nand/sunxi_nand.c | 38 +++++++++++++++++++++-----------------
14  1 file changed, 21 insertions(+), 17 deletions(-)
15
16 diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
17 index 72ab770..3668197 100644
18 --- a/drivers/mtd/nand/sunxi_nand.c
19 +++ b/drivers/mtd/nand/sunxi_nand.c
20 @@ -904,7 +904,7 @@ static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
21  
22         for (i = 0; i < ecc->steps; i++) {
23                 bool rndactiv = false;
24 -               u8 oob_buf[4];
25 +               u32 user_data;
26  
27                 if (i)
28                         chip->cmdfunc(mtd, NAND_CMD_RNDIN, i * ecc->size, -1);
29 @@ -915,15 +915,13 @@ static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
30                 offset = layout->eccpos[i * ecc->bytes] - 4 + mtd->writesize;
31  
32                 /* Fill OOB data in */
33 -               if (!oob_required)
34 -                       memset(oob_buf, 0xff, 4);
35 -               else
36 -                       memcpy(oob_buf,
37 -                              chip->oob_poi + layout->oobfree[i].offset,
38 -                              4);
39 -
40 -
41 -               memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE, oob_buf, 4);
42 +               if (!oob_required) {
43 +                       user_data = 0xffffffff;
44 +               } else {
45 +                       memcpy(&user_data,
46 +                              chip->oob_poi + layout->oobfree[i].offset, 4);
47 +                       user_data = le32_to_cpu(user_data);
48 +               }
49  
50                 if (i) {
51                         cnt = ecc->bytes + 4;
52 @@ -942,12 +940,16 @@ static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
53                 if (rndactiv) {
54                         /* pre randomize to generate FF patterns on the NAND */
55                         if (!i) {
56 +                               u8 oob_tmp[2];
57                                 u16 state = rnd->subseeds[rnd->page % rnd->nseeds];
58 +                               oob_tmp[0] = user_data;
59 +                               oob_tmp[1] = user_data >> 8;
60                                 state = sunxi_nfc_hwrnd_single_step(state, 15);
61 -                               oob_buf[0] ^= state;
62 +                               oob_tmp[0] ^= state;
63                                 state = sunxi_nfc_hwrnd_step(rnd, state, 1);
64 -                               oob_buf[1] ^= state;
65 -                               memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE, oob_buf, 4);
66 +                               oob_tmp[1] ^= state;
67 +                               user_data &= ~0xffff;
68 +                               user_data |= oob_tmp[0] | (oob_tmp[1] << 8);
69                         }
70                         tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
71                         tmp &= ~(NFC_RANDOM_DIRECTION | NFC_ECC_EXCEPTION);
72 @@ -955,6 +957,8 @@ static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
73                         writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
74                 }
75  
76 +               writel(user_data, nfc->regs + NFC_REG_USER_DATA_BASE);
77 +
78                 chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1);
79  
80                 ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
81 @@ -1164,13 +1168,13 @@ static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd,
82                 /* Fill OOB data in */
83                 if (oob_required) {
84                         tmp = 0xffffffff;
85 -                       memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE, &tmp,
86 -                                   4);
87                 } else {
88 -                       memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE, oob,
89 -                                   4);
90 +                       memcpy(&tmp, oob, sizeof(tmp));
91 +                       tmp = le32_to_cpu(tmp);
92                 }
93  
94 +               writel(tmp, nfc->regs + NFC_REG_USER_DATA_BASE);
95 +
96                 cnt = ecc->bytes + 4;
97                 if (rnd &&
98                     nand_rnd_is_activ(mtd, rnd->page, offset, &cnt) > 0 &&