Commit 54cd51bf7910164e6640c7f428f2fd95e15019da

Authored by Marek Vasut
Committed by Albert ARIBAUD
1 parent 5d877f4212

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
... ... @@ -52,5 +52,8 @@
52 52 extern void s3c64xx_onenand_init(struct mtd_info *);
53 53 extern void s3c64xx_set_width_regs(struct onenand_chip *);
54 54  
  55 +/* SPL */
  56 +void onenand_spl_load_image(uint32_t offs, uint32_t size, void *dst);
  57 +
55 58 #endif /* __UBOOT_ONENAND_H */
... ... @@ -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