From patchwork Tue Sep 23 14:07:34 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris BREZILLON X-Patchwork-Id: 4956701 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 1EC70BEEA5 for ; Tue, 23 Sep 2014 14:10:42 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 6AD662018E for ; Tue, 23 Sep 2014 14:10:37 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 111D320155 for ; Tue, 23 Sep 2014 14:10:28 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1XWQlg-0003SS-No; Tue, 23 Sep 2014 14:08:36 +0000 Received: from top.free-electrons.com ([176.31.233.9] helo=mail.free-electrons.com) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1XWQlA-0002tA-0A; Tue, 23 Sep 2014 14:08:05 +0000 Received: by mail.free-electrons.com (Postfix, from userid 106) id 811B375E; Tue, 23 Sep 2014 16:07:42 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Level: X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 Received: from localhost.localdomain (col31-4-88-188-83-94.fbx.proxad.net [88.188.83.94]) by mail.free-electrons.com (Postfix) with ESMTPSA id C119D73D; Tue, 23 Sep 2014 16:07:41 +0200 (CEST) From: Boris BREZILLON To: David Woodhouse , Brian Norris , linux-mtd@lists.infradead.org, Huang Shijie Subject: [PATCH v3 1/3] mtd: nand: gpmi: add gpmi_move_bits function Date: Tue, 23 Sep 2014 16:07:34 +0200 Message-Id: <1411481256-29141-2-git-send-email-boris.brezillon@free-electrons.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1411481256-29141-1-git-send-email-boris.brezillon@free-electrons.com> References: <1411481256-29141-1-git-send-email-boris.brezillon@free-electrons.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140923_070804_370266_E01C8966 X-CRM114-Status: GOOD ( 12.40 ) X-Spam-Score: 0.3 (/) Cc: Mike Voytovich , Boris BREZILLON , linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Roy Lee X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP Add a new function to move bits (not bytes) from a memory region to another one. This function is similar to memmove except it acts at bit level. This function is needed to implement GPMI raw access functions, given the fact that ECC engine does not pad ECC bits to the next byte boundary. Signed-off-by: Boris BREZILLON --- drivers/mtd/nand/gpmi-nand/gpmi-lib.c | 88 ++++++++++++++++++++++++++++++++++ drivers/mtd/nand/gpmi-nand/gpmi-nand.h | 4 ++ 2 files changed, 92 insertions(+) diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c index 87e658c..e2f706a 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c @@ -1353,3 +1353,91 @@ int gpmi_read_page(struct gpmi_nand_data *this, set_dma_type(this, DMA_FOR_READ_ECC_PAGE); return start_dma_with_bch_irq(this, desc); } + +void gpmi_move_bits(u8 *dst, size_t dst_bit_off, + const u8 *src, size_t src_bit_off, + size_t nbits) +{ + size_t i; + size_t nbytes; + u32 src_byte = 0; + + src += src_bit_off / 8; + src_bit_off %= 8; + + dst += dst_bit_off / 8; + dst_bit_off %= 8; + + if (src_bit_off) { + src_byte = src[0] >> src_bit_off; + nbits -= 8 - src_bit_off; + src++; + } + + nbytes = nbits / 8; + + if (dst_bit_off) { + if (src_bit_off <= dst_bit_off) { + dst[0] &= GENMASK(dst_bit_off - 1, 0); + dst[0] |= src_byte << dst_bit_off; + src_bit_off += (8 - dst_bit_off); + src_byte >>= (8 - dst_bit_off); + dst_bit_off = 0; + dst++; + } else if (nbytes) { + src_byte |= src[0] << (8 - src_bit_off); + dst[0] &= GENMASK(dst_bit_off - 1, 0); + dst[0] |= src_byte << dst_bit_off; + src_bit_off += dst_bit_off; + src_byte >>= (8 - dst_bit_off); + dst_bit_off = 0; + dst++; + nbytes--; + src++; + if (src_bit_off > 7) { + src_bit_off -= 8; + dst[0] = src_byte; + dst++; + src_byte >>= 8; + } + } + } + + if (!src_bit_off && !dst_bit_off) { + if (nbytes) + memcpy(dst, src, nbytes); + } else { + for (i = 0; i < nbytes; i++) { + src_byte |= src[i] << (8 - src_bit_off); + dst[i] = src_byte; + src_byte >>= 8; + } + } + + dst += nbytes; + src += nbytes; + nbits %= 8; + + if (!nbits && !src_bit_off) + return; + + if (nbits) + src_byte |= (*src & GENMASK(nbits - 1, 0)) << + ((8 - src_bit_off) % 8); + nbits += (8 - src_bit_off) % 8; + + if (dst_bit_off) + src_byte = (src_byte << dst_bit_off) | + (*dst & GENMASK(dst_bit_off - 1, 0)); + nbits += dst_bit_off; + + if (nbits % 8) + src_byte |= (dst[nbits / 8] & GENMASK(7, nbits % 8)) << + (nbits / 8); + + nbytes = DIV_ROUND_UP(nbits, 8); + for (i = 0; i < nbytes; i++) { + dst[i] = src_byte; + src_byte >>= 8; + } +} diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h index 32c6ba4..17d0736 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h @@ -290,6 +290,10 @@ extern int gpmi_send_page(struct gpmi_nand_data *, extern int gpmi_read_page(struct gpmi_nand_data *, dma_addr_t payload, dma_addr_t auxiliary); +void gpmi_move_bits(u8 *dst, size_t dst_bit_off, + const u8 *src, size_t src_bit_off, + size_t nbits); + /* BCH : Status Block Completion Codes */ #define STATUS_GOOD 0x00 #define STATUS_ERASED 0xff