blob: f72142817e7f85317332270ee1df9b76845303db [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Masahiro Yamadad182d542014-10-03 19:21:04 +09002/*
3 * Copyright (C) 2014 Panasonic Corporation
Masahiro Yamada06b47812015-08-27 18:52:36 +09004 * Copyright (C) 2014-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
Masahiro Yamadad182d542014-10-03 19:21:04 +09005 */
6
7#include <common.h>
Simon Glass0f2af882020-05-10 11:40:05 -06008#include <log.h>
Masahiro Yamadad182d542014-10-03 19:21:04 +09009#include <asm/io.h>
10#include <asm/unaligned.h>
Simon Glassdbd79542020-05-10 11:40:11 -060011#include <linux/delay.h>
Masahiro Yamada2b7a8732017-11-30 13:45:24 +090012#include <linux/mtd/rawnand.h>
Masahiro Yamadad182d542014-10-03 19:21:04 +090013#include "denali.h"
14
Masahiro Yamada8b0c16f2017-11-22 02:38:32 +090015#define DENALI_MAP01 (1 << 26) /* read/write pages in PIO */
16#define DENALI_MAP10 (2 << 26) /* high-level control plane */
17
18#define INDEX_CTRL_REG 0x0
19#define INDEX_DATA_REG 0x10
20
Masahiro Yamadad182d542014-10-03 19:21:04 +090021#define SPARE_ACCESS 0x41
22#define MAIN_ACCESS 0x42
23#define PIPELINE_ACCESS 0x2000
24
25#define BANK(x) ((x) << 24)
26
27static void __iomem *denali_flash_mem =
28 (void __iomem *)CONFIG_SYS_NAND_DATA_BASE;
29static void __iomem *denali_flash_reg =
30 (void __iomem *)CONFIG_SYS_NAND_REGS_BASE;
31
32static const int flash_bank;
Masahiro Yamadad182d542014-10-03 19:21:04 +090033static int page_size, oob_size, pages_per_block;
34
35static void index_addr(uint32_t address, uint32_t data)
36{
37 writel(address, denali_flash_mem + INDEX_CTRL_REG);
38 writel(data, denali_flash_mem + INDEX_DATA_REG);
39}
40
41static int wait_for_irq(uint32_t irq_mask)
42{
43 unsigned long timeout = 1000000;
44 uint32_t intr_status;
45
46 do {
47 intr_status = readl(denali_flash_reg + INTR_STATUS(flash_bank));
48
Masahiro Yamada8b0c16f2017-11-22 02:38:32 +090049 if (intr_status & INTR__ECC_UNCOR_ERR) {
Masahiro Yamadad182d542014-10-03 19:21:04 +090050 debug("Uncorrected ECC detected\n");
Scott Wood52ab7ce2016-05-30 13:57:58 -050051 return -EBADMSG;
Masahiro Yamadad182d542014-10-03 19:21:04 +090052 }
53
54 if (intr_status & irq_mask)
55 break;
56
57 udelay(1);
58 timeout--;
59 } while (timeout);
60
61 if (!timeout) {
62 debug("Timeout with interrupt status %08x\n", intr_status);
63 return -EIO;
64 }
65
66 return 0;
67}
68
69static void read_data_from_flash_mem(uint8_t *buf, int len)
70{
71 int i;
72 uint32_t *buf32;
73
74 /* transfer the data from the flash */
75 buf32 = (uint32_t *)buf;
76
77 /*
78 * Let's take care of unaligned access although it rarely happens.
79 * Avoid put_unaligned() for the normal use cases since it leads to
80 * a bit performance regression.
81 */
82 if ((unsigned long)buf32 % 4) {
83 for (i = 0; i < len / 4; i++)
84 put_unaligned(readl(denali_flash_mem + INDEX_DATA_REG),
85 buf32++);
86 } else {
87 for (i = 0; i < len / 4; i++)
88 *buf32++ = readl(denali_flash_mem + INDEX_DATA_REG);
89 }
90
91 if (len % 4) {
92 u32 tmp;
93
94 tmp = cpu_to_le32(readl(denali_flash_mem + INDEX_DATA_REG));
95 buf = (uint8_t *)buf32;
96 for (i = 0; i < len % 4; i++) {
97 *buf++ = tmp;
98 tmp >>= 8;
99 }
100 }
101}
102
103int denali_send_pipeline_cmd(int page, int ecc_en, int access_type)
104{
105 uint32_t addr, cmd;
106 static uint32_t page_count = 1;
107
108 writel(ecc_en, denali_flash_reg + ECC_ENABLE);
109
110 /* clear all bits of intr_status. */
111 writel(0xffff, denali_flash_reg + INTR_STATUS(flash_bank));
112
113 addr = BANK(flash_bank) | page;
114
115 /* setup the acccess type */
Masahiro Yamada8b0c16f2017-11-22 02:38:32 +0900116 cmd = DENALI_MAP10 | addr;
Masahiro Yamadad182d542014-10-03 19:21:04 +0900117 index_addr(cmd, access_type);
118
119 /* setup the pipeline command */
120 index_addr(cmd, PIPELINE_ACCESS | page_count);
121
Masahiro Yamada8b0c16f2017-11-22 02:38:32 +0900122 cmd = DENALI_MAP01 | addr;
Masahiro Yamadad182d542014-10-03 19:21:04 +0900123 writel(cmd, denali_flash_mem + INDEX_CTRL_REG);
124
Masahiro Yamada8b0c16f2017-11-22 02:38:32 +0900125 return wait_for_irq(INTR__LOAD_COMP);
Masahiro Yamadad182d542014-10-03 19:21:04 +0900126}
127
128static int nand_read_oob(void *buf, int page)
129{
130 int ret;
131
132 ret = denali_send_pipeline_cmd(page, 0, SPARE_ACCESS);
133 if (ret < 0)
134 return ret;
135
136 read_data_from_flash_mem(buf, oob_size);
137
138 return 0;
139}
140
141static int nand_read_page(void *buf, int page)
142{
143 int ret;
144
145 ret = denali_send_pipeline_cmd(page, 1, MAIN_ACCESS);
146 if (ret < 0)
147 return ret;
148
149 read_data_from_flash_mem(buf, page_size);
150
151 return 0;
152}
153
Masahiro Yamada06b47812015-08-27 18:52:36 +0900154static int nand_block_isbad(void *buf, int block)
Masahiro Yamadad182d542014-10-03 19:21:04 +0900155{
156 int ret;
157
Masahiro Yamada06b47812015-08-27 18:52:36 +0900158 ret = nand_read_oob(buf, block * pages_per_block);
Masahiro Yamadad182d542014-10-03 19:21:04 +0900159 if (ret < 0)
160 return ret;
161
Masahiro Yamada06b47812015-08-27 18:52:36 +0900162 return *((uint8_t *)buf + CONFIG_SYS_NAND_BAD_BLOCK_POS) != 0xff;
Masahiro Yamadad182d542014-10-03 19:21:04 +0900163}
164
165/* nand_init() - initialize data to make nand usable by SPL */
166void nand_init(void)
167{
168 /* access to main area */
169 writel(0, denali_flash_reg + TRANSFER_SPARE_REG);
170
171 /*
172 * These registers are expected to be already set by the hardware
173 * or earlier boot code. So we read these values out.
174 */
175 page_size = readl(denali_flash_reg + DEVICE_MAIN_AREA_SIZE);
176 oob_size = readl(denali_flash_reg + DEVICE_SPARE_AREA_SIZE);
177 pages_per_block = readl(denali_flash_reg + PAGES_PER_BLOCK);
Marek Vasut4f31a602020-01-21 20:03:09 +0100178
179 /* Do as denali_hw_init() does. */
180 writel(CONFIG_NAND_DENALI_SPARE_AREA_SKIP_BYTES,
181 denali_flash_reg + SPARE_AREA_SKIP_BYTES);
182 writel(0x0F, denali_flash_reg + RB_PIN_ENABLED);
183 writel(CHIP_EN_DONT_CARE__FLAG, denali_flash_reg + CHIP_ENABLE_DONT_CARE);
184 writel(0xffff, denali_flash_reg + SPARE_AREA_MARKER);
Masahiro Yamadad182d542014-10-03 19:21:04 +0900185}
186
187int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
188{
189 int block, page, column, readlen;
190 int ret;
191 int force_bad_block_check = 1;
192
193 page = offs / page_size;
194 column = offs % page_size;
195
196 block = page / pages_per_block;
197 page = page % pages_per_block;
198
199 while (size) {
200 if (force_bad_block_check || page == 0) {
Masahiro Yamada06b47812015-08-27 18:52:36 +0900201 ret = nand_block_isbad(dst, block);
Masahiro Yamadad182d542014-10-03 19:21:04 +0900202 if (ret < 0)
203 return ret;
204
205 if (ret) {
206 block++;
207 continue;
208 }
209 }
210
211 force_bad_block_check = 0;
212
Masahiro Yamada06b47812015-08-27 18:52:36 +0900213 ret = nand_read_page(dst, block * pages_per_block + page);
214 if (ret < 0)
215 return ret;
Masahiro Yamadad182d542014-10-03 19:21:04 +0900216
Masahiro Yamada06b47812015-08-27 18:52:36 +0900217 readlen = min(page_size - column, (int)size);
Masahiro Yamadad182d542014-10-03 19:21:04 +0900218
Masahiro Yamada06b47812015-08-27 18:52:36 +0900219 if (unlikely(column)) {
220 /* Partial page read */
221 memmove(dst, dst + column, readlen);
Masahiro Yamadad182d542014-10-03 19:21:04 +0900222 column = 0;
Masahiro Yamadad182d542014-10-03 19:21:04 +0900223 }
224
225 size -= readlen;
226 dst += readlen;
227 page++;
228 if (page == pages_per_block) {
229 block++;
230 page = 0;
231 }
232 }
233
234 return 0;
235}
236
237void nand_deselect(void) {}