Alexey Brodkin | a7069dd | 2014-02-04 12:56:19 +0400 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2013-2014 Synopsys, Inc. All rights reserved. |
| 3 | * |
| 4 | * SPDX-License-Identifier: GPL-2.0+ |
| 5 | */ |
| 6 | |
| 7 | #include <bouncebuf.h> |
| 8 | #include <common.h> |
| 9 | #include <malloc.h> |
| 10 | #include <nand.h> |
| 11 | #include <asm/io.h> |
Alexey Brodkin | 0241c31 | 2015-04-09 19:50:58 +0300 | [diff] [blame] | 12 | #include "axs10x.h" |
| 13 | |
| 14 | DECLARE_GLOBAL_DATA_PTR; |
Alexey Brodkin | a7069dd | 2014-02-04 12:56:19 +0400 | [diff] [blame] | 15 | |
| 16 | #define BUS_WIDTH 8 /* AXI data bus width in bytes */ |
| 17 | |
| 18 | /* DMA buffer descriptor bits & masks */ |
| 19 | #define BD_STAT_OWN (1 << 31) |
| 20 | #define BD_STAT_BD_FIRST (1 << 3) |
| 21 | #define BD_STAT_BD_LAST (1 << 2) |
| 22 | #define BD_SIZES_BUFFER1_MASK 0xfff |
| 23 | |
| 24 | #define BD_STAT_BD_COMPLETE (BD_STAT_BD_FIRST | BD_STAT_BD_LAST) |
| 25 | |
| 26 | /* Controller command flags */ |
| 27 | #define B_WFR (1 << 19) /* 1b - Wait for ready */ |
| 28 | #define B_LC (1 << 18) /* 1b - Last cycle */ |
| 29 | #define B_IWC (1 << 13) /* 1b - Interrupt when complete */ |
| 30 | |
| 31 | /* NAND cycle types */ |
| 32 | #define B_CT_ADDRESS (0x0 << 16) /* Address operation */ |
| 33 | #define B_CT_COMMAND (0x1 << 16) /* Command operation */ |
| 34 | #define B_CT_WRITE (0x2 << 16) /* Write operation */ |
| 35 | #define B_CT_READ (0x3 << 16) /* Write operation */ |
| 36 | |
| 37 | enum nand_isr_t { |
| 38 | NAND_ISR_DATAREQUIRED = 0, |
| 39 | NAND_ISR_TXUNDERFLOW, |
| 40 | NAND_ISR_TXOVERFLOW, |
| 41 | NAND_ISR_DATAAVAILABLE, |
| 42 | NAND_ISR_RXUNDERFLOW, |
| 43 | NAND_ISR_RXOVERFLOW, |
| 44 | NAND_ISR_TXDMACOMPLETE, |
| 45 | NAND_ISR_RXDMACOMPLETE, |
| 46 | NAND_ISR_DESCRIPTORUNAVAILABLE, |
| 47 | NAND_ISR_CMDDONE, |
| 48 | NAND_ISR_CMDAVAILABLE, |
| 49 | NAND_ISR_CMDERROR, |
| 50 | NAND_ISR_DATATRANSFEROVER, |
| 51 | NAND_ISR_NONE |
| 52 | }; |
| 53 | |
| 54 | enum nand_regs_t { |
| 55 | AC_FIFO = 0, /* address and command fifo */ |
| 56 | IDMAC_BDADDR = 0x18, /* idmac descriptor list base address */ |
| 57 | INT_STATUS = 0x118, /* interrupt status register */ |
| 58 | INT_CLR_STATUS = 0x120, /* interrupt clear status register */ |
| 59 | }; |
| 60 | |
| 61 | struct nand_bd { |
| 62 | uint32_t status; /* DES0 */ |
| 63 | uint32_t sizes; /* DES1 */ |
| 64 | uint32_t buffer_ptr0; /* DES2 */ |
| 65 | uint32_t buffer_ptr1; /* DES3 */ |
| 66 | }; |
| 67 | |
Vasili Galka | 2fea4f5 | 2014-08-26 17:50:29 +0300 | [diff] [blame] | 68 | #define NAND_REG_WRITE(r, v) \ |
| 69 | writel(v, (volatile void __iomem *)(CONFIG_SYS_NAND_BASE + r)) |
| 70 | #define NAND_REG_READ(r) \ |
| 71 | readl((const volatile void __iomem *)(CONFIG_SYS_NAND_BASE + r)) |
Alexey Brodkin | a7069dd | 2014-02-04 12:56:19 +0400 | [diff] [blame] | 72 | |
| 73 | static struct nand_bd *bd; /* DMA buffer descriptors */ |
| 74 | |
| 75 | /** |
| 76 | * axs101_nand_write_buf - write buffer to chip |
| 77 | * @mtd: MTD device structure |
| 78 | * @buf: data buffer |
| 79 | * @len: number of bytes to write |
| 80 | */ |
| 81 | static uint32_t nand_flag_is_set(uint32_t flag) |
| 82 | { |
| 83 | uint32_t reg = NAND_REG_READ(INT_STATUS); |
| 84 | |
| 85 | if (reg & (1 << NAND_ISR_CMDERROR)) |
| 86 | return 0; |
| 87 | |
| 88 | if (reg & (1 << flag)) { |
| 89 | NAND_REG_WRITE(INT_CLR_STATUS, 1 << flag); |
| 90 | return 1; |
| 91 | } |
| 92 | |
| 93 | return 0; |
| 94 | } |
| 95 | |
| 96 | /** |
| 97 | * axs101_nand_write_buf - write buffer to chip |
| 98 | * @mtd: MTD device structure |
| 99 | * @buf: data buffer |
| 100 | * @len: number of bytes to write |
| 101 | */ |
| 102 | static void axs101_nand_write_buf(struct mtd_info *mtd, const u_char *buf, |
| 103 | int len) |
| 104 | { |
| 105 | struct bounce_buffer bbstate; |
| 106 | |
| 107 | bounce_buffer_start(&bbstate, (void *)buf, len, GEN_BB_READ); |
| 108 | |
| 109 | /* Setup buffer descriptor */ |
| 110 | writel(BD_STAT_OWN | BD_STAT_BD_COMPLETE, &bd->status); |
| 111 | writel(ALIGN(len, BUS_WIDTH) & BD_SIZES_BUFFER1_MASK, &bd->sizes); |
| 112 | writel(bbstate.bounce_buffer, &bd->buffer_ptr0); |
| 113 | writel(0, &bd->buffer_ptr1); |
| 114 | |
Alexey Brodkin | 17b0da8 | 2014-03-21 16:57:47 +0400 | [diff] [blame] | 115 | /* Flush modified buffer descriptor */ |
| 116 | flush_dcache_range((unsigned long)bd, |
| 117 | (unsigned long)bd + sizeof(struct nand_bd)); |
| 118 | |
Alexey Brodkin | a7069dd | 2014-02-04 12:56:19 +0400 | [diff] [blame] | 119 | /* Issue "write" command */ |
| 120 | NAND_REG_WRITE(AC_FIFO, B_CT_WRITE | B_WFR | B_IWC | B_LC | (len-1)); |
| 121 | |
| 122 | /* Wait for NAND command and DMA to complete */ |
| 123 | while (!nand_flag_is_set(NAND_ISR_CMDDONE)) |
| 124 | ; |
| 125 | while (!nand_flag_is_set(NAND_ISR_TXDMACOMPLETE)) |
| 126 | ; |
| 127 | |
| 128 | bounce_buffer_stop(&bbstate); |
| 129 | } |
| 130 | |
| 131 | /** |
| 132 | * axs101_nand_read_buf - read chip data into buffer |
| 133 | * @mtd: MTD device structure |
| 134 | * @buf: buffer to store data |
| 135 | * @len: number of bytes to read |
| 136 | */ |
| 137 | static void axs101_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) |
| 138 | { |
| 139 | struct bounce_buffer bbstate; |
| 140 | |
| 141 | bounce_buffer_start(&bbstate, buf, len, GEN_BB_WRITE); |
| 142 | |
| 143 | /* Setup buffer descriptor */ |
| 144 | writel(BD_STAT_OWN | BD_STAT_BD_COMPLETE, &bd->status); |
| 145 | writel(ALIGN(len, BUS_WIDTH) & BD_SIZES_BUFFER1_MASK, &bd->sizes); |
| 146 | writel(bbstate.bounce_buffer, &bd->buffer_ptr0); |
| 147 | writel(0, &bd->buffer_ptr1); |
| 148 | |
Alexey Brodkin | 17b0da8 | 2014-03-21 16:57:47 +0400 | [diff] [blame] | 149 | /* Flush modified buffer descriptor */ |
| 150 | flush_dcache_range((unsigned long)bd, |
| 151 | (unsigned long)bd + sizeof(struct nand_bd)); |
| 152 | |
Alexey Brodkin | a7069dd | 2014-02-04 12:56:19 +0400 | [diff] [blame] | 153 | /* Issue "read" command */ |
| 154 | NAND_REG_WRITE(AC_FIFO, B_CT_READ | B_WFR | B_IWC | B_LC | (len - 1)); |
| 155 | |
| 156 | /* Wait for NAND command and DMA to complete */ |
| 157 | while (!nand_flag_is_set(NAND_ISR_CMDDONE)) |
| 158 | ; |
| 159 | while (!nand_flag_is_set(NAND_ISR_RXDMACOMPLETE)) |
| 160 | ; |
| 161 | |
| 162 | bounce_buffer_stop(&bbstate); |
| 163 | } |
| 164 | |
| 165 | /** |
| 166 | * axs101_nand_read_byte - read one byte from the chip |
| 167 | * @mtd: MTD device structure |
| 168 | */ |
| 169 | static u_char axs101_nand_read_byte(struct mtd_info *mtd) |
| 170 | { |
| 171 | u8 byte; |
| 172 | |
| 173 | axs101_nand_read_buf(mtd, (uchar *)&byte, sizeof(byte)); |
| 174 | return byte; |
| 175 | } |
| 176 | |
| 177 | /** |
| 178 | * axs101_nand_read_word - read one word from the chip |
| 179 | * @mtd: MTD device structure |
| 180 | */ |
| 181 | static u16 axs101_nand_read_word(struct mtd_info *mtd) |
| 182 | { |
| 183 | u16 word; |
| 184 | |
| 185 | axs101_nand_read_buf(mtd, (uchar *)&word, sizeof(word)); |
| 186 | return word; |
| 187 | } |
| 188 | |
| 189 | /** |
| 190 | * axs101_nand_hwcontrol - NAND control functions wrapper. |
| 191 | * @mtd: MTD device structure |
| 192 | * @cmd: Command |
| 193 | */ |
| 194 | static void axs101_nand_hwcontrol(struct mtd_info *mtdinfo, int cmd, |
| 195 | unsigned int ctrl) |
| 196 | { |
| 197 | if (cmd == NAND_CMD_NONE) |
| 198 | return; |
| 199 | |
| 200 | cmd = cmd & 0xff; |
| 201 | |
| 202 | switch (ctrl & (NAND_ALE | NAND_CLE)) { |
| 203 | /* Address */ |
| 204 | case NAND_ALE: |
| 205 | cmd |= B_CT_ADDRESS; |
| 206 | break; |
| 207 | |
| 208 | /* Command */ |
| 209 | case NAND_CLE: |
| 210 | cmd |= B_CT_COMMAND | B_WFR; |
| 211 | |
| 212 | break; |
| 213 | |
| 214 | default: |
| 215 | debug("%s: unknown ctrl %#x\n", __func__, ctrl); |
| 216 | } |
| 217 | |
| 218 | NAND_REG_WRITE(AC_FIFO, cmd | B_LC); |
| 219 | while (!nand_flag_is_set(NAND_ISR_CMDDONE)) |
| 220 | ; |
| 221 | } |
| 222 | |
| 223 | int board_nand_init(struct nand_chip *nand) |
| 224 | { |
| 225 | bd = (struct nand_bd *)memalign(ARCH_DMA_MINALIGN, |
| 226 | sizeof(struct nand_bd)); |
| 227 | |
| 228 | /* Set buffer descriptor address in IDMAC */ |
| 229 | NAND_REG_WRITE(IDMAC_BDADDR, bd); |
| 230 | |
| 231 | nand->ecc.mode = NAND_ECC_SOFT; |
| 232 | nand->cmd_ctrl = axs101_nand_hwcontrol; |
| 233 | nand->read_byte = axs101_nand_read_byte; |
| 234 | nand->read_word = axs101_nand_read_word; |
| 235 | nand->write_buf = axs101_nand_write_buf; |
| 236 | nand->read_buf = axs101_nand_read_buf; |
| 237 | |
Alexey Brodkin | 0241c31 | 2015-04-09 19:50:58 +0300 | [diff] [blame] | 238 | /* MBv3 has NAND IC with 16-bit data bus */ |
| 239 | if (gd->board_type == AXS_MB_V3) |
| 240 | nand->options |= NAND_BUSWIDTH_16; |
| 241 | |
Alexey Brodkin | a7069dd | 2014-02-04 12:56:19 +0400 | [diff] [blame] | 242 | return 0; |
| 243 | } |