Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S934129AbbFWVvj (ORCPT ); Tue, 23 Jun 2015 17:51:39 -0400 Received: from fish.king.net.pl ([79.190.246.46]:37023 "EHLO king.net.pl" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1755044AbbFWVvR (ORCPT ); Tue, 23 Jun 2015 17:51:17 -0400 From: Paul Osmialowski To: Andrew Morton , Anson Huang , Ard Biesheuvel , Arnd Bergmann , Bhupesh Sharma , Daniel Lezcano , Frank Li , Geert Uytterhoeven , Greg Kroah-Hartman , Guenter Roeck , Haojian Zhuang , Ian Campbell , Jingchang Lu , Jiri Slaby , Kees Cook , Kumar Gala , Laurent Pinchart , Linus Walleij , Magnus Damm , Michael Turquette , Nathan Lynch , Nicolas Pitre , Maxime Coquelin stm32 , Olof Johansson , Paul Bolle , Rob Herring , Rob Herring , Russell King , Sergey Senozhatsky , Shawn Guo , Simon Horman , Stefan Agner , Stephen Boyd , Thomas Gleixner , Uwe Kleine-Koenig , Catalin Marinas , Dave Martin , Mark Rutland , Pawel Moll , linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-clk@vger.kernel.org, linux-gpio@vger.kernel.org, linux-serial@vger.kernel.org, devicetree@vger.kernel.org, dmaengine@vger.kernel.org Cc: Paul Osmialowski , Yuri Tikhonov , Sergei Poselenov , Dmitry Cherkassov , Alexander Potashev Subject: [PATCH 8/9] arm: twr-k70f120m: extend Freescale eDMA driver with ability to support Kinetis SoC Date: Tue, 23 Jun 2015 23:19:46 +0200 Message-Id: <1435094387-20146-9-git-send-email-pawelo@king.net.pl> X-Mailer: git-send-email 2.3.6 In-Reply-To: <1435094387-20146-1-git-send-email-pawelo@king.net.pl> References: <1435094387-20146-1-git-send-email-pawelo@king.net.pl> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 13561 Lines: 435 Surprisingly small amount of work was required in order to extend already existing eDMA driver with the support for Kinetis SoC architecture. Note that is needed (which is denoted by CONFIG_NEED_MACH_MEMORY_H) as it provides macros required for proper operation of DMA allocation functions. Signed-off-by: Paul Osmialowski --- Documentation/devicetree/bindings/dma/fsl-edma.txt | 38 +++++++++- arch/arm/Kconfig | 4 ++ arch/arm/boot/dts/kinetis.dtsi | 34 +++++++++ arch/arm/mach-kinetis/include/mach/memory.h | 61 ++++++++++++++++ drivers/clk/clk-kinetis.c | 15 ++++ drivers/dma/fsl-edma.c | 81 +++++++++++++++++++++- include/dt-bindings/clock/kinetis-mcg.h | 5 +- 7 files changed, 235 insertions(+), 3 deletions(-) create mode 100644 arch/arm/mach-kinetis/include/mach/memory.h diff --git a/Documentation/devicetree/bindings/dma/fsl-edma.txt b/Documentation/devicetree/bindings/dma/fsl-edma.txt index 191d7bd..e1ee406 100644 --- a/Documentation/devicetree/bindings/dma/fsl-edma.txt +++ b/Documentation/devicetree/bindings/dma/fsl-edma.txt @@ -9,6 +9,7 @@ group, DMAMUX0 or DMAMUX1, but not both. Required properties: - compatible : - "fsl,vf610-edma" for eDMA used similar to that on Vybrid vf610 SoC + - "fsl,kinetis-edma" for eDMA used similar to that on Kinetis SoC - reg : Specifies base physical address(s) and size of the eDMA registers. The 1st region is eDMA control register's address and size. The 2nd and the 3rd regions are programmable channel multiplexing @@ -16,7 +17,8 @@ Required properties: - interrupts : A list of interrupt-specifiers, one for each entry in interrupt-names. - interrupt-names : Should contain: - "edma-tx" - the transmission interrupt + "edma-tx" - the transmission interrupt (Vybrid) + "edma-tx-n,m" - interrupt for channels n (0-15) and m (16-31) (Kinetis) "edma-err" - the error interrupt - #dma-cells : Must be <2>. The 1st cell specifies the DMAMUX(0 for DMAMUX0 and 1 for DMAMUX1). @@ -28,6 +30,7 @@ Required properties: - clock-names : A list of channel group clock names. Should contain: "dmamux0" - clock name of mux0 group "dmamux1" - clock name of mux1 group + "edma" - clock gate for whole controller (Kinetis only) - clocks : A list of phandle and clock-specifier pairs, one for each entry in clock-names. @@ -54,6 +57,39 @@ edma0: dma-controller@40018000 { <&clks VF610_CLK_DMAMUX1>; }; +edma: dma-controller@40008000 { + compatible = "fsl,kinetis-edma"; + reg = <0x40008000 0x2000>, /* DMAC */ + <0x40021000 0x1000>, /* DMAMUX0 */ + <0x40022000 0x1000>; /* DMAMUX1 */ + #dma-cells = <2>; + dma-channels = <32>; + interrupts = <0>, <1>, <2>, <3>, + <4>, <5>, <6>, <7>, + <8>, <9>, <10>, <11>, + <12>, <13>, <14>, <15>, + <16>; + interrupt-names = "edma-tx-0,16", + "edma-tx-1,17", + "edma-tx-2,18", + "edma-tx-3,19", + "edma-tx-4,20", + "edma-tx-5,21", + "edma-tx-6,22", + "edma-tx-7,23", + "edma-tx-8,24", + "edma-tx-9,25", + "edma-tx-10,26", + "edma-tx-11,27", + "edma-tx-12,28", + "edma-tx-13,29", + "edma-tx-14,30", + "edma-tx-15,31", + "edma-err"; + clocks = <&mcg CLOCK_EDMA>, + <&mcg CLOCK_DMAMUX0>, <&mcg CLOCK_DMAMUX1>; + clock-names = "edma", "dmamux0", "dmamux1"; +}; * DMA clients DMA client drivers that uses the DMA function must use the format described diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 662447c..154436a 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -981,6 +981,10 @@ config ARCH_KINETIS select ARMV7M_SYSTICK select CLKSRC_KINETIS select PINCTRL + select DMADEVICES + select FSL_EDMA + select DMA_OF + select NEED_MACH_MEMORY_H select ZLIB_INFLATE_STACK_SAVING if ZLIB_INFLATE help This enables support for the Freescale Kinetis MCUs diff --git a/arch/arm/boot/dts/kinetis.dtsi b/arch/arm/boot/dts/kinetis.dtsi index f3f22b5..7638103 100644 --- a/arch/arm/boot/dts/kinetis.dtsi +++ b/arch/arm/boot/dts/kinetis.dtsi @@ -20,6 +20,40 @@ }; soc { + edma: dma-controller@40008000 { + compatible = "fsl,kinetis-edma"; + reg = <0x40008000 0x2000>, /* DMAC */ + <0x40021000 0x1000>, /* DMAMUX0 */ + <0x40022000 0x1000>; /* DMAMUX1 */ + #dma-cells = <2>; + dma-channels = <32>; + interrupts = <0>, <1>, <2>, <3>, + <4>, <5>, <6>, <7>, + <8>, <9>, <10>, <11>, + <12>, <13>, <14>, <15>, + <16>; + interrupt-names = "edma-tx-0,16", + "edma-tx-1,17", + "edma-tx-2,18", + "edma-tx-3,19", + "edma-tx-4,20", + "edma-tx-5,21", + "edma-tx-6,22", + "edma-tx-7,23", + "edma-tx-8,24", + "edma-tx-9,25", + "edma-tx-10,26", + "edma-tx-11,27", + "edma-tx-12,28", + "edma-tx-13,29", + "edma-tx-14,30", + "edma-tx-15,31", + "edma-err"; + clocks = <&mcg CLOCK_EDMA>, + <&mcg CLOCK_DMAMUX0>, <&mcg CLOCK_DMAMUX1>; + clock-names = "edma", "dmamux0", "dmamux1"; + }; + portA: pinmux@40049000 { compatible = "fsl,kinetis-padconf"; reg = <0x40049000 0x1000>; diff --git a/arch/arm/mach-kinetis/include/mach/memory.h b/arch/arm/mach-kinetis/include/mach/memory.h new file mode 100644 index 0000000..8bad034 --- /dev/null +++ b/arch/arm/mach-kinetis/include/mach/memory.h @@ -0,0 +1,61 @@ +/* + * Based on original code by Alexander Potashev + * + * (C) Copyright 2011, 2012 + * Emcraft Systems, + * Alexander Potashev + * + * Copyright (C) 2015 Paul Osmialowski + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the + * Free Software Foundation. + */ + +#ifndef _MACH_KINETIS_MEMORY_H +#define _MACH_KINETIS_MEMORY_H + +#ifndef __ASSEMBLY__ + +/* + * On Kinetis K70, consistent DMA memory resides in a special + * DDRAM alias region (non-cacheable DDRAM at 0x80000000). + * + */ +#define KINETIS_PHYS_DMA_OFFSET UL(0x80000000) + +/* + * Mask of the field used to distinguish DDRAM aliases + */ +#define KINETIS_DRAM_ALIAS_MASK UL(0xf8000000) + +/* + * This macro converts an address in the kernel run-time memory + * to an alias in the non-cacheable memory region + */ +#define KINETIS_DMA_ALIAS_ADDR(addr) \ + (((unsigned long)(addr) & ~KINETIS_DRAM_ALIAS_MASK) | \ + (KINETIS_PHYS_DMA_OFFSET & KINETIS_DRAM_ALIAS_MASK)) + +/* + * This macro converts an address in the kernel code or + * in the non-cacheable DMA region to an alias in + * the run-time kernel memory region + */ +#define KINETIS_PHYS_ALIAS_ADDR(addr) \ + ((unsigned long)(addr) & ~KINETIS_DRAM_ALIAS_MASK) + +#define __arch_dma_to_pfn(dev, addr) __phys_to_pfn(addr) + +#define __arch_pfn_to_dma(dev, pfn) \ + ((dma_addr_t)KINETIS_DMA_ALIAS_ADDR(__pfn_to_phys(pfn))) + +#define __arch_dma_to_virt(dev, addr) \ + ((void *)KINETIS_PHYS_ALIAS_ADDR(addr)) + +#define __arch_virt_to_dma(dev, addr) \ + ((dma_addr_t)KINETIS_DMA_ALIAS_ADDR(addr)) + +#endif /* __ASSEMBLY__ */ + +#endif /*_MACH_KINETIS_MEMORY_H */ diff --git a/drivers/clk/clk-kinetis.c b/drivers/clk/clk-kinetis.c index b6620c0..454096c 100644 --- a/drivers/clk/clk-kinetis.c +++ b/drivers/clk/clk-kinetis.c @@ -248,6 +248,21 @@ static void __init kinetis_mcg_init(struct device_node *np) KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_PORTF)]), KINETIS_CG_IDX(KINETIS_CG_PORTF), 0, NULL); + /* + * DMA clock gates, see K70 Sub-Family Reference Manual, Rev. 3 pg. 223: + */ + clk[CLOCK_EDMA] = clk_register_gate(NULL, "EDMA", "CCLK", 0, + KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_DMA)]), + KINETIS_CG_IDX(KINETIS_CG_DMA), 0, NULL); + + clk[CLOCK_DMAMUX0] = clk_register_gate(NULL, "DMAMUX0", "PCLK", 0, + KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_DMAMUX0)]), + KINETIS_CG_IDX(KINETIS_CG_DMAMUX0), 0, NULL); + + clk[CLOCK_DMAMUX1] = clk_register_gate(NULL, "DMAMUX1", "PCLK", 0, + KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_DMAMUX1)]), + KINETIS_CG_IDX(KINETIS_CG_DMAMUX1), 0, NULL); + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); } diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c index 915eec3..655d819 100644 --- a/drivers/dma/fsl-edma.c +++ b/drivers/dma/fsl-edma.c @@ -161,14 +161,42 @@ struct fsl_edma_desc { struct fsl_edma_sw_tcd tcd[]; }; +#ifdef CONFIG_ARCH_KINETIS +static const char * const txirq_names[] = { + "edma-tx-0,16", + "edma-tx-1,17", + "edma-tx-2,18", + "edma-tx-3,19", + "edma-tx-4,20", + "edma-tx-5,21", + "edma-tx-6,22", + "edma-tx-7,23", + "edma-tx-8,24", + "edma-tx-9,25", + "edma-tx-10,26", + "edma-tx-11,27", + "edma-tx-12,28", + "edma-tx-13,29", + "edma-tx-14,30", + "edma-tx-15,31", +}; +#endif + struct fsl_edma_engine { struct dma_device dma_dev; void __iomem *membase; +#ifdef CONFIG_ARCH_KINETIS + struct clk *clk; +#endif void __iomem *muxbase[DMAMUX_NR]; struct clk *muxclk[DMAMUX_NR]; struct mutex fsl_edma_mutex; u32 n_chans; +#ifdef CONFIG_ARCH_KINETIS + int txirq[ARRAY_SIZE(txirq_names)]; +#else int txirq; +#endif int errirq; bool big_endian; struct fsl_edma_chan chans[]; @@ -709,6 +737,7 @@ static irqreturn_t fsl_edma_err_handler(int irq, void *dev_id) return IRQ_HANDLED; } +#ifndef CONFIG_ARCH_KINETIS static irqreturn_t fsl_edma_irq_handler(int irq, void *dev_id) { if (fsl_edma_tx_handler(irq, dev_id) == IRQ_HANDLED) @@ -716,6 +745,7 @@ static irqreturn_t fsl_edma_irq_handler(int irq, void *dev_id) return fsl_edma_err_handler(irq, dev_id); } +#endif static void fsl_edma_issue_pending(struct dma_chan *chan) { @@ -788,15 +818,29 @@ static void fsl_edma_free_chan_resources(struct dma_chan *chan) } static int -fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma) +fsl_edma_irq_init(struct platform_device *pdev, + struct fsl_edma_engine *fsl_edma) { int ret; +#ifdef CONFIG_ARCH_KINETIS + int i; + for (i = 0; i < ARRAY_SIZE(txirq_names); i++) { + fsl_edma->txirq[i] = platform_get_irq_byname(pdev, + txirq_names[i]); + if (fsl_edma->txirq[i] < 0) { + dev_err(&pdev->dev, "Can't get %s irq.\n", + txirq_names[i]); + return fsl_edma->txirq[i]; + } + } +#else fsl_edma->txirq = platform_get_irq_byname(pdev, "edma-tx"); if (fsl_edma->txirq < 0) { dev_err(&pdev->dev, "Can't get edma-tx irq.\n"); return fsl_edma->txirq; } +#endif fsl_edma->errirq = platform_get_irq_byname(pdev, "edma-err"); if (fsl_edma->errirq < 0) { @@ -804,6 +848,16 @@ fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma return fsl_edma->errirq; } +#ifdef CONFIG_ARCH_KINETIS + for (i = 0; i < ARRAY_SIZE(txirq_names); i++) { + ret = devm_request_irq(&pdev->dev, fsl_edma->txirq[i], + fsl_edma_tx_handler, 0, txirq_names[i], fsl_edma); + if (ret) { + dev_err(&pdev->dev, "Can't register eDMA tx IRQ.\n"); + return ret; + } + } +#else if (fsl_edma->txirq == fsl_edma->errirq) { ret = devm_request_irq(&pdev->dev, fsl_edma->txirq, fsl_edma_irq_handler, 0, "eDMA", fsl_edma); @@ -818,6 +872,7 @@ fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma dev_err(&pdev->dev, "Can't register eDMA tx IRQ.\n"); return ret; } +#endif ret = devm_request_irq(&pdev->dev, fsl_edma->errirq, fsl_edma_err_handler, 0, "eDMA err", fsl_edma); @@ -825,7 +880,9 @@ fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma dev_err(&pdev->dev, "Can't register eDMA err IRQ.\n"); return ret; } +#ifndef CONFIG_ARCH_KINETIS } +#endif return 0; } @@ -858,6 +915,20 @@ static int fsl_edma_probe(struct platform_device *pdev) if (IS_ERR(fsl_edma->membase)) return PTR_ERR(fsl_edma->membase); +#ifdef CONFIG_ARCH_KINETIS + fsl_edma->clk = devm_clk_get(&pdev->dev, "edma"); + if (IS_ERR(fsl_edma->clk)) { + dev_err(&pdev->dev, "Missing EDMA clock.\n"); + return PTR_ERR(fsl_edma->clk); + } + + ret = clk_prepare_enable(fsl_edma->clk); + if (ret) { + dev_err(&pdev->dev, "EDMA clk failed.\n"); + return ret; + } +#endif + for (i = 0; i < DMAMUX_NR; i++) { char clkname[32]; @@ -956,11 +1027,19 @@ static int fsl_edma_remove(struct platform_device *pdev) for (i = 0; i < DMAMUX_NR; i++) clk_disable_unprepare(fsl_edma->muxclk[i]); +#ifdef CONFIG_ARCH_KINETIS + clk_disable_unprepare(fsl_edma->clk); +#endif + return 0; } static const struct of_device_id fsl_edma_dt_ids[] = { +#ifdef CONFIG_ARCH_KINETIS + { .compatible = "fsl,kinetis-edma", }, +#else { .compatible = "fsl,vf610-edma", }, +#endif { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, fsl_edma_dt_ids); diff --git a/include/dt-bindings/clock/kinetis-mcg.h b/include/dt-bindings/clock/kinetis-mcg.h index 5eaeeec..d853c3c 100644 --- a/include/dt-bindings/clock/kinetis-mcg.h +++ b/include/dt-bindings/clock/kinetis-mcg.h @@ -11,6 +11,9 @@ #define CLOCK_PORTD 7 #define CLOCK_PORTE 8 #define CLOCK_PORTF 9 -#define CLOCK_END 10 +#define CLOCK_EDMA 10 +#define CLOCK_DMAMUX0 11 +#define CLOCK_DMAMUX1 12 +#define CLOCK_END 13 #endif /* _DT_BINDINGS_CLOCK_KINETIS_MCG_H */ -- 2.3.6 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/