#include <asm/io.h>
#include <linux/errno.h>
#include <nand.h>
+#include <linux/ioport.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/rawnand.h>
#include <linux/mtd/partitions.h>
u32 reserved2[2];
u32 eval0r; /* 0x418 */
};
-#define zynq_nand_smc_base ((struct zynq_nand_smc_regs __iomem *)\
- ZYNQ_SMC_BASEADDR)
/*
* struct nand_config - Defines the NAND flash driver instance
u8 end_cmd;
};
+struct nand_drv {
+ struct zynq_nand_smc_regs *reg;
+ struct nand_config config;
+};
+
struct zynq_nand_info {
struct udevice *dev;
+ struct nand_drv nand_ctrl;
struct nand_chip nand_chip;
};
*
* returns: status for command completion, -1 for Timeout
*/
-static int zynq_nand_waitfor_ecc_completion(void)
+static int zynq_nand_waitfor_ecc_completion(struct mtd_info *mtd)
{
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct nand_drv *smc = nand_get_controller_data(nand_chip);
unsigned long timeout;
u32 status;
/* Wait max 10us */
timeout = 10;
- status = readl(&zynq_nand_smc_base->esr);
+ status = readl(&smc->reg->esr);
while (status & ZYNQ_NAND_ECC_BUSY) {
- status = readl(&zynq_nand_smc_base->esr);
+ status = readl(&smc->reg->esr);
if (timeout == 0)
return -1;
timeout--;
*
* returns: 0 on success or error value on failure
*/
-static int zynq_nand_init_nand_flash(int option)
+static int zynq_nand_init_nand_flash(struct mtd_info *mtd, int option)
{
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct nand_drv *smc = nand_get_controller_data(nand_chip);
u32 status;
/* disable interrupts */
- writel(ZYNQ_NAND_CLR_CONFIG, &zynq_nand_smc_base->cfr);
+ writel(ZYNQ_NAND_CLR_CONFIG, &smc->reg->cfr);
#ifndef CONFIG_NAND_ZYNQ_USE_BOOTLOADER1_TIMINGS
/* Initialize the NAND interface by setting cycles and operation mode */
- writel(ZYNQ_NAND_SET_CYCLES, &zynq_nand_smc_base->scr);
+ writel(ZYNQ_NAND_SET_CYCLES, &smc->reg->scr);
#endif
if (option & NAND_BUSWIDTH_16)
- writel(ZYNQ_NAND_SET_OPMODE_16BIT, &zynq_nand_smc_base->sor);
+ writel(ZYNQ_NAND_SET_OPMODE_16BIT, &smc->reg->sor);
else
- writel(ZYNQ_NAND_SET_OPMODE_8BIT, &zynq_nand_smc_base->sor);
+ writel(ZYNQ_NAND_SET_OPMODE_8BIT, &smc->reg->sor);
- writel(ZYNQ_NAND_DIRECT_CMD, &zynq_nand_smc_base->dcr);
+ writel(ZYNQ_NAND_DIRECT_CMD, &smc->reg->dcr);
/* Wait till the ECC operation is complete */
- status = zynq_nand_waitfor_ecc_completion();
+ status = zynq_nand_waitfor_ecc_completion(mtd);
if (status < 0) {
printf("%s: Timeout\n", __func__);
return status;
}
/* Set the command1 and command2 register */
- writel(ZYNQ_NAND_ECC_CMD1, &zynq_nand_smc_base->emcmd1r);
- writel(ZYNQ_NAND_ECC_CMD2, &zynq_nand_smc_base->emcmd2r);
+ writel(ZYNQ_NAND_ECC_CMD1, &smc->reg->emcmd1r);
+ writel(ZYNQ_NAND_ECC_CMD2, &smc->reg->emcmd2r);
return 0;
}
static int zynq_nand_calculate_hwecc(struct mtd_info *mtd, const u8 *data,
u8 *ecc_code)
{
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct nand_drv *smc = nand_get_controller_data(nand_chip);
u32 ecc_value = 0;
u8 ecc_reg, ecc_byte;
u32 ecc_status;
/* Wait till the ECC operation is complete */
- ecc_status = zynq_nand_waitfor_ecc_completion();
+ ecc_status = zynq_nand_waitfor_ecc_completion(mtd);
if (ecc_status < 0) {
printf("%s: Timeout\n", __func__);
return ecc_status;
for (ecc_reg = 0; ecc_reg < 4; ecc_reg++) {
/* Read ECC value for each block */
- ecc_value = readl(&zynq_nand_smc_base->eval0r + ecc_reg);
+ ecc_value = readl(&smc->reg->eval0r + ecc_reg);
/* Get the ecc status from ecc read value */
ecc_status = (ecc_value >> 24) & 0xFF;
static void zynq_nand_cmd_function(struct mtd_info *mtd, unsigned int command,
int column, int page_addr)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct nand_drv *smc = nand_get_controller_data(chip);
const struct zynq_nand_command_format *curr_cmd = NULL;
u8 addr_cycles = 0;
- struct nand_config *xnand = (struct nand_config *)chip->priv;
+ struct nand_config *xnand = &smc->config;
void *cmd_addr;
unsigned long cmd_data = 0;
unsigned long cmd_phase_addr = 0;
curr_cmd = &zynq_nand_commands[index];
/* Clear interrupt */
- writel(ZYNQ_MEMC_CLRCR_INT_CLR1, &zynq_nand_smc_base->cfr);
+ writel(ZYNQ_MEMC_CLRCR_INT_CLR1, &smc->reg->cfr);
/* Get the command phase address */
if (curr_cmd->end_cmd_valid == ZYNQ_NAND_CMD_PHASE)
*/
static void zynq_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
/* Make sure that buf is 32 bit aligned */
if (((unsigned long)buf & 0x3) != 0) {
*/
static void zynq_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
const u32 *nand = chip->IO_ADDR_W;
/* Make sure that buf is 32 bit aligned */
*/
static int zynq_nand_device_ready(struct mtd_info *mtd)
{
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct nand_drv *smc = nand_get_controller_data(nand_chip);
u32 csr_val;
- csr_val = readl(&zynq_nand_smc_base->csr);
+ csr_val = readl(&smc->reg->csr);
/* Check the raw_int_status1 bit */
if (csr_val & ZYNQ_MEMC_SR_RAW_INT_ST1) {
/* Clear the interrupt condition */
- writel(ZYNQ_MEMC_SR_INT_ST1, &zynq_nand_smc_base->cfr);
+ writel(ZYNQ_MEMC_SR_INT_ST1, &smc->reg->cfr);
return 1;
}
{
struct zynq_nand_info *zynq = dev_get_priv(dev);
struct nand_chip *nand_chip = &zynq->nand_chip;
- struct nand_config *xnand;
+ struct nand_drv *smc = &zynq->nand_ctrl;
+ struct nand_config *xnand = &smc->config;
struct mtd_info *mtd;
+ struct resource res;
+ ofnode of_nand;
unsigned long ecc_page_size;
u8 maf_id, dev_id, i;
u8 get_feature[4];
int err = -1;
int is_16bit_bw;
- xnand = calloc(1, sizeof(struct nand_config));
- if (!xnand) {
- printf("%s: failed to allocate\n", __func__);
+ smc->reg = (struct zynq_nand_smc_regs *)dev_read_addr(dev);
+ of_nand = dev_read_subnode(dev, "flash@e1000000");
+ if (!ofnode_valid(of_nand)) {
+ printf("Failed to find nand node in dt\n");
+ goto fail;
+ }
+ if (ofnode_read_resource(of_nand, 0, &res)) {
+ printf("Failed to get nand resource\n");
goto fail;
}
- xnand->nand_base = (void __iomem *)ZYNQ_NAND_BASEADDR;
+ xnand->nand_base = (void __iomem *)res.start;
mtd = nand_to_mtd(nand_chip);
-
- nand_chip->priv = xnand;
- mtd->priv = nand_chip;
+ nand_set_controller_data(nand_chip, &zynq->nand_ctrl);
/* Set address of NAND IO lines */
nand_chip->IO_ADDR_R = xnand->nand_base;
nand_chip->bbt_options = NAND_BBT_USE_FLASH;
/* Initialize the NAND flash interface on NAND controller */
- if (zynq_nand_init_nand_flash(nand_chip->options) < 0) {
+ if (zynq_nand_init_nand_flash(mtd, nand_chip->options) < 0) {
printf("%s: nand flash init failed\n", __func__);
goto fail;
}
if (ondie_ecc_enabled) {
/* Bypass the controller ECC block */
- ecc_cfg = readl(&zynq_nand_smc_base->emcr);
+ ecc_cfg = readl(&smc->reg->emcr);
ecc_cfg &= ~ZYNQ_MEMC_NAND_ECC_MODE_MASK;
- writel(ecc_cfg, &zynq_nand_smc_base->emcr);
+ writel(ecc_cfg, &smc->reg->emcr);
/* The software ECC routines won't work
* with the SMC controller
ecc_page_size = 0x1;
/* Set the ECC memory config register */
writel((ZYNQ_NAND_ECC_CONFIG | ecc_page_size),
- &zynq_nand_smc_base->emcr);
+ &smc->reg->emcr);
break;
case 1024:
ecc_page_size = 0x2;
/* Set the ECC memory config register */
writel((ZYNQ_NAND_ECC_CONFIG | ecc_page_size),
- &zynq_nand_smc_base->emcr);
+ &smc->reg->emcr);
break;
case 2048:
ecc_page_size = 0x3;
/* Set the ECC memory config register */
writel((ZYNQ_NAND_ECC_CONFIG | ecc_page_size),
- &zynq_nand_smc_base->emcr);
+ &smc->reg->emcr);
break;
default:
nand_chip->ecc.mode = NAND_ECC_SOFT;