1*a430fa06SMiquel Raynal // SPDX-License-Identifier: GPL-2.0+ 2*a430fa06SMiquel Raynal /* 3*a430fa06SMiquel Raynal * (C) Copyright 2009 4*a430fa06SMiquel Raynal * Marvell Semiconductor <www.marvell.com> 5*a430fa06SMiquel Raynal * Written-by: Prafulla Wadaskar <prafulla@marvell.com> 6*a430fa06SMiquel Raynal */ 7*a430fa06SMiquel Raynal 8*a430fa06SMiquel Raynal #include <common.h> 9*a430fa06SMiquel Raynal #include <asm/io.h> 10*a430fa06SMiquel Raynal #include <asm/arch/soc.h> 11*a430fa06SMiquel Raynal #include <asm/arch/mpp.h> 12*a430fa06SMiquel Raynal #include <nand.h> 13*a430fa06SMiquel Raynal 14*a430fa06SMiquel Raynal /* NAND Flash Soc registers */ 15*a430fa06SMiquel Raynal struct kwnandf_registers { 16*a430fa06SMiquel Raynal u32 rd_params; /* 0x10418 */ 17*a430fa06SMiquel Raynal u32 wr_param; /* 0x1041c */ 18*a430fa06SMiquel Raynal u8 pad[0x10470 - 0x1041c - 4]; 19*a430fa06SMiquel Raynal u32 ctrl; /* 0x10470 */ 20*a430fa06SMiquel Raynal }; 21*a430fa06SMiquel Raynal 22*a430fa06SMiquel Raynal static struct kwnandf_registers *nf_reg = 23*a430fa06SMiquel Raynal (struct kwnandf_registers *)KW_NANDF_BASE; 24*a430fa06SMiquel Raynal 25*a430fa06SMiquel Raynal static u32 nand_mpp_backup[9] = { 0 }; 26*a430fa06SMiquel Raynal 27*a430fa06SMiquel Raynal /* 28*a430fa06SMiquel Raynal * hardware specific access to control-lines/bits 29*a430fa06SMiquel Raynal */ 30*a430fa06SMiquel Raynal #define NAND_ACTCEBOOT_BIT 0x02 31*a430fa06SMiquel Raynal 32*a430fa06SMiquel Raynal static void kw_nand_hwcontrol(struct mtd_info *mtd, int cmd, 33*a430fa06SMiquel Raynal unsigned int ctrl) 34*a430fa06SMiquel Raynal { 35*a430fa06SMiquel Raynal struct nand_chip *nc = mtd_to_nand(mtd); 36*a430fa06SMiquel Raynal u32 offs; 37*a430fa06SMiquel Raynal 38*a430fa06SMiquel Raynal if (cmd == NAND_CMD_NONE) 39*a430fa06SMiquel Raynal return; 40*a430fa06SMiquel Raynal 41*a430fa06SMiquel Raynal if (ctrl & NAND_CLE) 42*a430fa06SMiquel Raynal offs = (1 << 0); /* Commands with A[1:0] == 01 */ 43*a430fa06SMiquel Raynal else if (ctrl & NAND_ALE) 44*a430fa06SMiquel Raynal offs = (1 << 1); /* Addresses with A[1:0] == 10 */ 45*a430fa06SMiquel Raynal else 46*a430fa06SMiquel Raynal return; 47*a430fa06SMiquel Raynal 48*a430fa06SMiquel Raynal writeb(cmd, nc->IO_ADDR_W + offs); 49*a430fa06SMiquel Raynal } 50*a430fa06SMiquel Raynal 51*a430fa06SMiquel Raynal void kw_nand_select_chip(struct mtd_info *mtd, int chip) 52*a430fa06SMiquel Raynal { 53*a430fa06SMiquel Raynal u32 data; 54*a430fa06SMiquel Raynal static const u32 nand_config[] = { 55*a430fa06SMiquel Raynal MPP0_NF_IO2, 56*a430fa06SMiquel Raynal MPP1_NF_IO3, 57*a430fa06SMiquel Raynal MPP2_NF_IO4, 58*a430fa06SMiquel Raynal MPP3_NF_IO5, 59*a430fa06SMiquel Raynal MPP4_NF_IO6, 60*a430fa06SMiquel Raynal MPP5_NF_IO7, 61*a430fa06SMiquel Raynal MPP18_NF_IO0, 62*a430fa06SMiquel Raynal MPP19_NF_IO1, 63*a430fa06SMiquel Raynal 0 64*a430fa06SMiquel Raynal }; 65*a430fa06SMiquel Raynal 66*a430fa06SMiquel Raynal if (chip >= 0) 67*a430fa06SMiquel Raynal kirkwood_mpp_conf(nand_config, nand_mpp_backup); 68*a430fa06SMiquel Raynal else 69*a430fa06SMiquel Raynal kirkwood_mpp_conf(nand_mpp_backup, NULL); 70*a430fa06SMiquel Raynal 71*a430fa06SMiquel Raynal data = readl(&nf_reg->ctrl); 72*a430fa06SMiquel Raynal data |= NAND_ACTCEBOOT_BIT; 73*a430fa06SMiquel Raynal writel(data, &nf_reg->ctrl); 74*a430fa06SMiquel Raynal } 75*a430fa06SMiquel Raynal 76*a430fa06SMiquel Raynal int board_nand_init(struct nand_chip *nand) 77*a430fa06SMiquel Raynal { 78*a430fa06SMiquel Raynal nand->options = NAND_COPYBACK | NAND_CACHEPRG | NAND_NO_PADDING; 79*a430fa06SMiquel Raynal #if defined(CONFIG_SYS_NAND_NO_SUBPAGE_WRITE) 80*a430fa06SMiquel Raynal nand->options |= NAND_NO_SUBPAGE_WRITE; 81*a430fa06SMiquel Raynal #endif 82*a430fa06SMiquel Raynal #if defined(CONFIG_NAND_ECC_BCH) 83*a430fa06SMiquel Raynal nand->ecc.mode = NAND_ECC_SOFT_BCH; 84*a430fa06SMiquel Raynal #else 85*a430fa06SMiquel Raynal nand->ecc.mode = NAND_ECC_SOFT; 86*a430fa06SMiquel Raynal #endif 87*a430fa06SMiquel Raynal nand->cmd_ctrl = kw_nand_hwcontrol; 88*a430fa06SMiquel Raynal nand->chip_delay = 40; 89*a430fa06SMiquel Raynal nand->select_chip = kw_nand_select_chip; 90*a430fa06SMiquel Raynal return 0; 91*a430fa06SMiquel Raynal } 92