Re: [RFC PATCH v5 1/9] mmc: dw_mmc: Add external dma interface support
在 2015/8/17 5:10, Doug Anderson 写道: Heiko, On Fri, Aug 14, 2015 at 3:13 PM, Heiko Stübner wrote: Hi Shawn, Am Freitag, 14. August 2015, 16:34:35 schrieb Shawn Lin: DesignWare MMC Controller can supports two types of DMA mode: external dma and internal dma. We get a RK312x platform integrated dw_mmc and ARM pl330 dma controller. This patch add edmac ops to support these platforms. I've tested it on RK312x platform with edmac mode and RK3288 platform with idmac mode. Signed-off-by: Shawn Lin judging by your "from", I guess you're running this on some older Rockchip soc without the idma? Because I tried testing this on a Radxa Rock, but only got failures, from the start (failed to read card status register). In PIO mode everything works again. I guess I overlooked just some tiny detail, but to me the dma channel ids seem correct after all. Maybe you have any hints what I'm doing wrong? If I were a guessing man (which I'm not), I'd guess that perhaps you're running into troubles with our friend the PL330. There appear to be strange issues with the PL330 on Rockchip SoCs. I was only peripherally involved with them, but I know at least about some of the patches in our tree, like: Thanks, Doug, that's the root cause. PL330 on Rockchip Socs need your patches, and we might need another patch to limit pl330 burst_len to 16(Hmm...seems another quirks for rockchip but not on your tree); Hi Heiko, I just get a Radxa Rock luckily and test my patch based on http://radxa.com/Rock/Linux_Mainline. Yes, it can't work. If you test my patchset on Rockchip platform, pls apply pl330 patch from my tree based on kernel 4.2-RC3. AND, temporary hack dw_mmc to limit pl330 burst_len to 16. This is a dmaengine or pl330 problem(I guest it should be upstreamed later?), but my patchset is for *generic* dw_mmc to support emdac, so other platforms should never need the hack of pl330. pl330.patch is for pl330 changes r3xxx.patch is for pl330 quirks AND pls limit burst_len to 16 for BROKRN pl330 of rockchips. static int dw_mci_edmac_start_dma( ... +u32 burst_limit = 0; +u32 mburst; +u32 idx, rx_wmark, tx_wmark; ... /* Match burst msize with external dma config */ fifoth_val = mci_readl(host, FIFOTH); - cfg.dst_maxburst = mszs[(fifoth_val >> 28) & 0x7]; - cfg.src_maxburst = cfg.dst_maxburst; + /* HACK for BROKEN pl330 */ + mburst = mszs[(fifoth_val >> 28) & 0x7]; + burst_limit = 16; + if (mburst > burst_limit) { + mburst = burst_limit; + idx = (ilog2(mburst) > 0) ? (ilog2(mburst) - 1) : 0; + rx_wmark = mszs[idx] - 1; + tx_wmark = (host->fifo_depth) / 2; + fifoth_val = SDMMC_SET_FIFOTH(idx, rx_wmark, tx_wmark); + mci_writel(host, FIFOTH, fifoth_val); + } + cfg.dst_maxburst = mburst; + cfg.src_maxburst = cfg.dst_maxburst; https://chromium-review.googlesource.com/237607 FROMLIST: DMA: pl330: support burst mode for dev-to-mem and mem-to-dev transmit https://chromium-review.googlesource.com/237393 CHROMIUM: dmaengine: pl330: support quirks for some broken https://chromium-review.googlesource.com/237396 CHROMIUM: dmaengine: pl330: add quirk for broken no flushp https://chromium-review.googlesource.com/237394 CHROMIUM: ARM: dts: rockchip: Add broken-no-flushp into rk3288.dtsi https://chromium-review.googlesource.com/242063 CHROMIUM: ASoC: rockchip_i2s: modify DMA max burst to 1 -- Shawn Lin diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index ecab4ea..b2a950c 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -34,6 +34,14 @@ #define PL330_MAX_IRQS 32 #define PL330_MAX_PERI 32 +#define PL330_QUIRK_BROKEN_NO_FLUSHP BIT(0) + +enum pl330_cond { + SINGLE, + BURST, + ALWAYS, +}; + enum pl330_cachectrl { CCTRL0, /* Noncacheable and nonbufferable */ CCTRL1, /* Bufferable only */ @@ -344,12 +352,6 @@ enum pl330_dst { DST, }; -enum pl330_cond { - SINGLE, - BURST, - ALWAYS, -}; - struct dma_pl330_desc; struct _pl330_req { @@ -488,6 +490,17 @@ struct pl330_dmac { /* Peripheral channels connected to this DMAC */ unsigned int num_peripherals; struct dma_pl330_chan *peripherals; /* keep at end */ + int quirks; +}; + +static struct pl330_of_quirks { + char *quirk; + int id; +} of_quirks[] = { + { + .quirk = "broken-no-flushp", + .id = PL330_QUIRK_BROKEN_NO_FLUSHP, + } }; struct dma_pl330_desc { @@ -1137,47 +1150,64 @@ static inline int _ldst_memtomem(unsigned dry_run, u8 buf[], return off; } -static inline int _ldst_devtomem(unsigned dry_run, u8 buf[], +static inline int _ldst_devtomem(struct pl330_dmac *pi,unsigned dry_run, u8 buf[], const struct _xfer_spec *pxs, int cyc) { int off = 0; + enum p
Re: [RFC PATCH v5 1/9] mmc: dw_mmc: Add external dma interface support
在 2015/8/15 6:13, Heiko Stübner 写道: Hi Shawn, Am Freitag, 14. August 2015, 16:34:35 schrieb Shawn Lin: DesignWare MMC Controller can supports two types of DMA mode: external dma and internal dma. We get a RK312x platform integrated dw_mmc and ARM pl330 dma controller. This patch add edmac ops to support these platforms. I've tested it on RK312x platform with edmac mode and RK3288 platform with idmac mode. Signed-off-by: Shawn Lin judging by your "from", I guess you're running this on some older Rockchip soc without the idma? Because I tried testing this on a Radxa Rock, but only got failures, from the start (failed to read card status register). In PIO mode everything works again. I guess I overlooked just some tiny detail, but to me the dma channel ids seem correct after all. Maybe you have any hints what I'm doing wrong? Thanks, HeiKo. yes, I'm running a quite older low-end Rockchip soc w/o idma. Hmm... from your failure to read CSR, I think generic DMA of Radxa Rock was not runing properly. Your dma channel ids is correct, but it certainly work on my platform。 I will try to find a Radxa Rock to re-test my patch ASAP. diff --git a/arch/arm/boot/dts/rk3xxx.dtsi b/arch/arm/boot/dts/rk3xxx.dtsi index 4497d28..92d7156 100644 --- a/arch/arm/boot/dts/rk3xxx.dtsi +++ b/arch/arm/boot/dts/rk3xxx.dtsi @@ -217,6 +217,8 @@ interrupts = ; clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>; clock-names = "biu", "ciu"; + dmas = <&dmac2 1>; + dma-names = "rx-tx"; fifo-depth = <256>; status = "disabled"; }; @@ -227,6 +229,8 @@ interrupts = ; clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>; clock-names = "biu", "ciu"; + dmas = <&dmac2 3>; + dma-names = "rx-tx"; fifo-depth = <256>; status = "disabled"; }; @@ -237,6 +241,8 @@ interrupts = ; clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>; clock-names = "biu", "ciu"; + dmas = <&dmac2 4>; + dma-names = "rx-tx"; fifo-depth = <256>; status = "disabled"; }; [...] diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index fcbf552..e01ead3 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -2517,8 +2642,23 @@ static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id) static void dw_mci_init_dma(struct dw_mci *host) { int addr_config; + int trans_mode; + struct device *dev = host->dev; + struct device_node *np = dev->of_node; + + /* Check tansfer mode */ + trans_mode = SDMMC_GET_TRANS_MODE(mci_readl(host, HCON)); + if (trans_mode == 0) { + trans_mode = TRANS_MODE_IDMAC; + } else if (trans_mode == 1 || trans_mode == 2) { + trans_mode = TRANS_MODE_EDMAC; + } else { + trans_mode = TRANS_MODE_PIO; + goto no_dma; + } + /* Check ADDR_CONFIG bit in HCON to find IDMAC address bus width */ - addr_config = (mci_readl(host, HCON) >> 27) & 0x01; + addr_config = SDMMC_GET_ADDR_CONFIG(mci_readl(host, HCON)); if (addr_config == 1) { /* host supports IDMAC in 64-bit address mode */ I guess the idmac address size checking block /* Check ADDR_CONFIG bit in HCON to find IDMAC address bus width */ addr_config = SDMMC_GET_ADDR_CONFIG(mci_readl(host, HCON)); if (addr_config == 1) { /* host supports IDMAC in 64-bit address mode */ host->dma_64bit_address = 1; dev_info(host->dev, "IDMAC supports 64-bit address mode.\n"); if (!dma_set_mask(host->dev, DMA_BIT_MASK(64))) dma_set_coherent_mask(host->dev, DMA_BIT_MASK(64)); } else { /* host supports IDMAC in 32-bit address mode */ host->dma_64bit_address = 0; dev_info(host->dev, "IDMAC supports 32-bit address mode.\n"); } could either live inside the trans_mode == 0 conditional above or get its own if (trans_mode == 0) conditional. Either way I guess it should not talk about idmac when either pio or extdmac are used. Thanks Heiko -- Shawn Lin -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFC PATCH v5 1/9] mmc: dw_mmc: Add external dma interface support
Heiko, On Fri, Aug 14, 2015 at 3:13 PM, Heiko Stübner wrote: > Hi Shawn, > > Am Freitag, 14. August 2015, 16:34:35 schrieb Shawn Lin: >> DesignWare MMC Controller can supports two types of DMA >> mode: external dma and internal dma. We get a RK312x platform >> integrated dw_mmc and ARM pl330 dma controller. This patch add >> edmac ops to support these platforms. I've tested it on RK312x >> platform with edmac mode and RK3288 platform with idmac mode. >> >> Signed-off-by: Shawn Lin > > judging by your "from", I guess you're running this on some older Rockchip soc > without the idma? Because I tried testing this on a Radxa Rock, but only got > failures, from the start (failed to read card status register). In PIO mode > everything works again. > > > I guess I overlooked just some tiny detail, but to me the dma channel ids seem > correct after all. Maybe you have any hints what I'm doing wrong? If I were a guessing man (which I'm not), I'd guess that perhaps you're running into troubles with our friend the PL330. There appear to be strange issues with the PL330 on Rockchip SoCs. I was only peripherally involved with them, but I know at least about some of the patches in our tree, like: https://chromium-review.googlesource.com/237607 FROMLIST: DMA: pl330: support burst mode for dev-to-mem and mem-to-dev transmit https://chromium-review.googlesource.com/237393 CHROMIUM: dmaengine: pl330: support quirks for some broken https://chromium-review.googlesource.com/237396 CHROMIUM: dmaengine: pl330: add quirk for broken no flushp https://chromium-review.googlesource.com/237394 CHROMIUM: ARM: dts: rockchip: Add broken-no-flushp into rk3288.dtsi https://chromium-review.googlesource.com/242063 CHROMIUM: ASoC: rockchip_i2s: modify DMA max burst to 1 -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFC PATCH v5 1/9] mmc: dw_mmc: Add external dma interface support
Hi Shawn, Am Freitag, 14. August 2015, 16:34:35 schrieb Shawn Lin: > DesignWare MMC Controller can supports two types of DMA > mode: external dma and internal dma. We get a RK312x platform > integrated dw_mmc and ARM pl330 dma controller. This patch add > edmac ops to support these platforms. I've tested it on RK312x > platform with edmac mode and RK3288 platform with idmac mode. > > Signed-off-by: Shawn Lin judging by your "from", I guess you're running this on some older Rockchip soc without the idma? Because I tried testing this on a Radxa Rock, but only got failures, from the start (failed to read card status register). In PIO mode everything works again. I guess I overlooked just some tiny detail, but to me the dma channel ids seem correct after all. Maybe you have any hints what I'm doing wrong? diff --git a/arch/arm/boot/dts/rk3xxx.dtsi b/arch/arm/boot/dts/rk3xxx.dtsi index 4497d28..92d7156 100644 --- a/arch/arm/boot/dts/rk3xxx.dtsi +++ b/arch/arm/boot/dts/rk3xxx.dtsi @@ -217,6 +217,8 @@ interrupts = ; clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>; clock-names = "biu", "ciu"; + dmas = <&dmac2 1>; + dma-names = "rx-tx"; fifo-depth = <256>; status = "disabled"; }; @@ -227,6 +229,8 @@ interrupts = ; clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>; clock-names = "biu", "ciu"; + dmas = <&dmac2 3>; + dma-names = "rx-tx"; fifo-depth = <256>; status = "disabled"; }; @@ -237,6 +241,8 @@ interrupts = ; clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>; clock-names = "biu", "ciu"; + dmas = <&dmac2 4>; + dma-names = "rx-tx"; fifo-depth = <256>; status = "disabled"; }; [...] > diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c > index fcbf552..e01ead3 100644 > --- a/drivers/mmc/host/dw_mmc.c > +++ b/drivers/mmc/host/dw_mmc.c > @@ -2517,8 +2642,23 @@ static void dw_mci_cleanup_slot(struct dw_mci_slot > *slot, unsigned int id) static void dw_mci_init_dma(struct dw_mci *host) > { > int addr_config; > + int trans_mode; > + struct device *dev = host->dev; > + struct device_node *np = dev->of_node; > + > + /* Check tansfer mode */ > + trans_mode = SDMMC_GET_TRANS_MODE(mci_readl(host, HCON)); > + if (trans_mode == 0) { > + trans_mode = TRANS_MODE_IDMAC; > + } else if (trans_mode == 1 || trans_mode == 2) { > + trans_mode = TRANS_MODE_EDMAC; > + } else { > + trans_mode = TRANS_MODE_PIO; > + goto no_dma; > + } > + > /* Check ADDR_CONFIG bit in HCON to find IDMAC address bus width */ > - addr_config = (mci_readl(host, HCON) >> 27) & 0x01; > + addr_config = SDMMC_GET_ADDR_CONFIG(mci_readl(host, HCON)); > > if (addr_config == 1) { > /* host supports IDMAC in 64-bit address mode */ I guess the idmac address size checking block /* Check ADDR_CONFIG bit in HCON to find IDMAC address bus width */ addr_config = SDMMC_GET_ADDR_CONFIG(mci_readl(host, HCON)); if (addr_config == 1) { /* host supports IDMAC in 64-bit address mode */ host->dma_64bit_address = 1; dev_info(host->dev, "IDMAC supports 64-bit address mode.\n"); if (!dma_set_mask(host->dev, DMA_BIT_MASK(64))) dma_set_coherent_mask(host->dev, DMA_BIT_MASK(64)); } else { /* host supports IDMAC in 32-bit address mode */ host->dma_64bit_address = 0; dev_info(host->dev, "IDMAC supports 32-bit address mode.\n"); } could either live inside the trans_mode == 0 conditional above or get its own if (trans_mode == 0) conditional. Either way I guess it should not talk about idmac when either pio or extdmac are used. Thanks Heiko -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[RFC PATCH v5 1/9] mmc: dw_mmc: Add external dma interface support
DesignWare MMC Controller can supports two types of DMA mode: external dma and internal dma. We get a RK312x platform integrated dw_mmc and ARM pl330 dma controller. This patch add edmac ops to support these platforms. I've tested it on RK312x platform with edmac mode and RK3288 platform with idmac mode. Signed-off-by: Shawn Lin --- Changes in v5: - add the title of cover letter - fix typo of comment - add macro for reading HCON register - add "Acked-by: Krzysztof Kozlowski " for exynos_defconfig patch - add "Acked-by: Vineet Gupta " for axs10x_defconfig patch - add "Acked-by: Govindraj Raja " and "Acked-by: Ralf Baechle " for pistachio_defconfig patch - add "Acked-by: Joachim Eastwood " for lpc18xx_defconfig patch - add "Acked-by: Wei Xu " for hisi_defconfig patch - rebase on "https://github.com/jh80chung/dw-mmc.git tags/dw-mmc-for-ulf-v4.2" for merging easily Changes in v4: - remove "host->trans_mode" and use "host->use_dma" to indicate transfer mode. - remove all bt-bindings' changes since we don't need new properities. - check transfer mode at runtime by reading HCON reg - spilt defconfig changes for each sub-architecture - fix the title of cover letter - reuse some code for reducing code size Changes in v3: - choose transfer mode at runtime - remove all CONFIG_MMC_DW_IDMAC config option - add supports-idmac property for some platforms Changes in v2: - Fix typo of dev_info msg - remove unused dmach from declaration of dw_mci_dma_slave drivers/mmc/host/Kconfig| 11 +-- drivers/mmc/host/dw_mmc-pltfm.c | 2 + drivers/mmc/host/dw_mmc.c | 209 ++-- drivers/mmc/host/dw_mmc.h | 5 + include/linux/mmc/dw_mmc.h | 27 +- 5 files changed, 210 insertions(+), 44 deletions(-) diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 6a0f9c7..a86c0eb 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -607,15 +607,7 @@ config MMC_DW help This selects support for the Synopsys DesignWare Mobile Storage IP block, this provides host support for SD and MMC interfaces, in both - PIO and external DMA modes. - -config MMC_DW_IDMAC - bool "Internal DMAC interface" - depends on MMC_DW - help - This selects support for the internal DMAC block within the Synopsys - Designware Mobile Storage IP block. This disables the external DMA - interface. + PIO, internal DMA mode and external DMA modes. config MMC_DW_PLTFM tristate "Synopsys Designware MCI Support as platform device" @@ -644,7 +636,6 @@ config MMC_DW_K3 tristate "K3 specific extensions for Synopsys DW Memory Card Interface" depends on MMC_DW select MMC_DW_PLTFM - select MMC_DW_IDMAC help This selects support for Hisilicon K3 SoC specific extensions to the Synopsys DesignWare Memory Card Interface driver. Select this option diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c index ec6dbcd..7e1d13b 100644 --- a/drivers/mmc/host/dw_mmc-pltfm.c +++ b/drivers/mmc/host/dw_mmc-pltfm.c @@ -59,6 +59,8 @@ int dw_mci_pltfm_register(struct platform_device *pdev, host->pdata = pdev->dev.platform_data; regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + /* Get registers' physical base address */ + host->phy_regs = (void *)(regs->start); host->regs = devm_ioremap_resource(&pdev->dev, regs); if (IS_ERR(host->regs)) return PTR_ERR(host->regs); diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index fcbf552..e01ead3 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -56,7 +56,6 @@ #define DW_MCI_FREQ_MAX2 /* unit: HZ */ #define DW_MCI_FREQ_MIN40 /* unit: HZ */ -#ifdef CONFIG_MMC_DW_IDMAC #define IDMAC_INT_CLR (SDMMC_IDMAC_INT_AI | SDMMC_IDMAC_INT_NI | \ SDMMC_IDMAC_INT_CES | SDMMC_IDMAC_INT_DU | \ SDMMC_IDMAC_INT_FBE | SDMMC_IDMAC_INT_RI | \ @@ -102,7 +101,6 @@ struct idmac_desc { /* Each descriptor can transfer up to 4KB of data in chained mode */ #define DW_MCI_DESC_DATA_LENGTH0x1000 -#endif /* CONFIG_MMC_DW_IDMAC */ static bool dw_mci_reset(struct dw_mci *host); static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset); @@ -407,7 +405,6 @@ static int dw_mci_get_dma_dir(struct mmc_data *data) return DMA_FROM_DEVICE; } -#ifdef CONFIG_MMC_DW_IDMAC static void dw_mci_dma_cleanup(struct dw_mci *host) { struct mmc_data *data = host->data; @@ -445,12 +442,21 @@ static void dw_mci_idmac_stop_dma(struct dw_mci *host) mci_writel(host, BMOD, temp); } -static void dw_mci_idmac_complete_dma(struct dw_mci *host) +static void dw_mci_dmac_complete_dma(void *arg) { + struct dw_mci *host = arg; struct mmc_data