| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 | 
							- // SPDX-License-Identifier: GPL-2.0+
 
- /*
 
-  * Copyright (C) 2014       Panasonic Corporation
 
-  * Copyright (C) 2014-2015  Masahiro Yamada <yamada.masahiro@socionext.com>
 
-  */
 
- #include <common.h>
 
- #include <asm/io.h>
 
- #include <asm/unaligned.h>
 
- #include <linux/mtd/rawnand.h>
 
- #include "denali.h"
 
- #define DENALI_MAP01		(1 << 26)	/* read/write pages in PIO */
 
- #define DENALI_MAP10		(2 << 26)	/* high-level control plane */
 
- #define INDEX_CTRL_REG		0x0
 
- #define INDEX_DATA_REG		0x10
 
- #define SPARE_ACCESS		0x41
 
- #define MAIN_ACCESS		0x42
 
- #define PIPELINE_ACCESS		0x2000
 
- #define BANK(x) ((x) << 24)
 
- static void __iomem *denali_flash_mem =
 
- 			(void __iomem *)CONFIG_SYS_NAND_DATA_BASE;
 
- static void __iomem *denali_flash_reg =
 
- 			(void __iomem *)CONFIG_SYS_NAND_REGS_BASE;
 
- static const int flash_bank;
 
- static int page_size, oob_size, pages_per_block;
 
- static void index_addr(uint32_t address, uint32_t data)
 
- {
 
- 	writel(address, denali_flash_mem + INDEX_CTRL_REG);
 
- 	writel(data, denali_flash_mem + INDEX_DATA_REG);
 
- }
 
- static int wait_for_irq(uint32_t irq_mask)
 
- {
 
- 	unsigned long timeout = 1000000;
 
- 	uint32_t intr_status;
 
- 	do {
 
- 		intr_status = readl(denali_flash_reg + INTR_STATUS(flash_bank));
 
- 		if (intr_status & INTR__ECC_UNCOR_ERR) {
 
- 			debug("Uncorrected ECC detected\n");
 
- 			return -EBADMSG;
 
- 		}
 
- 		if (intr_status & irq_mask)
 
- 			break;
 
- 		udelay(1);
 
- 		timeout--;
 
- 	} while (timeout);
 
- 	if (!timeout) {
 
- 		debug("Timeout with interrupt status %08x\n", intr_status);
 
- 		return -EIO;
 
- 	}
 
- 	return 0;
 
- }
 
- static void read_data_from_flash_mem(uint8_t *buf, int len)
 
- {
 
- 	int i;
 
- 	uint32_t *buf32;
 
- 	/* transfer the data from the flash */
 
- 	buf32 = (uint32_t *)buf;
 
- 	/*
 
- 	 * Let's take care of unaligned access although it rarely happens.
 
- 	 * Avoid put_unaligned() for the normal use cases since it leads to
 
- 	 * a bit performance regression.
 
- 	 */
 
- 	if ((unsigned long)buf32 % 4) {
 
- 		for (i = 0; i < len / 4; i++)
 
- 			put_unaligned(readl(denali_flash_mem + INDEX_DATA_REG),
 
- 				      buf32++);
 
- 	} else {
 
- 		for (i = 0; i < len / 4; i++)
 
- 			*buf32++ = readl(denali_flash_mem + INDEX_DATA_REG);
 
- 	}
 
- 	if (len % 4) {
 
- 		u32 tmp;
 
- 		tmp = cpu_to_le32(readl(denali_flash_mem + INDEX_DATA_REG));
 
- 		buf = (uint8_t *)buf32;
 
- 		for (i = 0; i < len % 4; i++) {
 
- 			*buf++ = tmp;
 
- 			tmp >>= 8;
 
- 		}
 
- 	}
 
- }
 
- int denali_send_pipeline_cmd(int page, int ecc_en, int access_type)
 
