From patchwork Mon Apr 27 08:20:15 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Boris Brezillon X-Patchwork-Id: 1277419 X-Patchwork-Delegate: miquel.raynal@bootlin.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20170209 header.b=gn9nLDTL; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 499dDL6sNZz9sRf for ; Mon, 27 Apr 2020 18:26:58 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=EPaxZR7C16GT5RyyGHvwF3b8P7dtiVGGLjMwPIR5aDU=; b=gn9nLDTLf13sCV iGhP1bzkx7Mii2PaIJhgZ31UgEM5h7/Ge7TyHt13bjNp6FXIvoNngGrS7wO61qLeP7/v0EHrhJCnI E71N/fD0lHWKEFOL1zf8Fv0PFP877vs3pLuOudgBtn8VTDumIzEaD832pjs4d6faEaqRqlQhD6dd9 y6W0PH6U6K9koUI07LOJ/ulV2j0ngXzVK4DNFj+Lz+mx/temT8gzVJv7nKvBN3XTo1zlNNEQcdOJw FbPsr0keQQkbwem9clqMJoCZpifSTpoCQBaZWnIa54Y2zjyZNzst3A4RwQDzaN6slOUJcSidggkBO z89E38xb5L9ojJWWHxvQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jSz6C-0005J1-SS; Mon, 27 Apr 2020 08:26:44 +0000 Received: from bhuna.collabora.co.uk ([46.235.227.227]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jSz0K-000682-0D for linux-mtd@lists.infradead.org; Mon, 27 Apr 2020 08:20:45 +0000 Received: from localhost.localdomain (unknown [IPv6:2a01:e0a:2c:6930:5cf4:84a1:2763:fe0d]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: bbrezillon) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id C8B822A088B; Mon, 27 Apr 2020 09:20:36 +0100 (BST) From: Boris Brezillon To: David Woodhouse , Miquel Raynal , linux-mtd@lists.infradead.org Subject: [PATCH 05/17] mtd: rawnand: cafe: Demistify register fields Date: Mon, 27 Apr 2020 10:20:15 +0200 Message-Id: <20200427082028.394719-6-boris.brezillon@collabora.com> X-Mailer: git-send-email 2.25.3 In-Reply-To: <20200427082028.394719-1-boris.brezillon@collabora.com> References: <20200427082028.394719-1-boris.brezillon@collabora.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200427_012040_330027_DC3B235F X-CRM114-Status: GOOD ( 19.74 ) X-Spam-Score: -0.0 (/) X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: Content analysis details: (-0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [46.235.227.227 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -0.0 SPF_HELO_PASS SPF: HELO matches SPF record X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Richard Weinberger , Boris Brezillon , Vignesh Raghavendra , Tudor Ambarus Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org The driver has a bunch of magic values. Let's define proper register fields based on the this spec http://wiki.laptop.org/images/5/5c/88ALP01_Datasheet_July_2007.pdf and use them. Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/cafe_nand.c | 351 ++++++++++++++++++++++++------- 1 file changed, 270 insertions(+), 81 deletions(-) diff --git a/drivers/mtd/nand/raw/cafe_nand.c b/drivers/mtd/nand/raw/cafe_nand.c index 156a308b530b..fbc18bc3d46b 100644 --- a/drivers/mtd/nand/raw/cafe_nand.c +++ b/drivers/mtd/nand/raw/cafe_nand.c @@ -9,6 +9,7 @@ * Copyright © 2006 David Woodhouse */ +#include #define DEBUG #include @@ -25,37 +26,127 @@ #include #include -#define CAFE_NAND_CTRL1 0x00 -#define CAFE_NAND_CTRL2 0x04 -#define CAFE_NAND_CTRL3 0x08 -#define CAFE_NAND_STATUS 0x0c -#define CAFE_NAND_IRQ 0x10 -#define CAFE_NAND_IRQ_MASK 0x14 -#define CAFE_NAND_DATA_LEN 0x18 -#define CAFE_NAND_ADDR1 0x1c -#define CAFE_NAND_ADDR2 0x20 -#define CAFE_NAND_TIMING1 0x24 -#define CAFE_NAND_TIMING2 0x28 -#define CAFE_NAND_TIMING3 0x2c -#define CAFE_NAND_NONMEM 0x30 -#define CAFE_NAND_ECC_RESULT 0x3C -#define CAFE_NAND_DMA_CTRL 0x40 -#define CAFE_NAND_DMA_ADDR0 0x44 -#define CAFE_NAND_DMA_ADDR1 0x48 -#define CAFE_NAND_ECC_SYN01 0x50 -#define CAFE_NAND_ECC_SYN23 0x54 -#define CAFE_NAND_ECC_SYN45 0x58 -#define CAFE_NAND_ECC_SYN67 0x5c -#define CAFE_NAND_READ_DATA 0x1000 -#define CAFE_NAND_WRITE_DATA 0x2000 +#define CAFE_NAND_CTRL1 0x00 +#define CAFE_NAND_CTRL1_HAS_CMD BIT(31) +#define CAFE_NAND_CTRL1_HAS_ADDR BIT(30) +#define CAFE_NAND_CTRL1_NUM_ADDR_CYC GENMASK(29, 27) +#define CAFE_NAND_CTRL1_HAS_DATA_IN BIT(26) +#define CAFE_NAND_CTRL1_HAS_DATA_OUT BIT(25) +#define CAFE_NAND_CTRL1_NUM_NONMEM_READ_HIGH GENMASK(24, 22) +#define CAFE_NAND_CTRL1_WAIT_BSY_AFTER_SEQ BIT(21) +#define CAFE_NAND_CTRL1_NUM_NONMEM_READ_LOW BIT(20) +#define CAFE_NAND_CTRL1_CE BIT(19) +#define CAFE_NAND_CTRL1_CMD GENMASK(7, 0) -#define CAFE_GLOBAL_CTRL 0x3004 -#define CAFE_GLOBAL_IRQ 0x3008 -#define CAFE_GLOBAL_IRQ_MASK 0x300c -#define CAFE_NAND_RESET 0x3034 +#define CAFE_NAND_CTRL2 0x04 +#define CAFE_NAND_CTRL2_AUTO_WRITE_ECC BIT(30) +#define CAFE_NAND_CTRL2_PAGE_SIZE GENMASK(29, 28) +#define CAFE_NAND_CTRL2_ECC_ALG_RS BIT(27) +#define CAFE_NAND_CTRL2_HAS_CMD2 BIT(8) +#define CAFE_NAND_CTRL2_CMD2 GENMASK(7, 0) -/* Missing from the datasheet: bit 19 of CTRL1 sets CE0 vs. CE1 */ -#define CTRL1_CHIPSELECT (1<<19) +#define CAFE_NAND_CTRL3 0x08 +#define CAFE_NAND_CTRL3_READ_BUSY_RESET BIT(31) +#define CAFE_NAND_CTRL3_WP BIT(30) + +#define CAFE_NAND_STATUS 0x0c +#define CAFE_NAND_STATUS_CONTROLLER_BUSY BIT(31) +#define CAFE_NAND_STATUS_FLASH_BUSY BIT(30) + +#define CAFE_NAND_IRQ 0x10 +#define CAFE_NAND_IRQ_MASK 0x14 +#define CAFE_NAND_IRQ_CMD_DONE BIT(31) +#define CAFE_NAND_IRQ_FLASH_RDY BIT(30) +#define CAFE_NAND_IRQ_DMA_DONE BIT(28) +#define CAFE_NAND_IRQ_BOOT_DONE BIT(27) + +#define CAFE_NAND_DATA_LEN 0x18 +#define CAFE_NAND_ADDR1 0x1c +#define CAFE_NAND_ADDR2 0x20 + +#define CAFE_NAND_TIMING1 0x24 +#define CAFE_NAND_TIMING1_TCLS GENMASK(31, 28) +#define CAFE_NAND_TIMING1_TCLH GENMASK(27, 24) +#define CAFE_NAND_TIMING1_TALS GENMASK(23, 20) +#define CAFE_NAND_TIMING1_TALH GENMASK(19, 16) +#define CAFE_NAND_TIMING1_TWB GENMASK(15, 8) +#define CAFE_NAND_TIMING1_TRB GENMASK(7, 0) + +#define CAFE_NAND_TIMING2 0x28 +#define CAFE_NAND_TIMING2_TRR GENMASK(31, 28) +#define CAFE_NAND_TIMING2_TREA GENMASK(27, 24) +#define CAFE_NAND_TIMING2_TDH GENMASK(23, 20) +#define CAFE_NAND_TIMING2_TDS GENMASK(19, 16) +#define CAFE_NAND_TIMING2_TRH GENMASK(15, 12) +#define CAFE_NAND_TIMING2_TRP GENMASK(11, 8) +#define CAFE_NAND_TIMING2_TWH GENMASK(7, 4) +#define CAFE_NAND_TIMING2_TWP GENMASK(3, 0) + +#define CAFE_NAND_TIMING3 0x2c +#define CAFE_NAND_TIMING3_TAR GENMASK(31, 28) +#define CAFE_NAND_TIMING3_TCLR GENMASK(27, 24) + +#define CAFE_NAND_NONMEM_READ_DATA 0x30 +#define CAFE_NAND_ECC_READ_CODE 0x38 + +#define CAFE_NAND_ECC_RESULT 0x3C +#define CAFE_NAND_ECC_RESULT_RS_ERRORS BIT(18) +#define CAFE_NAND_ECC_RESULT_STATUS GENMASK(17, 16) +#define CAFE_NAND_ECC_RESULT_NO_ERROR (0 << 16) +#define CAFE_NAND_ECC_RESULT_CORRECTABLE_ERRS (1 << 16) +#define CAFE_NAND_ECC_RESULT_UNCORRECTABLE_ERRS (2 << 16) +#define CAFE_NAND_ECC_RESULT_FAIL_BIT_LOC GENMASK(13, 0) + +#define CAFE_NAND_DMA_CTRL 0x40 +#define CAFE_NAND_DMA_CTRL_ENABLE BIT(31) +#define CAFE_NAND_DMA_CTRL_RESERVED BIT(30) +#define CAFE_NAND_DMA_CTRL_DATA_IN BIT(29) +#define CAFE_NAND_DMA_CTRL_DATA_LEN GENMASK(11, 0) + +#define CAFE_NAND_DMA_ADDR0 0x44 +#define CAFE_NAND_DMA_ADDR1 0x48 +#define CAFE_NAND_ECC_SYN_REG(x) (((x) / 2) + 0x50) +#define CAFE_NAND_ECC_SYN_FIELD(x) (((x) % 2) ? GENMASK(31, 16) : GENMASK(15, 0)) + +#define CAFE_NAND_CTRL4 0x60 +#define CAFE_NAND_CTRL4_NO_READ_DELAY BIT(8) + +#define CAFE_NAND_DRIVE_STRENGTH 0x64 +#define CAFE_NAND_DRIVE_STRENGTH_VAL GENMASK(4, 0) + +#define CAFE_NAND_READ_DATA 0x1000 +#define CAFE_NAND_WRITE_DATA 0x2000 + +#define CAFE_GLOBAL_CTRL 0x3004 +#define CAFE_GLOBAL_CCIC_CLK_ENABLE BIT(14) +#define CAFE_GLOBAL_SDH_CLK_ENABLE BIT(13) +#define CAFE_GLOBAL_NAND_CLK_ENABLE BIT(12) +#define CAFE_GLOBAL_CLKRUN_ENABLE_SET BIT(11) +#define CAFE_GLOBAL_CLKRUN_ENABLE_CLEAR BIT(10) +#define CAFE_GLOBAL_SW_IRQ_SET BIT(7) +#define CAFE_GLOBAL_SW_IRQ_CLEAR BIT(6) +#define CAFE_GLOBAL_STOP_MASTER_DONE BIT(5) +#define CAFE_GLOBAL_STOP_MASTER BIT(4) +#define CAFE_GLOBAL_MASTER_RESET_CLEAR BIT(3) +#define CAFE_GLOBAL_MASTER_RESET_SET BIT(2) +#define CAFE_GLOBAL_SW_RESET_CLEAR BIT(1) +#define CAFE_GLOBAL_SW_RESET_SET BIT(0) + +#define CAFE_GLOBAL_IRQ 0x3008 +#define CAFE_GLOBAL_IRQ_MASK 0x300c +#define CAFE_GLOBAL_IRQ_PCI_ERROR BIT(31) +#define CAFE_GLOBAL_IRQ_VPD_TWSI BIT(26) +#define CAFE_GLOBAL_IRQ_CCIC BIT(2) +#define CAFE_GLOBAL_IRQ_SDH BIT(1) +#define CAFE_GLOBAL_IRQ_NAND BIT(0) + +#define CAFE_GLOBAL_RESET 0x3034 +#define CAFE_GLOBAL_RESET_CCIC BIT(2) +#define CAFE_GLOBAL_RESET_SDH BIT(1) +#define CAFE_GLOBAL_RESET_NAND BIT(0) + +#define CAFE_FIELD_PREP(reg, field, val) FIELD_PREP(CAFE_##reg##_##field, val) +#define CAFE_FIELD_GET(reg, field, val) FIELD_GET(CAFE_##reg##_##field, val) struct cafe_priv { struct nand_chip nand; @@ -104,7 +195,8 @@ static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL }; static int cafe_device_ready(struct nand_chip *chip) { struct cafe_priv *cafe = nand_get_controller_data(chip); - int result = !!(cafe_readl(cafe, NAND_STATUS) & 0x40000000); + int result = !!(cafe_readl(cafe, NAND_STATUS) & + CAFE_NAND_STATUS_FLASH_BUSY); uint32_t irqs = cafe_readl(cafe, NAND_IRQ); cafe_writel(cafe, irqs, NAND_IRQ); @@ -164,16 +256,20 @@ static void cafe_nand_cmdfunc(struct nand_chip *chip, unsigned command, struct cafe_priv *cafe = nand_get_controller_data(chip); int adrbytes = 0; uint32_t ctl1; - uint32_t doneint = 0x80000000; + uint32_t doneint = CAFE_NAND_IRQ_CMD_DONE; cafe_dev_dbg(&cafe->pdev->dev, "cmdfunc %02x, 0x%x, 0x%x\n", command, column, page_addr); if (command == NAND_CMD_ERASE2 || command == NAND_CMD_PAGEPROG) { /* Second half of a command we already calculated */ - cafe_writel(cafe, cafe->ctl2 | 0x100 | command, NAND_CTRL2); + cafe_writel(cafe, + cafe->ctl2 | + CAFE_NAND_CTRL2_CMD2 | + CAFE_FIELD_PREP(NAND_CTRL2, CMD2, command), + NAND_CTRL2); ctl1 = cafe->ctl1; - cafe->ctl2 &= ~(1<<30); + cafe->ctl2 &= ~CAFE_NAND_CTRL2_AUTO_WRITE_ECC; cafe_dev_dbg(&cafe->pdev->dev, "Continue command, ctl1 %08x, #data %d\n", cafe->ctl1, cafe->nr_data); goto do_command; @@ -209,26 +305,29 @@ static void cafe_nand_cmdfunc(struct nand_chip *chip, unsigned command, cafe->data_pos = cafe->datalen = 0; /* Set command valid bit, mask in the chip select bit */ - ctl1 = 0x80000000 | command | (cafe->ctl1 & CTRL1_CHIPSELECT); + ctl1 = CAFE_NAND_CTRL1_HAS_CMD | + CAFE_FIELD_PREP(NAND_CTRL1, CMD, command) | + (cafe->ctl1 & CAFE_NAND_CTRL1_CE); /* Set RD or WR bits as appropriate */ if (command == NAND_CMD_READID || command == NAND_CMD_STATUS) { - ctl1 |= (1<<26); /* rd */ + ctl1 |= CAFE_NAND_CTRL1_HAS_DATA_IN; /* Always 5 bytes, for now */ cafe->datalen = 4; /* And one address cycle -- even for STATUS, since the controller doesn't work without */ adrbytes = 1; } else if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 || command == NAND_CMD_READOOB || command == NAND_CMD_RNDOUT) { - ctl1 |= 1<<26; /* rd */ + ctl1 |= CAFE_NAND_CTRL1_HAS_DATA_IN; /* For now, assume just read to end of page */ cafe->datalen = mtd->writesize + mtd->oobsize - column; } else if (command == NAND_CMD_SEQIN) - ctl1 |= 1<<25; /* wr */ + ctl1 |= CAFE_NAND_CTRL1_HAS_DATA_OUT; /* Set number of address bytes */ if (adrbytes) - ctl1 |= ((adrbytes-1)|8) << 27; + ctl1 |= CAFE_NAND_CTRL1_HAS_ADDR | + CAFE_FIELD_PREP(NAND_CTRL1, NUM_ADDR_CYC, adrbytes - 1); if (command == NAND_CMD_SEQIN || command == NAND_CMD_ERASE1) { /* Ignore the first command of a pair; the hardware @@ -240,9 +339,15 @@ static void cafe_nand_cmdfunc(struct nand_chip *chip, unsigned command, } /* RNDOUT and READ0 commands need a following byte */ if (command == NAND_CMD_RNDOUT) - cafe_writel(cafe, cafe->ctl2 | 0x100 | NAND_CMD_RNDOUTSTART, NAND_CTRL2); + cafe_writel(cafe, + cafe->ctl2 | CAFE_NAND_CTRL2_CMD2 | + CAFE_FIELD_PREP(NAND_CTRL2, CMD2, NAND_CMD_RNDOUTSTART), + NAND_CTRL2); else if (command == NAND_CMD_READ0 && mtd->writesize > 512) - cafe_writel(cafe, cafe->ctl2 | 0x100 | NAND_CMD_READSTART, NAND_CTRL2); + cafe_writel(cafe, + cafe->ctl2 | CAFE_NAND_CTRL2_CMD2 | + CAFE_FIELD_PREP(NAND_CTRL2, CMD2, NAND_CMD_READSTART), + NAND_CTRL2); do_command: cafe_dev_dbg(&cafe->pdev->dev, "dlen %x, ctl1 %x, ctl2 %x\n", @@ -250,16 +355,23 @@ static void cafe_nand_cmdfunc(struct nand_chip *chip, unsigned command, /* NB: The datasheet lies -- we really should be subtracting 1 here */ cafe_writel(cafe, cafe->datalen, NAND_DATA_LEN); - cafe_writel(cafe, 0x90000000, NAND_IRQ); - if (cafe->usedma && (ctl1 & (3<<25))) { - uint32_t dmactl = 0xc0000000 + cafe->datalen; + cafe_writel(cafe, CAFE_NAND_IRQ_CMD_DONE | CAFE_NAND_IRQ_DMA_DONE, + NAND_IRQ); + if (cafe->usedma && + (ctl1 & (CAFE_NAND_CTRL1_HAS_DATA_IN | + CAFE_NAND_CTRL1_HAS_DATA_OUT))) { + uint32_t dmactl = CAFE_NAND_DMA_CTRL_ENABLE | + CAFE_NAND_DMA_CTRL_RESERVED; + + dmactl |= CAFE_FIELD_PREP(NAND_DMA_CTRL, DATA_LEN, + cafe->datalen); /* If WR or RD bits set, set up DMA */ - if (ctl1 & (1<<26)) { + if (ctl1 & CAFE_NAND_CTRL1_HAS_DATA_IN) { /* It's a read */ - dmactl |= (1<<29); + dmactl |= CAFE_NAND_DMA_CTRL_DATA_IN; /* ... so it's done when the DMA is done, not just the command. */ - doneint = 0x10000000; + doneint = CAFE_NAND_IRQ_DMA_DONE; } cafe_writel(cafe, dmactl, NAND_DMA_CTRL); } @@ -295,7 +407,7 @@ static void cafe_nand_cmdfunc(struct nand_chip *chip, unsigned command, command, 500000-c, irqs, cafe_readl(cafe, NAND_IRQ)); } - WARN_ON(cafe->ctl2 & (1<<30)); + WARN_ON(cafe->ctl2 & CAFE_NAND_CTRL2_AUTO_WRITE_ECC); switch (command) { @@ -318,14 +430,14 @@ static void cafe_select_chip(struct nand_chip *chip, int chipnr) { struct cafe_priv *cafe = nand_get_controller_data(chip); + if (chipnr < 0 || chipnr > 1) + return; + cafe_dev_dbg(&cafe->pdev->dev, "select_chip %d\n", chipnr); /* Mask the appropriate bit into the stored value of ctl1 which will be used by cafe_nand_cmdfunc() */ - if (chipnr) - cafe->ctl1 |= CTRL1_CHIPSELECT; - else - cafe->ctl1 &= ~CTRL1_CHIPSELECT; + cafe->ctl1 |= CAFE_FIELD_PREP(NAND_CTRL1, CE, chipnr); } static irqreturn_t cafe_nand_interrupt(int irq, void *id) @@ -334,7 +446,9 @@ static irqreturn_t cafe_nand_interrupt(int irq, void *id) struct nand_chip *chip = mtd_to_nand(mtd); struct cafe_priv *cafe = nand_get_controller_data(chip); uint32_t irqs = cafe_readl(cafe, NAND_IRQ); - cafe_writel(cafe, irqs & ~0x90000000, NAND_IRQ); + cafe_writel(cafe, + irqs & ~(CAFE_NAND_IRQ_CMD_DONE | CAFE_NAND_IRQ_DMA_DONE), + NAND_IRQ); if (!irqs) return IRQ_NONE; @@ -368,25 +482,31 @@ static int cafe_nand_read_page(struct nand_chip *chip, uint8_t *buf, struct mtd_info *mtd = nand_to_mtd(chip); struct cafe_priv *cafe = nand_get_controller_data(chip); unsigned int max_bitflips = 0; + u32 ecc_result, status; cafe_dev_dbg(&cafe->pdev->dev, "ECC result %08x SYN1,2 %08x\n", cafe_readl(cafe, NAND_ECC_RESULT), - cafe_readl(cafe, NAND_ECC_SYN01)); + cafe_readl(cafe, NAND_ECC_SYN_REG(0))); nand_read_page_op(chip, page, 0, buf, mtd->writesize); chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize); - if (checkecc && cafe_readl(cafe, NAND_ECC_RESULT) & (1<<18)) { + ecc_result = cafe_readl(cafe, NAND_ECC_RESULT); + status = CAFE_FIELD_GET(NAND_ECC_RESULT, STATUS, ecc_result); + if (checkecc && status == CAFE_NAND_ECC_RESULT_CORRECTABLE_ERRS) { unsigned short syn[8], pat[4]; int pos[4]; u8 *oob = chip->oob_poi; int i, n; for (i=0; i<8; i+=2) { - uint32_t tmp = cafe_readl(cafe, NAND_ECC_SYN01 + (i*2)); + uint32_t tmp = cafe_readl(cafe, NAND_ECC_SYN_REG(i)); + uint16_t idx; - syn[i] = cafe->rs->codec->index_of[tmp & 0xfff]; - syn[i+1] = cafe->rs->codec->index_of[(tmp >> 16) & 0xfff]; + idx = FIELD_GET(CAFE_NAND_ECC_SYN_FIELD(i), tmp); + syn[i] = cafe->rs->codec->index_of[idx]; + idx = FIELD_GET(CAFE_NAND_ECC_SYN_FIELD(i + 1), tmp); + syn[i+1] = cafe->rs->codec->index_of[idx]; } n = decode_rs16(cafe->rs, NULL, NULL, 1367, syn, 0, pos, 0, @@ -536,7 +656,7 @@ static int cafe_nand_write_page(struct nand_chip *chip, chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize); /* Set up ECC autogeneration */ - cafe->ctl2 |= (1<<30); + cafe->ctl2 |= CAFE_NAND_CTRL2_AUTO_WRITE_ECC; return nand_prog_page_end_op(chip); } @@ -604,9 +724,9 @@ static int cafe_nand_attach_chip(struct nand_chip *chip) /* Restore the DMA flag */ cafe->usedma = usedma; - cafe->ctl2 = BIT(27); /* Reed-Solomon ECC */ - if (mtd->writesize == 2048) - cafe->ctl2 |= BIT(29); /* 2KiB page size */ + cafe->ctl2 = CAFE_NAND_CTRL2_ECC_ALG_RS | + CAFE_FIELD_PREP(NAND_CTRL2, PAGE_SIZE, + mtd->writesize / 512); /* Set up ECC according to the type of chip we found */ mtd_set_ooblayout(mtd, &cafe_ooblayout_ops); @@ -734,8 +854,8 @@ static int cafe_nand_probe(struct pci_dev *pdev, } /* Start off by resetting the NAND controller completely */ - cafe_writel(cafe, 1, NAND_RESET); - cafe_writel(cafe, 0, NAND_RESET); + cafe_writel(cafe, CAFE_GLOBAL_RESET_NAND, GLOBAL_RESET); + cafe_writel(cafe, 0, GLOBAL_RESET); cafe_writel(cafe, timing[0], NAND_TIMING1); cafe_writel(cafe, timing[1], NAND_TIMING2); @@ -751,17 +871,49 @@ static int cafe_nand_probe(struct pci_dev *pdev, /* Disable master reset, enable NAND clock */ ctrl = cafe_readl(cafe, GLOBAL_CTRL); - ctrl &= 0xffffeff0; - ctrl |= 0x00007000; - cafe_writel(cafe, ctrl | 0x05, GLOBAL_CTRL); - cafe_writel(cafe, ctrl | 0x0a, GLOBAL_CTRL); + ctrl &= ~(CAFE_GLOBAL_SW_RESET_SET | + CAFE_GLOBAL_SW_RESET_CLEAR | + CAFE_GLOBAL_MASTER_RESET_SET | + CAFE_GLOBAL_MASTER_RESET_CLEAR | + CAFE_GLOBAL_NAND_CLK_ENABLE); + ctrl |= CAFE_GLOBAL_NAND_CLK_ENABLE | + CAFE_GLOBAL_SDH_CLK_ENABLE | + CAFE_GLOBAL_CCIC_CLK_ENABLE; + cafe_writel(cafe, + ctrl | + CAFE_GLOBAL_MASTER_RESET_SET | + CAFE_GLOBAL_SW_RESET_SET, + GLOBAL_CTRL); + cafe_writel(cafe, + ctrl | + CAFE_GLOBAL_MASTER_RESET_CLEAR | + CAFE_GLOBAL_SW_RESET_CLEAR, + GLOBAL_CTRL); + cafe_writel(cafe, 0, NAND_DMA_CTRL); - cafe_writel(cafe, 0x7006, GLOBAL_CTRL); - cafe_writel(cafe, 0x700a, GLOBAL_CTRL); + cafe_writel(cafe, + CAFE_GLOBAL_NAND_CLK_ENABLE | + CAFE_GLOBAL_SDH_CLK_ENABLE | + CAFE_GLOBAL_CCIC_CLK_ENABLE | + CAFE_GLOBAL_MASTER_RESET_SET | + CAFE_GLOBAL_SW_RESET_CLEAR, + GLOBAL_CTRL); + cafe_writel(cafe, + CAFE_GLOBAL_NAND_CLK_ENABLE | + CAFE_GLOBAL_SDH_CLK_ENABLE | + CAFE_GLOBAL_CCIC_CLK_ENABLE | + CAFE_GLOBAL_MASTER_RESET_CLEAR | + CAFE_GLOBAL_SW_RESET_CLEAR, + GLOBAL_CTRL); /* Enable NAND IRQ in global IRQ mask register */ - cafe_writel(cafe, 0x80000007, GLOBAL_IRQ_MASK); + cafe_writel(cafe, + CAFE_GLOBAL_IRQ_PCI_ERROR | + CAFE_GLOBAL_IRQ_CCIC | + CAFE_GLOBAL_IRQ_SDH | + CAFE_GLOBAL_IRQ_NAND, + GLOBAL_IRQ_MASK); cafe_dev_dbg(&cafe->pdev->dev, "Control %x, IRQ mask %x\n", cafe_readl(cafe, GLOBAL_CTRL), cafe_readl(cafe, GLOBAL_IRQ_MASK)); @@ -788,7 +940,9 @@ static int cafe_nand_probe(struct pci_dev *pdev, nand_cleanup(&cafe->nand); out_irq: /* Disable NAND IRQ in global IRQ mask register */ - cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK); + cafe_writel(cafe, + cafe_readl(cafe, GLOBAL_IRQ_MASK) & ~CAFE_GLOBAL_IRQ_NAND, + GLOBAL_IRQ_MASK); free_irq(pdev->irq, mtd); out_ior: pci_iounmap(pdev, cafe->mmio); @@ -805,7 +959,9 @@ static void cafe_nand_remove(struct pci_dev *pdev) struct cafe_priv *cafe = nand_get_controller_data(chip); /* Disable NAND IRQ in global IRQ mask register */ - cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK); + cafe_writel(cafe, + cafe_readl(cafe, GLOBAL_IRQ_MASK) & ~CAFE_GLOBAL_IRQ_NAND, + GLOBAL_IRQ_MASK); free_irq(pdev->irq, mtd); nand_release(chip); free_rs(cafe->rs); @@ -830,8 +986,8 @@ static int cafe_nand_resume(struct pci_dev *pdev) struct cafe_priv *cafe = nand_get_controller_data(chip); /* Start off by resetting the NAND controller completely */ - cafe_writel(cafe, 1, NAND_RESET); - cafe_writel(cafe, 0, NAND_RESET); + cafe_writel(cafe, CAFE_GLOBAL_RESET_NAND, GLOBAL_RESET); + cafe_writel(cafe, 0, GLOBAL_RESET); cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK); /* Restore timing configuration */ @@ -841,13 +997,41 @@ static int cafe_nand_resume(struct pci_dev *pdev) /* Disable master reset, enable NAND clock */ ctrl = cafe_readl(cafe, GLOBAL_CTRL); - ctrl &= 0xffffeff0; - ctrl |= 0x00007000; - cafe_writel(cafe, ctrl | 0x05, GLOBAL_CTRL); - cafe_writel(cafe, ctrl | 0x0a, GLOBAL_CTRL); + ctrl &= ~(CAFE_GLOBAL_SW_RESET_SET | + CAFE_GLOBAL_SW_RESET_CLEAR | + CAFE_GLOBAL_MASTER_RESET_SET | + CAFE_GLOBAL_MASTER_RESET_CLEAR | + CAFE_GLOBAL_NAND_CLK_ENABLE); + ctrl |= CAFE_GLOBAL_NAND_CLK_ENABLE | + CAFE_GLOBAL_SDH_CLK_ENABLE | + CAFE_GLOBAL_CCIC_CLK_ENABLE; + cafe_writel(cafe, + ctrl | + CAFE_GLOBAL_MASTER_RESET_SET | + CAFE_GLOBAL_SW_RESET_SET, + GLOBAL_CTRL); + cafe_writel(cafe, + ctrl | + CAFE_GLOBAL_MASTER_RESET_CLEAR | + CAFE_GLOBAL_SW_RESET_CLEAR, + GLOBAL_CTRL); + cafe_writel(cafe, 0, NAND_DMA_CTRL); - cafe_writel(cafe, 0x7006, GLOBAL_CTRL); - cafe_writel(cafe, 0x700a, GLOBAL_CTRL); + + cafe_writel(cafe, + CAFE_GLOBAL_NAND_CLK_ENABLE | + CAFE_GLOBAL_SDH_CLK_ENABLE | + CAFE_GLOBAL_CCIC_CLK_ENABLE | + CAFE_GLOBAL_MASTER_RESET_SET | + CAFE_GLOBAL_SW_RESET_CLEAR, + GLOBAL_CTRL); + cafe_writel(cafe, + CAFE_GLOBAL_NAND_CLK_ENABLE | + CAFE_GLOBAL_SDH_CLK_ENABLE | + CAFE_GLOBAL_CCIC_CLK_ENABLE | + CAFE_GLOBAL_MASTER_RESET_CLEAR | + CAFE_GLOBAL_SW_RESET_CLEAR, + GLOBAL_CTRL); /* Set up DMA address */ cafe_writel(cafe, cafe->dmaaddr & 0xffffffff, NAND_DMA_ADDR0); @@ -858,7 +1042,12 @@ static int cafe_nand_resume(struct pci_dev *pdev) cafe_writel(cafe, 0, NAND_DMA_ADDR1); /* Enable NAND IRQ in global IRQ mask register */ - cafe_writel(cafe, 0x80000007, GLOBAL_IRQ_MASK); + cafe_writel(cafe, + CAFE_GLOBAL_IRQ_PCI_ERROR | + CAFE_GLOBAL_IRQ_CCIC | + CAFE_GLOBAL_IRQ_SDH | + CAFE_GLOBAL_IRQ_NAND, + GLOBAL_IRQ_MASK); return 0; }