From patchwork Tue Sep 23 09:15:19 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jingchang Lu X-Patchwork-Id: 4954861 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 27DA59F348 for ; Tue, 23 Sep 2014 10:11:18 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id AE6602013D for ; Tue, 23 Sep 2014 10:11:16 +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 323B42013A for ; Tue, 23 Sep 2014 10:11:15 +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 1XWN1r-0003GH-4K; Tue, 23 Sep 2014 10:09:03 +0000 Received: from mail-bn1on0135.outbound.protection.outlook.com ([157.56.110.135] helo=na01-bn1-obe.outbound.protection.outlook.com) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1XWN1n-00035A-0A for linux-arm-kernel@lists.infradead.org; Tue, 23 Sep 2014 10:08:59 +0000 Received: from CH1PR03CA005.namprd03.prod.outlook.com (10.255.156.150) by DM2PR03MB480.namprd03.prod.outlook.com (10.141.85.26) with Microsoft SMTP Server (TLS) id 15.0.1034.13; Tue, 23 Sep 2014 10:08:35 +0000 Received: from BY2FFO11FD057.protection.gbl (10.255.156.132) by CH1PR03CA005.outlook.office365.com (10.255.156.150) with Microsoft SMTP Server (TLS) id 15.0.1034.13 via Frontend Transport; Tue, 23 Sep 2014 10:08:34 +0000 Received: from tx30smr01.am.freescale.net (192.88.168.50) by BY2FFO11FD057.mail.protection.outlook.com (10.1.15.185) with Microsoft SMTP Server (TLS) id 15.0.1029.15 via Frontend Transport; Tue, 23 Sep 2014 10:08:34 +0000 Received: from rock.ap.freescale.net (rock.ap.freescale.net [10.193.20.106]) by tx30smr01.am.freescale.net (8.14.3/8.14.0) with ESMTP id s8NA8UqN017715; Tue, 23 Sep 2014 03:08:31 -0700 From: Jingchang Lu To: Subject: [PATCH] dmaengine: fsl-edma: fixup reg offset and hw S/G support in big-endian model Date: Tue, 23 Sep 2014 17:15:19 +0800 Message-ID: <1411463719-7728-1-git-send-email-jingchang.lu@freescale.com> X-Mailer: git-send-email 1.8.0 X-EOPAttributedMessage: 0 X-Forefront-Antispam-Report: CIP:192.88.168.50; CTRY:US; IPV:NLI; EFV:NLI; SFV:NSPM; SFS:(10019020)(6009001)(199003)(189002)(87286001)(87936001)(84676001)(89996001)(50466002)(105606002)(31966008)(106466001)(50226001)(48376002)(77156001)(21056001)(85306004)(97736003)(88136002)(10300001)(4396001)(68736004)(95666004)(83322001)(6806004)(44976005)(19580395003)(85852003)(19580405001)(104016003)(90102001)(46102003)(81542003)(80022003)(81342003)(33646002)(79102003)(74502003)(74662003)(62966002)(110136001)(99396002)(50986999)(229853001)(107046002)(2351001)(102836001)(77982003)(92726001)(76482002)(92566001)(104166001)(36756003)(120916001)(83072002)(86362001)(20776003)(47776003)(93916002)(64706001); DIR:OUT; SFP:1102; SCL:1; SRVR:DM2PR03MB480; H:tx30smr01.am.freescale.net; FPR:; MLV:sfv; PTR:InfoDomainNonexistent; A:1; MX:1; LANG:en; MIME-Version: 1.0 X-Microsoft-Antispam: UriScan:; X-Microsoft-Antispam: BCL:0;PCL:0;RULEID:;SRVR:DM2PR03MB480; X-Forefront-PRVS: 0343AC1D30 Received-SPF: Fail (protection.outlook.com: domain of freescale.com does not designate 192.88.168.50 as permitted sender) receiver=protection.outlook.com; client-ip=192.88.168.50; helo=tx30smr01.am.freescale.net; Authentication-Results: spf=fail (sender IP is 192.88.168.50) smtp.mailfrom=jingchang.lu@freescale.com; X-OriginatorOrg: freescale.com X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140923_030859_287498_1B97CA7D X-CRM114-Status: GOOD ( 13.78 ) X-Spam-Score: -0.2 (/) Cc: dmaengine@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Jingchang Lu 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: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org 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 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The offset of all 8-/16-bit register in big-endian eDMA model are swapped in a 32-bit size opposite those in the little-endian model. The hardware Scatter/Gather requires the subsequent TCDs in memory to be auto loaded should retain the same endian as the core independent of the register endian model, the dma engine will do the swap if need. Signed-off-by: Jingchang Lu --- drivers/dma/fsl-edma.c | 104 +++++++++++++++++++++++++++++++------------------ 1 file changed, 66 insertions(+), 38 deletions(-) diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c index 3c5711d..499af8f 100644 --- a/drivers/dma/fsl-edma.c +++ b/drivers/dma/fsl-edma.c @@ -177,14 +177,20 @@ struct fsl_edma_engine { /* * R/W functions for big- or little-endian registers * the eDMA controller's endian is independent of the CPU core's endian. + * for the big-endian IP module, the offset for 8-bit or 16-bit register + * should also be swapped oposite to that in little-endian IP. */ static u16 edma_readw(struct fsl_edma_engine *edma, void __iomem *addr) { - if (edma->big_endian) - return ioread16be(addr); - else + u32 dst; + /* swap the reg offset for these in big-endian mode */ + if (edma->big_endian) { + dst = ((u32)addr & ~0x3) | (((u32)addr & 0x3) ^ 0x2); + return ioread16be((void __iomem *)dst); + } else { return ioread16(addr); + } } static u32 edma_readl(struct fsl_edma_engine *edma, void __iomem *addr) @@ -197,15 +203,26 @@ static u32 edma_readl(struct fsl_edma_engine *edma, void __iomem *addr) static void edma_writeb(struct fsl_edma_engine *edma, u8 val, void __iomem *addr) { - iowrite8(val, addr); + u32 dst; + /* swap the reg offset for these in big-endian mode */ + if (edma->big_endian) { + dst = ((u32)addr & ~0x3) | (((u32)addr & 0x3) ^ 0x3); + iowrite8(val, (void __iomem *)dst); + } else { + iowrite8(val, addr); + } } static void edma_writew(struct fsl_edma_engine *edma, u16 val, void __iomem *addr) { - if (edma->big_endian) - iowrite16be(val, addr); - else + u32 dst; + /* swap the reg offset for these in big-endian mode */ + if (edma->big_endian) { + dst = ((u32)addr & ~0x3) | (((u32)addr & 0x3) ^ 0x2); + iowrite16be(val, (void __iomem *)dst); + } else { iowrite16(val, addr); + } } static void edma_writel(struct fsl_edma_engine *edma, u32 val, void __iomem *addr) @@ -256,11 +273,10 @@ static void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan, muxaddr = fsl_chan->edma->muxbase[ch / chans_per_mux]; if (enable) - edma_writeb(fsl_chan->edma, - EDMAMUX_CHCFG_ENBL | EDMAMUX_CHCFG_SOURCE(slot), + writeb(EDMAMUX_CHCFG_ENBL | EDMAMUX_CHCFG_SOURCE(slot), muxaddr + ch_off); else - edma_writeb(fsl_chan->edma, EDMAMUX_CHCFG_DIS, muxaddr + ch_off); + writeb(EDMAMUX_CHCFG_DIS, muxaddr + ch_off); } static unsigned int fsl_edma_get_tcd_attr(enum dma_slave_buswidth addr_width) @@ -433,21 +449,26 @@ static void fsl_edma_set_tcd_params(struct fsl_edma_chan *fsl_chan, u32 ch = fsl_chan->vchan.chan.chan_id; /* - * TCD parameters have been swapped in fill_tcd_params(), - * so just write them to registers in the cpu endian here + * TCD parameters should be swapped according the eDMA + * engine requirement. */ - writew(0, addr + EDMA_TCD_CSR(ch)); - writel(src, addr + EDMA_TCD_SADDR(ch)); - writel(dst, addr + EDMA_TCD_DADDR(ch)); - writew(attr, addr + EDMA_TCD_ATTR(ch)); - writew(soff, addr + EDMA_TCD_SOFF(ch)); - writel(nbytes, addr + EDMA_TCD_NBYTES(ch)); - writel(slast, addr + EDMA_TCD_SLAST(ch)); - writew(citer, addr + EDMA_TCD_CITER(ch)); - writew(biter, addr + EDMA_TCD_BITER(ch)); - writew(doff, addr + EDMA_TCD_DOFF(ch)); - writel(dlast_sga, addr + EDMA_TCD_DLAST_SGA(ch)); - writew(csr, addr + EDMA_TCD_CSR(ch)); + edma_writew(fsl_chan->edma, 0, addr + EDMA_TCD_CSR(ch)); + edma_writel(fsl_chan->edma, src, addr + EDMA_TCD_SADDR(ch)); + edma_writel(fsl_chan->edma, dst, addr + EDMA_TCD_DADDR(ch)); + + edma_writew(fsl_chan->edma, attr, addr + EDMA_TCD_ATTR(ch)); + edma_writew(fsl_chan->edma, soff, addr + EDMA_TCD_SOFF(ch)); + + edma_writel(fsl_chan->edma, nbytes, addr + EDMA_TCD_NBYTES(ch)); + edma_writel(fsl_chan->edma, slast, addr + EDMA_TCD_SLAST(ch)); + + edma_writew(fsl_chan->edma, citer, addr + EDMA_TCD_CITER(ch)); + edma_writew(fsl_chan->edma, biter, addr + EDMA_TCD_BITER(ch)); + edma_writew(fsl_chan->edma, doff, addr + EDMA_TCD_DOFF(ch)); + + edma_writel(fsl_chan->edma, dlast_sga, addr + EDMA_TCD_DLAST_SGA(ch)); + + edma_writew(fsl_chan->edma, csr, addr + EDMA_TCD_CSR(ch)); } static void fill_tcd_params(struct fsl_edma_engine *edma, @@ -459,20 +480,27 @@ static void fill_tcd_params(struct fsl_edma_engine *edma, u16 csr = 0; /* - * eDMA hardware SGs require the TCD parameters stored in memory - * the same endian as the eDMA module so that they can be loaded - * automatically by the engine + * eDMA hardware SGs requires the TCDs to be auto loaded + * in the same endian as the core whenver the eDAM engine's + * register endian. So we don't swap the value, waitting + * for fsl_set_tcd_params doing the swap. */ - edma_writel(edma, src, &(tcd->saddr)); - edma_writel(edma, dst, &(tcd->daddr)); - edma_writew(edma, attr, &(tcd->attr)); - edma_writew(edma, EDMA_TCD_SOFF_SOFF(soff), &(tcd->soff)); - edma_writel(edma, EDMA_TCD_NBYTES_NBYTES(nbytes), &(tcd->nbytes)); - edma_writel(edma, EDMA_TCD_SLAST_SLAST(slast), &(tcd->slast)); - edma_writew(edma, EDMA_TCD_CITER_CITER(citer), &(tcd->citer)); - edma_writew(edma, EDMA_TCD_DOFF_DOFF(doff), &(tcd->doff)); - edma_writel(edma, EDMA_TCD_DLAST_SGA_DLAST_SGA(dlast_sga), &(tcd->dlast_sga)); - edma_writew(edma, EDMA_TCD_BITER_BITER(biter), &(tcd->biter)); + writel(src, &(tcd->saddr)); + writel(dst, &(tcd->daddr)); + + writew(attr, &(tcd->attr)); + + writew(EDMA_TCD_SOFF_SOFF(soff), &(tcd->soff)); + + writel(EDMA_TCD_NBYTES_NBYTES(nbytes), &(tcd->nbytes)); + writel(EDMA_TCD_SLAST_SLAST(slast), &(tcd->slast)); + + writew(EDMA_TCD_CITER_CITER(citer), &(tcd->citer)); + writew(EDMA_TCD_DOFF_DOFF(doff), &(tcd->doff)); + + writel(EDMA_TCD_DLAST_SGA_DLAST_SGA(dlast_sga), &(tcd->dlast_sga)); + + writew(EDMA_TCD_BITER_BITER(biter), &(tcd->biter)); if (major_int) csr |= EDMA_TCD_CSR_INT_MAJOR; @@ -482,7 +510,7 @@ static void fill_tcd_params(struct fsl_edma_engine *edma, if (enable_sg) csr |= EDMA_TCD_CSR_E_SG; - edma_writew(edma, csr, &(tcd->csr)); + writew(csr, &(tcd->csr)); } static struct fsl_edma_desc *fsl_edma_alloc_desc(struct fsl_edma_chan *fsl_chan,