/*
- * (C) Copyright 2005-2008 Samsung Electronis
+ * (C) Copyright 2005-2008 Samsung Electronics
* Kyungmin Park <kyungmin.park@samsung.com>
*
* See file CREDITS for list of people who contributed to this
extern void *memcpy32(void *dest, void *src, int size);
#endif
-static int (*onenand_read_page)(ulong block, ulong page,
+int (*onenand_read_page)(ulong block, ulong page,
u_char *buf, int pagesize);
-static int s5pc100_onenand_read_page(ulong block, ulong page,
- u_char * buf, int pagesize)
-{
- unsigned int *p = (unsigned int *) buf;
- int mem_addr, i;
-
- mem_addr = MEM_ADDR(block, page, 0);
-
- pagesize >>= 2;
-
- for (i = 0; i < pagesize; i++)
- *p++ = readl(CMD_MAP_01(mem_addr));
-
- return 0;
-}
-
/* read a page with ECC */
static int generic_onenand_read_page(ulong block, ulong page,
u_char * buf, int pagesize)
#endif
#define ONENAND_PAGES_PER_BLOCK 64
+static int onenand_generic_init(int *page_is_4KiB, int *page)
+{
+ int dev_id, density;
+
+ if (onenand_readw(ONENAND_REG_TECHNOLOGY))
+ *page_is_4KiB = 1;
+ dev_id = onenand_readw(ONENAND_REG_DEVICE_ID);
+ density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT;
+ if (density >= ONENAND_DEVICE_DENSITY_4Gb &&
+ !(dev_id & ONENAND_DEVICE_IS_DDP))
+ *page_is_4KiB = 1;
+
+ return ONENAND_USE_DEFAULT;
+}
+
+int onenand_board_init(int *page_is_4KiB, int *page)
+ __attribute__((weak, alias("onenand_generic_init")));
+
/**
* onenand_read_block - Read CONFIG_SYS_MONITOR_LEN from begining
* of OneNAND, skipping bad blocks
*/
int onenand_read_block(unsigned char *buf)
{
- int block;
+ int block, nblocks;
int page = CONFIG_ONENAND_START_PAGE, offset = 0;
- int pagesize = 0, erase_shift = 0;
- int erasesize = 0, nblocks = 0;
- int page_is_4KiB = 0, dev_id, density;
-
- if ((readl(0xE0000000) & 0x00FFF000) == 0x00110000) {
- onenand_read_page = generic_onenand_read_page;
- if (onenand_readw(ONENAND_REG_TECHNOLOGY))
- page_is_4KiB = 1;
- dev_id = onenand_readw(ONENAND_REG_DEVICE_ID);
- density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT;
- if (density >= ONENAND_DEVICE_DENSITY_4Gb &&
- !(dev_id & ONENAND_DEVICE_IS_DDP))
- page_is_4KiB = 1;
- } else {
- onenand_read_page = s5pc100_onenand_read_page;
- if (onenand_ahb_readw(ONENAND_REG_TECHNOLOGY))
- page_is_4KiB = 1;
- page = 8;
- }
+ int pagesize, erasesize, erase_shift;
+ int page_is_4KiB = 0, ret;
+
+ pagesize = 2048; /* OneNAND has 2KiB pagesize */
+ erase_shift = 17;
+ onenand_read_page = generic_onenand_read_page;
+
+ ret = onenand_board_init(&page_is_4KiB, &page);
+ if (ret == ONENAND_USE_GENERIC)
+ onenand_generic_init(&page_is_4KiB, &page);
if (page_is_4KiB) {
pagesize = 4096; /* OneNAND has 4KiB pagesize */
erase_shift = 18;
- } else {
- pagesize = 2048;
- erase_shift = 17;
}
- erasesize = ONENAND_PAGES_PER_BLOCK * pagesize;
+ erasesize = (1 << erase_shift);
nblocks = (CONFIG_SYS_MONITOR_LEN + erasesize - 1) >> erase_shift;
/* NOTE: you must read page from page 1 of block 0 */
- /* read the block page by page*/
+ /* read the block page by page */
for (block = 0; block < nblocks; block++) {
for (; page < ONENAND_PAGES_PER_BLOCK; page++) {
if (onenand_read_page(block, page, buf + offset,
--- /dev/null
+/*
+ * Copyright (C) 2008-2009 Samsung Electronics
+ * Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#include <asm/io.h>
+
+#include "onenand_ipl.h"
+
+/* S5PC100 specific */
+#define S5PC100_AHB_ADDR 0xB0000000
+#define MEM_ADDR(fba, fpa, fsa) ((fba) << 13 | (fpa) << 7 | (fsa) << 5)
+#define CMD_MAP_01(mem_addr) (S5PC100_AHB_ADDR | (1 << 26) | (mem_addr))
+#define CMD_MAP_11(addr) (S5PC100_AHB_ADDR | (3 << 26) | ((addr) << 2))
+#define onenand_ahb_readw(a) (readl(CMD_MAP_11((a) >> 1)) & 0xffff)
+
+static int s5pc100_onenand_read_page(ulong block, ulong page,
+ u_char * buf, int pagesize)
+{
+ unsigned int *p = (unsigned int *) buf;
+ int mem_addr, i;
+
+ mem_addr = MEM_ADDR(block, page, 0);
+
+ pagesize >>= 2;
+
+ for (i = 0; i < pagesize; i++)
+ *p++ = readl(CMD_MAP_01(mem_addr));
+
+ return 0;
+}
+
+int onenand_board_init(int *page_is_4KiB, int *page)
+{
+ if ((readl(0xE0000000) & 0x00FFF000) == 0x00110000)
+ return ONENAND_USE_GENERIC;
+
+ onenand_read_page = s5pc100_onenand_read_page;
+ *page = 8;
+
+ return ONENAND_USE_BOARD;
+}