- {
 
- 	uint32_t addr, cmd;
 
- 	static uint32_t page_count = 1;
 
- 	writel(ecc_en, denali_flash_reg + ECC_ENABLE);
 
- 	/* clear all bits of intr_status. */
 
- 	writel(0xffff, denali_flash_reg + INTR_STATUS(flash_bank));
 
- 	addr = BANK(flash_bank) | page;
 
- 	/* setup the acccess type */
 
- 	cmd = DENALI_MAP10 | addr;
 
- 	index_addr(cmd, access_type);
 
- 	/* setup the pipeline command */
 
- 	index_addr(cmd, PIPELINE_ACCESS | page_count);
 
- 	cmd = DENALI_MAP01 | addr;
 
- 	writel(cmd, denali_flash_mem + INDEX_CTRL_REG);
 
- 	return wait_for_irq(INTR__LOAD_COMP);
 
- }
 
- static int nand_read_oob(void *buf, int page)
 
- {
 
- 	int ret;
 
- 	ret = denali_send_pipeline_cmd(page, 0, SPARE_ACCESS);
 
- 	if (ret < 0)
 
- 		return ret;
 
- 	read_data_from_flash_mem(buf, oob_size);
 
- 	return 0;
 
- }
 
- static int nand_read_page(void *buf, int page)
 
- {
 
- 	int ret;
 
- 	ret = denali_send_pipeline_cmd(page, 1, MAIN_ACCESS);
 
- 	if (ret < 0)
 
- 		return ret;
 
- 	read_data_from_flash_mem(buf, page_size);
 
- 	return 0;
 
- }
 
- static int nand_block_isbad(void *buf, int block)
 
- {
 
- 	int ret;
 
- 	ret = nand_read_oob(buf, block * pages_per_block);
 
- 	if (ret < 0)
 
- 		return ret;
 
- 	return *((uint8_t *)buf + CONFIG_SYS_NAND_BAD_BLOCK_POS) != 0xff;
 
- }
 
- /* nand_init() - initialize data to make nand usable by SPL */
 
- void nand_init(void)
 
- {
 
- 	/* access to main area */
 
- 	writel(0, denali_flash_reg + TRANSFER_SPARE_REG);
 
- 	/*
 
- 	 * These registers are expected to be already set by the hardware
 
- 	 * or earlier boot code.  So we read these values out.
 
- 	 */
 
- 	page_size = readl(denali_flash_reg + DEVICE_MAIN_AREA_SIZE);
 
- 	oob_size = readl(denali_flash_reg + DEVICE_SPARE_AREA_SIZE);
 
- 	pages_per_block = readl(denali_flash_reg + PAGES_PER_BLOCK);
 
- }
 
- int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
 
- {
 
- 	int block, page, column, readlen;
 
- 	int ret;
 
- 	int force_bad_block_check = 1;
 
- 	page = offs / page_size;
 
- 	column = offs % page_size;
 
- 	block = page / pages_per_block;
 
- 	page = page % pages_per_block;
 
- 	while (size) {
 
- 		if (force_bad_block_check || page == 0) {
 
- 			ret = nand_block_isbad(dst, block);
 
- 			if (ret < 0)
 
- 				return ret;
 
- 			if (ret) {
 
- 				block++;
 
- 				continue;
 
- 			}
 
- 		}
 
- 		force_bad_block_check = 0;
 
- 		ret = nand_read_page(dst, block * pages_per_block + page);
 
- 		if (ret < 0)
 
- 			return ret;
 
- 		readlen = min(page_size - column, (int)size);
 
- 		if (unlikely(column)) {
 
- 			/* Partial page read */
 
- 			memmove(dst, dst + column, readlen);
 
- 			column = 0;
 
- 		}
 
- 		size -= readlen;
 
- 		dst += readlen;
 
- 		page++;
 
- 		if (page == pages_per_block) {
 
- 			block++;
 
- 			page = 0;
 
- 		}
 
- 	}
 
- 	return 0;
 
- }
 
- void nand_deselect(void) {}
 
 
  |