Commit 54cd51bf7910164e6640c7f428f2fd95e15019da
Committed by
Albert ARIBAUD
1 parent
5d877f4212
Exists in
master
and in
54 other branches
OneNAND: Add simple OneNAND SPL
This introduces small OneNAND loader, fitting into 1kB of space (smallest possible OneNAND RAM size). Some devices equipped with such crappy chips will use this. Signed-off-by: Marek Vasut <marek.vasut@gmail.com> Cc: Albert ARIBAUD <albert.u.boot@aribaud.net> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Scott Wood <scottwood@freescale.com> V2: Introduce spl_onenand_load_image() to load data from OneNAND in SPL V3: Cleanup, align with nand_spl. Skip whole blocks.
Showing 4 changed files with 154 additions and 0 deletions Side-by-side Diff
drivers/mtd/onenand/Makefile
... | ... | @@ -25,8 +25,12 @@ |
25 | 25 | |
26 | 26 | LIB := $(obj)libonenand.o |
27 | 27 | |
28 | +ifndef CONFIG_SPL_BUILD | |
28 | 29 | COBJS-$(CONFIG_CMD_ONENAND) := onenand_uboot.o onenand_base.o onenand_bbt.o |
29 | 30 | COBJS-$(CONFIG_SAMSUNG_ONENAND) += samsung.o |
31 | +else | |
32 | +COBJS-y := onenand_spl.o | |
33 | +endif | |
30 | 34 | |
31 | 35 | COBJS := $(COBJS-y) |
32 | 36 | SRCS := $(COBJS:.o=.c) |
drivers/mtd/onenand/onenand_spl.c
1 | +/* | |
2 | + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> | |
3 | + * | |
4 | + * Based on code: | |
5 | + * Copyright (C) 2005-2009 Samsung Electronics | |
6 | + * Kyungmin Park <kyungmin.park@samsung.com> | |
7 | + * | |
8 | + * See file CREDITS for list of people who contributed to this | |
9 | + * project. | |
10 | + * | |
11 | + * This program is free software; you can redistribute it and/or | |
12 | + * modify it under the terms of the GNU General Public License as | |
13 | + * published by the Free Software Foundation; either version 2 of | |
14 | + * the License, or (at your option) any later version. | |
15 | + * | |
16 | + * This program is distributed in the hope that it will be useful, | |
17 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 | + * GNU General Public License for more details. | |
20 | + * | |
21 | + * You should have received a copy of the GNU General Public License | |
22 | + * along with this program; if not, write to the Free Software | |
23 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
24 | + * MA 02111-1307 USA | |
25 | + */ | |
26 | + | |
27 | +#include <common.h> | |
28 | +#include <asm/io.h> | |
29 | +#include <linux/mtd/onenand_regs.h> | |
30 | +#include <onenand_uboot.h> | |
31 | + | |
32 | +/* | |
33 | + * Device geometry: | |
34 | + * - 2048b page, 128k erase block. | |
35 | + * - 4096b page, 256k erase block. | |
36 | + */ | |
37 | +enum onenand_spl_pagesize { | |
38 | + PAGE_2K = 2048, | |
39 | + PAGE_4K = 4096, | |
40 | +}; | |
41 | + | |
42 | +#define ONENAND_PAGES_PER_BLOCK 64 | |
43 | +#define onenand_block_address(block) (block) | |
44 | +#define onenand_sector_address(page) (page << 2) | |
45 | +#define onenand_buffer_address() ((1 << 3) << 8) | |
46 | +#define onenand_bufferram_address(block) (0) | |
47 | + | |
48 | +static inline uint16_t onenand_readw(uint32_t addr) | |
49 | +{ | |
50 | + return readw(CONFIG_SYS_ONENAND_BASE + addr); | |
51 | +} | |
52 | + | |
53 | +static inline void onenand_writew(uint16_t value, uint32_t addr) | |
54 | +{ | |
55 | + writew(value, CONFIG_SYS_ONENAND_BASE + addr); | |
56 | +} | |
57 | + | |
58 | +static enum onenand_spl_pagesize onenand_spl_get_geometry(void) | |
59 | +{ | |
60 | + uint32_t dev_id, density; | |
61 | + | |
62 | + if (!onenand_readw(ONENAND_REG_TECHNOLOGY)) { | |
63 | + dev_id = onenand_readw(ONENAND_REG_DEVICE_ID); | |
64 | + density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT; | |
65 | + density &= ONENAND_DEVICE_DENSITY_MASK; | |
66 | + | |
67 | + if (density < ONENAND_DEVICE_DENSITY_4Gb) | |
68 | + return PAGE_2K; | |
69 | + | |
70 | + if (dev_id & ONENAND_DEVICE_IS_DDP) | |
71 | + return PAGE_2K; | |
72 | + } | |
73 | + | |
74 | + return PAGE_4K; | |
75 | +} | |
76 | + | |
77 | +static int onenand_spl_read_page(uint32_t block, uint32_t page, uint32_t *buf, | |
78 | + enum onenand_spl_pagesize pagesize) | |
79 | +{ | |
80 | + const uint32_t addr = CONFIG_SYS_ONENAND_BASE + ONENAND_DATARAM; | |
81 | + uint32_t offset; | |
82 | + | |
83 | + onenand_writew(onenand_block_address(block), | |
84 | + ONENAND_REG_START_ADDRESS1); | |
85 | + | |
86 | + onenand_writew(onenand_bufferram_address(block), | |
87 | + ONENAND_REG_START_ADDRESS2); | |
88 | + | |
89 | + onenand_writew(onenand_sector_address(page), | |
90 | + ONENAND_REG_START_ADDRESS8); | |
91 | + | |
92 | + onenand_writew(onenand_buffer_address(), | |
93 | + ONENAND_REG_START_BUFFER); | |
94 | + | |
95 | + onenand_writew(ONENAND_INT_CLEAR, ONENAND_REG_INTERRUPT); | |
96 | + | |
97 | + onenand_writew(ONENAND_CMD_READ, ONENAND_REG_COMMAND); | |
98 | + | |
99 | + while (!(onenand_readw(ONENAND_REG_INTERRUPT) & ONENAND_INT_READ)) | |
100 | + continue; | |
101 | + | |
102 | + /* Check for invalid block mark */ | |
103 | + if (page < 2 && (onenand_readw(ONENAND_SPARERAM) != 0xffff)) | |
104 | + return 1; | |
105 | + | |
106 | + for (offset = 0; offset < pagesize; offset += 4) | |
107 | + buf[offset / 4] = readl(addr + offset); | |
108 | + | |
109 | + return 0; | |
110 | +} | |
111 | + | |
112 | +void onenand_spl_load_image(uint32_t offs, uint32_t size, void *dst) | |
113 | +{ | |
114 | + uint32_t *addr = (uint32_t *)dst; | |
115 | + uint32_t total_pages; | |
116 | + uint32_t block; | |
117 | + uint32_t page, rpage; | |
118 | + enum onenand_spl_pagesize pagesize; | |
119 | + int ret; | |
120 | + | |
121 | + pagesize = onenand_spl_get_geometry(); | |
122 | + | |
123 | + /* | |
124 | + * The page can be either 2k or 4k, avoid using DIV_ROUND_UP to avoid | |
125 | + * pulling further unwanted functions into the SPL. | |
126 | + */ | |
127 | + if (pagesize == 2048) { | |
128 | + total_pages = DIV_ROUND_UP(size, 2048); | |
129 | + page = offs / 2048; | |
130 | + } else { | |
131 | + total_pages = DIV_ROUND_UP(size, 4096); | |
132 | + page = offs / 4096; | |
133 | + } | |
134 | + | |
135 | + for (; page <= total_pages; page++) { | |
136 | + block = page / ONENAND_PAGES_PER_BLOCK; | |
137 | + rpage = page & (ONENAND_PAGES_PER_BLOCK - 1); | |
138 | + ret = onenand_spl_read_page(block, rpage, addr, pagesize); | |
139 | + if (ret) { | |
140 | + total_pages += ONENAND_PAGES_PER_BLOCK; | |
141 | + page += ONENAND_PAGES_PER_BLOCK - 1; | |
142 | + } else { | |
143 | + addr += pagesize / 4; | |
144 | + } | |
145 | + } | |
146 | +} |
include/onenand_uboot.h
spl/Makefile
... | ... | @@ -54,6 +54,7 @@ |
54 | 54 | LIBS-$(CONFIG_SPL_LIBGENERIC_SUPPORT) += lib/libgeneric.o |
55 | 55 | LIBS-$(CONFIG_SPL_POWER_SUPPORT) += drivers/power/libpower.o |
56 | 56 | LIBS-$(CONFIG_SPL_NAND_SUPPORT) += drivers/mtd/nand/libnand.o |
57 | +LIBS-$(CONFIG_SPL_ONENAND_SUPPORT) += drivers/mtd/onenand/libonenand.o | |
57 | 58 | LIBS-$(CONFIG_SPL_DMA_SUPPORT) += drivers/dma/libdma.o |
58 | 59 | LIBS-$(CONFIG_SPL_POST_MEM_SUPPORT) += post/drivers/memory.o |
59 | 60 |