From patchwork Tue Jul 12 04:48:42 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: b35362@freescale.com X-Patchwork-Id: 104321 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from merlin.infradead.org (merlin.infradead.org [IPv6:2001:4978:20e::2]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id E96E5B6F7C for ; Tue, 12 Jul 2011 15:45:10 +1000 (EST) Received: from canuck.infradead.org ([2001:4978:20e::1]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1QgVm7-0007rx-O6; Tue, 12 Jul 2011 05:44:51 +0000 Received: from localhost ([127.0.0.1] helo=canuck.infradead.org) by canuck.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1QgVm7-0007rD-Cq; Tue, 12 Jul 2011 05:44:51 +0000 Received: from db3ehsobe005.messaging.microsoft.com ([213.199.154.143] helo=DB3EHSOBE005.bigfish.com) by canuck.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1QgVlz-0007qt-4q for linux-mtd@lists.infradead.org; Tue, 12 Jul 2011 05:44:44 +0000 Received: from mail71-db3-R.bigfish.com (10.3.81.243) by DB3EHSOBE005.bigfish.com (10.3.84.25) with Microsoft SMTP Server id 14.1.225.22; Tue, 12 Jul 2011 05:44:38 +0000 Received: from mail71-db3 (localhost.localdomain [127.0.0.1]) by mail71-db3-R.bigfish.com (Postfix) with ESMTP id D9CD0DC8278; Tue, 12 Jul 2011 05:44:38 +0000 (UTC) X-SpamScore: 0 X-BigFish: VS0(zzzz1202hzz8275bhz2dh2a8h668h839h) X-Forefront-Antispam-Report: CIP:70.37.183.190; KIP:(null); UIP:(null); IPVD:NLI; H:mail.freescale.net; RD:none; EFVD:NLI Received: from mail71-db3 (localhost.localdomain [127.0.0.1]) by mail71-db3 (MessageSwitch) id 1310449478619439_5969; Tue, 12 Jul 2011 05:44:38 +0000 (UTC) Received: from DB3EHSMHS018.bigfish.com (unknown [10.3.81.253]) by mail71-db3.bigfish.com (Postfix) with ESMTP id 89632A6804B; Tue, 12 Jul 2011 05:44:38 +0000 (UTC) Received: from mail.freescale.net (70.37.183.190) by DB3EHSMHS018.bigfish.com (10.3.87.118) with Microsoft SMTP Server (TLS) id 14.1.225.22; Tue, 12 Jul 2011 05:44:38 +0000 Received: from az33smr01.freescale.net (10.64.34.199) by 039-SN1MMR1-002.039d.mgd.msft.net (10.84.1.15) with Microsoft SMTP Server id 14.1.289.8; Tue, 12 Jul 2011 00:44:35 -0500 Received: from localhost (rock.ap.freescale.net [10.193.20.106]) by az33smr01.freescale.net (8.13.1/8.13.0) with ESMTP id p6C5iX9I025500; Tue, 12 Jul 2011 00:44:34 -0500 (CDT) From: To: Subject: [PATCH v2] mtd/nand : workaround for Freescale FCM to support large-page Nand chip Date: Tue, 12 Jul 2011 12:48:42 +0800 Message-ID: <1310446122-18050-1-git-send-email-b35362@freescale.com> X-Mailer: git-send-email 1.6.4 MIME-Version: 1.0 X-OriginatorOrg: freescale.com X-CRM114-Version: 20090807-BlameThorstenAndJenny ( TRE 0.7.6 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20110712_014443_441873_F67FE46B X-CRM114-Status: GOOD ( 19.54 ) X-Spam-Score: -0.7 (/) X-Spam-Report: SpamAssassin version 3.3.1 on canuck.infradead.org summary: Content analysis details: (-0.7 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [213.199.154.143 listed in list.dnswl.org] Cc: Liu Shuo , linuxppc-dev@ozlabs.org, Li Yang , linux-mtd@lists.infradead.org X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-mtd-bounces@lists.infradead.org Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org From: Liu Shuo Freescale FCM controller has a 2K size limitation of buffer RAM. In order to support the Nand flash chip whose page size is larger than 2K bytes, we divide a page into multi-2K pages for MTD layer driver. In that case, we force to set the page size to 2K bytes. We convert the page address of MTD layer driver to a real page address in flash chips and a column index in fsl_elbc driver. We can issue any column address by UA instruction of elbc controller. Signed-off-by: Liu Shuo Signed-off-by: Li Yang --- drivers/mtd/nand/fsl_elbc_nand.c | 66 ++++++++++++++++++++++++++++++------- 1 files changed, 53 insertions(+), 13 deletions(-) diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index a212116..884a9f1 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -76,6 +76,13 @@ struct fsl_elbc_fcm_ctrl { unsigned int oob; /* Non zero if operating on OOB data */ unsigned int counter; /* counter for the initializations */ char *oob_poi; /* Place to write ECC after read back */ + + /* + * If writesize > 2048, these two members are used to calculate + * the real page address and real column address. + */ + int subpage_shift; + int subpage_mask; }; /* These map to the positions used by the FCM hardware ECC generator */ @@ -164,18 +171,27 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob) struct fsl_lbc_regs __iomem *lbc = ctrl->regs; struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand; int buf_num; + u32 real_ca = column; - elbc_fcm_ctrl->page = page_addr; + if (priv->page_size && elbc_fcm_ctrl->subpage_shift) { + real_ca = (page_addr & elbc_fcm_ctrl->subpage_mask) * 2112; + page_addr >>= elbc_fcm_ctrl->subpage_shift; + } - out_be32(&lbc->fbar, - page_addr >> (chip->phys_erase_shift - chip->page_shift)); + elbc_fcm_ctrl->page = page_addr; if (priv->page_size) { + real_ca += (oob ? 2048 : 0); + elbc_fcm_ctrl->use_mdr = 1; + elbc_fcm_ctrl->mdr = real_ca; + + out_be32(&lbc->fbar, page_addr >> 6); out_be32(&lbc->fpar, ((page_addr << FPAR_LP_PI_SHIFT) & FPAR_LP_PI) | (oob ? FPAR_LP_MS : 0) | column); buf_num = (page_addr & 1) << 2; } else { + out_be32(&lbc->fbar, page_addr >> 5); out_be32(&lbc->fpar, ((page_addr << FPAR_SP_PI_SHIFT) & FPAR_SP_PI) | (oob ? FPAR_SP_MS : 0) | column); @@ -256,10 +272,11 @@ static void fsl_elbc_do_read(struct nand_chip *chip, int oob) if (priv->page_size) { out_be32(&lbc->fir, (FIR_OP_CM0 << FIR_OP0_SHIFT) | - (FIR_OP_CA << FIR_OP1_SHIFT) | - (FIR_OP_PA << FIR_OP2_SHIFT) | - (FIR_OP_CM1 << FIR_OP3_SHIFT) | - (FIR_OP_RBW << FIR_OP4_SHIFT)); + (FIR_OP_UA << FIR_OP1_SHIFT) | + (FIR_OP_UA << FIR_OP2_SHIFT) | + (FIR_OP_PA << FIR_OP3_SHIFT) | + (FIR_OP_CM1 << FIR_OP4_SHIFT) | + (FIR_OP_RBW << FIR_OP5_SHIFT)); out_be32(&lbc->fcr, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) | (NAND_CMD_READSTART << FCR_CMD1_SHIFT)); @@ -399,12 +416,13 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, if (priv->page_size) { out_be32(&lbc->fir, (FIR_OP_CM2 << FIR_OP0_SHIFT) | - (FIR_OP_CA << FIR_OP1_SHIFT) | - (FIR_OP_PA << FIR_OP2_SHIFT) | - (FIR_OP_WB << FIR_OP3_SHIFT) | - (FIR_OP_CM3 << FIR_OP4_SHIFT) | - (FIR_OP_CW1 << FIR_OP5_SHIFT) | - (FIR_OP_RS << FIR_OP6_SHIFT)); + (FIR_OP_UA << FIR_OP1_SHIFT) | + (FIR_OP_UA << FIR_OP2_SHIFT) | + (FIR_OP_PA << FIR_OP3_SHIFT) | + (FIR_OP_WB << FIR_OP4_SHIFT) | + (FIR_OP_CM3 << FIR_OP5_SHIFT) | + (FIR_OP_CW1 << FIR_OP6_SHIFT) | + (FIR_OP_RS << FIR_OP7_SHIFT)); } else { out_be32(&lbc->fir, (FIR_OP_CM0 << FIR_OP0_SHIFT) | @@ -453,6 +471,9 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, full_page = 1; } + if (priv->page_size) + elbc_fcm_ctrl->use_mdr = 1; + fsl_elbc_run_command(mtd); /* Read back the page in order to fill in the ECC for the @@ -654,9 +675,28 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd) struct nand_chip *chip = mtd->priv; struct fsl_elbc_mtd *priv = chip->priv; struct fsl_lbc_ctrl *ctrl = priv->ctrl; + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand; struct fsl_lbc_regs __iomem *lbc = ctrl->regs; unsigned int al; + /* + * Hack for supporting the flash chip whose writesize is + * larger than 2K bytes. + */ + if (mtd->writesize > 2048) { + elbc_fcm_ctrl->subpage_shift = ffs(mtd->writesize >> 11) - 1; + elbc_fcm_ctrl->subpage_mask = + (1 << elbc_fcm_ctrl->subpage_shift) - 1; + /* + * Rewrite mtd->writesize, mtd->oobsize, chip->page_shift + * and chip->pagemask. + */ + mtd->writesize = 2048; + mtd->oobsize = 64; + chip->page_shift = ffs(mtd->writesize) - 1; + chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; + } + /* calculate FMR Address Length field */ al = 0; if (chip->pagemask & 0xffff0000)