[PATCH 00/11] ARM: OMAP: core/hwmod: first set of fixes for 3.5-rc
Hi, Here is an initial set of fixes for power management and OMAP core infrastructure for 3.5-rc. Most of these patches address boot warnings and power management problems on OMAP4, although a few of them address more general issues. Compile-test information is below. The patches been boot-tested on OMAP3530 ES3.0 BeagleBoard and OMAP4430 ES2.0 PandaBoard. Suspend and idle are broken on both of these platforms right now. Unfortunately my board farm is down at the moment, so I'm unable to do further testing on other boards. Boot logs, such as they are, are available from: http://www.pwsan.com/omap/bootlogs/20120606/omap_fixes_a_3.5rc__23a432a1860498d0dfbe36319de3b86d9832c6e7/ These patches are available via git from git://git.pwsan.com/linux-2.6 in the branch 'omap_fixes_a_3.5rc'. Will plan to send a pull request tomorrow unless there are actionable comments. - Paul --- object size (delta in bytes from v3.5-rc1 (f8f5701bdaf9134b1f90e5044a82c66324d2073f)): textdata bss total kernel 0 0 0 0 5912osk_testconfig/vmlinux +352 +88 0+440 n800_multi_omap2xxx/vmlinux +384 +96 0+480 n800_testconfig/vmlinux 0 0 0 0 omap1510_defconfig/vmlinux 0 0 0 0 omap1_defconfig/vmlinux +352+312 0+664 omap2_4_testconfig/vmlinux +384+448 0+832 omap2plus_defconfig/vmlinux +384+384 0+768 omap2plus_no_pm/vmlinux +320+320 0+640 omap3_4_testconfig/vmlinux +320 +88 0+408 omap3_testconfig/vmlinux +320+256 0+576 omap4_testconfig/vmlinux Djamil Elaidi (1): ARM: OMAP4+: hwmod: fix issue causing IPs not going back to Smart-Standby Paul Walmsley (8): ARM: OMAP2+: hwmod: add setup_preprogram hook ARM: OMAP4+: AESS: enable internal auto-gating during initial setup ARM: OMAP4: hwmod data: add SL2IF hardreset line ARM: OMAP2+: hwmod code/data: fix 32K sync timer ARM: OMAP2+: CM: increase the module disable timeout ARM: OMAP4: clock data: add clockdomains for clocks used as main clocks ARM: OMAP2+: hwmod: add flag to prevent hwmod code from touching IP block during init ARM: OMAP4: hwmod data: do not enable or reset the McPDM during kernel init Tero Kristo (1): ARM: OMAP2+: usb_host_fs: add custom reset for usb_host_fs (fsusb) Todd Poynor (1): ARM: OMAP: PM: Lock clocks list while generating summary arch/arm/mach-omap2/Makefile |6 +-- arch/arm/mach-omap2/aess.c | 55 +++ arch/arm/mach-omap2/clock44xx_data.c |5 ++ arch/arm/mach-omap2/cm.h | 19 arch/arm/mach-omap2/cminst44xx.c |4 +- arch/arm/mach-omap2/common.h |2 + arch/arm/mach-omap2/omap_hwmod.c | 58 +--- arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 23 ++ arch/arm/mach-omap2/usb-fs.c | 62 ++ arch/arm/plat-omap/clock.c |2 + arch/arm/plat-omap/include/plat/omap_hwmod.h | 15 ++ arch/arm/plat-omap/include/plat/usb.h|3 + 12 files changed, 238 insertions(+), 16 deletions(-) create mode 100644 arch/arm/mach-omap2/aess.c -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 01/11] ARM: OMAP2+: hwmod: add setup_preprogram hook
After reset, some IP blocks cannot indicate to the PRCM that they are inactive until they are configured. One example on OMAP4 is the AESS IP block. To fix this cleanly, this patch adds another optional function pointer, setup_preprogram, to the IP block's hwmod data. The function that is pointed to is called by the hwmod code immediately after the IP block is reset. Signed-off-by: Paul Walmsley p...@pwsan.com Cc: Benoît Cousson b-cous...@ti.com Cc: Péter Ujfalusi peter.ujfal...@ti.com --- arch/arm/mach-omap2/omap_hwmod.c | 21 - arch/arm/plat-omap/include/plat/omap_hwmod.h |9 + 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index bf86f7e..b0d3064 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -2103,6 +2103,23 @@ static void __init _setup_iclk_autoidle(struct omap_hwmod *oh) } /** + * _setup_preprogram - Pre-program an IP block during the _setup() process + * @oh: struct omap_hwmod * + * + * Some IP blocks (such as AESS) require some additional programming + * after reset before they can enter idle. If a function pointer to + * do so is present in the hwmod data, then call it and pass along the + * return value; otherwise, return 0. + */ +static int __init _setup_preprogram(struct omap_hwmod *oh) +{ + if (!oh-class-setup_preprogram) + return 0; + + return oh-class-setup_preprogram(oh); +} + +/** * _setup_reset - reset an IP block during the setup process * @oh: struct omap_hwmod * * @@ -2224,8 +2241,10 @@ static int __init _setup(struct omap_hwmod *oh, void *data) _setup_iclk_autoidle(oh); - if (!_setup_reset(oh)) + if (!_setup_reset(oh)) { + _setup_preprogram(oh); _setup_postsetup(oh); + } return 0; } diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index c835b71..fdc4b2a 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h @@ -458,6 +458,7 @@ struct omap_hwmod_omap4_prcm { * @rev: revision of the IP class * @pre_shutdown: ptr to fn to be executed immediately prior to device shutdown * @reset: ptr to fn to be executed in place of the standard hwmod reset fn + * @setup_preprogram: ptr to fn to be executed after the reset in _setup() * * Represent the class of a OMAP hardware modules (e.g. timer, * smartreflex, gpio, uart...) @@ -474,6 +475,13 @@ struct omap_hwmod_omap4_prcm { * executed in place of the standard hwmod _reset() code in * mach-omap2/omap_hwmod.c. This is needed for IP blocks which have * unusual reset sequences - usually processor IP blocks like the IVA. + * + * @setup_preprogram is called between the calls to _setup_reset() and + * _setup_postsetup(). It is intended to be used for IP blocks that + * require some initial configuration during their first + * initialization. (For example, the AESS IP block on OMAP4+ cannot + * enter idle until its internal autogating bit is set.) Most IP blocks + * will not need this. */ struct omap_hwmod_class { const char *name; @@ -481,6 +489,7 @@ struct omap_hwmod_class { u32 rev; int (*pre_shutdown)(struct omap_hwmod *oh); int (*reset)(struct omap_hwmod *oh); + int (*setup_preprogram)(struct omap_hwmod *oh); }; /** -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 04/11] ARM: OMAP2+: usb_host_fs: add custom reset for usb_host_fs (fsusb)
From: Tero Kristo t-kri...@ti.com Add a custom reset function for the usb_host_fs/fsusb IP block, and connect it to the OMAP4 FSUSB block. This is the first of two fixes required to get rid of the boot warning: omap_hwmod: usb_host_fs: _wait_target_disable failed and to allow the module to idle. It may be necessary to use this reset method for OMAP2xxx SoCs as well; this is left for a future patch. Signed-off-by: Tero Kristo t-kri...@ti.com [p...@pwsan.com: rewrote the custom reset function, documented it and updated the commit message, and moved the code to mach-omap2/fs-usb.c] Signed-off-by: Paul Walmsley p...@pwsan.com Cc: Benoît Cousson b-cous...@ti.com Cc: Felipe Balbi ba...@ti.com --- arch/arm/mach-omap2/Makefile |4 -- arch/arm/mach-omap2/cm.h |8 +++- arch/arm/mach-omap2/omap_hwmod_44xx_data.c |1 arch/arm/mach-omap2/usb-fs.c | 62 arch/arm/plat-omap/include/plat/usb.h |3 + 5 files changed, 73 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index bc2ac4f..fc2ff91 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -245,9 +245,7 @@ omap-hsmmc-$(CONFIG_MMC_OMAP_HS):= hsmmc.o obj-y += $(omap-hsmmc-m) $(omap-hsmmc-y) -usbfs-$(CONFIG_ARCH_OMAP_OTG) := usb-fs.o -obj-y += $(usbfs-m) $(usbfs-y) -obj-y += usb-musb.o +obj-y += usb-fs.o usb-musb.o obj-y += omap_phy_internal.o obj-$(CONFIG_MACH_OMAP2_TUSB6010) += usb-tusb6010.o diff --git a/arch/arm/mach-omap2/cm.h b/arch/arm/mach-omap2/cm.h index a7bc096..99978c7 100644 --- a/arch/arm/mach-omap2/cm.h +++ b/arch/arm/mach-omap2/cm.h @@ -1,7 +1,7 @@ /* * OMAP2+ Clock Management prototypes * - * Copyright (C) 2007-2009 Texas Instruments, Inc. + * Copyright (C) 2007-2012 Texas Instruments, Inc. * Copyright (C) 2007-2009 Nokia Corporation * * Written by Paul Walmsley @@ -14,6 +14,12 @@ #define __ARCH_ASM_MACH_OMAP2_CM_H /* + * MAX_MODULE_SOFTRESET_TIME: maximum time in microseconds to wait for + * an IP block to finish an OCP SOFTRESET. + */ +#define MAX_MODULE_SOFTRESET_WAIT 1 + +/* * MAX_MODULE_READY_TIME: max duration in microseconds to wait for the * PRCM to request that a module exit the inactive state in the case of * OMAP2 3. diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index a93ce48..02daacc 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -3314,6 +3314,7 @@ static struct omap_hwmod_class_sysconfig omap44xx_usb_host_fs_sysc = { static struct omap_hwmod_class omap44xx_usb_host_fs_hwmod_class = { .name = usb_host_fs, .sysc = omap44xx_usb_host_fs_sysc, + .reset = omap_usb_host_fs_reset, }; /* usb_host_fs */ diff --git a/arch/arm/mach-omap2/usb-fs.c b/arch/arm/mach-omap2/usb-fs.c index 1481078..4faf0f7 100644 --- a/arch/arm/mach-omap2/usb-fs.c +++ b/arch/arm/mach-omap2/usb-fs.c @@ -1,7 +1,7 @@ /* * Platform level USB initialization for FS USB OTG controller on omap1 and 24xx * - * Copyright (C) 2004 Texas Instruments, Inc. + * Copyright (C) 2004, 2012 Texas Instruments, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,6 +32,8 @@ #include plat/usb.h #include plat/board.h +#include cm.h +#include common.h #include control.h #include mux.h @@ -41,6 +43,64 @@ #define INT_USB_IRQ_HGEN INT_24XX_USB_IRQ_HGEN #define INT_USB_IRQ_OTGINT_24XX_USB_IRQ_OTG +/* HCCOMMANDSTATUS: the register offset of the HCCOMMANDSTATUS register */ +#define HCCOMMANDSTATUS0x0008 + +/* HCCOMMANDSTATUS_HCR: the bitmask of the host controller reset flag */ +#define HCCOMMANDSTATUS_HCR_MASK (1 0) + +/** + * omap_usb_host_fs_reset - custom reset function for the FSUSB IP block + * @oh: struct omap_hwmod * of the usb_host_fs IP block + * + * Reset the FSUSB IP block. This IP block requires a custom + * two-stage reset; otherwise the IP block won't idle-ack to the PRCM. + * First the OCP SOFTRESET method must be used. Next, the IP block's + * internal reset bit must be toggled. This will place the OHCI + * controller state into UsbSuspend, which allows the IP block to + * idle-ack to the PRCM. Note that the FSUSB still takes almost 4 + * milliseconds to idle-ack after this function returns. Returns 0 + * upon success, -EINVAL if the IP block softreset data wasn't + * supplied, or -EBUSY if the IP block reset times out. + */ +int omap_usb_host_fs_reset(struct omap_hwmod *oh) +{ + int c; + + if (omap_hwmod_softreset(oh)) + return
[PATCH 05/11] ARM: OMAP2+: hwmod code/data: fix 32K sync timer
Kevin discovered that commit c8d82ff68fb6873691536cf33021977efbf5593c (ARM: OMAP2/3: hwmod data: Add 32k-sync timer data to hwmod database) broke CORE idle on OMAP3. This prevents device low power states. The root cause is that the 32K sync timer IP block does not support smart-idle mode[1], and so the hwmod code keeps the IP block in no-idle mode while it is active. This in turn prevents the WKUP clockdomain from transitioning to idle. There is a hardcoded sleep dependency that prevents the CORE_L3 and CORE_CM clockdomains from transitioning to idle when the WKUP clockdomain is active[2], so the chip cannot enter any device low power states. It turns out that there is no need to take the 32k sync timer out of idle. The IP block itself probably does not have any native idle handling at all, due to its simplicity. Furthermore, the PRCM will never request target idle for this IP block while the kernel is running, due to the sleep dependency that prevents the WKUP clockdomain from idling while the CORE_L3 clockdomain is active. So we can safely leave the 32k sync timer in target-no-idle mode, even while we continue to access it. This workaround is implemented by programming the force-idle mode for any IP block that only supports the force-idle and no-idle modes. If an IP block is ever released that doesn't support smart-idle and requires no-idle mode to be programmed while it's in use, we'll have to change this behavior. Another theoretically clean fix for this problem would be to implement PM runtime-based control for 32k sync timer accesses. These PM runtime calls would need to located in a custom clocksource, since the 32k sync timer is currently used as an MMIO clocksource. But in practice, there would be little benefit to doing so; and there would be some cost, due to the addition of unnecessary lines of code and the additional CPU overhead of the PM runtime and hwmod code - unnecessary in this case. Another possible fix would have been to modify the pm34xx.c code to force the IP block idle before entering WFI. But this would not have been an acceptable approach: we are trying to remove this type of centralized IP block idle control from the PM code. This patch is effectively a workaround for a hardware problem. A better hardware approach would have been to implement a smart-idle target idle mode for this IP block. The smart-idle mode in this case would behave identically to the force-idle mode. We consider the force-idle and no-idle target idle mode settings to be intended for debugging and automatic idle management bug workarounds only[4]. This patch is a collaboration between Kevin Hilman khil...@ti.com and Paul Walmsley p...@pwsan.com. References: 1. Table 16-96 REG_32KSYNCNT_SYSCONFIG of the OMAP34xx TRM Rev. ZU (SWPU223U), available from: http://www.ti.com/pdfs/wtbu/OMAP34x_ES3.1.x_PUBLIC_TRM_vzU.zip 2. Table 4-72 Sleep Dependencies of the OMAP34xx TRM Rev. ZU (SWPU223U) 3. ibid. 4. Section 3.1.1.1.2 Module-Level Clock Management of The OMAP4430 TRM Rev. vAA (SWPU231AA). Cc: Tony Lindgren t...@atomide.com Cc: Vaibhav Hiremath hvaib...@ti.com Cc: Benoît Cousson b-cous...@ti.com Tested-by: Kevin Hilman khil...@ti.com Signed-off-by: Kevin Hilman khil...@ti.com Signed-off-by: Paul Walmsley p...@pwsan.com --- arch/arm/mach-omap2/omap_hwmod.c | 32 ++-- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index b0d3064..6b4ae31 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -1124,10 +1124,12 @@ static struct omap_hwmod_addr_space * __init _find_mpu_rt_addr_space(struct omap * _enable_sysc - try to bring a module out of idle via OCP_SYSCONFIG * @oh: struct omap_hwmod * * - * If module is marked as SWSUP_SIDLE, force the module out of slave - * idle; otherwise, configure it for smart-idle. If module is marked - * as SWSUP_MSUSPEND, force the module out of master standby; - * otherwise, configure it for smart-standby. No return value. + * Ensure that the OCP_SYSCONFIG register for the IP block represented + * by @oh is set to indicate to the PRCM that the IP block is active. + * Usually this means placing the module into smart-idle mode and + * smart-standby, but if there is a bug in the automatic idle handling + * for the IP block, it may need to be placed into the force-idle or + * no-idle variants of these modes. No return value. */ static void _enable_sysc(struct omap_hwmod *oh) { @@ -1141,8 +1143,26 @@ static void _enable_sysc(struct omap_hwmod *oh) sf = oh-class-sysc-sysc_flags; if (sf SYSC_HAS_SIDLEMODE) { - idlemode = (oh-flags HWMOD_SWSUP_SIDLE) ? - HWMOD_IDLEMODE_NO : HWMOD_IDLEMODE_SMART; + if (oh-flags HWMOD_SWSUP_SIDLE) { + /* +* IP blocks without smart idle should be left +
[PATCH 03/11] ARM: OMAP4: hwmod data: add SL2IF hardreset line
On boot, the sl2if module can't be enabled. The following message is logged: omap_hwmod: sl2if: cannot be enabled for reset (3) This is probably because the SL2IF is still being held in hardreset. The SL2IF's hardreset line is shared with one of the IVAHD's hardreset lines; see for example Table 3-536 RM_IVAHD_RSTCTRL in the OMAP4430 TRM Rev. AA (SWPU231AA). To work around this, add the SL2IF's hardreset line to the hwmod data. This is correct from a hardware perspective and also will prevent the hwmod from attempting to enable the SL2IF during reset. The driver for this IP block will need to handle its integration until the appropriate way to handle the IVAHD integration can be elucidated. Signed-off-by: Paul Walmsley p...@pwsan.com Cc: Tero Kristo t-kri...@ti.com --- arch/arm/mach-omap2/omap_hwmod_44xx_data.c |7 +++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index 4a2f2cc..a93ce48 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -2597,15 +2597,22 @@ static struct omap_hwmod_class omap44xx_sl2if_hwmod_class = { .name = sl2if, }; +static struct omap_hwmod_rst_info omap44xx_sl2if_resets[] = { + { .name = logic, .rst_shift = 2 }, +}; + /* sl2if */ static struct omap_hwmod omap44xx_sl2if_hwmod = { .name = sl2if, .class = omap44xx_sl2if_hwmod_class, .clkdm_name = ivahd_clkdm, + .rst_lines = omap44xx_sl2if_resets, + .rst_lines_cnt = ARRAY_SIZE(omap44xx_sl2if_resets), .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_IVAHD_SL2_CLKCTRL_OFFSET, .context_offs = OMAP4_RM_IVAHD_SL2_CONTEXT_OFFSET, + .rstctrl_offs = OMAP4_RM_IVAHD_RSTCTRL_OFFSET, .modulemode = MODULEMODE_HWCTRL, }, }, -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 06/11] ARM: OMAP4+: hwmod: fix issue causing IPs not going back to Smart-Standby
From: Djamil Elaidi d-ela...@ti.com If an IP is configured in Smart-Standby-Wakeup, when disabling wakeup feature the IP will not go back to Smart-Standby, but will remain in Smart-Standby-Wakeup. Signed-off-by: Djamil Elaidi d-ela...@ti.com Signed-off-by: Paul Walmsley p...@pwsan.com --- arch/arm/mach-omap2/omap_hwmod.c |2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 6b4ae31..d3afac5 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -530,7 +530,7 @@ static int _disable_wakeup(struct omap_hwmod *oh, u32 *v) if (oh-class-sysc-idlemodes SIDLE_SMART_WKUP) _set_slave_idlemode(oh, HWMOD_IDLEMODE_SMART, v); if (oh-class-sysc-idlemodes MSTANDBY_SMART_WKUP) - _set_master_standbymode(oh, HWMOD_IDLEMODE_SMART_WKUP, v); + _set_master_standbymode(oh, HWMOD_IDLEMODE_SMART, v); /* XXX test pwrdm_get_wken for this hwmod's subsystem */ -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 11/11] ARM: OMAP4: hwmod data: do not enable or reset the McPDM during kernel init
Resolve this kernel boot message: omap_hwmod: mcpdm: cannot be enabled for reset (3) It appears that the McPDM on OMAP4 can only receive its functional clock from an off-chip source. This source is not guaranteed to be present on the board, and when present, it is controlled by I2C. This would introduce a board dependency to the early hwmod code which it was not designed to handle. Also, neither the driver for this off-chip clock provider nor the I2C code is available early in boot when the hwmod code is attempting to enable and reset IP blocks. This effectively makes it impossible to enable and reset this device during hwmod init. At its core, this patch is a workaround for an OMAP hardware problem. It should be possible to configure the OMAP to provide any IP block's functional clock from an on-chip source. (This is true for almost every IP block on the chip. As far as I know, McPDM is the only exception.) If the kernel cannot reset and configure IP blocks, it cannot guarantee a sane SoC state. Relying on an optional off-chip clock also creates a board dependency which is beyond the scope of the early hwmod code. This patch works around the issue by marking the McPDM hwmod record with the HWMOD_UNKNOWN_MAIN_FCLK_STATE flag. This prevents the hwmod code from touching the device early during boot. Signed-off-by: Paul Walmsley p...@pwsan.com Cc: Péter Ujfalusi peter.ujfal...@ti.com Cc: Benoît Cousson b-cous...@ti.com --- arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 12 1 file changed, 12 insertions(+) diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index 20e45a6..cc1310a 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -2090,6 +2090,18 @@ static struct omap_hwmod omap44xx_mcpdm_hwmod = { .name = mcpdm, .class = omap44xx_mcpdm_hwmod_class, .clkdm_name = abe_clkdm, + /* +* It's suspected that the McPDM requires an off-chip main +* functional clock, controlled via I2C. This IP block is +* currently reset very early during boot, before I2C is +* available, so it doesn't seem that we have any choice in +* the kernel other than to avoid resetting it. XXX This is +* really a hardware issue workaround: every IP block should +* be able to source its main functional clock from either +* on-chip or off-chip sources. McPDM seems to be the only +* current exception. +*/ + .flags = HWMOD_EXT_OPT_MAIN_CLK, .mpu_irqs = omap44xx_mcpdm_irqs, .sdma_reqs = omap44xx_mcpdm_sdma_reqs, .main_clk = mcpdm_fck, -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 10/11] ARM: OMAP2+: hwmod: add flag to prevent hwmod code from touching IP block during init
Add HWMOD_EXT_OPT_MAIN_CLK flag to indicate that this IP block is dependent on an off-chip functional clock that is not guaranteed to be present during initialization. IP blocks marked with this flag are left in the INITIALIZED state during kernel init. This is a workaround for a hardware problem. It should be possible to guarantee that at least one clock source will be present and active for any IP block's main functional clock. This ensures that the hwmod code can enable and reset the IP block. Resetting the IP block during kernel init prevents any bogus bootloader, ROM code, or previous OS configuration from affecting the kernel. Hopefully a clock multiplexer can be added on future SoCs. N.B., at some point in the future, it should be possible to query the clock framework for this type of information. Then this flag should no longer be needed. Signed-off-by: Paul Walmsley p...@pwsan.com Cc: Benoît Cousson b-cous...@ti.com --- arch/arm/mach-omap2/omap_hwmod.c |3 +++ arch/arm/plat-omap/include/plat/omap_hwmod.h |6 ++ 2 files changed, 9 insertions(+) diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index d3afac5..c8655c0 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -2155,6 +2155,9 @@ static int __init _setup_reset(struct omap_hwmod *oh) if (oh-_state != _HWMOD_STATE_INITIALIZED) return -EINVAL; + if (oh-flags HWMOD_EXT_OPT_MAIN_CLK) + return -EPERM; + if (oh-rst_lines_cnt == 0) { r = _enable(oh); if (r) { diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index fdc4b2a..d117931 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h @@ -409,6 +409,11 @@ struct omap_hwmod_omap4_prcm { * in order to complete the reset. Optional clocks will be disabled * again after the reset. * HWMOD_16BIT_REG: Module has 16bit registers + * HWMOD_EXT_OPT_MAIN_CLK: The only main functional clock source for + * this IP block comes from an off-chip source and is not always + * enabled. This prevents the hwmod code from being able to + * enable and reset the IP block early. XXX Eventually it should + * be possible to query the clock framework for this information. */ #define HWMOD_SWSUP_SIDLE (1 0) #define HWMOD_SWSUP_MSTANDBY (1 1) @@ -419,6 +424,7 @@ struct omap_hwmod_omap4_prcm { #define HWMOD_NO_IDLEST(1 6) #define HWMOD_CONTROL_OPT_CLKS_IN_RESET(1 7) #define HWMOD_16BIT_REG(1 8) +#define HWMOD_EXT_OPT_MAIN_CLK (1 9) /* * omap_hwmod._int_flags definitions -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 08/11] ARM: OMAP2+: CM: increase the module disable timeout
Increase the timeout for disabling an IP block to five milliseconds. This is to handle the usb_host_fs idle latency, which takes almost four milliseconds after a host controller reset. This is the second of two patches needed to resolve the following boot warning: omap_hwmod: usb_host_fs: _wait_target_disable failed Signed-off-by: Paul Walmsley p...@pwsan.com Cc: Tero Kristo t-kri...@ti.com --- arch/arm/mach-omap2/cm.h | 11 +++ arch/arm/mach-omap2/cminst44xx.c |4 ++-- arch/arm/mach-omap2/omap_hwmod_44xx_data.c |1 + 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-omap2/cm.h b/arch/arm/mach-omap2/cm.h index 99978c7..cf67617 100644 --- a/arch/arm/mach-omap2/cm.h +++ b/arch/arm/mach-omap2/cm.h @@ -28,4 +28,15 @@ */ #define MAX_MODULE_READY_TIME 2000 +/* + * MAX_MODULE_DISABLE_TIME: max duration in microseconds to wait for + * the PRCM to request that a module enter the inactive state in the + * case of OMAP2 3. In the case of OMAP4 this is the max duration + * in microseconds for the module to reach the inactive state from + * a functional state. + * XXX FSUSB on OMAP4430 takes ~4ms to idle after reset during + * kernel init. + */ +#define MAX_MODULE_DISABLE_TIME5000 + #endif diff --git a/arch/arm/mach-omap2/cminst44xx.c b/arch/arm/mach-omap2/cminst44xx.c index 8c86d29..1a39945 100644 --- a/arch/arm/mach-omap2/cminst44xx.c +++ b/arch/arm/mach-omap2/cminst44xx.c @@ -313,9 +313,9 @@ int omap4_cminst_wait_module_idle(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_off omap_test_timeout((_clkctrl_idlest(part, inst, cdoffs, clkctrl_offs) == CLKCTRL_IDLEST_DISABLED), - MAX_MODULE_READY_TIME, i); + MAX_MODULE_DISABLE_TIME, i); - return (i MAX_MODULE_READY_TIME) ? 0 : -EBUSY; + return (i MAX_MODULE_DISABLE_TIME) ? 0 : -EBUSY; } /** diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index 02daacc..20e45a6 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -30,6 +30,7 @@ #include plat/mmc.h #include plat/dmtimer.h #include plat/common.h +#include plat/usb.h #include omap_hwmod_common_data.h -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 09/11] ARM: OMAP4: clock data: add clockdomains for clocks used as main clocks
Until the OMAP4 code is converted to disable the use of the clock framework-based clockdomain enable/disable sequence, any clock used as a hwmod main_clk must have a clockdomain associated with it. This patch populates some clock structure clockdomain names to resolve the following warnings during kernel init: omap_hwmod: dpll_mpu_m2_ck: missing clockdomain for dpll_mpu_m2_ck. omap_hwmod: trace_clk_div_ck: missing clockdomain for trace_clk_div_ck. omap_hwmod: l3_div_ck: missing clockdomain for l3_div_ck. omap_hwmod: ddrphy_ck: missing clockdomain for ddrphy_ck. Signed-off-by: Paul Walmsley p...@pwsan.com Cc: Rajendra Nayak rna...@ti.com Cc: Benoît Cousson b-cous...@ti.com --- arch/arm/mach-omap2/clock44xx_data.c |5 + 1 file changed, 5 insertions(+) diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c index 2172f66..e2b701e 100644 --- a/arch/arm/mach-omap2/clock44xx_data.c +++ b/arch/arm/mach-omap2/clock44xx_data.c @@ -84,6 +84,7 @@ static struct clk slimbus_clk = { static struct clk sys_32k_ck = { .name = sys_32k_ck, + .clkdm_name = prm_clkdm, .rate = 32768, .ops= clkops_null, }; @@ -512,6 +513,7 @@ static struct clk ddrphy_ck = { .name = ddrphy_ck, .parent = dpll_core_m2_ck, .ops= clkops_null, + .clkdm_name = l3_emif_clkdm, .fixed_div = 2, .recalc = omap_fixed_divisor_recalc, }; @@ -769,6 +771,7 @@ static const struct clksel dpll_mpu_m2_div[] = { static struct clk dpll_mpu_m2_ck = { .name = dpll_mpu_m2_ck, .parent = dpll_mpu_ck, + .clkdm_name = cm_clkdm, .clksel = dpll_mpu_m2_div, .clksel_reg = OMAP4430_CM_DIV_M2_DPLL_MPU, .clksel_mask= OMAP4430_DPLL_CLKOUT_DIV_MASK, @@ -1149,6 +1152,7 @@ static const struct clksel l3_div_div[] = { static struct clk l3_div_ck = { .name = l3_div_ck, .parent = div_core_ck, + .clkdm_name = cm_clkdm, .clksel = l3_div_div, .clksel_reg = OMAP4430_CM_CLKSEL_CORE, .clksel_mask= OMAP4430_CLKSEL_L3_MASK, @@ -2824,6 +2828,7 @@ static const struct clksel trace_clk_div_div[] = { static struct clk trace_clk_div_ck = { .name = trace_clk_div_ck, .parent = pmd_trace_clk_mux_ck, + .clkdm_name = emu_sys_clkdm, .clksel = trace_clk_div_div, .clksel_reg = OMAP4430_CM_EMU_DEBUGSS_CLKCTRL, .clksel_mask= OMAP4430_CLKSEL_PMD_TRACE_CLK_MASK, -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 07/11] ARM: OMAP: PM: Lock clocks list while generating summary
From: Todd Poynor toddpoy...@google.com Commit a53025724052b2b1edbc982a4a248784638f563d (OMAP: Add debugfs node to show the summary of all clocks) introduced clock summary, however, we are interested in seeing snapshot of the clock state, not in dynamically changing clock configurations as the data provided by clock summary will then be useless for debugging configuration issues. So, hold the common lock when dumping the clock summary. Cc: Paul Walmsley p...@pwsan.com Cc: Tony Lindgren t...@atomide.com Signed-off-by: Todd Poynor toddpoy...@google.com [n...@ti.com: added commit message] Signed-off-by: Nishanth Menon n...@ti.com [p...@pwsan.com: minor edits to commit message] Signed-off-by: Paul Walmsley p...@pwsan.com --- arch/arm/plat-omap/clock.c |2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c index 62ec5c4..706b7e2 100644 --- a/arch/arm/plat-omap/clock.c +++ b/arch/arm/plat-omap/clock.c @@ -461,6 +461,7 @@ static int clk_dbg_show_summary(struct seq_file *s, void *unused) struct clk *c; struct clk *pa; + mutex_lock(clocks_mutex); seq_printf(s, %-30s %-30s %-10s %s\n, clock-name, parent-name, rate, use-count); @@ -469,6 +470,7 @@ static int clk_dbg_show_summary(struct seq_file *s, void *unused) seq_printf(s, %-30s %-30s %-10lu %d\n, c-name, pa ? pa-name : none, c-rate, c-usecount); } + mutex_unlock(clocks_mutex); return 0; } -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 02/11] ARM: OMAP4+: AESS: enable internal auto-gating during initial setup
Enable the AESS auto-gating control bit during AESS hwmod setup. This fixes the following boot warning on OMAP4: omap_hwmod: aess: _wait_target_disable failed Without this patch, the AESS IP block does not indicate to the PRCM that it is idle after it is reset. This prevents some types of SoC power management until something sets the auto-gating control bit. Signed-off-by: Paul Walmsley p...@pwsan.com Cc: Benoît Cousson b-cous...@ti.com Cc: Péter Ujfalusi peter.ujfal...@ti.com --- arch/arm/mach-omap2/Makefile |2 + arch/arm/mach-omap2/aess.c | 55 arch/arm/mach-omap2/common.h |2 + arch/arm/mach-omap2/omap_hwmod_44xx_data.c |2 + 4 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-omap2/aess.c diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index fa742f3..bc2ac4f 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -4,7 +4,7 @@ # Common support obj-y := id.o io.o control.o mux.o devices.o serial.o gpmc.o timer.o pm.o \ -common.o gpio.o dma.o wd_timer.o display.o i2c.o hdq1w.o +common.o gpio.o dma.o wd_timer.o display.o i2c.o hdq1w.o aess.o omap-2-3-common= irq.o sdrc.o hwmod-common = omap_hwmod.o \ diff --git a/arch/arm/mach-omap2/aess.c b/arch/arm/mach-omap2/aess.c new file mode 100644 index 000..d5ca3d2 --- /dev/null +++ b/arch/arm/mach-omap2/aess.c @@ -0,0 +1,55 @@ +/* + * AESS IP block integration + * + * Copyright (C) 2012 Texas Instruments, Inc. + * Paul Walmsley + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include linux/kernel.h + +#include plat/omap_hwmod.h + +#include common.h + +/* + * AESS_AUTO_GATING_ENABLE_OFFSET: offset in bytes of the AESS IP + * block's AESS_AUTO_GATING_ENABLE__1 register from the IP block's + * base address + */ +#define AESS_AUTO_GATING_ENABLE_OFFSET 0x07c + +/* Register bitfields in the AESS_AUTO_GATING_ENABLE__1 register */ +#define AESS_AUTO_GATING_ENABLE_SHIFT 0 + +/** + * omap_aess_preprogram - enable AESS internal autogating + * @oh: struct omap_hwmod * + * + * Since the AESS will not IdleAck to the PRCM until its internal + * autogating is enabled, we must enable autogating during the initial + * AESS hwmod setup. Returns 0. + */ +int omap_aess_preprogram(struct omap_hwmod *oh) +{ + u32 v; + + /* Set AESS_AUTO_GATING_ENABLE__1.ENABLE to allow idle entry */ + v = 1 AESS_AUTO_GATING_ENABLE_SHIFT; + omap_hwmod_write(v, oh, AESS_AUTO_GATING_ENABLE_OFFSET); + + return 0; +} diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h index be9dfd1..d9b8b06 100644 --- a/arch/arm/mach-omap2/common.h +++ b/arch/arm/mach-omap2/common.h @@ -304,5 +304,7 @@ extern void omap_sdrc_init(struct omap_sdrc_params *sdrc_cs0, struct omap2_hsmmc_info; extern int omap4_twl6030_hsmmc_init(struct omap2_hsmmc_info *controllers); +extern int omap_aess_preprogram(struct omap_hwmod *oh); + #endif /* __ASSEMBLER__ */ #endif /* __ARCH_ARM_MACH_OMAP2PLUS_COMMON_H */ diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index 950454a..4a2f2cc 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -39,6 +39,7 @@ #include prm44xx.h #include prm-regbits-44xx.h #include wd_timer.h +#include common.h /* Base offset for all OMAP4 interrupts external to MPUSS */ #define OMAP44XX_IRQ_GIC_START 32 @@ -313,6 +314,7 @@ static struct omap_hwmod_class_sysconfig omap44xx_aess_sysc = { static struct omap_hwmod_class omap44xx_aess_hwmod_class = { .name = aess, .sysc = omap44xx_aess_sysc, + .setup_preprogram = omap_aess_preprogram, }; /* aess */ -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] ARM: omap: clock: Get rid of unwanted clkdm assocations within clks
Hi Paul, On Thursday 17 May 2012 03:54 PM, Rajendra Nayak wrote: clkdm assocations with clocks in the clock framework are useful only for 'gate' clocks which have enable/disable ops populated. Get rid of the clkdm_names populated in any other type of clocks. Any comments on this one? regards, Rajendra Signed-off-by: Rajendra Nayakrna...@ti.com --- arch/arm/mach-omap2/clock2420_data.c | 16 arch/arm/mach-omap2/clock2430_data.c | 15 --- arch/arm/mach-omap2/clock3xxx_data.c | 44 -- 3 files changed, 0 insertions(+), 75 deletions(-) diff --git a/arch/arm/mach-omap2/clock2420_data.c b/arch/arm/mach-omap2/clock2420_data.c index bace930..914d12a 100644 --- a/arch/arm/mach-omap2/clock2420_data.c +++ b/arch/arm/mach-omap2/clock2420_data.c @@ -56,14 +56,12 @@ static struct clk func_32k_ck = { .name = func_32k_ck, .ops=clkops_null, .rate = 32768, - .clkdm_name = wkup_clkdm, }; static struct clk secure_32k_ck = { .name = secure_32k_ck, .ops=clkops_null, .rate = 32768, - .clkdm_name = wkup_clkdm, }; /* Typical 12/13MHz in standalone mode, will be 26Mhz in chassis mode */ @@ -79,7 +77,6 @@ static struct clk sys_ck = { /* (*12, *13, 19.2, 26, 38.4)MHz */ .name = sys_ck, /* ~ ref_clk also */ .ops=clkops_null, .parent =osc_ck, - .clkdm_name = wkup_clkdm, .recalc =omap2xxx_sys_clk_recalc, }; @@ -87,7 +84,6 @@ static struct clk alt_ck = { /* Typical 54M or 48M, may not exist */ .name = alt_ck, .ops=clkops_null, .rate = 5400, - .clkdm_name = wkup_clkdm, }; /* Optional external clock input for McBSP CLKS */ @@ -180,7 +176,6 @@ static struct clk func_54m_ck = { .name = func_54m_ck, .ops=clkops_null, .parent =apll54_ck,/* can also be alt_clk */ - .clkdm_name = wkup_clkdm, .init =omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1), .clksel_mask= OMAP24XX_54M_SOURCE_MASK, @@ -192,7 +187,6 @@ static struct clk core_ck = { .name = core_ck, .ops=clkops_null, .parent =dpll_ck, /* can also be 32k */ - .clkdm_name = wkup_clkdm, .recalc =followparent_recalc, }; @@ -200,7 +194,6 @@ static struct clk func_96m_ck = { .name = func_96m_ck, .ops=clkops_null, .parent =apll96_ck, - .clkdm_name = wkup_clkdm, .recalc =followparent_recalc, }; @@ -226,7 +219,6 @@ static struct clk func_48m_ck = { .name = func_48m_ck, .ops=clkops_null, .parent =apll96_ck, /* 96M or Alt */ - .clkdm_name = wkup_clkdm, .init =omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1), .clksel_mask= OMAP24XX_48M_SOURCE_MASK, @@ -241,7 +233,6 @@ static struct clk func_12m_ck = { .ops=clkops_null, .parent =func_48m_ck, .fixed_div = 4, - .clkdm_name = wkup_clkdm, .recalc =omap_fixed_divisor_recalc, }; @@ -323,7 +314,6 @@ static struct clk sys_clkout = { .name = sys_clkout, .ops=clkops_null, .parent =sys_clkout_src, - .clkdm_name = wkup_clkdm, .clksel_reg = OMAP2420_PRCM_CLKOUT_CTRL, .clksel_mask= OMAP24XX_CLKOUT_DIV_MASK, .clksel = sys_clkout_clksel, @@ -359,7 +349,6 @@ static struct clk sys_clkout2 = { .name = sys_clkout2, .ops=clkops_null, .parent =sys_clkout2_src, - .clkdm_name = wkup_clkdm, .clksel_reg = OMAP2420_PRCM_CLKOUT_CTRL, .clksel_mask= OMAP2420_CLKOUT2_DIV_MASK, .clksel = sys_clkout2_clksel, @@ -407,7 +396,6 @@ static struct clk mpu_ck = {/* Control cpu */ .name = mpu_ck, .ops=clkops_null, .parent =core_ck, - .clkdm_name = mpu_clkdm, .init =omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(MPU_MOD, CM_CLKSEL), .clksel_mask= OMAP24XX_CLKSEL_MPU_MASK, @@ -541,7 +529,6 @@ static struct clk core_l3_ck = {/* Used for ick and fck, interconnect */ .name = core_l3_ck, .ops=clkops_null, .parent =core_ck, - .clkdm_name = core_l3_clkdm, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1), .clksel_mask= OMAP24XX_CLKSEL_L3_MASK, .clksel
Re: [PATCH 09/11] ARM: OMAP4: clock data: add clockdomains for clocks used as main clocks
On Thursday 07 June 2012 11:43 AM, Paul Walmsley wrote: Until the OMAP4 code is converted to disable the use of the clock framework-based clockdomain enable/disable sequence, any clock used as a hwmod main_clk must have a clockdomain associated with it. This patch populates some clock structure clockdomain names to resolve the following warnings during kernel init: But these associations are useless if the clock is not a 'gate' clock, except for getting rid of these warnings. Maybe we should make hwmod understand that not all clocks need to have a clockdomain associated with it and stop complaining. omap_hwmod: dpll_mpu_m2_ck: missing clockdomain for dpll_mpu_m2_ck. omap_hwmod: trace_clk_div_ck: missing clockdomain for trace_clk_div_ck. omap_hwmod: l3_div_ck: missing clockdomain for l3_div_ck. omap_hwmod: ddrphy_ck: missing clockdomain for ddrphy_ck. Signed-off-by: Paul Walmsleyp...@pwsan.com Cc: Rajendra Nayakrna...@ti.com Cc: Benoît Coussonb-cous...@ti.com --- arch/arm/mach-omap2/clock44xx_data.c |5 + 1 file changed, 5 insertions(+) diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c index 2172f66..e2b701e 100644 --- a/arch/arm/mach-omap2/clock44xx_data.c +++ b/arch/arm/mach-omap2/clock44xx_data.c @@ -84,6 +84,7 @@ static struct clk slimbus_clk = { static struct clk sys_32k_ck = { .name = sys_32k_ck, + .clkdm_name = prm_clkdm, .rate = 32768, .ops=clkops_null, }; @@ -512,6 +513,7 @@ static struct clk ddrphy_ck = { .name = ddrphy_ck, .parent =dpll_core_m2_ck, .ops=clkops_null, + .clkdm_name = l3_emif_clkdm, .fixed_div = 2, .recalc =omap_fixed_divisor_recalc, }; @@ -769,6 +771,7 @@ static const struct clksel dpll_mpu_m2_div[] = { static struct clk dpll_mpu_m2_ck = { .name = dpll_mpu_m2_ck, .parent =dpll_mpu_ck, + .clkdm_name = cm_clkdm, .clksel = dpll_mpu_m2_div, .clksel_reg = OMAP4430_CM_DIV_M2_DPLL_MPU, .clksel_mask= OMAP4430_DPLL_CLKOUT_DIV_MASK, @@ -1149,6 +1152,7 @@ static const struct clksel l3_div_div[] = { static struct clk l3_div_ck = { .name = l3_div_ck, .parent =div_core_ck, + .clkdm_name = cm_clkdm, .clksel = l3_div_div, .clksel_reg = OMAP4430_CM_CLKSEL_CORE, .clksel_mask= OMAP4430_CLKSEL_L3_MASK, @@ -2824,6 +2828,7 @@ static const struct clksel trace_clk_div_div[] = { static struct clk trace_clk_div_ck = { .name = trace_clk_div_ck, .parent =pmd_trace_clk_mux_ck, + .clkdm_name = emu_sys_clkdm, .clksel = trace_clk_div_div, .clksel_reg = OMAP4430_CM_EMU_DEBUGSS_CLKCTRL, .clksel_mask= OMAP4430_CLKSEL_PMD_TRACE_CLK_MASK, -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
RE: [PATCH 05/11] ARM: OMAP2+: hwmod code/data: fix 32K sync timer
On Thu, Jun 07, 2012 at 11:43:10, Paul Walmsley wrote: Kevin discovered that commit c8d82ff68fb6873691536cf33021977efbf5593c (ARM: OMAP2/3: hwmod data: Add 32k-sync timer data to hwmod database) broke CORE idle on OMAP3. This prevents device low power states. The root cause is that the 32K sync timer IP block does not support smart-idle mode[1], and so the hwmod code keeps the IP block in no-idle mode while it is active. This in turn prevents the WKUP clockdomain from transitioning to idle. There is a hardcoded sleep dependency that prevents the CORE_L3 and CORE_CM clockdomains from transitioning to idle when the WKUP clockdomain is active[2], so the chip cannot enter any device low power states. It turns out that there is no need to take the 32k sync timer out of idle. The IP block itself probably does not have any native idle handling at all, due to its simplicity. Furthermore, the PRCM will never request target idle for this IP block while the kernel is running, due to the sleep dependency that prevents the WKUP clockdomain from idling while the CORE_L3 clockdomain is active. So we can safely leave the 32k sync timer in target-no-idle mode, even while we continue to access it. This workaround is implemented by programming the force-idle mode for any IP block that only supports the force-idle and no-idle modes. If an IP block is ever released that doesn't support smart-idle and requires no-idle mode to be programmed while it's in use, we'll have to change this behavior. Isn't this impact AM33xx devices, where we do not support smart idle mode??? Anyway, I will also test it on both OMAP3EVM and AM33xx platform now... Thanks, Vaibhav -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] ARM: omap: clock: Get rid of unwanted clkdm assocations within clks
Hi On Thu, 7 Jun 2012, Rajendra Nayak wrote: On Thursday 17 May 2012 03:54 PM, Rajendra Nayak wrote: clkdm assocations with clocks in the clock framework are useful only for 'gate' clocks which have enable/disable ops populated. Get rid of the clkdm_names populated in any other type of clocks. I don't really see the point in changing this before the common clock conversion. The design of most of the current low-level OMAP PM layers was predicated on each clock belonging to a clockdomain. The testing overhead of changing this before the common clock conversion is something that I don't have time for, and almost no one else seems interested in doing. Your common clock conversion moots this patch anyway, right? - Paul -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
RE: [PATCH 05/11] ARM: OMAP2+: hwmod code/data: fix 32K sync timer
Hi On Thu, 7 Jun 2012, Hiremath, Vaibhav wrote: Isn't this impact AM33xx devices, where we do not support smart idle mode??? Anyway, I will also test it on both OMAP3EVM and AM33xx platform now... Thanks, please let me know how your tests go. If it doesn't work, we'll go back to the flag-based approach in the patch I posted already. - Paul -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 02/11] ARM: OMAP4+: AESS: enable internal auto-gating during initial setup
* Paul Walmsley p...@pwsan.com [120606 23:26]: Enable the AESS auto-gating control bit during AESS hwmod setup. This fixes the following boot warning on OMAP4: omap_hwmod: aess: _wait_target_disable failed Without this patch, the AESS IP block does not indicate to the PRCM that it is idle after it is reset. This prevents some types of SoC power management until something sets the auto-gating control bit. I don't like the idea of having custom platform init code for every driver to reset it, let's see if there's some better way to deal with stuff like this. It seems that most/many IP blocks need their custom reset hacks, and it's not limited to just few instances? Maybe we can distribute custom hacks like this to the drivers? If there is no generic way to reset some IP block, then the driver should pass it's whatever workaround bits/methdod/ to the bus level (hwmod) code during the init rather than piling up all the possible hacks to the bus level code. This way the driver init can still do the bus level reset during it's init, and bail out after that if the module is not in use for the board in question. That is already being flagged in device tree with status = disable flag, and can also passed in platform data if necessary. AFAIK there's no need to reset the IP blocks before the driver init, it's really needed for PM. So it's not needed early on, and it's OK to require running the driver init for driver modules that are not in use to reset them properly. After all, the hardware is on the device, even if it's not being used. Regards, Tony -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 04/11] ARM: OMAP2+: usb_host_fs: add custom reset for usb_host_fs (fsusb)
* Paul Walmsley p...@pwsan.com [120606 23:26]: From: Tero Kristo t-kri...@ti.com Add a custom reset function for the usb_host_fs/fsusb IP block, and connect it to the OMAP4 FSUSB block. This is the first of two fixes required to get rid of the boot warning: omap_hwmod: usb_host_fs: _wait_target_disable failed and to allow the module to idle. It may be necessary to use this reset method for OMAP2xxx SoCs as well; this is left for a future patch. Here too I think driver like features like this should live in the driver init for omap OHCI driver. In the likely case that FS OHCI is not in use on the board, the OHCI glue can just reset it. +/* HCCOMMANDSTATUS: the register offset of the HCCOMMANDSTATUS register */ +#define HCCOMMANDSTATUS 0x0008 + +/* HCCOMMANDSTATUS_HCR: the bitmask of the host controller reset flag */ +#define HCCOMMANDSTATUS_HCR_MASK (1 0) I don't think the bus layer code should need to know anything about driver specific registers. + omap_hwmod_write(HCCOMMANDSTATUS_HCR_MASK, oh, HCCOMMANDSTATUS); + + omap_test_timeout(!(omap_hwmod_read(oh, HCCOMMANDSTATUS) + HCCOMMANDSTATUS_HCR_MASK), + MAX_MODULE_SOFTRESET_WAIT, c); + These should be accessed by the driver in a standard way after ioremapping the device. Tony -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 02/11] ARM: OMAP4+: AESS: enable internal auto-gating during initial setup
On Thu, 7 Jun 2012, Tony Lindgren wrote: It seems that most/many IP blocks need their custom reset hacks, and it's not limited to just few instances? Only four out of the fifty-seven omap_hwmod_classes defined in mach-omap2/omap_hwmod_44xx_data.c after this series have custom reset functions used: $ fgrep 'struct omap_hwmod_class ' arch/arm/mach-omap2/omap_hwmod_44xx_data.c | wc -l 57 $ fgrep '.reset' arch/arm/mach-omap2/omap_hwmod_44xx_data.c | wc -l 4 That's 7% of the classes. In terms of the total number of IP block instances that use custom reset functions viewed against the total number of instances on the chip, the percentage is even smaller. AFAIK there's no need to reset the IP blocks before the driver init, it's really needed for PM. So it's not needed early on, and it's OK to require running the driver init for driver modules that are not in use to reset them properly. After all, the hardware is on the device, even if it's not being used. I don't think I'm following you. It's not just PM; the problem is also with kexec or buggy bootloaders. If an IP block isn't reset when the kernel boots, and is doing DMA or anything else that could affect the reset of the system, it could easily cause unpredictable behavior or crashes in unrelated kernel code. It's also worth mentioning that many IP blocks, such as AESS, don't have Linux drivers. - Paul -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 04/11] ARM: OMAP2+: usb_host_fs: add custom reset for usb_host_fs (fsusb)
Hi, On Thu, Jun 07, 2012 at 12:31:13AM -0700, Tony Lindgren wrote: * Paul Walmsley p...@pwsan.com [120606 23:26]: From: Tero Kristo t-kri...@ti.com Add a custom reset function for the usb_host_fs/fsusb IP block, and connect it to the OMAP4 FSUSB block. This is the first of two fixes required to get rid of the boot warning: omap_hwmod: usb_host_fs: _wait_target_disable failed and to allow the module to idle. It may be necessary to use this reset method for OMAP2xxx SoCs as well; this is left for a future patch. Here too I think driver like features like this should live in the driver init for omap OHCI driver. In the likely case that FS OHCI is not in use on the board, the OHCI glue can just reset it. this I don't agree. It means we will have to add some OHCI code even when OHCI is disabled. +/* HCCOMMANDSTATUS: the register offset of the HCCOMMANDSTATUS register */ +#define HCCOMMANDSTATUS0x0008 + +/* HCCOMMANDSTATUS_HCR: the bitmask of the host controller reset flag */ +#define HCCOMMANDSTATUS_HCR_MASK (1 0) I don't think the bus layer code should need to know anything about driver specific registers. + omap_hwmod_write(HCCOMMANDSTATUS_HCR_MASK, oh, HCCOMMANDSTATUS); + + omap_test_timeout(!(omap_hwmod_read(oh, HCCOMMANDSTATUS) +HCCOMMANDSTATUS_HCR_MASK), + MAX_MODULE_SOFTRESET_WAIT, c); + These should be accessed by the driver in a standard way after ioremapping the device. agree. -- balbi signature.asc Description: Digital signature
Re: [PATCH 04/11] ARM: OMAP2+: usb_host_fs: add custom reset for usb_host_fs (fsusb)
On Thu, 7 Jun 2012, Tony Lindgren wrote: Here too I think driver like features like this should live in the driver init for omap OHCI driver. In the likely case that FS OHCI is not in use on the board, the OHCI glue can just reset it. What if the driver is not compiled into the kernel, but instead is built as a loadable module? - Paul -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 02/11] ARM: OMAP4+: AESS: enable internal auto-gating during initial setup
* Paul Walmsley p...@pwsan.com [120607 00:35]: On Thu, 7 Jun 2012, Tony Lindgren wrote: It seems that most/many IP blocks need their custom reset hacks, and it's not limited to just few instances? Only four out of the fifty-seven omap_hwmod_classes defined in mach-omap2/omap_hwmod_44xx_data.c after this series have custom reset functions used: $ fgrep 'struct omap_hwmod_class ' arch/arm/mach-omap2/omap_hwmod_44xx_data.c | wc -l 57 $ fgrep '.reset' arch/arm/mach-omap2/omap_hwmod_44xx_data.c | wc -l 4 That's 7% of the classes. In terms of the total number of IP block instances that use custom reset functions viewed against the total number of instances on the chip, the percentage is even smaller. OK so that's not too bad then. But there's also the omap2_wd_timer_disable pre_shutdown too. And there's also the sysconfig autoidle bit for each driver that we're tweaking in the bus level code? If we can remove the ioremapping and accessing driver registers in the bus level code things get much simpler for the bus level code. AFAIK there's no need to reset the IP blocks before the driver init, it's really needed for PM. So it's not needed early on, and it's OK to require running the driver init for driver modules that are not in use to reset them properly. After all, the hardware is on the device, even if it's not being used. I don't think I'm following you. It's not just PM; the problem is also with kexec or buggy bootloaders. If an IP block isn't reset when the kernel boots, and is doing DMA or anything else that could affect the reset of the system, it could easily cause unpredictable behavior or crashes in unrelated kernel code. Still sounds like the responsibility of the bootloaders and drivers to set things up properly, that's the standard behaviour. It's also worth mentioning that many IP blocks, such as AESS, don't have Linux drivers. Sounds like it should have a minimal driver then, just to reset it if nothing else. Regards, Tony -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 04/11] ARM: OMAP2+: usb_host_fs: add custom reset for usb_host_fs (fsusb)
* Paul Walmsley p...@pwsan.com [120607 00:44]: On Thu, 7 Jun 2012, Tony Lindgren wrote: Here too I think driver like features like this should live in the driver init for omap OHCI driver. In the likely case that FS OHCI is not in use on the board, the OHCI glue can just reset it. What if the driver is not compiled into the kernel, but instead is built as a loadable module? You can still have a core piece of the driver that's always built in, such as omap-ohci-common. But it should live under drivers, not in the bus level code. Or you can insmod/rmmod it to reset things properly. Regards, Tony -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 04/11] ARM: OMAP2+: usb_host_fs: add custom reset for usb_host_fs (fsusb)
* Felipe Balbi ba...@ti.com [120607 00:39]: Hi, On Thu, Jun 07, 2012 at 12:31:13AM -0700, Tony Lindgren wrote: * Paul Walmsley p...@pwsan.com [120606 23:26]: From: Tero Kristo t-kri...@ti.com Add a custom reset function for the usb_host_fs/fsusb IP block, and connect it to the OMAP4 FSUSB block. This is the first of two fixes required to get rid of the boot warning: omap_hwmod: usb_host_fs: _wait_target_disable failed and to allow the module to idle. It may be necessary to use this reset method for OMAP2xxx SoCs as well; this is left for a future patch. Here too I think driver like features like this should live in the driver init for omap OHCI driver. In the likely case that FS OHCI is not in use on the board, the OHCI glue can just reset it. this I don't agree. It means we will have to add some OHCI code even when OHCI is disabled. That's because the bus level code alone is not enough for the reset and driver features are needed to reset it. Nothing wrong with the code itself, it should be just something that's part of the driver rather than the bus level code. It could be always built in for sure even if it lives under drivers. Tony -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 04/11] ARM: OMAP2+: usb_host_fs: add custom reset for usb_host_fs (fsusb)
On 6/7/2012 9:55 AM, Felipe Balbi wrote: On Thu, Jun 07, 2012 at 12:51:58AM -0700, Tony Lindgren wrote: * Paul Walmsleyp...@pwsan.com [120607 00:44]: On Thu, 7 Jun 2012, Tony Lindgren wrote: Here too I think driver like features like this should live in the driver init for omap OHCI driver. In the likely case that FS OHCI is not in use on the board, the OHCI glue can just reset it. What if the driver is not compiled into the kernel, but instead is built as a loadable module? You can still have a core piece of the driver that's always built in, such as omap-ohci-common. But it should live under drivers, not in the bus level code. Or you can insmod/rmmod it to reset things properly. that's such a hack... both solutions are quite hacky. The only problem here is because some bootloaders are leaving controller in an unknown state and I guess to be completely safe, resets should be done before any driver kicks in. But, driver will probably reset again the IP block during probe... Ideally it should be done only in the probe if needed. In the case of the DSS, the bootloader can init it with a splash screen and we do not want to blindly reset it and thus produce some ugly artifact on the screen. In fact we should delay the reset to the very last moment and potentially reset the IPs not under driver control later after a couple of second for example. It will avoid reseting every IP that will be handled properly by drivers. Regards, Benoit -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 04/11] ARM: OMAP2+: usb_host_fs: add custom reset for usb_host_fs (fsusb)
* Cousson, Benoit b-cous...@ti.com [120607 01:07]: On 6/7/2012 9:55 AM, Felipe Balbi wrote: On Thu, Jun 07, 2012 at 12:51:58AM -0700, Tony Lindgren wrote: * Paul Walmsleyp...@pwsan.com [120607 00:44]: On Thu, 7 Jun 2012, Tony Lindgren wrote: Here too I think driver like features like this should live in the driver init for omap OHCI driver. In the likely case that FS OHCI is not in use on the board, the OHCI glue can just reset it. What if the driver is not compiled into the kernel, but instead is built as a loadable module? You can still have a core piece of the driver that's always built in, such as omap-ohci-common. But it should live under drivers, not in the bus level code. Or you can insmod/rmmod it to reset things properly. that's such a hack... both solutions are quite hacky. The only problem here is because some bootloaders are leaving controller in an unknown state and I guess to be completely safe, resets should be done before any driver kicks in. But, driver will probably reset again the IP block during probe... Well I see two advantages moving the reset and idle responsibility to the drivers: 1. We can avoid ioremapping the devices in the bus level code and simplify things 2. We don't need to duplicate driver code into the bus level code Ideally it should be done only in the probe if needed. In the case of the DSS, the bootloader can init it with a splash screen and we do not want to blindly reset it and thus produce some ugly artifact on the screen. In fact we should delay the reset to the very last moment and potentially reset the IPs not under driver control later after a couple of second for example. It will avoid reseting every IP that will be handled properly by drivers. Good point. Regards, Tony -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 04/11] ARM: OMAP2+: usb_host_fs: add custom reset for usb_host_fs (fsusb)
On Thu, Jun 07, 2012 at 10:02:51AM +0200, Cousson, Benoit wrote: On 6/7/2012 9:55 AM, Felipe Balbi wrote: On Thu, Jun 07, 2012 at 12:51:58AM -0700, Tony Lindgren wrote: * Paul Walmsleyp...@pwsan.com [120607 00:44]: On Thu, 7 Jun 2012, Tony Lindgren wrote: Here too I think driver like features like this should live in the driver init for omap OHCI driver. In the likely case that FS OHCI is not in use on the board, the OHCI glue can just reset it. What if the driver is not compiled into the kernel, but instead is built as a loadable module? You can still have a core piece of the driver that's always built in, such as omap-ohci-common. But it should live under drivers, not in the bus level code. Or you can insmod/rmmod it to reset things properly. that's such a hack... both solutions are quite hacky. The only problem here is because some bootloaders are leaving controller in an unknown state and I guess to be completely safe, resets should be done before any driver kicks in. But, driver will probably reset again the IP block during probe... Ideally it should be done only in the probe if needed. In the case of the DSS, the bootloader can init it with a splash screen and we do not want to blindly reset it and thus produce some ugly artifact on the screen. In fact we should delay the reset to the very last moment and potentially reset the IPs not under driver control later after a couple of second for example. It will avoid reseting every IP that will be handled properly by drivers. you could have a late_initcall() that will iterate over hwmods and reset the ones which aren't used. That would mean adding some extra code to omap_device_build_ss() which would set a flag on each hwmod, or something similar. -- balbi signature.asc Description: Digital signature
RE: Please help! AM35xx mm/slab.c BUG
Hi , On Wed, Jun 06, 2012 at 13:21:23, CF Adad wrote: Thanks again. I'm really starting to think the GPMC almost has to be contributing. Does adding cycle2cycle delay / bus turnaround prevent the issue ?, SMSC datasheet mentions about special restrictions on back to back read and write-read, reading BYTE_TEST should take care of it, not sure whether driver takes care of all scenarios as per datasheet. Perhaps cycle2cycledelay would help us achieve it if driver doesn't take care of it. Regards Afzal -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 04/11] ARM: OMAP2+: usb_host_fs: add custom reset for usb_host_fs (fsusb)
On Thu, 7 Jun 2012, Tony Lindgren wrote: * Paul Walmsley p...@pwsan.com [120607 00:44]: On Thu, 7 Jun 2012, Tony Lindgren wrote: Here too I think driver like features like this should live in the driver init for omap OHCI driver. In the likely case that FS OHCI is not in use on the board, the OHCI glue can just reset it. What if the driver is not compiled into the kernel, but instead is built as a loadable module? You can still have a core piece of the driver that's always built in, such as omap-ohci-common. But it should live under drivers, not in the bus level code. Or you can insmod/rmmod it to reset things properly. Do you know of any device drivers that do this now, with a core built-in piece separate from a dynamically loadable part? Seems like it would be tricky to avoid linking in the entire driver, due to the symbol dependencies. Either that, or an extra, largely useless, layer of indirection would be needed in the shim layer. - Paul -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT] DMA engine patches
I am intending to post the _entire_ set of DMA patches I have so far. I'm going to be doing this in a slightly different way to normal, because of the way the branches are structured. What will come first is a set of three common patches to all the branches. Following on from that will be the individual sets for sa11x0, pl08x and OMAP. These are for testing, and are based on v3.5-rc1. drivers/dma/Kconfig |4 + drivers/dma/Makefile |1 + drivers/dma/sa11x0-dma.c | 249 ++--- drivers/dma/virt-dma.c | 123 +++ drivers/dma/virt-dma.h | 152 5 files changed, 358 insertions(+), 171 deletions(-) -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT 2/3] dmaengine: virt-dma: vchan_find_desc()
Add a function to find a descriptor within the depths of the virtualized DMA channel support. Needed for tx_status functionality. Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/virt-dma.c | 13 + drivers/dma/virt-dma.h |2 +- 2 files changed, 14 insertions(+), 1 deletions(-) diff --git a/drivers/dma/virt-dma.c b/drivers/dma/virt-dma.c index bd85b05..a8054fc 100644 --- a/drivers/dma/virt-dma.c +++ b/drivers/dma/virt-dma.c @@ -39,6 +39,19 @@ dma_cookie_t vchan_tx_submit(struct dma_async_tx_descriptor *tx) } EXPORT_SYMBOL_GPL(vchan_tx_submit); +struct virt_dma_desc *vchan_find_desc(struct virt_dma_chan *vc, + dma_cookie_t cookie) +{ + struct virt_dma_desc *vd; + + list_for_each_entry(vd, vc-desc_issued, node) + if (vd-tx.cookie == cookie) + return vd; + + return NULL; +} +EXPORT_SYMBOL_GPL(vchan_find_desc); + /* * This tasklet handles the completion of a DMA descriptor by * calling its callback and freeing it. diff --git a/drivers/dma/virt-dma.h b/drivers/dma/virt-dma.h index 825bb96..44ec57e 100644 --- a/drivers/dma/virt-dma.h +++ b/drivers/dma/virt-dma.h @@ -40,8 +40,8 @@ static inline struct virt_dma_chan *to_virt_chan(struct dma_chan *chan) } void vchan_dma_desc_free_list(struct virt_dma_chan *vc, struct list_head *head); - void vchan_init(struct virt_dma_chan *vc, struct dma_device *dmadev); +struct virt_dma_desc *vchan_find_desc(struct virt_dma_chan *, dma_cookie_t); /** * vchan_tx_prep - prepare a descriptor -- 1.7.4.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT 3/3] dmaengine: virt-dma: add support for cyclic DMA periodic callbacks
Add support for cyclic DMA's periodic callbacks. Drivers are expected to call vchan_cyclic_callback() when a period has completed, which will schedule the tasklet to make the callback into the driver. As callbacks are made from tasklet context, it is important to realise that we don't guarantee a callback for each completed period, but for N completed periods where N may be greater than one. Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/virt-dma.c | 19 +++ drivers/dma/virt-dma.h | 14 ++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/drivers/dma/virt-dma.c b/drivers/dma/virt-dma.c index a8054fc..6f80432 100644 --- a/drivers/dma/virt-dma.c +++ b/drivers/dma/virt-dma.c @@ -59,17 +59,28 @@ EXPORT_SYMBOL_GPL(vchan_find_desc); static void vchan_complete(unsigned long arg) { struct virt_dma_chan *vc = (struct virt_dma_chan *)arg; + struct virt_dma_desc *vd; + dma_async_tx_callback cb = NULL; + void *cb_data = NULL; LIST_HEAD(head); spin_lock_irq(vc-lock); list_splice_tail_init(vc-desc_completed, head); + vd = vc-cyclic; + if (vd) { + vc-cyclic = NULL; + cb = vd-tx.callback; + cb_data = vd-tx.callback_param; + } spin_unlock_irq(vc-lock); + if (cb) + cb(cb_data); + while (!list_empty(head)) { - struct virt_dma_desc *vd = list_first_entry(head, - struct virt_dma_desc, node); - dma_async_tx_callback cb = vd-tx.callback; - void *cb_data = vd-tx.callback_param; + vd = list_first_entry(head, struct virt_dma_desc, node); + cb = vd-tx.callback; + cb_data = vd-tx.callback_param; list_del(vd-node); diff --git a/drivers/dma/virt-dma.h b/drivers/dma/virt-dma.h index 44ec57e..85c19d6 100644 --- a/drivers/dma/virt-dma.h +++ b/drivers/dma/virt-dma.h @@ -32,6 +32,8 @@ struct virt_dma_chan { struct list_head desc_submitted; struct list_head desc_issued; struct list_head desc_completed; + + struct virt_dma_desc *cyclic; }; static inline struct virt_dma_chan *to_virt_chan(struct dma_chan *chan) @@ -92,6 +94,18 @@ static inline void vchan_cookie_complete(struct virt_dma_desc *vd) } /** + * vchan_cyclic_callback - report the completion of a period + * vd: virtual descriptor + */ +static inline void vchan_cyclic_callback(struct virt_dma_desc *vd) +{ + struct virt_dma_chan *vc = to_virt_chan(vd-tx.chan); + + vc-cyclic = vd; + tasklet_schedule(vc-task); +} + +/** * vchan_next_desc - peek at the next descriptor to be processed * vc: virtual channel to obtain descriptor from * -- 1.7.4.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT] SA11x0 patches
Updates to the SA11x0 DMA engine driver. This fixes the residue calculation, and implements cyclic transfers. drivers/dma/sa11x0-dma.c | 153 -- 1 files changed, 121 insertions(+), 32 deletions(-) -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT 1/2] dmaengine: sa11x0-dma: fix DMA residue support
The semantics now implemented are: - If the cookie has completed successfully, the residue will be zero. - If the cookie is in progress or the channel is paused, it will be the number of bytes yet to be transferred. [*] - If the cookie is queued, it will be the number of bytes in the descriptor. * - where this is the number of bytes yet to be transferred to/from RAM. Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/sa11x0-dma.c | 45 + 1 files changed, 29 insertions(+), 16 deletions(-) diff --git a/drivers/dma/sa11x0-dma.c b/drivers/dma/sa11x0-dma.c index 5f1d2e6..db4fcbd 100644 --- a/drivers/dma/sa11x0-dma.c +++ b/drivers/dma/sa11x0-dma.c @@ -416,27 +416,47 @@ static enum dma_status sa11x0_dma_tx_status(struct dma_chan *chan, struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan); struct sa11x0_dma_dev *d = to_sa11x0_dma(chan-device); struct sa11x0_dma_phy *p; - struct sa11x0_dma_desc *txd; + struct virt_dma_desc *vd; unsigned long flags; enum dma_status ret; - size_t bytes = 0; ret = dma_cookie_status(c-vc.chan, cookie, state); if (ret == DMA_SUCCESS) return ret; + if (!state) + return c-status; + spin_lock_irqsave(c-vc.lock, flags); p = c-phy; - ret = c-status; - if (p) { - dma_addr_t addr = sa11x0_dma_pos(p); - dev_vdbg(d-slave.dev, tx_status: addr:%x\n, addr); + /* +* If the cookie is on our issue queue, then the residue is +* its total size. +*/ + vd = vchan_find_desc(c-vc, cookie); + if (vd) { + state-residue = container_of(vd, struct sa11x0_dma_desc, vd)-size; + } else if (!p) { + state-residue = 0; + } else { + struct sa11x0_dma_desc *txd; + size_t bytes = 0; + + if (p-txd_done p-txd_done-vd.tx.cookie == cookie) + txd = p-txd_done; + else if (p-txd_load p-txd_load-vd.tx.cookie == cookie) + txd = p-txd_load; + else + txd = NULL; - txd = p-txd_done; + ret = c-status; if (txd) { + dma_addr_t addr = sa11x0_dma_pos(p); unsigned i; + dev_vdbg(d-slave.dev, tx_status: addr:%x\n, addr); + for (i = 0; i txd-sglen; i++) { dev_vdbg(d-slave.dev, tx_status: [%u] %x+%x\n, i, txd-sg[i].addr, txd-sg[i].len); @@ -459,18 +479,11 @@ static enum dma_status sa11x0_dma_tx_status(struct dma_chan *chan, bytes += txd-sg[i].len; } } - if (txd != p-txd_load p-txd_load) - bytes += p-txd_load-size; - } - list_for_each_entry(txd, c-vc.desc_issued, vd.node) { - bytes += txd-size; + state-residue = bytes; } spin_unlock_irqrestore(c-vc.lock, flags); - if (state) - state-residue = bytes; - - dev_vdbg(d-slave.dev, tx_status: bytes 0x%zx\n, bytes); + dev_vdbg(d-slave.dev, tx_status: bytes 0x%zx\n, state-residue); return ret; } -- 1.7.4.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT 2/2] dmaengine: sa11x0-dma: add cyclic DMA support
Add support for cyclic DMA on sa11x0 platforms. This follows the discussed behaviour that the callback will be called at some point after period expires, and may coalesce multiple period expiries into one callback (due to the tasklet behaviour.) Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/sa11x0-dma.c | 108 +++--- 1 files changed, 92 insertions(+), 16 deletions(-) diff --git a/drivers/dma/sa11x0-dma.c b/drivers/dma/sa11x0-dma.c index db4fcbd..f5a7360 100644 --- a/drivers/dma/sa11x0-dma.c +++ b/drivers/dma/sa11x0-dma.c @@ -78,6 +78,8 @@ struct sa11x0_dma_desc { u32 ddar; size_t size; + unsignedperiod; + boolcyclic; unsignedsglen; struct sa11x0_dma_sgsg[0]; @@ -178,19 +180,24 @@ static void noinline sa11x0_dma_start_sg(struct sa11x0_dma_phy *p, return; if (p-sg_load == txd-sglen) { - struct sa11x0_dma_desc *txn = sa11x0_dma_next_desc(c); + if (!txd-cyclic) { + struct sa11x0_dma_desc *txn = sa11x0_dma_next_desc(c); - /* -* We have reached the end of the current descriptor. -* Peek at the next descriptor, and if compatible with -* the current, start processing it. -*/ - if (txn txn-ddar == txd-ddar) { - txd = txn; - sa11x0_dma_start_desc(p, txn); + /* +* We have reached the end of the current descriptor. +* Peek at the next descriptor, and if compatible with +* the current, start processing it. +*/ + if (txn txn-ddar == txd-ddar) { + txd = txn; + sa11x0_dma_start_desc(p, txn); + } else { + p-txd_load = NULL; + return; + } } else { - p-txd_load = NULL; - return; + /* Cyclic: reset back to beginning */ + p-sg_load = 0; } } @@ -224,13 +231,21 @@ static void noinline sa11x0_dma_complete(struct sa11x0_dma_phy *p, struct sa11x0_dma_desc *txd = p-txd_done; if (++p-sg_done == txd-sglen) { - vchan_cookie_complete(txd-vd); + if (!txd-cyclic) { + vchan_cookie_complete(txd-vd); - p-sg_done = 0; - p-txd_done = p-txd_load; + p-sg_done = 0; + p-txd_done = p-txd_load; + + if (!p-txd_done) + tasklet_schedule(p-dev-task); + } else { + if ((p-sg_done % txd-period) == 0) + vchan_cyclic_callback(txd-vd); - if (!p-txd_done) - tasklet_schedule(p-dev-task); + /* Cyclic: reset back to beginning */ + p-sg_done = 0; + } } sa11x0_dma_start_sg(p, c); @@ -597,6 +612,65 @@ static struct dma_async_tx_descriptor *sa11x0_dma_prep_slave_sg( return vchan_tx_prep(c-vc, txd-vd, flags); } +static struct dma_async_tx_descriptor *sa11x0_dma_prep_dma_cyclic( + struct dma_chan *chan, dma_addr_t addr, size_t size, size_t period, + enum dma_transfer_direction dir, void *context) +{ + struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan); + struct sa11x0_dma_desc *txd; + unsigned i, j, k, sglen, sgperiod; + + /* SA11x0 channels can only operate in their native direction */ + if (dir != (c-ddar DDAR_RW ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV)) { + dev_err(chan-device-dev, vchan %p: bad DMA direction: DDAR:%08x dir:%u\n, + c-vc, c-ddar, dir); + return NULL; + } + + sgperiod = DIV_ROUND_UP(period, DMA_MAX_SIZE ~DMA_ALIGN); + sglen = size * sgperiod / period; + + /* Do not allow zero-sized txds */ + if (sglen == 0) + return NULL; + + txd = kzalloc(sizeof(*txd) + sglen * sizeof(txd-sg[0]), GFP_ATOMIC); + if (!txd) { + dev_dbg(chan-device-dev, vchan %p: kzalloc failed\n, c-vc); + return NULL; + } + + for (i = k = 0; i size / period; i++) { + size_t tlen, len = period; + + for (j = 0; j sgperiod; j++, k++) { + tlen = len; + + if (tlen DMA_MAX_SIZE) { + unsigned mult = DIV_ROUND_UP(tlen, DMA_MAX_SIZE ~DMA_ALIGN); +
Re: [PATCH 02/11] ARM: OMAP4+: AESS: enable internal auto-gating during initial setup
On Thu, 7 Jun 2012, Tony Lindgren wrote: OK so that's not too bad then. But there's also the omap2_wd_timer_disable pre_shutdown too. And there's also the sysconfig autoidle bit for each driver that we're tweaking in the bus level code? I think I lost your point here. The ioremap() issue is separate from the reset functions, etc., in my view. Moving the reset functions out to drivers/ seems potentially more reasonable than dropping the ioremap(). If we can remove the ioremapping and accessing driver registers in the bus level code things get much simpler for the bus level code. That's like saying if PCI Configuration Header handling were to be moved into the driver code, then the PCI bus-level code would be much simpler :-) The hwmod code ioremaps the device registers to handle the integration-level registers at the beginning of the device's address space. These registers can be thought of as part of the PRCM, not part of the IP block. It would have been better if TI had put these integration registers in a separate address space like PCI does. But we are stuck with the existing hardware design. The integration registers also differ from chip to chip even with the same underlying IP block, see for example the 32k sync timer. The main reasons why these integration registers are handled now in common code are: 1. to avoid duplicating integration code between lots of different drivers that is unrelated to the driver itself, such as bus-level reset 2. to ensure consistency of the OCP registers with the rest of the PM state 3. to avoid callbacks into drivers that might otherwise be needed for bitfields like CLOCKACTIVITY 4. to make it easier to debug integration problems with drivers If we don't handle those registers in common code, the number of SoC integration workarounds that need to be placed into the drivers will increase. For example, when OMAP4 added the smart-idle-with-wakeup and smart-standby-with-wakeup OCP idle modes, only a couple of files needed to be changed. If those integration-level details were still in the drivers, a large number of files would need to be changed. And $DEITY help us if the code sequence for dealing with those bits were to ever change in the future - we'd need to change a bunch of drivers, rather than just one or two files. Also some people are going to need to audit the driver code from an integration level pretty carefully for PM to work consistently. I suppose one option, if we were to have a real omap_device, would be to define callbacks for each driver to implement that would read and write the OCP header registers. Then the omap_bus code could call those callbacks to handle the OCP register accesses, when called from the driver's PM runtime calls. Adds another layer of indirection, but would localize IP block register accesses to the IP block's driver. ... As far as the reset and preconfiguration aspects of the hwmod code go, they just happen to be possible since we're doing the ioremap anyway. It can be ensured that no matter what drivers are present, or what the bootloader or previous OS did or didn't do, a minimal kernel should behave predictably. It seems like it might be reasonable to move these to some built-in driver shim layer as you suggest in your other E-mail. But that is assuming that it can be made to work without needless layers of indirection. I don't know of any driver that does this now. Maybe you know of one? - Paul -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [CFT] PL08x patches
Here's the PL08x patches. drivers/dma/Kconfig|1 + drivers/dma/amba-pl08x.c | 941 ++-- include/linux/amba/pl08x.h | 156 +--- 3 files changed, 482 insertions(+), 616 deletions(-) -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT 01/31] dmaengine: PL08x: remove runtime PM support
The runtime PM support conflicts with the generic AMBA bus PM, and also causes a potential deadlock with the PL011 driver as it results in interrupts being enabled beneath a spinlock. I don't presently see any solution to this other than by removing the runtime PM support entirely from the DMA engine driver. Alternative suggestions welcome. Acked-by: Linus Walleij linus.wall...@linaro.org Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/amba-pl08x.c | 10 -- 1 files changed, 0 insertions(+), 10 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 49ecbbb..5586d9a 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -404,7 +404,6 @@ pl08x_get_phy_channel(struct pl08x_driver_data *pl08x, return NULL; } - pm_runtime_get_sync(pl08x-adev-dev); return ch; } @@ -418,8 +417,6 @@ static inline void pl08x_put_phy_channel(struct pl08x_driver_data *pl08x, /* Stop the channel and clear its interrupts */ pl08x_terminate_phy_chan(pl08x, ch); - pm_runtime_put(pl08x-adev-dev); - /* Mark it as free */ ch-serving = NULL; spin_unlock_irqrestore(ch-lock, flags); @@ -1851,9 +1848,6 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) goto out_no_pl08x; } - pm_runtime_set_active(adev-dev); - pm_runtime_enable(adev-dev); - /* Initialize memcpy engine */ dma_cap_set(DMA_MEMCPY, pl08x-memcpy.cap_mask); pl08x-memcpy.dev = adev-dev; @@ -2007,7 +2001,6 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) amba_part(adev), amba_rev(adev), (unsigned long long)adev-res.start, adev-irq[0]); - pm_runtime_put(adev-dev); return 0; out_no_slave_reg: @@ -2026,9 +2019,6 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) dma_pool_destroy(pl08x-pool); out_no_lli_pool: out_no_platdata: - pm_runtime_put(adev-dev); - pm_runtime_disable(adev-dev); - kfree(pl08x); out_no_pl08x: amba_release_regions(adev); -- 1.7.4.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT 02/31] dmaengine: PL08x: fix missed dma_transfer_direction fixup
db8196df4 (dmaengine: move drivers to dma_transfer_direction) missed fixing up the DMA_NONE case. Acked-by: Linus Walleij linus.wall...@linaro.org Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/amba-pl08x.c |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 5586d9a..f3ab004 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -1287,7 +1287,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy( } list_add_tail(dsg-node, txd-dsg_list); - txd-direction = DMA_NONE; + txd-direction = DMA_MEM_TO_MEM; dsg-src_addr = src; dsg-dst_addr = dest; dsg-len = len; -- 1.7.4.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT 03/31] dmaengine: PL08x: remove redundant spinlock
The pl08x_driver_data spinlock is only ever initialized. Nothing else uses it. Let's get rid of it. Acked-by: Linus Walleij linus.wall...@linaro.org Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/amba-pl08x.c |3 --- 1 files changed, 0 insertions(+), 3 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index f3ab004..9c5bae6 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -146,7 +146,6 @@ struct pl08x_driver_data { int pool_ctr; u8 lli_buses; u8 mem_buses; - spinlock_t lock; }; /* @@ -1897,8 +1896,6 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) goto out_no_lli_pool; } - spin_lock_init(pl08x-lock); - pl08x-base = ioremap(adev-res.start, resource_size(adev-res)); if (!pl08x-base) { ret = -ENOMEM; -- 1.7.4.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT 04/31] dmaengine: PL08x: remove circular_buffer boolean from channel data
Circular buffers are not handled in this way; we have a separate API call now to setup circular buffers. So lets not mislead people with this bool. Acked-by: Linus Walleij linus.wall...@linaro.org Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/amba-pl08x.c |7 --- include/linux/amba/pl08x.h |4 2 files changed, 0 insertions(+), 11 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 9c5bae6..5821125 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -1701,13 +1701,6 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x, return -ENOMEM; } } - if (chan-cd-circular_buffer) { - dev_err(pl08x-adev-dev, - channel %s: circular buffers not supported\n, - chan-name); - kfree(chan); - continue; - } dev_dbg(pl08x-adev-dev, initialize virtual channel \%s\\n, chan-name); diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index 0254901..0f5b34d 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -51,9 +51,6 @@ enum { * can be the address of a FIFO register for burst requests for example. * This can be left undefined if the PrimeCell API is used for configuring * this. - * @circular_buffer: whether the buffer passed in is circular and - * shall simply be looped round round (like a record baby round - * round round round) * @single: the device connected to this channel will request single DMA * transfers, not bursts. (Bursts are default.) * @periph_buses: the device connected to this channel is accessible via @@ -66,7 +63,6 @@ struct pl08x_channel_data { u32 muxval; u32 cctl; dma_addr_t addr; - bool circular_buffer; bool single; u8 periph_buses; }; -- 1.7.4.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT 05/31] dmaengine: PL08x: clean up get_signal/put_signal
Try to avoid dereferencing the DMA engine's channel struct in these platform helpers; instead, pass a pointer to the channel data into get_signal(), and the returned signal number to put_signal(). Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/amba-pl08x.c |4 ++-- include/linux/amba/pl08x.h |4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 5821125..cc08c8c 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -874,7 +874,7 @@ static int prep_phy_channel(struct pl08x_dma_chan *plchan, * Can the platform allow us to use this channel? */ if (plchan-slave pl08x-pd-get_signal) { - ret = pl08x-pd-get_signal(plchan); + ret = pl08x-pd-get_signal(plchan-cd); if (ret 0) { dev_dbg(pl08x-adev-dev, unable to use physical channel %d for transfer on %s due to platform restrictions\n, @@ -909,7 +909,7 @@ static void release_phy_channel(struct pl08x_dma_chan *plchan) struct pl08x_driver_data *pl08x = plchan-host; if ((plchan-phychan-signal = 0) pl08x-pd-put_signal) { - pl08x-pd-put_signal(plchan); + pl08x-pd-put_signal(plchan-cd, plchan-phychan-signal); plchan-phychan-signal = -1; } pl08x_put_phy_channel(pl08x, plchan-phychan); diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index 0f5b34d..88765a6 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -225,8 +225,8 @@ struct pl08x_platform_data { const struct pl08x_channel_data *slave_channels; unsigned int num_slave_channels; struct pl08x_channel_data memcpy_channel; - int (*get_signal)(struct pl08x_dma_chan *); - void (*put_signal)(struct pl08x_dma_chan *); + int (*get_signal)(const struct pl08x_channel_data *); + void (*put_signal)(const struct pl08x_channel_data *, int); u8 lli_buses; u8 mem_buses; }; -- 1.7.4.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT 06/31] dmaengine: PL08x: move private data structures into amba-pl08x.c
Move the driver private data structures into the driver itself, rather than having them exposed to everyone in a header file. Acked-by: Linus Walleij linus.wall...@linaro.org Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/amba-pl08x.c | 136 ++ include/linux/amba/pl08x.h | 141 +--- 2 files changed, 138 insertions(+), 139 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index cc08c8c..9494990 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -90,6 +90,7 @@ #define DRIVER_NAMEpl08xdmac static struct amba_driver pl08x_amba_driver; +struct pl08x_driver_data; /** * struct vendor_data - vendor-specific config parameters for PL08x derivatives @@ -119,6 +120,141 @@ struct pl08x_lli { }; /** + * struct pl08x_bus_data - information of source or destination + * busses for a transfer + * @addr: current address + * @maxwidth: the maximum width of a transfer on this bus + * @buswidth: the width of this bus in bytes: 1, 2 or 4 + */ +struct pl08x_bus_data { + dma_addr_t addr; + u8 maxwidth; + u8 buswidth; +}; + +/** + * struct pl08x_phy_chan - holder for the physical channels + * @id: physical index to this channel + * @lock: a lock to use when altering an instance of this struct + * @signal: the physical signal (aka channel) serving this physical channel + * right now + * @serving: the virtual channel currently being served by this physical + * channel + */ +struct pl08x_phy_chan { + unsigned int id; + void __iomem *base; + spinlock_t lock; + int signal; + struct pl08x_dma_chan *serving; +}; + +/** + * struct pl08x_sg - structure containing data per sg + * @src_addr: src address of sg + * @dst_addr: dst address of sg + * @len: transfer len in bytes + * @node: node for txd's dsg_list + */ +struct pl08x_sg { + dma_addr_t src_addr; + dma_addr_t dst_addr; + size_t len; + struct list_head node; +}; + +/** + * struct pl08x_txd - wrapper for struct dma_async_tx_descriptor + * @tx: async tx descriptor + * @node: node for txd list for channels + * @dsg_list: list of children sg's + * @direction: direction of transfer + * @llis_bus: DMA memory address (physical) start for the LLIs + * @llis_va: virtual memory address start for the LLIs + * @cctl: control reg values for current txd + * @ccfg: config reg values for current txd + */ +struct pl08x_txd { + struct dma_async_tx_descriptor tx; + struct list_head node; + struct list_head dsg_list; + enum dma_transfer_direction direction; + dma_addr_t llis_bus; + struct pl08x_lli *llis_va; + /* Default cctl value for LLIs */ + u32 cctl; + /* +* Settings to be put into the physical channel when we +* trigger this txd. Other registers are in llis_va[0]. +*/ + u32 ccfg; +}; + +/** + * struct pl08x_dma_chan_state - holds the PL08x specific virtual channel + * states + * @PL08X_CHAN_IDLE: the channel is idle + * @PL08X_CHAN_RUNNING: the channel has allocated a physical transport + * channel and is running a transfer on it + * @PL08X_CHAN_PAUSED: the channel has allocated a physical transport + * channel, but the transfer is currently paused + * @PL08X_CHAN_WAITING: the channel is waiting for a physical transport + * channel to become available (only pertains to memcpy channels) + */ +enum pl08x_dma_chan_state { + PL08X_CHAN_IDLE, + PL08X_CHAN_RUNNING, + PL08X_CHAN_PAUSED, + PL08X_CHAN_WAITING, +}; + +/** + * struct pl08x_dma_chan - this structure wraps a DMA ENGINE channel + * @chan: wrappped abstract channel + * @phychan: the physical channel utilized by this channel, if there is one + * @phychan_hold: if non-zero, hold on to the physical channel even if we + * have no pending entries + * @tasklet: tasklet scheduled by the IRQ to handle actual work etc + * @name: name of channel + * @cd: channel platform data + * @runtime_addr: address for RX/TX according to the runtime config + * @runtime_direction: current direction of this channel according to + * runtime config + * @pend_list: queued transactions pending on this channel + * @at: active transaction on this channel + * @lock: a lock for this channel data + * @host: a pointer to the host (internal use) + * @state: whether the channel is idle, paused, running etc + * @slave: whether this channel is a device (slave) or for memcpy + * @device_fc: Flow Controller Settings for ccfg register. Only valid for slave + * channels. Fill with 'true' if peripheral should be flow controller. Direction + * will be selected at Runtime. + * @waiting: a TX descriptor on this channel which is waiting for a physical + * channel to become available + */ +struct pl08x_dma_chan { + struct dma_chan chan; + struct pl08x_phy_chan *phychan; + int phychan_hold; + struct tasklet_struct
[CFT 07/31] dmaengine: PL08x: constify channel names and bus_id strings
Acked-by: Linus Walleij linus.wall...@linaro.org Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/amba-pl08x.c |2 +- include/linux/amba/pl08x.h |2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 9494990..775efef 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -237,7 +237,7 @@ struct pl08x_dma_chan { struct pl08x_phy_chan *phychan; int phychan_hold; struct tasklet_struct tasklet; - char *name; + const char *name; const struct pl08x_channel_data *cd; dma_addr_t src_addr; dma_addr_t dst_addr; diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index 48d02bf..158ce26 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -58,7 +58,7 @@ enum { * these buses (use PL08X_AHB1 | PL08X_AHB2). */ struct pl08x_channel_data { - char *bus_id; + const char *bus_id; int min_signal; int max_signal; u32 muxval; -- 1.7.4.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT 08/31] dmaengine: PL08x: get src/dst addr direct from dma_slave_config struct
Add a dma_slave_config struct to struct pl08x_dma_chan, and move the src_addr/dst_addr arguments into this struct. This is a step away from using the dma_slave_config's direction member. Acked-by: Linus Walleij linus.wall...@linaro.org Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/amba-pl08x.c | 15 +++ 1 files changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 775efef..31447db 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -239,8 +239,7 @@ struct pl08x_dma_chan { struct tasklet_struct tasklet; const char *name; const struct pl08x_channel_data *cd; - dma_addr_t src_addr; - dma_addr_t dst_addr; + struct dma_slave_config cfg; u32 src_cctl; u32 dst_cctl; enum dma_transfer_direction runtime_direction; @@ -1245,6 +1244,8 @@ static int dma_set_runtime_config(struct dma_chan *chan, return -EINVAL; } + plchan-cfg = *config; + cctl |= width PL080_CONTROL_SWIDTH_SHIFT; cctl |= width PL080_CONTROL_DWIDTH_SHIFT; @@ -1263,12 +1264,10 @@ static int dma_set_runtime_config(struct dma_chan *chan, plchan-device_fc = config-device_fc; if (plchan-runtime_direction == DMA_DEV_TO_MEM) { - plchan-src_addr = config-src_addr; plchan-src_cctl = pl08x_cctl(cctl) | PL080_CONTROL_DST_INCR | pl08x_select_bus(plchan-cd-periph_buses, pl08x-mem_buses); } else { - plchan-dst_addr = config-dst_addr; plchan-dst_cctl = pl08x_cctl(cctl) | PL080_CONTROL_SRC_INCR | pl08x_select_bus(pl08x-mem_buses, plchan-cd-periph_buses); @@ -1482,10 +1481,10 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( if (direction == DMA_MEM_TO_DEV) { txd-cctl = plchan-dst_cctl; - slave_addr = plchan-dst_addr; + slave_addr = plchan-cfg.dst_addr; } else if (direction == DMA_DEV_TO_MEM) { txd-cctl = plchan-src_cctl; - slave_addr = plchan-src_addr; + slave_addr = plchan-cfg.src_addr; } else { pl08x_free_txd(pl08x, txd); dev_err(pl08x-adev-dev, @@ -1790,8 +1789,8 @@ static void pl08x_dma_slave_init(struct pl08x_dma_chan *chan) chan-slave = true; chan-name = chan-cd-bus_id; - chan-src_addr = chan-cd-addr; - chan-dst_addr = chan-cd-addr; + chan-cfg.src_addr = chan-cd-addr; + chan-cfg.dst_addr = chan-cd-addr; chan-src_cctl = cctl | PL080_CONTROL_DST_INCR | pl08x_select_bus(chan-cd-periph_buses, chan-host-mem_buses); chan-dst_cctl = cctl | PL080_CONTROL_SRC_INCR | -- 1.7.4.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT 09/31] dmaengine: PL08x: get rid of device_fc in struct pl08x_dma_chan
As we now store the dma_slave_config in pl08x_dma_chan, we don't need to store this separately. Use the one in dma_slave_config directly. Acked-by: Linus Walleij linus.wall...@linaro.org Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/amba-pl08x.c |8 +--- 1 files changed, 1 insertions(+), 7 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 31447db..7eb0e8e 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -226,9 +226,6 @@ enum pl08x_dma_chan_state { * @host: a pointer to the host (internal use) * @state: whether the channel is idle, paused, running etc * @slave: whether this channel is a device (slave) or for memcpy - * @device_fc: Flow Controller Settings for ccfg register. Only valid for slave - * channels. Fill with 'true' if peripheral should be flow controller. Direction - * will be selected at Runtime. * @waiting: a TX descriptor on this channel which is waiting for a physical * channel to become available */ @@ -249,7 +246,6 @@ struct pl08x_dma_chan { struct pl08x_driver_data *host; enum pl08x_dma_chan_state state; bool slave; - bool device_fc; struct pl08x_txd *waiting; }; @@ -1261,8 +1257,6 @@ static int dma_set_runtime_config(struct dma_chan *chan, cctl |= burst PL080_CONTROL_SB_SIZE_SHIFT; cctl |= burst PL080_CONTROL_DB_SIZE_SHIFT; - plchan-device_fc = config-device_fc; - if (plchan-runtime_direction == DMA_DEV_TO_MEM) { plchan-src_cctl = pl08x_cctl(cctl) | PL080_CONTROL_DST_INCR | pl08x_select_bus(plchan-cd-periph_buses, @@ -1492,7 +1486,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( return NULL; } - if (plchan-device_fc) + if (plchan-cfg.device_fc) tmp = (direction == DMA_MEM_TO_DEV) ? PL080_FLOW_MEM2PER_PER : PL080_FLOW_PER2MEM_PER; else -- 1.7.4.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT 10/31] dmaengine: PL08x: move the bus and increment selection to dma prepare function
Move the bus and transfer increment selection to the DMA prepare function rather than the slave configuration function. Acked-by: Linus Walleij linus.wall...@linaro.org Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/amba-pl08x.c | 26 ++ 1 files changed, 14 insertions(+), 12 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 7eb0e8e..bd51a44 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -1258,13 +1258,9 @@ static int dma_set_runtime_config(struct dma_chan *chan, cctl |= burst PL080_CONTROL_DB_SIZE_SHIFT; if (plchan-runtime_direction == DMA_DEV_TO_MEM) { - plchan-src_cctl = pl08x_cctl(cctl) | PL080_CONTROL_DST_INCR | - pl08x_select_bus(plchan-cd-periph_buses, -pl08x-mem_buses); + plchan-src_cctl = pl08x_cctl(cctl); } else { - plchan-dst_cctl = pl08x_cctl(cctl) | PL080_CONTROL_SRC_INCR | - pl08x_select_bus(pl08x-mem_buses, -plchan-cd-periph_buses); + plchan-dst_cctl = pl08x_cctl(cctl); } dev_dbg(pl08x-adev-dev, @@ -1451,6 +1447,8 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( struct scatterlist *sg; dma_addr_t slave_addr; int ret, tmp; + u8 src_buses, dst_buses; + u32 cctl; dev_dbg(pl08x-adev-dev, %s prepare transaction of %d bytes from %s\n, __func__, sg_dma_len(sgl), plchan-name); @@ -1474,11 +1472,15 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( txd-direction = direction; if (direction == DMA_MEM_TO_DEV) { - txd-cctl = plchan-dst_cctl; + cctl = plchan-dst_cctl | PL080_CONTROL_SRC_INCR; slave_addr = plchan-cfg.dst_addr; + src_buses = pl08x-mem_buses; + dst_buses = plchan-cd-periph_buses; } else if (direction == DMA_DEV_TO_MEM) { - txd-cctl = plchan-src_cctl; + cctl = plchan-src_cctl | PL080_CONTROL_DST_INCR; slave_addr = plchan-cfg.src_addr; + src_buses = plchan-cd-periph_buses; + dst_buses = pl08x-mem_buses; } else { pl08x_free_txd(pl08x, txd); dev_err(pl08x-adev-dev, @@ -1486,6 +1488,8 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( return NULL; } + txd-cctl = cctl | pl08x_select_bus(src_buses, dst_buses); + if (plchan-cfg.device_fc) tmp = (direction == DMA_MEM_TO_DEV) ? PL080_FLOW_MEM2PER_PER : PL080_FLOW_PER2MEM_PER; @@ -1785,10 +1789,8 @@ static void pl08x_dma_slave_init(struct pl08x_dma_chan *chan) chan-name = chan-cd-bus_id; chan-cfg.src_addr = chan-cd-addr; chan-cfg.dst_addr = chan-cd-addr; - chan-src_cctl = cctl | PL080_CONTROL_DST_INCR | - pl08x_select_bus(chan-cd-periph_buses, chan-host-mem_buses); - chan-dst_cctl = cctl | PL080_CONTROL_SRC_INCR | - pl08x_select_bus(chan-host-mem_buses, chan-cd-periph_buses); + chan-src_cctl = cctl; + chan-dst_cctl = cctl; } /* -- 1.7.4.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT 11/31] dmaengine: PL08x: extract function to to generate cctl values
Extract the functionality from dma_slave_config to generate the cctl values for a given bus width and burst size. This allows us to use this elsewhere in the driver, namely the prepare functions. Acked-by: Linus Walleij linus.wall...@linaro.org Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/amba-pl08x.c | 53 +++-- 1 files changed, 32 insertions(+), 21 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index bd51a44..fde801f 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -1207,14 +1207,40 @@ static u32 pl08x_burst(u32 maxburst) return burst_sizes[i].reg; } +static u32 pl08x_get_cctl(struct pl08x_dma_chan *plchan, + enum dma_slave_buswidth addr_width, u32 maxburst) +{ + u32 width, burst, cctl = 0; + + width = pl08x_width(addr_width); + if (width == ~0) + return ~0; + + cctl |= width PL080_CONTROL_SWIDTH_SHIFT; + cctl |= width PL080_CONTROL_DWIDTH_SHIFT; + + /* +* If this channel will only request single transfers, set this +* down to ONE element. Also select one element if no maxburst +* is specified. +*/ + if (plchan-cd-single) + maxburst = 1; + + burst = pl08x_burst(maxburst); + cctl |= burst PL080_CONTROL_SB_SIZE_SHIFT; + cctl |= burst PL080_CONTROL_DB_SIZE_SHIFT; + + return pl08x_cctl(cctl); +} + static int dma_set_runtime_config(struct dma_chan *chan, struct dma_slave_config *config) { struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); struct pl08x_driver_data *pl08x = plchan-host; enum dma_slave_buswidth addr_width; - u32 width, burst, maxburst; - u32 cctl = 0; + u32 maxburst, cctl = 0; if (!plchan-slave) return -EINVAL; @@ -1233,8 +1259,8 @@ static int dma_set_runtime_config(struct dma_chan *chan, return -EINVAL; } - width = pl08x_width(addr_width); - if (width == ~0) { + cctl = pl08x_get_cctl(plchan, addr_width, maxburst); + if (cctl == ~0) { dev_err(pl08x-adev-dev, bad runtime_config: alien address width\n); return -EINVAL; @@ -1242,25 +1268,10 @@ static int dma_set_runtime_config(struct dma_chan *chan, plchan-cfg = *config; - cctl |= width PL080_CONTROL_SWIDTH_SHIFT; - cctl |= width PL080_CONTROL_DWIDTH_SHIFT; - - /* -* If this channel will only request single transfers, set this -* down to ONE element. Also select one element if no maxburst -* is specified. -*/ - if (plchan-cd-single) - maxburst = 1; - - burst = pl08x_burst(maxburst); - cctl |= burst PL080_CONTROL_SB_SIZE_SHIFT; - cctl |= burst PL080_CONTROL_DB_SIZE_SHIFT; - if (plchan-runtime_direction == DMA_DEV_TO_MEM) { - plchan-src_cctl = pl08x_cctl(cctl); + plchan-src_cctl = cctl; } else { - plchan-dst_cctl = pl08x_cctl(cctl); + plchan-dst_cctl = cctl; } dev_dbg(pl08x-adev-dev, -- 1.7.4.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT 12/31] dmaengine: PL08x: ignore 'direction' argument in dma_slave_config
Ignore the direction argument in dma_slave_config, and configure both directions independently. We still check that the configuration for the intended direction is valid; this check will eventually be dropped. This check is just for debugging at present. Acked-by: Linus Walleij linus.wall...@linaro.org Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/amba-pl08x.c | 56 ++--- 1 files changed, 18 insertions(+), 38 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index fde801f..50b9a83 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -218,8 +218,6 @@ enum pl08x_dma_chan_state { * @name: name of channel * @cd: channel platform data * @runtime_addr: address for RX/TX according to the runtime config - * @runtime_direction: current direction of this channel according to - * runtime config * @pend_list: queued transactions pending on this channel * @at: active transaction on this channel * @lock: a lock for this channel data @@ -239,7 +237,6 @@ struct pl08x_dma_chan { struct dma_slave_config cfg; u32 src_cctl; u32 dst_cctl; - enum dma_transfer_direction runtime_direction; struct list_head pend_list; struct pl08x_txd *at; spinlock_t lock; @@ -1239,50 +1236,31 @@ static int dma_set_runtime_config(struct dma_chan *chan, { struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); struct pl08x_driver_data *pl08x = plchan-host; - enum dma_slave_buswidth addr_width; - u32 maxburst, cctl = 0; + u32 src_cctl, dst_cctl; if (!plchan-slave) return -EINVAL; - /* Transfer direction */ - plchan-runtime_direction = config-direction; - if (config-direction == DMA_MEM_TO_DEV) { - addr_width = config-dst_addr_width; - maxburst = config-dst_maxburst; - } else if (config-direction == DMA_DEV_TO_MEM) { - addr_width = config-src_addr_width; - maxburst = config-src_maxburst; - } else { + dst_cctl = pl08x_get_cctl(plchan, config-dst_addr_width, + config-dst_maxburst); + if (dst_cctl == ~0 config-direction == DMA_MEM_TO_DEV) { dev_err(pl08x-adev-dev, - bad runtime_config: alien transfer direction\n); + bad runtime_config: alien address width (M2D)\n); return -EINVAL; } - cctl = pl08x_get_cctl(plchan, addr_width, maxburst); - if (cctl == ~0) { + src_cctl = pl08x_get_cctl(plchan, config-src_addr_width, + config-src_maxburst); + if (src_cctl == ~0 config-direction == DMA_DEV_TO_MEM) { dev_err(pl08x-adev-dev, - bad runtime_config: alien address width\n); + bad runtime_config: alien address width (D2M)\n); return -EINVAL; } + plchan-dst_cctl = dst_cctl; + plchan-src_cctl = src_cctl; plchan-cfg = *config; - if (plchan-runtime_direction == DMA_DEV_TO_MEM) { - plchan-src_cctl = cctl; - } else { - plchan-dst_cctl = cctl; - } - - dev_dbg(pl08x-adev-dev, - configured channel %s (%s) for %s, data width %d, - maxburst %d words, LE, CCTL=0x%08x\n, - dma_chan_name(chan), plchan-name, - (config-direction == DMA_DEV_TO_MEM) ? RX : TX, - addr_width, - maxburst, - cctl); - return 0; } @@ -1470,11 +1448,6 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( return NULL; } - if (direction != plchan-runtime_direction) - dev_err(pl08x-adev-dev, %s DMA setup does not match - the direction configured for the PrimeCell\n, - __func__); - /* * Set up addresses, the PrimeCell configured address * will take precedence since this may configure the @@ -1499,6 +1472,13 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( return NULL; } + if (cctl == ~0) { + pl08x_free_txd(pl08x, txd); + dev_err(pl08x-adev-dev, + DMA slave configuration botched?\n); + return NULL; + } + txd-cctl = cctl | pl08x_select_bus(src_buses, dst_buses); if (plchan-cfg.device_fc) -- 1.7.4.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT 13/31] dmaengine: PL08x: get rid of unnecessary checks in dma_slave_config
Get rid of the unnecessary checks in dma_slave_config utilizing the DMA direction. This allows us to move the computation of cctl to the prepare function. Acked-by: Linus Walleij linus.wall...@linaro.org Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/amba-pl08x.c | 41 + include/linux/amba/pl08x.h |5 +++-- 2 files changed, 16 insertions(+), 30 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 50b9a83..f739778 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -235,8 +235,6 @@ struct pl08x_dma_chan { const char *name; const struct pl08x_channel_data *cd; struct dma_slave_config cfg; - u32 src_cctl; - u32 dst_cctl; struct list_head pend_list; struct pl08x_txd *at; spinlock_t lock; @@ -1235,30 +1233,15 @@ static int dma_set_runtime_config(struct dma_chan *chan, struct dma_slave_config *config) { struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); - struct pl08x_driver_data *pl08x = plchan-host; - u32 src_cctl, dst_cctl; if (!plchan-slave) return -EINVAL; - dst_cctl = pl08x_get_cctl(plchan, config-dst_addr_width, - config-dst_maxburst); - if (dst_cctl == ~0 config-direction == DMA_MEM_TO_DEV) { - dev_err(pl08x-adev-dev, - bad runtime_config: alien address width (M2D)\n); + /* Reject definitely invalid configurations */ + if (config-src_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES || + config-dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES) return -EINVAL; - } - src_cctl = pl08x_get_cctl(plchan, config-src_addr_width, - config-src_maxburst); - if (src_cctl == ~0 config-direction == DMA_DEV_TO_MEM) { - dev_err(pl08x-adev-dev, - bad runtime_config: alien address width (D2M)\n); - return -EINVAL; - } - - plchan-dst_cctl = dst_cctl; - plchan-src_cctl = src_cctl; plchan-cfg = *config; return 0; @@ -1407,7 +1390,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy( /* Set platform data for m2m */ txd-ccfg |= PL080_FLOW_MEM2MEM PL080_CONFIG_FLOW_CONTROL_SHIFT; - txd-cctl = pl08x-pd-memcpy_channel.cctl + txd-cctl = pl08x-pd-memcpy_channel.cctl_memcpy ~(PL080_CONTROL_DST_AHB2 | PL080_CONTROL_SRC_AHB2); /* Both to be incremented or the code will break */ @@ -1434,10 +1417,11 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( struct pl08x_txd *txd; struct pl08x_sg *dsg; struct scatterlist *sg; + enum dma_slave_buswidth addr_width; dma_addr_t slave_addr; int ret, tmp; u8 src_buses, dst_buses; - u32 cctl; + u32 maxburst, cctl; dev_dbg(pl08x-adev-dev, %s prepare transaction of %d bytes from %s\n, __func__, sg_dma_len(sgl), plchan-name); @@ -1456,13 +1440,17 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( txd-direction = direction; if (direction == DMA_MEM_TO_DEV) { - cctl = plchan-dst_cctl | PL080_CONTROL_SRC_INCR; + cctl = PL080_CONTROL_SRC_INCR; slave_addr = plchan-cfg.dst_addr; + addr_width = plchan-cfg.dst_addr_width; + maxburst = plchan-cfg.dst_maxburst; src_buses = pl08x-mem_buses; dst_buses = plchan-cd-periph_buses; } else if (direction == DMA_DEV_TO_MEM) { - cctl = plchan-src_cctl | PL080_CONTROL_DST_INCR; + cctl = PL080_CONTROL_DST_INCR; slave_addr = plchan-cfg.src_addr; + addr_width = plchan-cfg.src_addr_width; + maxburst = plchan-cfg.src_maxburst; src_buses = plchan-cd-periph_buses; dst_buses = pl08x-mem_buses; } else { @@ -1472,6 +1460,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( return NULL; } + cctl |= pl08x_get_cctl(plchan, addr_width, maxburst); if (cctl == ~0) { pl08x_free_txd(pl08x, txd); dev_err(pl08x-adev-dev, @@ -1774,14 +1763,10 @@ static irqreturn_t pl08x_irq(int irq, void *dev) static void pl08x_dma_slave_init(struct pl08x_dma_chan *chan) { - u32 cctl = pl08x_cctl(chan-cd-cctl); - chan-slave = true; chan-name = chan-cd-bus_id; chan-cfg.src_addr = chan-cd-addr; chan-cfg.dst_addr = chan-cd-addr; - chan-src_cctl = cctl; - chan-dst_cctl = cctl; } /* diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index 158ce26..2a5f64a 100644 --- a/include/linux/amba/pl08x.h +++
[CFT 14/31] dmaengine: PL08x: split DMA signal muxing from channel alloc
Split the DMA request mux signal handling from the physical channel allocation code. The physical channel has very little to do with the DMA request input which will be used, so these should be two separate operations. Acked-by: Linus Walleij linus.wall...@linaro.org Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/amba-pl08x.c | 43 --- 1 files changed, 36 insertions(+), 7 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index f739778..b579bac 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -296,6 +296,39 @@ static inline struct pl08x_txd *to_pl08x_txd(struct dma_async_tx_descriptor *tx) } /* + * Mux handling. + * + * This gives us the DMA request input to the PL08x primecell which the + * peripheral described by the channel data will be routed to, possibly + * via a board/SoC specific external MUX. One important point to note + * here is that this does not depend on the physical channel. + */ +static int pl08x_request_mux(struct pl08x_dma_chan *plchan, struct pl08x_phy_chan *ch) +{ + const struct pl08x_platform_data *pd = plchan-host-pd; + int ret; + + if (pd-get_signal) { + ret = pd-get_signal(plchan-cd); + if (ret 0) + return ret; + + ch-signal = ret; + } + return 0; +} + +static void pl08x_release_mux(struct pl08x_dma_chan *plchan) +{ + const struct pl08x_platform_data *pd = plchan-host-pd; + + if (plchan-phychan-signal = 0 pd-put_signal) { + pd-put_signal(plchan-cd, plchan-phychan-signal); + plchan-phychan-signal = -1; + } +} + +/* * Physical channel handling */ @@ -999,8 +1032,8 @@ static int prep_phy_channel(struct pl08x_dma_chan *plchan, * need, but for slaves the physical signals may be muxed! * Can the platform allow us to use this channel? */ - if (plchan-slave pl08x-pd-get_signal) { - ret = pl08x-pd-get_signal(plchan-cd); + if (plchan-slave) { + ret = pl08x_request_mux(plchan, ch); if (ret 0) { dev_dbg(pl08x-adev-dev, unable to use physical channel %d for transfer on %s due to platform restrictions\n, @@ -1009,7 +1042,6 @@ static int prep_phy_channel(struct pl08x_dma_chan *plchan, pl08x_put_phy_channel(pl08x, ch); return -EBUSY; } - ch-signal = ret; } plchan-phychan = ch; @@ -1034,10 +1066,7 @@ static void release_phy_channel(struct pl08x_dma_chan *plchan) { struct pl08x_driver_data *pl08x = plchan-host; - if ((plchan-phychan-signal = 0) pl08x-pd-put_signal) { - pl08x-pd-put_signal(plchan-cd, plchan-phychan-signal); - plchan-phychan-signal = -1; - } + pl08x_release_mux(plchan); pl08x_put_phy_channel(pl08x, plchan-phychan); plchan-phychan = NULL; } -- 1.7.4.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT 15/31] dmaengine: PL08x: move DMA signal muxing into pl08x_dma_chan struct
Move the signal handling out of the physical channel structure into the virtual channel structure, where it should belong as it has more to do with the virtual channel than the physical one. Acked-by: Linus Walleij linus.wall...@linaro.org Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/amba-pl08x.c | 29 +++-- 1 files changed, 15 insertions(+), 14 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index b579bac..c203d2f 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -136,17 +136,17 @@ struct pl08x_bus_data { * struct pl08x_phy_chan - holder for the physical channels * @id: physical index to this channel * @lock: a lock to use when altering an instance of this struct - * @signal: the physical signal (aka channel) serving this physical channel - * right now * @serving: the virtual channel currently being served by this physical * channel + * @locked: channel unavailable for the system, e.g. dedicated to secure + * world */ struct pl08x_phy_chan { unsigned int id; void __iomem *base; spinlock_t lock; - int signal; struct pl08x_dma_chan *serving; + bool locked; }; /** @@ -226,6 +226,7 @@ enum pl08x_dma_chan_state { * @slave: whether this channel is a device (slave) or for memcpy * @waiting: a TX descriptor on this channel which is waiting for a physical * channel to become available + * @signal: the physical DMA request signal which this channel is using */ struct pl08x_dma_chan { struct dma_chan chan; @@ -242,6 +243,7 @@ struct pl08x_dma_chan { enum pl08x_dma_chan_state state; bool slave; struct pl08x_txd *waiting; + int signal; }; /** @@ -303,7 +305,7 @@ static inline struct pl08x_txd *to_pl08x_txd(struct dma_async_tx_descriptor *tx) * via a board/SoC specific external MUX. One important point to note * here is that this does not depend on the physical channel. */ -static int pl08x_request_mux(struct pl08x_dma_chan *plchan, struct pl08x_phy_chan *ch) +static int pl08x_request_mux(struct pl08x_dma_chan *plchan) { const struct pl08x_platform_data *pd = plchan-host-pd; int ret; @@ -313,7 +315,7 @@ static int pl08x_request_mux(struct pl08x_dma_chan *plchan, struct pl08x_phy_cha if (ret 0) return ret; - ch-signal = ret; + plchan-signal = ret; } return 0; } @@ -322,9 +324,9 @@ static void pl08x_release_mux(struct pl08x_dma_chan *plchan) { const struct pl08x_platform_data *pd = plchan-host-pd; - if (plchan-phychan-signal = 0 pd-put_signal) { - pd-put_signal(plchan-cd, plchan-phychan-signal); - plchan-phychan-signal = -1; + if (plchan-signal = 0 pd-put_signal) { + pd-put_signal(plchan-cd, plchan-signal); + plchan-signal = -1; } } @@ -549,7 +551,6 @@ pl08x_get_phy_channel(struct pl08x_driver_data *pl08x, if (!ch-locked !ch-serving) { ch-serving = virt_chan; - ch-signal = -1; spin_unlock_irqrestore(ch-lock, flags); break; } @@ -1033,7 +1034,7 @@ static int prep_phy_channel(struct pl08x_dma_chan *plchan, * Can the platform allow us to use this channel? */ if (plchan-slave) { - ret = pl08x_request_mux(plchan, ch); + ret = pl08x_request_mux(plchan); if (ret 0) { dev_dbg(pl08x-adev-dev, unable to use physical channel %d for transfer on %s due to platform restrictions\n, @@ -1047,15 +1048,15 @@ static int prep_phy_channel(struct pl08x_dma_chan *plchan, plchan-phychan = ch; dev_dbg(pl08x-adev-dev, allocated physical channel %d and signal %d for xfer on %s\n, ch-id, -ch-signal, +plchan-signal, plchan-name); got_channel: /* Assign the flow control signal to this channel */ if (txd-direction == DMA_MEM_TO_DEV) - txd-ccfg |= ch-signal PL080_CONFIG_DST_SEL_SHIFT; + txd-ccfg |= plchan-signal PL080_CONFIG_DST_SEL_SHIFT; else if (txd-direction == DMA_DEV_TO_MEM) - txd-ccfg |= ch-signal PL080_CONFIG_SRC_SEL_SHIFT; + txd-ccfg |= plchan-signal PL080_CONFIG_SRC_SEL_SHIFT; plchan-phychan_hold++; @@ -1825,6 +1826,7 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x, chan-host = pl08x; chan-state = PL08X_CHAN_IDLE; + chan-signal = -1; if (slave) { chan-cd = pl08x-pd-slave_channels[i]; @@ -2062,7 +2064,6 @@ static int pl08x_probe(struct amba_device *adev, const struct
[CFT 16/31] dmaengine: PL08x: track mux usage on a per-channel basis.
Keep track of the number of descriptors currently using a MUX setting on a per-channel basis. This allows us to know when we have descriptors queued somewhere which have been assigned a DMA request signal. Acked-by: Linus Walleij linus.wall...@linaro.org Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/amba-pl08x.c | 18 +- 1 files changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index c203d2f..ac9fdcc 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -227,6 +227,7 @@ enum pl08x_dma_chan_state { * @waiting: a TX descriptor on this channel which is waiting for a physical * channel to become available * @signal: the physical DMA request signal which this channel is using + * @mux_use: count of descriptors using this DMA request signal setting */ struct pl08x_dma_chan { struct dma_chan chan; @@ -244,6 +245,7 @@ struct pl08x_dma_chan { bool slave; struct pl08x_txd *waiting; int signal; + unsigned mux_use; }; /** @@ -310,10 +312,12 @@ static int pl08x_request_mux(struct pl08x_dma_chan *plchan) const struct pl08x_platform_data *pd = plchan-host-pd; int ret; - if (pd-get_signal) { + if (plchan-mux_use++ == 0 pd-get_signal) { ret = pd-get_signal(plchan-cd); - if (ret 0) + if (ret 0) { + plchan-mux_use = 0; return ret; + } plchan-signal = ret; } @@ -324,9 +328,13 @@ static void pl08x_release_mux(struct pl08x_dma_chan *plchan) { const struct pl08x_platform_data *pd = plchan-host-pd; - if (plchan-signal = 0 pd-put_signal) { - pd-put_signal(plchan-cd, plchan-signal); - plchan-signal = -1; + if (plchan-signal = 0) { + WARN_ON(plchan-mux_use == 0); + + if (--plchan-mux_use == 0 pd-put_signal) { + pd-put_signal(plchan-cd, plchan-signal); + plchan-signal = -1; + } } } -- 1.7.4.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT 17/31] dmaengine: PL08x: convert to a list of completed descriptors
Convert PL08x to use a list of completed descriptors rather than merely relying upon a single pointer. This makes it possible to schedule the tasklet for other purposes, and makes our behaviour similar to virt-dma. Acked-by: Linus Walleij linus.wall...@linaro.org Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/amba-pl08x.c | 30 -- 1 files changed, 20 insertions(+), 10 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index ac9fdcc..54e3eb0 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -219,6 +219,7 @@ enum pl08x_dma_chan_state { * @cd: channel platform data * @runtime_addr: address for RX/TX according to the runtime config * @pend_list: queued transactions pending on this channel + * @done_list: list of completed transactions * @at: active transaction on this channel * @lock: a lock for this channel data * @host: a pointer to the host (internal use) @@ -238,6 +239,7 @@ struct pl08x_dma_chan { const struct pl08x_channel_data *cd; struct dma_slave_config cfg; struct list_head pend_list; + struct list_head done_list; struct pl08x_txd *at; spinlock_t lock; struct pl08x_driver_data *host; @@ -1673,18 +1675,11 @@ static void pl08x_tasklet(unsigned long data) { struct pl08x_dma_chan *plchan = (struct pl08x_dma_chan *) data; struct pl08x_driver_data *pl08x = plchan-host; - struct pl08x_txd *txd; unsigned long flags; + LIST_HEAD(head); spin_lock_irqsave(plchan-lock, flags); - - txd = plchan-at; - plchan-at = NULL; - - if (txd) { - /* Update last completed */ - dma_cookie_complete(txd-tx); - } + list_splice_tail_init(plchan-done_list, head); /* If a new descriptor is queued, set it up plchan-at is NULL here */ if (!list_empty(plchan-pend_list)) { @@ -1739,10 +1734,14 @@ static void pl08x_tasklet(unsigned long data) spin_unlock_irqrestore(plchan-lock, flags); - if (txd) { + while (!list_empty(head)) { + struct pl08x_txd *txd = list_first_entry(head, + struct pl08x_txd, node); dma_async_tx_callback callback = txd-tx.callback; void *callback_param = txd-tx.callback_param; + list_del(txd-node); + /* Don't try to unmap buffers on slave channels */ if (!plchan-slave) pl08x_unmap_buffers(txd); @@ -1782,6 +1781,7 @@ static irqreturn_t pl08x_irq(int irq, void *dev) /* Locate physical channel */ struct pl08x_phy_chan *phychan = pl08x-phy_chans[i]; struct pl08x_dma_chan *plchan = phychan-serving; + struct pl08x_txd *tx; if (!plchan) { dev_err(pl08x-adev-dev, @@ -1790,6 +1790,15 @@ static irqreturn_t pl08x_irq(int irq, void *dev) continue; } + spin_lock(plchan-lock); + tx = plchan-at; + if (tx) { + plchan-at = NULL; + dma_cookie_complete(tx-tx); + list_add_tail(tx-node, plchan-done_list); + } + spin_unlock(plchan-lock); + /* Schedule tasklet on this channel */ tasklet_schedule(plchan-tasklet); mask |= (1 i); @@ -1856,6 +1865,7 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x, spin_lock_init(chan-lock); INIT_LIST_HEAD(chan-pend_list); + INIT_LIST_HEAD(chan-done_list); tasklet_init(chan-tasklet, pl08x_tasklet, (unsigned long) chan); -- 1.7.4.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT 18/31] dmaengine: PL08x: move DMA signal muxing into slave prepare code
Move the DMA request muxing into the slave prepare code and txd release/completion code. This means we only hold the DMA request mux while there are descriptors waiting to be started or are in progress. This leaves txd-direction as a write-only variable; remove it. Acked-by: Linus Walleij linus.wall...@linaro.org Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/amba-pl08x.c | 79 ++--- 1 files changed, 32 insertions(+), 47 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 54e3eb0..e04ca0b 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -168,7 +168,6 @@ struct pl08x_sg { * @tx: async tx descriptor * @node: node for txd list for channels * @dsg_list: list of children sg's - * @direction: direction of transfer * @llis_bus: DMA memory address (physical) start for the LLIs * @llis_va: virtual memory address start for the LLIs * @cctl: control reg values for current txd @@ -178,7 +177,6 @@ struct pl08x_txd { struct dma_async_tx_descriptor tx; struct list_head node; struct list_head dsg_list; - enum dma_transfer_direction direction; dma_addr_t llis_bus; struct pl08x_lli *llis_va; /* Default cctl value for LLIs */ @@ -997,6 +995,7 @@ static void pl08x_free_txd_list(struct pl08x_driver_data *pl08x, if (!list_empty(plchan-pend_list)) { list_for_each_entry_safe(txdi, next, plchan-pend_list, node) { + pl08x_release_mux(plchan); list_del(txdi-node); pl08x_free_txd(pl08x, txdi); } @@ -1018,12 +1017,10 @@ static void pl08x_free_chan_resources(struct dma_chan *chan) /* * This should be called with the channel plchan-lock held */ -static int prep_phy_channel(struct pl08x_dma_chan *plchan, - struct pl08x_txd *txd) +static int prep_phy_channel(struct pl08x_dma_chan *plchan) { struct pl08x_driver_data *pl08x = plchan-host; struct pl08x_phy_chan *ch; - int ret; /* Check if we already have a channel */ if (plchan-phychan) { @@ -1038,36 +1035,11 @@ static int prep_phy_channel(struct pl08x_dma_chan *plchan, return -EBUSY; } - /* -* OK we have a physical channel: for memcpy() this is all we -* need, but for slaves the physical signals may be muxed! -* Can the platform allow us to use this channel? -*/ - if (plchan-slave) { - ret = pl08x_request_mux(plchan); - if (ret 0) { - dev_dbg(pl08x-adev-dev, - unable to use physical channel %d for transfer on %s due to platform restrictions\n, - ch-id, plchan-name); - /* Release physical channel return */ - pl08x_put_phy_channel(pl08x, ch); - return -EBUSY; - } - } - plchan-phychan = ch; - dev_dbg(pl08x-adev-dev, allocated physical channel %d and signal %d for xfer on %s\n, -ch-id, -plchan-signal, -plchan-name); + dev_dbg(pl08x-adev-dev, allocated physical channel %d for xfer on %s\n, +ch-id, plchan-name); got_channel: - /* Assign the flow control signal to this channel */ - if (txd-direction == DMA_MEM_TO_DEV) - txd-ccfg |= plchan-signal PL080_CONFIG_DST_SEL_SHIFT; - else if (txd-direction == DMA_DEV_TO_MEM) - txd-ccfg |= plchan-signal PL080_CONFIG_SRC_SEL_SHIFT; - plchan-phychan_hold++; return 0; @@ -1077,7 +1049,6 @@ static void release_phy_channel(struct pl08x_dma_chan *plchan) { struct pl08x_driver_data *pl08x = plchan-host; - pl08x_release_mux(plchan); pl08x_put_phy_channel(pl08x, plchan-phychan); plchan-phychan = NULL; } @@ -1340,19 +1311,12 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, * See if we already have a physical channel allocated, * else this is the time to try to get one. */ - ret = prep_phy_channel(plchan, txd); + ret = prep_phy_channel(plchan); if (ret) { /* * No physical channel was available. * * memcpy transfers can be sorted out at submission time. -* -* Slave transfers may have been denied due to platform -* channel muxing restrictions. Since there is no guarantee -* that this will ever be resolved, and the signal must be -* acquired AFTER acquiring the physical channel, we will let -* them be NACK:ed with -EBUSY here. The drivers can retry -* the
[CFT 19/31] dmaengine: PL08x: remove waiting descriptor pointer
As we no longer need to pass a descriptor to prep_phy_channel(), we don't need to keep track of the descriptor which is waiting for a channel to become available. So let's get rid of it. Acked-by: Linus Walleij linus.wall...@linaro.org Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/amba-pl08x.c |8 +--- 1 files changed, 1 insertions(+), 7 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index e04ca0b..88661fa 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -223,8 +223,6 @@ enum pl08x_dma_chan_state { * @host: a pointer to the host (internal use) * @state: whether the channel is idle, paused, running etc * @slave: whether this channel is a device (slave) or for memcpy - * @waiting: a TX descriptor on this channel which is waiting for a physical - * channel to become available * @signal: the physical DMA request signal which this channel is using * @mux_use: count of descriptors using this DMA request signal setting */ @@ -243,7 +241,6 @@ struct pl08x_dma_chan { struct pl08x_driver_data *host; enum pl08x_dma_chan_state state; bool slave; - struct pl08x_txd *waiting; int signal; unsigned mux_use; }; @@ -1074,7 +1071,6 @@ static dma_cookie_t pl08x_tx_submit(struct dma_async_tx_descriptor *tx) if (!plchan-slave !plchan-phychan) { /* Do this memcpy whenever there is a channel ready */ plchan-state = PL08X_CHAN_WAITING; - plchan-waiting = txd; } else { plchan-phychan_hold--; } @@ -1696,8 +1692,7 @@ static void pl08x_tasklet(unsigned long data) */ list_for_each_entry(waiting, pl08x-memcpy.channels, chan.device_node) { - if (waiting-state == PL08X_CHAN_WAITING - waiting-waiting != NULL) { + if (waiting-state == PL08X_CHAN_WAITING) { int ret; /* This should REALLY not fail now */ @@ -1705,7 +1700,6 @@ static void pl08x_tasklet(unsigned long data) BUG_ON(ret); waiting-phychan_hold--; waiting-state = PL08X_CHAN_RUNNING; - waiting-waiting = NULL; pl08x_issue_pending(waiting-chan); break; } -- 1.7.4.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 04/11] ARM: OMAP2+: usb_host_fs: add custom reset for usb_host_fs (fsusb)
* Paul Walmsley p...@pwsan.com [120607 03:24]: On Thu, 7 Jun 2012, Tony Lindgren wrote: * Paul Walmsley p...@pwsan.com [120607 00:44]: On Thu, 7 Jun 2012, Tony Lindgren wrote: Here too I think driver like features like this should live in the driver init for omap OHCI driver. In the likely case that FS OHCI is not in use on the board, the OHCI glue can just reset it. What if the driver is not compiled into the kernel, but instead is built as a loadable module? You can still have a core piece of the driver that's always built in, such as omap-ohci-common. But it should live under drivers, not in the bus level code. Or you can insmod/rmmod it to reset things properly. Do you know of any device drivers that do this now, with a core built-in piece separate from a dynamically loadable part? Hmm yeah good point, only driver frameworks tend to do that. It would require the module registering with the core driver. Seems like it would be tricky to avoid linking in the entire driver, due to the symbol dependencies. Either that, or an extra, largely useless, layer of indirection would be needed in the shim layer. Yes probably better approach would be to only build in the reset and idle part of the driver in the minimal case. And that too can get messy as the makefiles may not even be included. Until we have something generic in place to deal with stuff like unused driver reset and idle, how about we set up the driver specific reset parts as inline functions in the driver header? That way the hwmod code can include those functions using the driver register defines. Something like: static inline int xyz_driver_reset(void __iomem *base, int flags) { ... } Then instead of having a separate platform init file for each driver, we could just have a list of reset functions: static int hwmod_xyz_driver_reset(void __iomem *base, int flags) { int res; /* do bus related reset here */ ... /* call the driver reset */ res = xyz_driver_reset(base, flags) /* do more bus related reset here */ ... } Regards, Tony -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT 20/31] dmaengine: PL08x: re-jig the starting of txds
Rather than code the de-queue of the txd several times, move that into the start_txd function. Rename this to better illustrate what it's now doing, and call this function when starting a delayed memcpy(). Acked-by: Linus Walleij linus.wall...@linaro.org Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/amba-pl08x.c | 37 + 1 files changed, 17 insertions(+), 20 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 88661fa..c278d23 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -354,20 +354,25 @@ static int pl08x_phy_channel_busy(struct pl08x_phy_chan *ch) * been set when the LLIs were constructed. Poke them into the hardware * and start the transfer. */ -static void pl08x_start_txd(struct pl08x_dma_chan *plchan, - struct pl08x_txd *txd) +static void pl08x_start_next_txd(struct pl08x_dma_chan *plchan) { struct pl08x_driver_data *pl08x = plchan-host; struct pl08x_phy_chan *phychan = plchan-phychan; - struct pl08x_lli *lli = txd-llis_va[0]; + struct pl08x_lli *lli; + struct pl08x_txd *txd; u32 val; + txd = list_first_entry(plchan-pend_list, struct pl08x_txd, node); + list_del(txd-node); + plchan-at = txd; /* Wait for channel inactive */ while (pl08x_phy_channel_busy(phychan)) cpu_relax(); + lli = txd-llis_va[0]; + dev_vdbg(pl08x-adev-dev, WRITE channel %d: csrc=0x%08x, cdst=0x%08x, clli=0x%08x, cctl=0x%08x, ccfg=0x%08x\n, @@ -1272,15 +1277,8 @@ static void pl08x_issue_pending(struct dma_chan *chan) /* Take the first element in the queue and execute it */ if (!list_empty(plchan-pend_list)) { - struct pl08x_txd *next; - - next = list_first_entry(plchan-pend_list, - struct pl08x_txd, - node); - list_del(next-node); plchan-state = PL08X_CHAN_RUNNING; - - pl08x_start_txd(plchan, next); + pl08x_start_next_txd(plchan); } spin_unlock_irqrestore(plchan-lock, flags); @@ -1661,14 +1659,7 @@ static void pl08x_tasklet(unsigned long data) /* If a new descriptor is queued, set it up plchan-at is NULL here */ if (!list_empty(plchan-pend_list)) { - struct pl08x_txd *next; - - next = list_first_entry(plchan-pend_list, - struct pl08x_txd, - node); - list_del(next-node); - - pl08x_start_txd(plchan, next); + pl08x_start_next_txd(plchan); } else if (plchan-phychan_hold) { /* * This channel is still in use - we have a new txd being @@ -1700,7 +1691,13 @@ static void pl08x_tasklet(unsigned long data) BUG_ON(ret); waiting-phychan_hold--; waiting-state = PL08X_CHAN_RUNNING; - pl08x_issue_pending(waiting-chan); + /* +* Eww. We know this isn't going to deadlock +* but lockdep probably doens't. +*/ + spin_lock(waiting-lock); + pl08x_start_next_txd(waiting); + spin_unlock(waiting-lock); break; } } -- 1.7.4.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 04/11] ARM: OMAP2+: usb_host_fs: add custom reset for usb_host_fs (fsusb)
On Thu, 7 Jun 2012, Cousson, Benoit wrote: In fact we should delay the reset to the very last moment and potentially reset the IPs not under driver control later after a couple of second for example. It will avoid reseting every IP that will be handled properly by drivers. We discussed this a couple of years ago on the list and aligned on late and lazy resets, from my recollection. The main reason why it wasn't implemented was because there were some drivers that were not yet PM runtime-converted. This would have caused crashes, since the core code would have no idea that the non-PM-runtime drivers had initialized their devices, and so the core just went ahead and reset those anyway. It might actually be safe now to switch to the late reset arrangement, depending on whether the rest of the drivers have been PM runtime-converted by now. Of course, it would all be moot if the reset is moved away from the hwmod code into the drivers. - Paul -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT 21/31] dmaengine: PL08x: split the pend_list in two
Our behaviour wasn't correct; issue_pending is supposed to be called before any submitted descriptors are available for processing by the DMA engine. Split the pend_list in two, one for submitted descriptors and another list for issued descriptors. Acked-by: Linus Walleij linus.wall...@linaro.org Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/amba-pl08x.c | 41 - 1 files changed, 28 insertions(+), 13 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index c278d23..b613284 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -217,6 +217,7 @@ enum pl08x_dma_chan_state { * @cd: channel platform data * @runtime_addr: address for RX/TX according to the runtime config * @pend_list: queued transactions pending on this channel + * @issued_list: issued transactions for this channel * @done_list: list of completed transactions * @at: active transaction on this channel * @lock: a lock for this channel data @@ -235,6 +236,7 @@ struct pl08x_dma_chan { const struct pl08x_channel_data *cd; struct dma_slave_config cfg; struct list_head pend_list; + struct list_head issued_list; struct list_head done_list; struct pl08x_txd *at; spinlock_t lock; @@ -362,7 +364,7 @@ static void pl08x_start_next_txd(struct pl08x_dma_chan *plchan) struct pl08x_txd *txd; u32 val; - txd = list_first_entry(plchan-pend_list, struct pl08x_txd, node); + txd = list_first_entry(plchan-issued_list, struct pl08x_txd, node); list_del(txd-node); plchan-at = txd; @@ -525,6 +527,15 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan) } /* Sum up all queued transactions */ + if (!list_empty(plchan-issued_list)) { + struct pl08x_txd *txdi; + list_for_each_entry(txdi, plchan-issued_list, node) { + struct pl08x_sg *dsg; + list_for_each_entry(dsg, txd-dsg_list, node) + bytes += dsg-len; + } + } + if (!list_empty(plchan-pend_list)) { struct pl08x_txd *txdi; list_for_each_entry(txdi, plchan-pend_list, node) { @@ -991,16 +1002,17 @@ static void pl08x_free_txd(struct pl08x_driver_data *pl08x, static void pl08x_free_txd_list(struct pl08x_driver_data *pl08x, struct pl08x_dma_chan *plchan) { - struct pl08x_txd *txdi = NULL; - struct pl08x_txd *next; + LIST_HEAD(head); + struct pl08x_txd *txd; - if (!list_empty(plchan-pend_list)) { - list_for_each_entry_safe(txdi, -next, plchan-pend_list, node) { - pl08x_release_mux(plchan); - list_del(txdi-node); - pl08x_free_txd(pl08x, txdi); - } + list_splice_tail_init(plchan-issued_list, head); + list_splice_tail_init(plchan-pend_list, head); + + while (!list_empty(head)) { + txd = list_first_entry(head, struct pl08x_txd, node); + pl08x_release_mux(plchan); + list_del(txd-node); + pl08x_free_txd(pl08x, txd); } } @@ -1269,6 +1281,8 @@ static void pl08x_issue_pending(struct dma_chan *chan) unsigned long flags; spin_lock_irqsave(plchan-lock, flags); + list_splice_tail_init(plchan-pend_list, plchan-issued_list); + /* Something is already active, or we're waiting for a channel... */ if (plchan-at || plchan-state == PL08X_CHAN_WAITING) { spin_unlock_irqrestore(plchan-lock, flags); @@ -1276,7 +1290,7 @@ static void pl08x_issue_pending(struct dma_chan *chan) } /* Take the first element in the queue and execute it */ - if (!list_empty(plchan-pend_list)) { + if (!list_empty(plchan-issued_list)) { plchan-state = PL08X_CHAN_RUNNING; pl08x_start_next_txd(plchan); } @@ -1658,9 +1672,9 @@ static void pl08x_tasklet(unsigned long data) list_splice_tail_init(plchan-done_list, head); /* If a new descriptor is queued, set it up plchan-at is NULL here */ - if (!list_empty(plchan-pend_list)) { + if (!list_empty(plchan-issued_list)) { pl08x_start_next_txd(plchan); - } else if (plchan-phychan_hold) { + } else if (!list_empty(plchan-pend_list) || plchan-phychan_hold) { /* * This channel is still in use - we have a new txd being * prepared and will soon be queued. Don't give up the @@ -1841,6 +1855,7 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x, spin_lock_init(chan-lock); INIT_LIST_HEAD(chan-pend_list); + INIT_LIST_HEAD(chan-issued_list);
Re: [PATCH] ARM: omap: clock: Get rid of unwanted clkdm assocations within clks
Hi Paul, On Thursday 07 June 2012 12:37 PM, Paul Walmsley wrote: Hi On Thu, 7 Jun 2012, Rajendra Nayak wrote: On Thursday 17 May 2012 03:54 PM, Rajendra Nayak wrote: clkdm assocations with clocks in the clock framework are useful only for 'gate' clocks which have enable/disable ops populated. Get rid of the clkdm_names populated in any other type of clocks. I don't really see the point in changing this before the common clock conversion. The design of most of the current low-level OMAP PM layers was predicated on each clock belonging to a clockdomain. The testing overhead of changing this before the common clock conversion is something that I don't have time for, and almost no one else seems interested in doing. Your common clock conversion moots this patch anyway, right? Yes, I can include this as part of the common clock conversion series. What I was trying to say is that neither the clock framework not any other OMAP PM layer today makes any use of this information except for gate clocks. The only 2 places in the clock framework this is used is in omap2_dflt_clk_enable()/omap2_dflt_clk_disable() functions, which are nops for non gate clocks. So I don;t fully understand what you mean by our current low-level PM design being based on this assumption that every clock belongs to a clockdomain. Did I miss anything else our PM frameworks do with the clock-clkdm association? The reason I am asking is because I am doing a lot of changes around based on this assumption and would really like to know if I am missing something. regards, Rajendra - Paul -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT 22/31] dmaengine: PL08x: start next descriptor from irq context
Rather than waiting for the tasklet to run, we can start the next descriptor from interrupt context, as soon as we know that the previous descriptor has completed. Acked-by: Linus Walleij linus.wall...@linaro.org Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/amba-pl08x.c |9 + 1 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index b613284..30b6921 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -1671,10 +1671,7 @@ static void pl08x_tasklet(unsigned long data) spin_lock_irqsave(plchan-lock, flags); list_splice_tail_init(plchan-done_list, head); - /* If a new descriptor is queued, set it up plchan-at is NULL here */ - if (!list_empty(plchan-issued_list)) { - pl08x_start_next_txd(plchan); - } else if (!list_empty(plchan-pend_list) || plchan-phychan_hold) { + if (plchan-at || !list_empty(plchan-pend_list) || plchan-phychan_hold) { /* * This channel is still in use - we have a new txd being * prepared and will soon be queued. Don't give up the @@ -1786,6 +1783,10 @@ static irqreturn_t pl08x_irq(int irq, void *dev) pl08x_release_mux(plchan); dma_cookie_complete(tx-tx); list_add_tail(tx-node, plchan-done_list); + + /* And start the next descriptor */ + if (!list_empty(plchan-issued_list)) + pl08x_start_next_txd(plchan); } spin_unlock(plchan-lock); -- 1.7.4.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT 23/31] dmaengine: PL08x: rejig physical channel allocation
Rework the physical channel allocation mechanism to only allocate physical channels to virtual channels when they're about to be used. This eliminates all the complexity with holding channels while descriptors are being prepared, which is completely unnecessary. This also brings this driver to a state where the generic virtual DMA code can be used with this driver, and opens up the possibility of properly scheduling and prioritorising physical DMA channels to virtual DMA channels. Acked-by: Linus Walleij linus.wall...@linaro.org Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/amba-pl08x.c | 268 +++--- 1 files changed, 112 insertions(+), 156 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 30b6921..bbae30c 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -210,8 +210,6 @@ enum pl08x_dma_chan_state { * struct pl08x_dma_chan - this structure wraps a DMA ENGINE channel * @chan: wrappped abstract channel * @phychan: the physical channel utilized by this channel, if there is one - * @phychan_hold: if non-zero, hold on to the physical channel even if we - * have no pending entries * @tasklet: tasklet scheduled by the IRQ to handle actual work etc * @name: name of channel * @cd: channel platform data @@ -230,7 +228,6 @@ enum pl08x_dma_chan_state { struct pl08x_dma_chan { struct dma_chan chan; struct pl08x_phy_chan *phychan; - int phychan_hold; struct tasklet_struct tasklet; const char *name; const struct pl08x_channel_data *cd; @@ -587,19 +584,111 @@ pl08x_get_phy_channel(struct pl08x_driver_data *pl08x, return ch; } +/* Mark the physical channel as free. Note, this write is atomic. */ static inline void pl08x_put_phy_channel(struct pl08x_driver_data *pl08x, struct pl08x_phy_chan *ch) { - unsigned long flags; + ch-serving = NULL; +} - spin_lock_irqsave(ch-lock, flags); +/* + * Try to allocate a physical channel. When successful, assign it to + * this virtual channel, and initiate the next descriptor. The + * virtual channel lock must be held at this point. + */ +static void pl08x_phy_alloc_and_start(struct pl08x_dma_chan *plchan) +{ + struct pl08x_driver_data *pl08x = plchan-host; + struct pl08x_phy_chan *ch; - /* Stop the channel and clear its interrupts */ - pl08x_terminate_phy_chan(pl08x, ch); + ch = pl08x_get_phy_channel(pl08x, plchan); + if (!ch) { + dev_dbg(pl08x-adev-dev, no physical channel available for xfer on %s\n, plchan-name); + plchan-state = PL08X_CHAN_WAITING; + return; + } - /* Mark it as free */ - ch-serving = NULL; - spin_unlock_irqrestore(ch-lock, flags); + dev_dbg(pl08x-adev-dev, allocated physical channel %d for xfer on %s\n, + ch-id, plchan-name); + + plchan-phychan = ch; + plchan-state = PL08X_CHAN_RUNNING; + pl08x_start_next_txd(plchan); +} + +static void pl08x_phy_reassign_start(struct pl08x_phy_chan *ch, + struct pl08x_dma_chan *plchan) +{ + struct pl08x_driver_data *pl08x = plchan-host; + + dev_dbg(pl08x-adev-dev, reassigned physical channel %d for xfer on %s\n, + ch-id, plchan-name); + + /* +* We do this without taking the lock; we're really only concerned +* about whether this pointer is NULL or not, and we're guaranteed +* that this will only be called when it _already_ is non-NULL. +*/ + ch-serving = plchan; + plchan-phychan = ch; + plchan-state = PL08X_CHAN_RUNNING; + pl08x_start_next_txd(plchan); +} + +/* + * Free a physical DMA channel, potentially reallocating it to another + * virtual channel if we have any pending. + */ +static void pl08x_phy_free(struct pl08x_dma_chan *plchan) +{ + struct pl08x_driver_data *pl08x = plchan-host; + struct pl08x_dma_chan *p, *next; + + retry: + next = NULL; + + /* Find a waiting virtual channel for the next transfer. */ + list_for_each_entry(p, pl08x-memcpy.channels, chan.device_node) + if (p-state == PL08X_CHAN_WAITING) { + next = p; + break; + } + + if (!next) { + list_for_each_entry(p, pl08x-slave.channels, chan.device_node) + if (p-state == PL08X_CHAN_WAITING) { + next = p; + break; + } + } + + /* Ensure that the physical channel is stopped */ + pl08x_terminate_phy_chan(pl08x, plchan-phychan); + + if (next) { + bool success; + + /* +* Eww. We know this isn't going to deadlock +* but lockdep probably doesn't. +*/ +
[CFT 24/31] dmaengine: PL08x: convert to use virt-dma structs
Convert PL08x to use the virt-dma structures. Acked-by: Linus Walleij linus.wall...@linaro.org Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/amba-pl08x.c | 57 +++-- 1 files changed, 29 insertions(+), 28 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index bbae30c..9a06428 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -86,6 +86,7 @@ #include asm/hardware/pl080.h #include dmaengine.h +#include virt-dma.h #define DRIVER_NAMEpl08xdmac @@ -165,7 +166,7 @@ struct pl08x_sg { /** * struct pl08x_txd - wrapper for struct dma_async_tx_descriptor - * @tx: async tx descriptor + * @vd: virtual DMA descriptor * @node: node for txd list for channels * @dsg_list: list of children sg's * @llis_bus: DMA memory address (physical) start for the LLIs @@ -174,7 +175,7 @@ struct pl08x_sg { * @ccfg: config reg values for current txd */ struct pl08x_txd { - struct dma_async_tx_descriptor tx; + struct virt_dma_desc vd; struct list_head node; struct list_head dsg_list; dma_addr_t llis_bus; @@ -208,7 +209,7 @@ enum pl08x_dma_chan_state { /** * struct pl08x_dma_chan - this structure wraps a DMA ENGINE channel - * @chan: wrappped abstract channel + * @vc: wrappped virtual channel * @phychan: the physical channel utilized by this channel, if there is one * @tasklet: tasklet scheduled by the IRQ to handle actual work etc * @name: name of channel @@ -226,7 +227,7 @@ enum pl08x_dma_chan_state { * @mux_use: count of descriptors using this DMA request signal setting */ struct pl08x_dma_chan { - struct dma_chan chan; + struct virt_dma_chan vc; struct pl08x_phy_chan *phychan; struct tasklet_struct tasklet; const char *name; @@ -287,12 +288,12 @@ struct pl08x_driver_data { static inline struct pl08x_dma_chan *to_pl08x_chan(struct dma_chan *chan) { - return container_of(chan, struct pl08x_dma_chan, chan); + return container_of(chan, struct pl08x_dma_chan, vc.chan); } static inline struct pl08x_txd *to_pl08x_txd(struct dma_async_tx_descriptor *tx) { - return container_of(tx, struct pl08x_txd, tx); + return container_of(tx, struct pl08x_txd, vd.tx); } /* @@ -648,14 +649,14 @@ static void pl08x_phy_free(struct pl08x_dma_chan *plchan) next = NULL; /* Find a waiting virtual channel for the next transfer. */ - list_for_each_entry(p, pl08x-memcpy.channels, chan.device_node) + list_for_each_entry(p, pl08x-memcpy.channels, vc.chan.device_node) if (p-state == PL08X_CHAN_WAITING) { next = p; break; } if (!next) { - list_for_each_entry(p, pl08x-slave.channels, chan.device_node) + list_for_each_entry(p, pl08x-slave.channels, vc.chan.device_node) if (p-state == PL08X_CHAN_WAITING) { next = p; break; @@ -1351,9 +1352,9 @@ static struct pl08x_txd *pl08x_get_txd(struct pl08x_dma_chan *plchan, struct pl08x_txd *txd = kzalloc(sizeof(*txd), GFP_NOWAIT); if (txd) { - dma_async_tx_descriptor_init(txd-tx, plchan-chan); - txd-tx.flags = flags; - txd-tx.tx_submit = pl08x_tx_submit; + dma_async_tx_descriptor_init(txd-vd.tx, plchan-vc.chan); + txd-vd.tx.flags = flags; + txd-vd.tx.tx_submit = pl08x_tx_submit; INIT_LIST_HEAD(txd-node); INIT_LIST_HEAD(txd-dsg_list); @@ -1413,7 +1414,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy( if (ret) return NULL; - return txd-tx; + return txd-vd.tx; } static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( @@ -1529,7 +1530,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( if (ret) return NULL; - return txd-tx; + return txd-vd.tx; } static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, @@ -1630,11 +1631,11 @@ static void pl08x_ensure_on(struct pl08x_driver_data *pl08x) static void pl08x_unmap_buffers(struct pl08x_txd *txd) { - struct device *dev = txd-tx.chan-device-dev; + struct device *dev = txd-vd.tx.chan-device-dev; struct pl08x_sg *dsg; - if (!(txd-tx.flags DMA_COMPL_SKIP_SRC_UNMAP)) { - if (txd-tx.flags DMA_COMPL_SRC_UNMAP_SINGLE) + if (!(txd-vd.tx.flags DMA_COMPL_SKIP_SRC_UNMAP)) { + if (txd-vd.tx.flags DMA_COMPL_SRC_UNMAP_SINGLE) list_for_each_entry(dsg, txd-dsg_list, node) dma_unmap_single(dev, dsg-src_addr, dsg-len, DMA_TO_DEVICE); @@ -1644,8 +1645,8 @@ static void
[CFT 25/31] dmaengine: PL08x: use vchan's spinlock
Initialize the vchan struct, and use the provided spinlock rather than our own. Acked-by: Linus Walleij linus.wall...@linaro.org Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/Kconfig |1 + drivers/dma/amba-pl08x.c | 45 - 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index eb2b60e..be0dc3b 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -53,6 +53,7 @@ config AMBA_PL08X bool ARM PrimeCell PL080 or PL081 support depends on ARM_AMBA EXPERIMENTAL select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS help Platform has a PL08x DMAC device which can provide DMA engine support diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 9a06428..398a5da 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -237,7 +237,6 @@ struct pl08x_dma_chan { struct list_head issued_list; struct list_head done_list; struct pl08x_txd *at; - spinlock_t lock; struct pl08x_driver_data *host; enum pl08x_dma_chan_state state; bool slave; @@ -484,7 +483,7 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan) unsigned long flags; size_t bytes = 0; - spin_lock_irqsave(plchan-lock, flags); + spin_lock_irqsave(plchan-vc.lock, flags); ch = plchan-phychan; txd = plchan-at; @@ -543,7 +542,7 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan) } } - spin_unlock_irqrestore(plchan-lock, flags); + spin_unlock_irqrestore(plchan-vc.lock, flags); return bytes; } @@ -673,12 +672,12 @@ static void pl08x_phy_free(struct pl08x_dma_chan *plchan) * Eww. We know this isn't going to deadlock * but lockdep probably doesn't. */ - spin_lock(next-lock); + spin_lock(next-vc.lock); /* Re-check the state now that we have the lock */ success = next-state == PL08X_CHAN_WAITING; if (success) pl08x_phy_reassign_start(plchan-phychan, next); - spin_unlock(next-lock); + spin_unlock(next-vc.lock); /* If the state changed, try to find another channel */ if (!success) @@ -1125,12 +1124,12 @@ static dma_cookie_t pl08x_tx_submit(struct dma_async_tx_descriptor *tx) unsigned long flags; dma_cookie_t cookie; - spin_lock_irqsave(plchan-lock, flags); + spin_lock_irqsave(plchan-vc.lock, flags); cookie = dma_cookie_assign(tx); /* Put this onto the pending list */ list_add_tail(txd-node, plchan-pend_list); - spin_unlock_irqrestore(plchan-lock, flags); + spin_unlock_irqrestore(plchan-vc.lock, flags); return cookie; } @@ -1318,13 +1317,13 @@ static void pl08x_issue_pending(struct dma_chan *chan) struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); unsigned long flags; - spin_lock_irqsave(plchan-lock, flags); + spin_lock_irqsave(plchan-vc.lock, flags); list_splice_tail_init(plchan-pend_list, plchan-issued_list); if (!list_empty(plchan-issued_list)) { if (!plchan-phychan plchan-state != PL08X_CHAN_WAITING) pl08x_phy_alloc_and_start(plchan); } - spin_unlock_irqrestore(plchan-lock, flags); + spin_unlock_irqrestore(plchan-vc.lock, flags); } static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, @@ -1337,9 +1336,9 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, if (!num_llis) { unsigned long flags; - spin_lock_irqsave(plchan-lock, flags); + spin_lock_irqsave(plchan-vc.lock, flags); pl08x_free_txd(pl08x, txd); - spin_unlock_irqrestore(plchan-lock, flags); + spin_unlock_irqrestore(plchan-vc.lock, flags); return -EINVAL; } @@ -1551,9 +1550,9 @@ static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, * Anything succeeds on channels with no physical allocation and * no queued transfers. */ - spin_lock_irqsave(plchan-lock, flags); + spin_lock_irqsave(plchan-vc.lock, flags); if (!plchan-phychan !plchan-at) { - spin_unlock_irqrestore(plchan-lock, flags); + spin_unlock_irqrestore(plchan-vc.lock, flags); return 0; } @@ -1592,7 +1591,7 @@ static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, break; } - spin_unlock_irqrestore(plchan-lock, flags); + spin_unlock_irqrestore(plchan-vc.lock, flags); return ret; } @@ -1664,9 +1663,9 @@ static void
[CFT 26/31] dmaengine: PL08x: convert to use vchan submitted/issued lists
Convert to use the virtual dma channel submitted/issued descriptor lists rather than our own private lists, and use the virtual dma channel support functions to manage these lists. Acked-by: Linus Walleij linus.wall...@linaro.org Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/amba-pl08x.c | 64 - 1 files changed, 17 insertions(+), 47 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 398a5da..5333a91 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -215,8 +215,6 @@ enum pl08x_dma_chan_state { * @name: name of channel * @cd: channel platform data * @runtime_addr: address for RX/TX according to the runtime config - * @pend_list: queued transactions pending on this channel - * @issued_list: issued transactions for this channel * @done_list: list of completed transactions * @at: active transaction on this channel * @lock: a lock for this channel data @@ -233,8 +231,6 @@ struct pl08x_dma_chan { const char *name; const struct pl08x_channel_data *cd; struct dma_slave_config cfg; - struct list_head pend_list; - struct list_head issued_list; struct list_head done_list; struct pl08x_txd *at; struct pl08x_driver_data *host; @@ -357,12 +353,12 @@ static void pl08x_start_next_txd(struct pl08x_dma_chan *plchan) { struct pl08x_driver_data *pl08x = plchan-host; struct pl08x_phy_chan *phychan = plchan-phychan; + struct virt_dma_desc *vd = vchan_next_desc(plchan-vc); + struct pl08x_txd *txd = to_pl08x_txd(vd-tx); struct pl08x_lli *lli; - struct pl08x_txd *txd; u32 val; - txd = list_first_entry(plchan-issued_list, struct pl08x_txd, node); - list_del(txd-node); + list_del(txd-vd.node); plchan-at = txd; @@ -524,18 +520,18 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan) } /* Sum up all queued transactions */ - if (!list_empty(plchan-issued_list)) { + if (!list_empty(plchan-vc.desc_issued)) { struct pl08x_txd *txdi; - list_for_each_entry(txdi, plchan-issued_list, node) { + list_for_each_entry(txdi, plchan-vc.desc_issued, vd.node) { struct pl08x_sg *dsg; list_for_each_entry(dsg, txd-dsg_list, node) bytes += dsg-len; } } - if (!list_empty(plchan-pend_list)) { + if (!list_empty(plchan-vc.desc_submitted)) { struct pl08x_txd *txdi; - list_for_each_entry(txdi, plchan-pend_list, node) { + list_for_each_entry(txdi, plchan-vc.desc_submitted, vd.node) { struct pl08x_sg *dsg; list_for_each_entry(dsg, txd-dsg_list, node) bytes += dsg-len; @@ -1094,13 +1090,12 @@ static void pl08x_free_txd_list(struct pl08x_driver_data *pl08x, LIST_HEAD(head); struct pl08x_txd *txd; - list_splice_tail_init(plchan-issued_list, head); - list_splice_tail_init(plchan-pend_list, head); + vchan_get_all_descriptors(plchan-vc, head); while (!list_empty(head)) { - txd = list_first_entry(head, struct pl08x_txd, node); + txd = list_first_entry(head, struct pl08x_txd, vd.node); pl08x_release_mux(plchan); - list_del(txd-node); + list_del(txd-vd.node); pl08x_free_txd(pl08x, txd); } } @@ -1117,23 +1112,6 @@ static void pl08x_free_chan_resources(struct dma_chan *chan) { } -static dma_cookie_t pl08x_tx_submit(struct dma_async_tx_descriptor *tx) -{ - struct pl08x_dma_chan *plchan = to_pl08x_chan(tx-chan); - struct pl08x_txd *txd = to_pl08x_txd(tx); - unsigned long flags; - dma_cookie_t cookie; - - spin_lock_irqsave(plchan-vc.lock, flags); - cookie = dma_cookie_assign(tx); - - /* Put this onto the pending list */ - list_add_tail(txd-node, plchan-pend_list); - spin_unlock_irqrestore(plchan-vc.lock, flags); - - return cookie; -} - static struct dma_async_tx_descriptor *pl08x_prep_dma_interrupt( struct dma_chan *chan, unsigned long flags) { @@ -1318,8 +1296,7 @@ static void pl08x_issue_pending(struct dma_chan *chan) unsigned long flags; spin_lock_irqsave(plchan-vc.lock, flags); - list_splice_tail_init(plchan-pend_list, plchan-issued_list); - if (!list_empty(plchan-issued_list)) { + if (vchan_issue_pending(plchan-vc)) { if (!plchan-phychan plchan-state != PL08X_CHAN_WAITING) pl08x_phy_alloc_and_start(plchan); } @@ -1345,16 +1322,11 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, return 0; } -static struct pl08x_txd
[CFT 29/31] dmaengine: PL08x: get rid of pl08x_prep_channel_resources
This function is now unnecessary; we can move its internals inline instead. Acked-by: Linus Walleij linus.wall...@linaro.org Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/amba-pl08x.c | 32 +--- 1 files changed, 9 insertions(+), 23 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index c42c7ef..9297240 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -1352,25 +1352,6 @@ static void pl08x_issue_pending(struct dma_chan *chan) spin_unlock_irqrestore(plchan-vc.lock, flags); } -static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, - struct pl08x_txd *txd) -{ - struct pl08x_driver_data *pl08x = plchan-host; - int num_llis; - - num_llis = pl08x_fill_llis_for_desc(pl08x, txd); - if (!num_llis) { - unsigned long flags; - - spin_lock_irqsave(plchan-vc.lock, flags); - pl08x_free_txd(pl08x, txd); - spin_unlock_irqrestore(plchan-vc.lock, flags); - - return -EINVAL; - } - return 0; -} - static struct pl08x_txd *pl08x_get_txd(struct pl08x_dma_chan *plchan) { struct pl08x_txd *txd = kzalloc(sizeof(*txd), GFP_NOWAIT); @@ -1430,9 +1411,11 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy( txd-cctl |= pl08x_select_bus(pl08x-mem_buses, pl08x-mem_buses); - ret = pl08x_prep_channel_resources(plchan, txd); - if (ret) + ret = pl08x_fill_llis_for_desc(plchan-host, txd); + if (!ret) { + pl08x_free_txd(pl08x, txd); return NULL; + } return vchan_tx_prep(plchan-vc, txd-vd, flags); } @@ -1546,9 +1529,12 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( } } - ret = pl08x_prep_channel_resources(plchan, txd); - if (ret) + ret = pl08x_fill_llis_for_desc(plchan-host, txd); + if (!ret) { + pl08x_release_mux(plchan); + pl08x_free_txd(pl08x, txd); return NULL; + } return vchan_tx_prep(plchan-vc, txd-vd, flags); } -- 1.7.4.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT 30/31] dmaengine: PL08x: get rid of write only pool_ctr and free_txd locking
The free function says the pl08x lock should be taken before calling it. However, the DMA pool allocation/freeing is already properly locked. The only thing that would need this is pool_ctr, which happens to be a write-only variable. Let's get rid of this, and eliminate any need for additional locking here. Acked-by: Linus Walleij linus.wall...@linaro.org Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/amba-pl08x.c | 12 1 files changed, 0 insertions(+), 12 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 9297240..a5d85b1 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -247,7 +247,6 @@ struct pl08x_dma_chan { * @pd: platform data passed in from the platform/machine * @phy_chans: array of data for the physical channels * @pool: a pool for the LLI descriptors - * @pool_ctr: counter of LLIs in the pool * @lli_buses: bitmask to or in to LLI pointer selecting AHB port for LLI * fetches * @mem_buses: set to indicate memory transfers on AHB2. @@ -262,7 +261,6 @@ struct pl08x_driver_data { struct pl08x_platform_data *pd; struct pl08x_phy_chan *phy_chans; struct dma_pool *pool; - int pool_ctr; u8 lli_buses; u8 mem_buses; }; @@ -821,8 +819,6 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, return 0; } - pl08x-pool_ctr++; - bd.txd = txd; bd.lli_bus = (pl08x-lli_buses PL08X_AHB2) ? PL080_LLI_LM_AHB2 : 0; cctl = txd-cctl; @@ -1038,18 +1034,14 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, return num_llis; } -/* You should call this with the struct pl08x lock held */ static void pl08x_free_txd(struct pl08x_driver_data *pl08x, struct pl08x_txd *txd) { struct pl08x_sg *dsg, *_dsg; - /* Free the LLI */ if (txd-llis_va) dma_pool_free(pl08x-pool, txd-llis_va, txd-llis_bus); - pl08x-pool_ctr--; - list_for_each_entry_safe(dsg, _dsg, txd-dsg_list, node) { list_del(dsg-node); kfree(dsg); @@ -1090,8 +1082,6 @@ static void pl08x_desc_free(struct virt_dma_desc *vd) { struct pl08x_txd *txd = to_pl08x_txd(vd-tx); struct pl08x_dma_chan *plchan = to_pl08x_chan(vd-tx.chan); - struct pl08x_driver_data *pl08x = plchan-host; - unsigned long flags; if (!plchan-slave) pl08x_unmap_buffers(txd); @@ -1099,9 +1089,7 @@ static void pl08x_desc_free(struct virt_dma_desc *vd) if (!txd-done) pl08x_release_mux(plchan); - spin_lock_irqsave(pl08x-lock, flags); pl08x_free_txd(plchan-host, txd); - spin_unlock_irqrestore(pl08x-lock, flags); } static void pl08x_free_txd_list(struct pl08x_driver_data *pl08x, -- 1.7.4.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT 28/31] dmaengine: PL08x: fix tx_status function to return correct residue
Now that we're converted to use the generic vchan support, we can fix the residue return from tx_status to be compliant with dmaengine. This returns the number of bytes remaining for the _specified_ cookie, not the number of bytes in all pending transfers on the channel. Acked-by: Linus Walleij linus.wall...@linaro.org Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/amba-pl08x.c | 61 + 1 files changed, 34 insertions(+), 27 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 6a35e37..c42c7ef 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -473,10 +473,8 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan) { struct pl08x_phy_chan *ch; struct pl08x_txd *txd; - unsigned long flags; size_t bytes = 0; - spin_lock_irqsave(plchan-vc.lock, flags); ch = plchan-phychan; txd = plchan-at; @@ -516,27 +514,6 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan) } } - /* Sum up all queued transactions */ - if (!list_empty(plchan-vc.desc_issued)) { - struct pl08x_txd *txdi; - list_for_each_entry(txdi, plchan-vc.desc_issued, vd.node) { - struct pl08x_sg *dsg; - list_for_each_entry(dsg, txd-dsg_list, node) - bytes += dsg-len; - } - } - - if (!list_empty(plchan-vc.desc_submitted)) { - struct pl08x_txd *txdi; - list_for_each_entry(txdi, plchan-vc.desc_submitted, vd.node) { - struct pl08x_sg *dsg; - list_for_each_entry(dsg, txd-dsg_list, node) - bytes += dsg-len; - } - } - - spin_unlock_irqrestore(plchan-vc.lock, flags); - return bytes; } @@ -1171,23 +1148,53 @@ static enum dma_status pl08x_dma_tx_status(struct dma_chan *chan, dma_cookie_t cookie, struct dma_tx_state *txstate) { struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); + struct virt_dma_desc *vd; + unsigned long flags; enum dma_status ret; + size_t bytes = 0; ret = dma_cookie_status(chan, cookie, txstate); if (ret == DMA_SUCCESS) return ret; /* +* There's no point calculating the residue if there's +* no txstate to store the value. +*/ + if (!txstate) { + if (plchan-state == PL08X_CHAN_PAUSED) + ret = DMA_PAUSED; + return ret; + } + + spin_lock_irqsave(plchan-vc.lock, flags); + ret = dma_cookie_status(chan, cookie, txstate); + if (ret != DMA_SUCCESS) { + vd = vchan_find_desc(plchan-vc, cookie); + if (vd) { + /* On the issued list, so hasn't been processed yet */ + struct pl08x_txd *txd = to_pl08x_txd(vd-tx); + struct pl08x_sg *dsg; + + list_for_each_entry(dsg, txd-dsg_list, node) + bytes += dsg-len; + } else { + bytes = pl08x_getbytes_chan(plchan); + } + } + spin_unlock_irqrestore(plchan-vc.lock, flags); + + /* * This cookie not complete yet * Get number of bytes left in the active transactions and queue */ - dma_set_residue(txstate, pl08x_getbytes_chan(plchan)); + dma_set_residue(txstate, bytes); - if (plchan-state == PL08X_CHAN_PAUSED) - return DMA_PAUSED; + if (plchan-state == PL08X_CHAN_PAUSED ret == DMA_IN_PROGRESS) + ret = DMA_PAUSED; /* Whether waiting or running, we're in progress */ - return DMA_IN_PROGRESS; + return ret; } /* PrimeCell DMA extension */ -- 1.7.4.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT 31/31] dmaengine: PL08x: ensure all descriptors are freed when channel is released
Ensure all queued descriptors are freed when the channel is released, ensuring we don't leak memory Acked-by: Linus Walleij linus.wall...@linaro.org Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/amba-pl08x.c |2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index a5d85b1..6fbeebb 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -1117,6 +1117,8 @@ static int pl08x_alloc_chan_resources(struct dma_chan *chan) static void pl08x_free_chan_resources(struct dma_chan *chan) { + /* Ensure all queued descriptors are freed */ + vchan_free_chan_resources(to_virt_chan(chan)); } static struct dma_async_tx_descriptor *pl08x_prep_dma_interrupt( -- 1.7.4.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT] OMAP patches
And the last set - the OMAP patches. Documentation/feature-removal-schedule.txt | 11 + arch/arm/mach-omap1/board-h2-mmc.c |1 - arch/arm/mach-omap1/board-h3-mmc.c |1 - arch/arm/mach-omap1/board-nokia770.c |1 - arch/arm/mach-omap2/board-n8x0.c |1 - arch/arm/mach-omap2/hsmmc.c|1 - arch/arm/plat-omap/include/plat/mmc.h |2 - drivers/dma/Kconfig|6 + drivers/dma/Makefile |1 + drivers/dma/omap-dma.c | 522 drivers/mmc/host/omap.c| 368 +--- drivers/mmc/host/omap_hsmmc.c | 202 ++-- drivers/mtd/nand/omap2.c | 106 +++--- drivers/spi/spi-omap2-mcspi.c | 229 +++-- include/linux/omap-dma.h | 24 ++ 15 files changed, 1010 insertions(+), 466 deletions(-) -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT 01/11] dmaengine: add OMAP DMA engine driver
Tested-by: Tony Lindgren t...@atomide.com Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/Kconfig |6 + drivers/dma/Makefile |1 + drivers/dma/omap-dma.c | 522 ++ include/linux/omap-dma.h | 24 ++ 4 files changed, 553 insertions(+), 0 deletions(-) create mode 100644 drivers/dma/omap-dma.c create mode 100644 include/linux/omap-dma.h diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index eb2b60e..8be3bf6 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -261,6 +261,12 @@ config DMA_SA11X0 SA-1110 SoCs. This DMA engine can only be used with on-chip devices. +config DMA_OMAP + tristate OMAP DMA support + depends on ARCH_OMAP + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + config DMA_ENGINE bool diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index fc05f7d..ddc291a 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -29,3 +29,4 @@ obj-$(CONFIG_PCH_DMA) += pch_dma.o obj-$(CONFIG_AMBA_PL08X) += amba-pl08x.o obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o +obj-$(CONFIG_DMA_OMAP) += omap-dma.o diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c new file mode 100644 index 000..500bc71 --- /dev/null +++ b/drivers/dma/omap-dma.c @@ -0,0 +1,522 @@ +/* + * OMAP DMAengine support + * + * 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. + */ +#include linux/dmaengine.h +#include linux/dma-mapping.h +#include linux/err.h +#include linux/init.h +#include linux/interrupt.h +#include linux/list.h +#include linux/module.h +#include linux/omap-dma.h +#include linux/platform_device.h +#include linux/slab.h +#include linux/spinlock.h + +#include virt-dma.h +#include plat/dma.h + +struct omap_dmadev { + struct dma_device ddev; + spinlock_t lock; + struct tasklet_struct task; + struct list_head pending; +}; + +struct omap_chan { + struct virt_dma_chan vc; + struct list_head node; + + struct dma_slave_config cfg; + unsigned dma_sig; + + int dma_ch; + struct omap_desc *desc; + unsigned sgidx; +}; + +struct omap_sg { + dma_addr_t addr; + uint32_t en;/* number of elements (24-bit) */ + uint32_t fn;/* number of frames (16-bit) */ +}; + +struct omap_desc { + struct virt_dma_desc vd; + enum dma_transfer_direction dir; + dma_addr_t dev_addr; + + uint8_t es; /* element size */ + uint8_t sync_mode; /* OMAP_DMA_SYNC_xxx */ + uint8_t sync_type; /* OMAP_DMA_xxx_SYNC* */ + uint8_t periph_port;/* Peripheral port */ + + unsigned sglen; + struct omap_sg sg[0]; +}; + +static inline struct omap_dmadev *to_omap_dma_dev(struct dma_device *d) +{ + return container_of(d, struct omap_dmadev, ddev); +} + +static inline struct omap_chan *to_omap_dma_chan(struct dma_chan *c) +{ + return container_of(c, struct omap_chan, vc.chan); +} + +static inline struct omap_desc *to_omap_dma_desc(struct dma_async_tx_descriptor *t) +{ + return container_of(t, struct omap_desc, vd.tx); +} + +static void omap_dma_desc_free(struct virt_dma_desc *vd) +{ + kfree(container_of(vd, struct omap_desc, vd)); +} + +static void omap_dma_start_sg(struct omap_chan *c, struct omap_desc *d, + unsigned idx) +{ + struct omap_sg *sg = d-sg + idx; + + if (d-dir == DMA_DEV_TO_MEM) + omap_set_dma_dest_params(c-dma_ch, OMAP_DMA_PORT_EMIFF, + OMAP_DMA_AMODE_POST_INC, sg-addr, 0, 0); + else + omap_set_dma_src_params(c-dma_ch, OMAP_DMA_PORT_EMIFF, + OMAP_DMA_AMODE_POST_INC, sg-addr, 0, 0); + + omap_set_dma_transfer_params(c-dma_ch, d-es, sg-en, sg-fn, + d-sync_mode, c-dma_sig, d-sync_type); + + omap_start_dma(c-dma_ch); +} + +static void omap_dma_start_desc(struct omap_chan *c) +{ + struct virt_dma_desc *vd = vchan_next_desc(c-vc); + struct omap_desc *d; + + if (!vd) { + c-desc = NULL; + return; + } + + list_del(vd-node); + + c-desc = d = to_omap_dma_desc(vd-tx); + c-sgidx = 0; + + if (d-dir == DMA_DEV_TO_MEM) + omap_set_dma_src_params(c-dma_ch, d-periph_port, + OMAP_DMA_AMODE_CONSTANT, d-dev_addr, 0, 0); + else + omap_set_dma_dest_params(c-dma_ch, d-periph_port, + OMAP_DMA_AMODE_CONSTANT, d-dev_addr, 0, 0); + + omap_dma_start_sg(c, d, 0); +} + +static void omap_dma_callback(int ch, u16 status, void *data) +{ + struct omap_chan *c = data; + struct omap_desc *d; + unsigned long flags; + +
[CFT 02/11] mmc: omap_hsmmc: add DMA engine support
Add DMA engine support to the OMAP HSMMC driver. This supplements the private DMA API implementation contained within this driver, and the driver can be switched at build time between using DMA engine and the private DMA API. Tested-by: Grazvydas Ignotas nota...@gmail.com Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/mmc/host/omap_hsmmc.c | 192 +++-- 1 files changed, 165 insertions(+), 27 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 9a7a60a..f80361f 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -19,6 +19,7 @@ #include linux/init.h #include linux/kernel.h #include linux/debugfs.h +#include linux/dmaengine.h #include linux/seq_file.h #include linux/interrupt.h #include linux/delay.h @@ -167,7 +168,9 @@ struct omap_hsmmc_host { u32 bytesleft; int suspended; int irq; - int use_dma, dma_ch; + int use_dma, dma_ch, dma2; + struct dma_chan *tx_chan; + struct dma_chan *rx_chan; int dma_line_tx, dma_line_rx; int slot_id; int response_busy; @@ -802,19 +805,26 @@ omap_hsmmc_get_dma_dir(struct omap_hsmmc_host *host, struct mmc_data *data) return DMA_FROM_DEVICE; } +static struct dma_chan *omap_hsmmc_get_dma_chan(struct omap_hsmmc_host *host, + struct mmc_data *data) +{ + return data-flags MMC_DATA_WRITE ? host-tx_chan : host-rx_chan; +} + static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_request *mrq) { - int dma_ch; + int dma_ch, dma2; unsigned long flags; spin_lock_irqsave(host-irq_lock, flags); host-req_in_progress = 0; dma_ch = host-dma_ch; + dma2 = host-dma2; spin_unlock_irqrestore(host-irq_lock, flags); omap_hsmmc_disable_irq(host); /* Do not complete the request if DMA is still in progress */ - if (mrq-data host-use_dma dma_ch != -1) + if (mrq-data host-use_dma (dma_ch != -1 || dma2 != -1)) return; host-mrq = NULL; mmc_request_done(host-mmc, mrq); @@ -886,7 +896,7 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd) */ static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno) { - int dma_ch; + int dma_ch, dma2; unsigned long flags; host-data-error = errno; @@ -894,8 +904,20 @@ static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno) spin_lock_irqsave(host-irq_lock, flags); dma_ch = host-dma_ch; host-dma_ch = -1; + dma2 = host-dma2; + host-dma2 = -1; spin_unlock_irqrestore(host-irq_lock, flags); + if (host-use_dma dma2 != -1) { + struct dma_chan *chan = omap_hsmmc_get_dma_chan(host, host-data); + + dmaengine_terminate_all(chan); + dma_unmap_sg(chan-device-dev, + host-data-sg, host-data-sg_len, + omap_hsmmc_get_dma_dir(host, host-data)); + + host-data-host_cookie = 0; + } if (host-use_dma dma_ch != -1) { dma_unmap_sg(mmc_dev(host-mmc), host-data-sg, host-data-sg_len, @@ -1292,9 +1314,43 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data) } } +static void omap_hsmmc_dma_callback(void *param) +{ + struct omap_hsmmc_host *host = param; + struct dma_chan *chan; + struct mmc_data *data; + int req_in_progress; + + spin_lock_irq(host-irq_lock); + if (host-dma2 0) { + spin_unlock_irq(host-irq_lock); + return; + } + + data = host-mrq-data; + chan = omap_hsmmc_get_dma_chan(host, data); + if (!data-host_cookie) + dma_unmap_sg(chan-device-dev, +data-sg, data-sg_len, +omap_hsmmc_get_dma_dir(host, data)); + + req_in_progress = host-req_in_progress; + host-dma2 = -1; + spin_unlock_irq(host-irq_lock); + + /* If DMA has finished after TC, complete the request */ + if (!req_in_progress) { + struct mmc_request *mrq = host-mrq; + + host-mrq = NULL; + mmc_request_done(host-mmc, mrq); + } +} + static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host, struct mmc_data *data, - struct omap_hsmmc_next *next) + struct omap_hsmmc_next *next, + struct device *dev) { int dma_len; @@ -1309,8 +1365,7 @@ static int
[CFT 03/11] mmc: omap_hsmmc: remove private DMA API implementation
Remove the private DMA API implementation from omap_hsmmc, making it use entirely the DMA engine API. Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/mmc/host/omap_hsmmc.c | 265 ++--- 1 files changed, 64 insertions(+), 201 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index f80361f..9504092 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -38,7 +38,6 @@ #include linux/gpio.h #include linux/regulator/consumer.h #include linux/pm_runtime.h -#include plat/dma.h #include mach/hardware.h #include plat/board.h #include plat/mmc.h @@ -168,10 +167,9 @@ struct omap_hsmmc_host { u32 bytesleft; int suspended; int irq; - int use_dma, dma_ch, dma2; + int use_dma, dma_ch; struct dma_chan *tx_chan; struct dma_chan *rx_chan; - int dma_line_tx, dma_line_rx; int slot_id; int response_busy; int context_loss; @@ -813,18 +811,17 @@ static struct dma_chan *omap_hsmmc_get_dma_chan(struct omap_hsmmc_host *host, static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_request *mrq) { - int dma_ch, dma2; + int dma_ch; unsigned long flags; spin_lock_irqsave(host-irq_lock, flags); host-req_in_progress = 0; dma_ch = host-dma_ch; - dma2 = host-dma2; spin_unlock_irqrestore(host-irq_lock, flags); omap_hsmmc_disable_irq(host); /* Do not complete the request if DMA is still in progress */ - if (mrq-data host-use_dma (dma_ch != -1 || dma2 != -1)) + if (mrq-data host-use_dma dma_ch != -1) return; host-mrq = NULL; mmc_request_done(host-mmc, mrq); @@ -896,7 +893,7 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd) */ static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno) { - int dma_ch, dma2; + int dma_ch; unsigned long flags; host-data-error = errno; @@ -904,11 +901,9 @@ static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno) spin_lock_irqsave(host-irq_lock, flags); dma_ch = host-dma_ch; host-dma_ch = -1; - dma2 = host-dma2; - host-dma2 = -1; spin_unlock_irqrestore(host-irq_lock, flags); - if (host-use_dma dma2 != -1) { + if (host-use_dma dma_ch != -1) { struct dma_chan *chan = omap_hsmmc_get_dma_chan(host, host-data); dmaengine_terminate_all(chan); @@ -918,13 +913,6 @@ static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno) host-data-host_cookie = 0; } - if (host-use_dma dma_ch != -1) { - dma_unmap_sg(mmc_dev(host-mmc), host-data-sg, - host-data-sg_len, - omap_hsmmc_get_dma_dir(host, host-data)); - omap_free_dma(dma_ch); - host-data-host_cookie = 0; - } host-data = NULL; } @@ -1220,100 +1208,6 @@ static irqreturn_t omap_hsmmc_detect(int irq, void *dev_id) return IRQ_HANDLED; } -static int omap_hsmmc_get_dma_sync_dev(struct omap_hsmmc_host *host, -struct mmc_data *data) -{ - int sync_dev; - - if (data-flags MMC_DATA_WRITE) - sync_dev = host-dma_line_tx; - else - sync_dev = host-dma_line_rx; - return sync_dev; -} - -static void omap_hsmmc_config_dma_params(struct omap_hsmmc_host *host, - struct mmc_data *data, - struct scatterlist *sgl) -{ - int blksz, nblk, dma_ch; - - dma_ch = host-dma_ch; - if (data-flags MMC_DATA_WRITE) { - omap_set_dma_dest_params(dma_ch, 0, OMAP_DMA_AMODE_CONSTANT, - (host-mapbase + OMAP_HSMMC_DATA), 0, 0); - omap_set_dma_src_params(dma_ch, 0, OMAP_DMA_AMODE_POST_INC, - sg_dma_address(sgl), 0, 0); - } else { - omap_set_dma_src_params(dma_ch, 0, OMAP_DMA_AMODE_CONSTANT, - (host-mapbase + OMAP_HSMMC_DATA), 0, 0); - omap_set_dma_dest_params(dma_ch, 0, OMAP_DMA_AMODE_POST_INC, - sg_dma_address(sgl), 0, 0); - } - - blksz = host-data-blksz; - nblk = sg_dma_len(sgl) / blksz; - - omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S32, - blksz / 4, nblk, OMAP_DMA_SYNC_FRAME, - omap_hsmmc_get_dma_sync_dev(host, data), - !(data-flags MMC_DATA_WRITE)); - - omap_start_dma(dma_ch); -} -
[CFT 04/11] mmc: omap: add DMA engine support
Add DMA engine support to the OMAP driver. This supplements the private DMA API implementation contained within this driver, and the driver can be switched at build time between using DMA engine and the private DMA API. Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/mmc/host/omap.c | 199 ++-- drivers/mmc/host/omap_hsmmc.c |3 +- 2 files changed, 190 insertions(+), 12 deletions(-) diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 552196c..eaea251 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -17,10 +17,12 @@ #include linux/ioport.h #include linux/platform_device.h #include linux/interrupt.h +#include linux/dmaengine.h #include linux/dma-mapping.h #include linux/delay.h #include linux/spinlock.h #include linux/timer.h +#include linux/omap-dma.h #include linux/mmc/host.h #include linux/mmc/card.h #include linux/clk.h @@ -99,6 +101,8 @@ struct mmc_omap_host; +#define USE_DMA_PRIVATE + struct mmc_omap_slot { int id; unsigned intvdd; @@ -128,6 +132,10 @@ struct mmc_omap_host { unsigned char id; /* 16xx chips have 2 MMC blocks */ struct clk *iclk; struct clk *fclk; + struct dma_chan *dma_rx; + u32 dma_rx_burst; + struct dma_chan *dma_tx; + u32 dma_tx_burst; struct resource *mem_res; void __iomem*virt_base; unsigned intphys_base; @@ -153,12 +161,14 @@ struct mmc_omap_host { unsigneduse_dma:1; unsignedbrs_received:1, dma_done:1; - unsigneddma_is_read:1; unsigneddma_in_use:1; +#ifdef USE_DMA_PRIVATE + unsigneddma_is_read:1; int dma_ch; - spinlock_t dma_lock; struct timer_list dma_timer; unsigneddma_len; +#endif + spinlock_t dma_lock; struct mmc_omap_slot*slots[OMAP_MMC_MAX_SLOTS]; struct mmc_omap_slot*current_slot; @@ -406,18 +416,32 @@ mmc_omap_release_dma(struct mmc_omap_host *host, struct mmc_data *data, int abort) { enum dma_data_direction dma_data_dir; + struct device *dev = mmc_dev(host-mmc); + struct dma_chan *c; +#ifdef USE_DMA_PRIVATE BUG_ON(host-dma_ch 0); if (data-error) omap_stop_dma(host-dma_ch); /* Release DMA channel lazily */ mod_timer(host-dma_timer, jiffies + HZ); - if (data-flags MMC_DATA_WRITE) +#endif + if (data-flags MMC_DATA_WRITE) { dma_data_dir = DMA_TO_DEVICE; - else + c = host-dma_tx; + } else { dma_data_dir = DMA_FROM_DEVICE; - dma_unmap_sg(mmc_dev(host-mmc), data-sg, host-sg_len, -dma_data_dir); + c = host-dma_rx; + } + if (c) { + if (data-error) { + dmaengine_terminate_all(c); + /* Claim nothing transferred on error... */ + data-bytes_xfered = 0; + } + dev = c-device-dev; + } + dma_unmap_sg(dev, data-sg, host-sg_len, dma_data_dir); } static void mmc_omap_send_stop_work(struct work_struct *work) @@ -524,6 +548,7 @@ mmc_omap_end_of_data(struct mmc_omap_host *host, struct mmc_data *data) mmc_omap_xfer_done(host, data); } +#ifdef USE_DMA_PRIVATE static void mmc_omap_dma_timer(unsigned long data) { @@ -533,6 +558,7 @@ mmc_omap_dma_timer(unsigned long data) omap_free_dma(host-dma_ch); host-dma_ch = -1; } +#endif static void mmc_omap_dma_done(struct mmc_omap_host *host, struct mmc_data *data) @@ -891,6 +917,18 @@ static void mmc_omap_cover_handler(unsigned long param) jiffies + msecs_to_jiffies(OMAP_MMC_COVER_POLL_DELAY)); } +static void mmc_omap_dma_callback(void *priv) +{ + struct mmc_omap_host *host = priv; + struct mmc_data *data = host-data; + + /* If we got to the end of DMA, assume everything went well */ + data-bytes_xfered += data-blocks * data-blksz; + + mmc_omap_dma_done(host, data); +} + +#ifdef USE_DMA_PRIVATE /* Prepare to transfer the next segment of a scatterlist */ static void mmc_omap_prepare_dma(struct mmc_omap_host *host, struct mmc_data *data) @@ -1045,6 +1083,7 @@ static int mmc_omap_get_dma_channel(struct mmc_omap_host *host, struct mmc_data return 0; } +#endif static inline void set_cmd_timeout(struct mmc_omap_host *host, struct mmc_request *req) { @@ -1118,6 +1157,80 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req) host-sg_idx = 0; if (use_dma) { +
[CFT 05/11] mmc: omap: remove private DMA API implementation
Remove the private DMA API implementation from omap, making it use entirely the DMA engine API. Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/mmc/host/omap.c | 235 +- 1 files changed, 6 insertions(+), 229 deletions(-) diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index eaea251..4026392 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -101,8 +101,6 @@ struct mmc_omap_host; -#define USE_DMA_PRIVATE - struct mmc_omap_slot { int id; unsigned intvdd; @@ -162,12 +160,6 @@ struct mmc_omap_host { unsigneduse_dma:1; unsignedbrs_received:1, dma_done:1; unsigneddma_in_use:1; -#ifdef USE_DMA_PRIVATE - unsigneddma_is_read:1; - int dma_ch; - struct timer_list dma_timer; - unsigneddma_len; -#endif spinlock_t dma_lock; struct mmc_omap_slot*slots[OMAP_MMC_MAX_SLOTS]; @@ -419,13 +411,6 @@ mmc_omap_release_dma(struct mmc_omap_host *host, struct mmc_data *data, struct device *dev = mmc_dev(host-mmc); struct dma_chan *c; -#ifdef USE_DMA_PRIVATE - BUG_ON(host-dma_ch 0); - if (data-error) - omap_stop_dma(host-dma_ch); - /* Release DMA channel lazily */ - mod_timer(host-dma_timer, jiffies + HZ); -#endif if (data-flags MMC_DATA_WRITE) { dma_data_dir = DMA_TO_DEVICE; c = host-dma_tx; @@ -548,18 +533,6 @@ mmc_omap_end_of_data(struct mmc_omap_host *host, struct mmc_data *data) mmc_omap_xfer_done(host, data); } -#ifdef USE_DMA_PRIVATE -static void -mmc_omap_dma_timer(unsigned long data) -{ - struct mmc_omap_host *host = (struct mmc_omap_host *) data; - - BUG_ON(host-dma_ch 0); - omap_free_dma(host-dma_ch); - host-dma_ch = -1; -} -#endif - static void mmc_omap_dma_done(struct mmc_omap_host *host, struct mmc_data *data) { @@ -928,163 +901,6 @@ static void mmc_omap_dma_callback(void *priv) mmc_omap_dma_done(host, data); } -#ifdef USE_DMA_PRIVATE -/* Prepare to transfer the next segment of a scatterlist */ -static void -mmc_omap_prepare_dma(struct mmc_omap_host *host, struct mmc_data *data) -{ - int dma_ch = host-dma_ch; - unsigned long data_addr; - u16 buf, frame; - u32 count; - struct scatterlist *sg = data-sg[host-sg_idx]; - int src_port = 0; - int dst_port = 0; - int sync_dev = 0; - - data_addr = host-phys_base + OMAP_MMC_REG(host, DATA); - frame = data-blksz; - count = sg_dma_len(sg); - - if ((data-blocks == 1) (count data-blksz)) - count = frame; - - host-dma_len = count; - - /* FIFO is 16x2 bytes on 15xx, and 32x2 bytes on 16xx and 24xx. -* Use 16 or 32 word frames when the blocksize is at least that large. -* Blocksize is usually 512 bytes; but not for some SD reads. -*/ - if (cpu_is_omap15xx() frame 32) - frame = 32; - else if (frame 64) - frame = 64; - count /= frame; - frame = 1; - - if (!(data-flags MMC_DATA_WRITE)) { - buf = 0x800f | ((frame - 1) 8); - - if (cpu_class_is_omap1()) { - src_port = OMAP_DMA_PORT_TIPB; - dst_port = OMAP_DMA_PORT_EMIFF; - } - if (cpu_is_omap24xx()) - sync_dev = OMAP24XX_DMA_MMC1_RX; - - omap_set_dma_src_params(dma_ch, src_port, - OMAP_DMA_AMODE_CONSTANT, - data_addr, 0, 0); - omap_set_dma_dest_params(dma_ch, dst_port, -OMAP_DMA_AMODE_POST_INC, -sg_dma_address(sg), 0, 0); - omap_set_dma_dest_data_pack(dma_ch, 1); - omap_set_dma_dest_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_4); - } else { - buf = 0x0f80 | ((frame - 1) 0); - - if (cpu_class_is_omap1()) { - src_port = OMAP_DMA_PORT_EMIFF; - dst_port = OMAP_DMA_PORT_TIPB; - } - if (cpu_is_omap24xx()) - sync_dev = OMAP24XX_DMA_MMC1_TX; - - omap_set_dma_dest_params(dma_ch, dst_port, -OMAP_DMA_AMODE_CONSTANT, -data_addr, 0, 0); - omap_set_dma_src_params(dma_ch, src_port, - OMAP_DMA_AMODE_POST_INC, - sg_dma_address(sg), 0, 0); - omap_set_dma_src_data_pack(dma_ch, 1); - omap_set_dma_src_burst_mode(dma_ch,
[CFT 06/11] ARM: omap: remove mmc platform data dma_mask and initialization
DMAengine uses the DMA engine device structure when mapping/unmapping memory for DMA, so the MMC devices do not need their DMA masks initialized (this reflects hardware: the MMC device is not the device doing DMA.) Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- arch/arm/mach-omap1/board-h2-mmc.c|1 - arch/arm/mach-omap1/board-h3-mmc.c|1 - arch/arm/mach-omap1/board-nokia770.c |1 - arch/arm/mach-omap2/board-n8x0.c |1 - arch/arm/mach-omap2/hsmmc.c |1 - arch/arm/plat-omap/include/plat/mmc.h |2 -- 6 files changed, 0 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-omap1/board-h2-mmc.c b/arch/arm/mach-omap1/board-h2-mmc.c index da0e37d..e1362ce 100644 --- a/arch/arm/mach-omap1/board-h2-mmc.c +++ b/arch/arm/mach-omap1/board-h2-mmc.c @@ -54,7 +54,6 @@ static struct omap_mmc_platform_data mmc1_data = { .nr_slots = 1, .init = mmc_late_init, .cleanup= mmc_cleanup, - .dma_mask = 0x, .slots[0] = { .set_power = mmc_set_power, .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, diff --git a/arch/arm/mach-omap1/board-h3-mmc.c b/arch/arm/mach-omap1/board-h3-mmc.c index f8242aa..c74daac 100644 --- a/arch/arm/mach-omap1/board-h3-mmc.c +++ b/arch/arm/mach-omap1/board-h3-mmc.c @@ -36,7 +36,6 @@ static int mmc_set_power(struct device *dev, int slot, int power_on, */ static struct omap_mmc_platform_data mmc1_data = { .nr_slots = 1, - .dma_mask = 0x, .slots[0] = { .set_power = mmc_set_power, .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c index 7212ae9..c54b45f 100644 --- a/arch/arm/mach-omap1/board-nokia770.c +++ b/arch/arm/mach-omap1/board-nokia770.c @@ -185,7 +185,6 @@ static int nokia770_mmc_get_cover_state(struct device *dev, int slot) static struct omap_mmc_platform_data nokia770_mmc2_data = { .nr_slots = 1, - .dma_mask = 0x, .max_freq = 1200, .slots[0] = { .set_power = nokia770_mmc_set_power, diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c index 8ca14e8..6d70e81 100644 --- a/arch/arm/mach-omap2/board-n8x0.c +++ b/arch/arm/mach-omap2/board-n8x0.c @@ -470,7 +470,6 @@ static struct omap_mmc_platform_data mmc1_data = { .cleanup= n8x0_mmc_cleanup, .shutdown = n8x0_mmc_shutdown, .max_freq = 2400, - .dma_mask = 0x, .slots[0] = { .wires = 4, .set_power = n8x0_mmc_set_power, diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c index be697d4..a9675d8 100644 --- a/arch/arm/mach-omap2/hsmmc.c +++ b/arch/arm/mach-omap2/hsmmc.c @@ -315,7 +315,6 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c, mmc-slots[0].caps = c-caps; mmc-slots[0].pm_caps = c-pm_caps; mmc-slots[0].internal_clock = !c-ext_clock; - mmc-dma_mask = 0x; mmc-max_freq = c-max_freq; if (cpu_is_omap44xx()) mmc-reg_offset = OMAP4_MMC_REG_OFFSET; diff --git a/arch/arm/plat-omap/include/plat/mmc.h b/arch/arm/plat-omap/include/plat/mmc.h index a7754a8..a76f423 100644 --- a/arch/arm/plat-omap/include/plat/mmc.h +++ b/arch/arm/plat-omap/include/plat/mmc.h @@ -81,8 +81,6 @@ struct omap_mmc_platform_data { /* Return context loss count due to PM states changing */ int (*get_context_loss_count)(struct device *dev); - u64 dma_mask; - /* Integrating attributes from the omap_hwmod layer */ u8 controller_flags; -- 1.7.4.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT 07/11] spi: omap2-mcspi: add DMA engine support
Add DMA engine support to the OMAP SPI driver. This supplements the private DMA API implementation contained within this driver, and the driver can be independently switched at build time between using DMA engine and the private DMA API for the transmit and receive sides. Tested-by: Shubhrajyoti shubhrajy...@ti.com Acked-by: Grant Likely grant.lik...@secretlab.ca Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/spi/spi-omap2-mcspi.c | 183 +--- 1 files changed, 151 insertions(+), 32 deletions(-) diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 46ef5fe..ca016df 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -20,6 +20,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ +#define USE_DMA_ENGINE_RX +#define USE_DMA_ENGINE_TX #include linux/kernel.h #include linux/init.h @@ -28,6 +30,8 @@ #include linux/device.h #include linux/delay.h #include linux/dma-mapping.h +#include linux/dmaengine.h +#include linux/omap-dma.h #include linux/platform_device.h #include linux/err.h #include linux/clk.h @@ -93,6 +97,8 @@ /* We have 2 DMA channels per CS, one for RX and one for TX */ struct omap2_mcspi_dma { + struct dma_chan *dma_tx; + struct dma_chan *dma_rx; int dma_tx_channel; int dma_rx_channel; @@ -300,6 +306,30 @@ static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit) return 0; } +static void omap2_mcspi_rx_callback(void *data) +{ + struct spi_device *spi = data; + struct omap2_mcspi *mcspi = spi_master_get_devdata(spi-master); + struct omap2_mcspi_dma *mcspi_dma = mcspi-dma_channels[spi-chip_select]; + + complete(mcspi_dma-dma_rx_completion); + + /* We must disable the DMA RX request */ + omap2_mcspi_set_dma_req(spi, 1, 0); +} + +static void omap2_mcspi_tx_callback(void *data) +{ + struct spi_device *spi = data; + struct omap2_mcspi *mcspi = spi_master_get_devdata(spi-master); + struct omap2_mcspi_dma *mcspi_dma = mcspi-dma_channels[spi-chip_select]; + + complete(mcspi_dma-dma_tx_completion); + + /* We must disable the DMA TX request */ + omap2_mcspi_set_dma_req(spi, 0, 0); +} + static unsigned omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) { @@ -314,6 +344,9 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) u8 * rx; const u8* tx; void __iomem*chstat_reg; + struct dma_slave_config cfg; + enum dma_slave_buswidth width; + unsigned es; mcspi = spi_master_get_devdata(spi-master); mcspi_dma = mcspi-dma_channels[spi-chip_select]; @@ -321,6 +354,71 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) chstat_reg = cs-base + OMAP2_MCSPI_CHSTAT0; + if (cs-word_len = 8) { + width = DMA_SLAVE_BUSWIDTH_1_BYTE; + es = 1; + } else if (cs-word_len = 16) { + width = DMA_SLAVE_BUSWIDTH_2_BYTES; + es = 2; + } else { + width = DMA_SLAVE_BUSWIDTH_4_BYTES; + es = 4; + } + + memset(cfg, 0, sizeof(cfg)); + cfg.src_addr = cs-phys + OMAP2_MCSPI_RX0; + cfg.dst_addr = cs-phys + OMAP2_MCSPI_TX0; + cfg.src_addr_width = width; + cfg.dst_addr_width = width; + cfg.src_maxburst = 1; + cfg.dst_maxburst = 1; + + if (xfer-tx_buf mcspi_dma-dma_tx) { + struct dma_async_tx_descriptor *tx; + struct scatterlist sg; + + dmaengine_slave_config(mcspi_dma-dma_tx, cfg); + + sg_init_table(sg, 1); + sg_dma_address(sg) = xfer-tx_dma; + sg_dma_len(sg) = xfer-len; + + tx = dmaengine_prep_slave_sg(mcspi_dma-dma_tx, sg, 1, + DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (tx) { + tx-callback = omap2_mcspi_tx_callback; + tx-callback_param = spi; + dmaengine_submit(tx); + } else { + /* FIXME: fall back to PIO? */ + } + } + + if (xfer-rx_buf mcspi_dma-dma_rx) { + struct dma_async_tx_descriptor *tx; + struct scatterlist sg; + size_t len = xfer-len - es; + + dmaengine_slave_config(mcspi_dma-dma_rx, cfg); + + if (l OMAP2_MCSPI_CHCONF_TURBO) + len -= es; + + sg_init_table(sg, 1); + sg_dma_address(sg) = xfer-rx_dma; + sg_dma_len(sg) = len; + + tx = dmaengine_prep_slave_sg(mcspi_dma-dma_rx, sg, 1, + DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (tx) { +
Re: [PATCH 02/11] ARM: OMAP4+: AESS: enable internal auto-gating during initial setup
* Paul Walmsley p...@pwsan.com [120607 03:49]: On Thu, 7 Jun 2012, Tony Lindgren wrote: OK so that's not too bad then. But there's also the omap2_wd_timer_disable pre_shutdown too. And there's also the sysconfig autoidle bit for each driver that we're tweaking in the bus level code? I think I lost your point here. The ioremap() issue is separate from the reset functions, etc., in my view. Moving the reset functions out to drivers/ seems potentially more reasonable than dropping the ioremap(). If we can remove the ioremapping and accessing driver registers in the bus level code things get much simpler for the bus level code. That's like saying if PCI Configuration Header handling were to be moved into the driver code, then the PCI bus-level code would be much simpler :-) The hwmod code ioremaps the device registers to handle the integration-level registers at the beginning of the device's address space. These registers can be thought of as part of the PRCM, not part of the IP block. It would have been better if TI had put these integration registers in a separate address space like PCI does. But we are stuck with the existing hardware design. The integration registers also differ from chip to chip even with the same underlying IP block, see for example the 32k sync timer. Yes having these registers in the device address space sucks. The main reasons why these integration registers are handled now in common code are: 1. to avoid duplicating integration code between lots of different drivers that is unrelated to the driver itself, such as bus-level reset 2. to ensure consistency of the OCP registers with the rest of the PM state 3. to avoid callbacks into drivers that might otherwise be needed for bitfields like CLOCKACTIVITY 4. to make it easier to debug integration problems with drivers Sure that all makes sense. If we don't handle those registers in common code, the number of SoC integration workarounds that need to be placed into the drivers will increase. For example, when OMAP4 added the smart-idle-with-wakeup and smart-standby-with-wakeup OCP idle modes, only a couple of files needed to be changed. If those integration-level details were still in the drivers, a large number of files would need to be changed. And $DEITY help us if the code sequence for dealing with those bits were to ever change in the future - we'd need to change a bunch of drivers, rather than just one or two files. Also some people are going to need to audit the driver code from an integration level pretty carefully for PM to work consistently. I suppose one option, if we were to have a real omap_device, would be to define callbacks for each driver to implement that would read and write the OCP header registers. Then the omap_bus code could call those callbacks to handle the OCP register accesses, when called from the driver's PM runtime calls. Adds another layer of indirection, but would localize IP block register accesses to the IP block's driver. Yes there may be some way to deal with this cleanly while keeping the driver registers in the drivers. Maybe inline functions in the driver headers that hwmod code could include would be enough here. ... As far as the reset and preconfiguration aspects of the hwmod code go, they just happen to be possible since we're doing the ioremap anyway. It can be ensured that no matter what drivers are present, or what the bootloader or previous OS did or didn't do, a minimal kernel should behave predictably. It seems like it might be reasonable to move these to some built-in driver shim layer as you suggest in your other E-mail. But that is assuming that it can be made to work without needless layers of indirection. I don't know of any driver that does this now. Maybe you know of one? Yes good point, see the suggestion on the driver header inline functions in the other email I just sent. Regards, Tony -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[CFT 08/11] spi: omap2-mcspi: remove private DMA API implementation
Remove the private DMA API implementation from spi-omap2-mcspi.c, making it use entirely the DMA engine API. Acked-by: Grant Likely grant.lik...@secretlab.ca Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/spi/spi-omap2-mcspi.c | 104 ++--- 1 files changed, 5 insertions(+), 99 deletions(-) diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index ca016df..9d3409a 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -20,8 +20,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ -#define USE_DMA_ENGINE_RX -#define USE_DMA_ENGINE_TX #include linux/kernel.h #include linux/init.h @@ -43,7 +41,6 @@ #include linux/spi/spi.h -#include plat/dma.h #include plat/clock.h #include plat/mcspi.h @@ -99,8 +96,6 @@ struct omap2_mcspi_dma { struct dma_chan *dma_tx; struct dma_chan *dma_rx; - int dma_tx_channel; - int dma_rx_channel; int dma_tx_sync_dev; int dma_rx_sync_dev; @@ -336,9 +331,8 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) struct omap2_mcspi *mcspi; struct omap2_mcspi_cs *cs = spi-controller_state; struct omap2_mcspi_dma *mcspi_dma; - unsigned intcount, c; - unsigned long base, tx_reg, rx_reg; - int word_len, data_type, element_count; + unsigned intcount; + int word_len, element_count; int elements = 0; u32 l; u8 * rx; @@ -420,73 +414,26 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) } count = xfer-len; - c = count; word_len = cs-word_len; - base = cs-phys; - tx_reg = base + OMAP2_MCSPI_TX0; - rx_reg = base + OMAP2_MCSPI_RX0; rx = xfer-rx_buf; tx = xfer-tx_buf; if (word_len = 8) { - data_type = OMAP_DMA_DATA_TYPE_S8; element_count = count; } else if (word_len = 16) { - data_type = OMAP_DMA_DATA_TYPE_S16; element_count = count 1; } else /* word_len = 32 */ { - data_type = OMAP_DMA_DATA_TYPE_S32; element_count = count 2; } - if (tx != NULL mcspi_dma-dma_tx_channel != -1) { - omap_set_dma_transfer_params(mcspi_dma-dma_tx_channel, - data_type, element_count, 1, - OMAP_DMA_SYNC_ELEMENT, - mcspi_dma-dma_tx_sync_dev, 0); - - omap_set_dma_dest_params(mcspi_dma-dma_tx_channel, 0, - OMAP_DMA_AMODE_CONSTANT, - tx_reg, 0, 0); - - omap_set_dma_src_params(mcspi_dma-dma_tx_channel, 0, - OMAP_DMA_AMODE_POST_INC, - xfer-tx_dma, 0, 0); - } - - if (rx != NULL mcspi_dma-dma_rx_channel != -1) { - elements = element_count - 1; - if (l OMAP2_MCSPI_CHCONF_TURBO) - elements--; - - omap_set_dma_transfer_params(mcspi_dma-dma_rx_channel, - data_type, elements, 1, - OMAP_DMA_SYNC_ELEMENT, - mcspi_dma-dma_rx_sync_dev, 1); - - omap_set_dma_src_params(mcspi_dma-dma_rx_channel, 0, - OMAP_DMA_AMODE_CONSTANT, - rx_reg, 0, 0); - - omap_set_dma_dest_params(mcspi_dma-dma_rx_channel, 0, - OMAP_DMA_AMODE_POST_INC, - xfer-rx_dma, 0, 0); - } - if (tx != NULL) { - if (mcspi_dma-dma_tx) - dma_async_issue_pending(mcspi_dma-dma_tx); - else - omap_start_dma(mcspi_dma-dma_tx_channel); + dma_async_issue_pending(mcspi_dma-dma_tx); omap2_mcspi_set_dma_req(spi, 0, 1); } if (rx != NULL) { - if (mcspi_dma-dma_rx) - dma_async_issue_pending(mcspi_dma-dma_rx); - else - omap_start_dma(mcspi_dma-dma_rx_channel); + dma_async_issue_pending(mcspi_dma-dma_rx); omap2_mcspi_set_dma_req(spi, 1, 1); } @@ -830,16 +777,6 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi, return 0; } -static void omap2_mcspi_dma_rx_callback(int lch, u16 ch_status, void *data) -{ - omap2_mcspi_rx_callback(data); -} - -static void omap2_mcspi_dma_tx_callback(int lch, u16 ch_status, void *data) -{ - omap2_mcspi_tx_callback(data); -} - static int omap2_mcspi_request_dma(struct
[CFT 09/11] mtd: omap2: add DMA engine support
Add DMA engine support to the OMAP2 NAND driver. This supplements the private DMA API implementation contained within this driver, and the driver can be independently switched at build time between using DMA engine and the private DMA API. Tested-by: Grazvydas Ignotas nota...@gmail.com Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/mtd/nand/omap2.c | 92 +- 1 files changed, 91 insertions(+), 1 deletions(-) diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index d7f681d..2912d6c 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -9,6 +9,7 @@ */ #include linux/platform_device.h +#include linux/dmaengine.h #include linux/dma-mapping.h #include linux/delay.h #include linux/module.h @@ -18,6 +19,7 @@ #include linux/mtd/mtd.h #include linux/mtd/nand.h #include linux/mtd/partitions.h +#include linux/omap-dma.h #include linux/io.h #include linux/slab.h @@ -123,6 +125,7 @@ struct omap_nand_info { int gpmc_cs; unsigned long phys_base; struct completion comp; + struct dma_chan *dma; int dma_ch; int gpmc_irq; enum { @@ -345,6 +348,10 @@ static void omap_nand_dma_cb(int lch, u16 ch_status, void *data) { complete((struct completion *) data); } +static void omap_nand_dma_callback(void *data) +{ + complete((struct completion *) data); +} /* * omap_nand_dma_transfer: configer and start dma transfer @@ -382,6 +389,56 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr, addr = page_address(p1) + ((size_t)addr ~PAGE_MASK); } + if (info-dma) { + struct dma_async_tx_descriptor *tx; + struct scatterlist sg; + unsigned n; + + sg_init_one(sg, addr, len); + n = dma_map_sg(info-dma-device-dev, sg, 1, dir); + if (n == 0) { + dev_err(info-pdev-dev, + Couldn't DMA map a %d byte buffer\n, len); + goto out_copy; + } + + tx = dmaengine_prep_slave_sg(info-dma, sg, n, + is_write ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!tx) { + dma_unmap_sg(info-dma-device-dev, sg, 1, dir); + goto out_copy; + } + tx-callback = omap_nand_dma_callback; + tx-callback_param = info-comp; + dmaengine_submit(tx); + + /* configure and start prefetch transfer */ + ret = gpmc_prefetch_enable(info-gpmc_cs, + PREFETCH_FIFOTHRESHOLD_MAX, 0x1, len, is_write); + if (ret) { + /* PFPW engine is busy, use cpu copy method */ + dma_unmap_sg(info-dma-device-dev, sg, 1, dir); + goto out_copy; + } + + init_completion(info-comp); + dma_async_issue_pending(info-dma); + + /* setup and start DMA using dma_addr */ + wait_for_completion(info-comp); + tim = 0; + limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS)); + while (gpmc_read_status(GPMC_PREFETCH_COUNT) (tim++ limit)) + cpu_relax(); + + /* disable and stop the PFPW engine */ + gpmc_prefetch_reset(info-gpmc_cs); + + dma_unmap_sg(info-dma-device-dev, sg, 1, dir); + return 0; + } + dma_addr = dma_map_single(info-pdev-dev, addr, len, dir); if (dma_mapping_error(info-pdev-dev, dma_addr)) { dev_err(info-pdev-dev, @@ -414,7 +471,6 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr, goto out_copy_unmap; init_completion(info-comp); - omap_start_dma(info-dma_ch); /* setup and start DMA using dma_addr */ @@ -1164,6 +1220,8 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) struct omap_nand_platform_data *pdata; int err; int i, offset; + dma_cap_mask_t mask; + unsigned sig; pdata = pdev-dev.platform_data; if (pdata == NULL) { @@ -1244,6 +1302,33 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) break; case NAND_OMAP_PREFETCH_DMA: + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + sig = OMAP24XX_DMA_GPMC; + info-dma = dma_request_channel(mask, omap_dma_filter_fn, sig); + if (!info-dma) { +
[CFT 10/11] mtd: omap2: remove private DMA API implementation
Remove the private DMA API implementation from nand/omap2.c making it use entirely the DMA engine API. Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/mtd/nand/omap2.c | 136 +- 1 files changed, 26 insertions(+), 110 deletions(-) diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 2912d6c..e9309b3 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -126,7 +126,6 @@ struct omap_nand_info { unsigned long phys_base; struct completion comp; struct dma_chan *dma; - int dma_ch; int gpmc_irq; enum { OMAP_NAND_IO_READ = 0, /* read */ @@ -339,15 +338,9 @@ static void omap_write_buf_pref(struct mtd_info *mtd, } /* - * omap_nand_dma_cb: callback on the completion of dma transfer - * @lch: logical channel - * @ch_satuts: channel status + * omap_nand_dma_callback: callback on the completion of dma transfer * @data: pointer to completion data structure */ -static void omap_nand_dma_cb(int lch, u16 ch_status, void *data) -{ - complete((struct completion *) data); -} static void omap_nand_dma_callback(void *data) { complete((struct completion *) data); @@ -365,17 +358,13 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr, { struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, mtd); + struct dma_async_tx_descriptor *tx; enum dma_data_direction dir = is_write ? DMA_TO_DEVICE : DMA_FROM_DEVICE; - dma_addr_t dma_addr; - int ret; + struct scatterlist sg; unsigned long tim, limit; - - /* The fifo depth is 64 bytes max. -* But configure the FIFO-threahold to 32 to get a sync at each frame -* and frame length is 32 bytes. -*/ - int buf_len = len 6; + unsigned n; + int ret; if (addr = high_memory) { struct page *p1; @@ -389,89 +378,33 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr, addr = page_address(p1) + ((size_t)addr ~PAGE_MASK); } - if (info-dma) { - struct dma_async_tx_descriptor *tx; - struct scatterlist sg; - unsigned n; - - sg_init_one(sg, addr, len); - n = dma_map_sg(info-dma-device-dev, sg, 1, dir); - if (n == 0) { - dev_err(info-pdev-dev, - Couldn't DMA map a %d byte buffer\n, len); - goto out_copy; - } - - tx = dmaengine_prep_slave_sg(info-dma, sg, n, - is_write ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!tx) { - dma_unmap_sg(info-dma-device-dev, sg, 1, dir); - goto out_copy; - } - tx-callback = omap_nand_dma_callback; - tx-callback_param = info-comp; - dmaengine_submit(tx); - - /* configure and start prefetch transfer */ - ret = gpmc_prefetch_enable(info-gpmc_cs, - PREFETCH_FIFOTHRESHOLD_MAX, 0x1, len, is_write); - if (ret) { - /* PFPW engine is busy, use cpu copy method */ - dma_unmap_sg(info-dma-device-dev, sg, 1, dir); - goto out_copy; - } - - init_completion(info-comp); - dma_async_issue_pending(info-dma); - - /* setup and start DMA using dma_addr */ - wait_for_completion(info-comp); - tim = 0; - limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS)); - while (gpmc_read_status(GPMC_PREFETCH_COUNT) (tim++ limit)) - cpu_relax(); - - /* disable and stop the PFPW engine */ - gpmc_prefetch_reset(info-gpmc_cs); - - dma_unmap_sg(info-dma-device-dev, sg, 1, dir); - return 0; - } - - dma_addr = dma_map_single(info-pdev-dev, addr, len, dir); - if (dma_mapping_error(info-pdev-dev, dma_addr)) { + sg_init_one(sg, addr, len); + n = dma_map_sg(info-dma-device-dev, sg, 1, dir); + if (n == 0) { dev_err(info-pdev-dev, Couldn't DMA map a %d byte buffer\n, len); goto out_copy; } - if (is_write) { - omap_set_dma_dest_params(info-dma_ch, 0, OMAP_DMA_AMODE_CONSTANT, - info-phys_base, 0, 0); - omap_set_dma_src_params(info-dma_ch, 0,
[CFT 11/11] Add feature removal of old OMAP private DMA implementation
Acked-by: Linus Walleij linus.wall...@linaro.org Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- Documentation/feature-removal-schedule.txt | 11 +++ 1 files changed, 11 insertions(+), 0 deletions(-) diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 56000b3..1f7ba35 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -612,3 +612,14 @@ When: June 2013 Why: Unsupported/unmaintained/unused since 2.6 + +What: OMAP private DMA implementation +When: 2013 +Why: We have a DMA engine implementation; all users should be updated + to use this rather than persisting with the old APIs. The old APIs + block merging the old DMA engine implementation into the DMA + engine driver. +Who: Russell King li...@arm.linux.org.uk, + Santosh Shilimkar santosh.shilim...@ti.com + + -- 1.7.4.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 04/11] ARM: OMAP2+: usb_host_fs: add custom reset for usb_host_fs (fsusb)
+ Ohad On 6/7/2012 12:52 PM, Paul Walmsley wrote: On Thu, 7 Jun 2012, Cousson, Benoit wrote: In fact we should delay the reset to the very last moment and potentially reset the IPs not under driver control later after a couple of second for example. It will avoid reseting every IP that will be handled properly by drivers. We discussed this a couple of years ago on the list and aligned on late and lazy resets, from my recollection. Indeed, what I did not mention is that potentially the whole device init should be done ondemand as well. Meaning the whole hwmod setup phase should be done only when the driver will probe the device. The main reason why it wasn't implemented was because there were some drivers that were not yet PM runtime-converted. This would have caused crashes, since the core code would have no idea that the non-PM-runtime drivers had initialized their devices, and so the core just went ahead and reset those anyway. It might actually be safe now to switch to the late reset arrangement, depending on whether the rest of the drivers have been PM runtime-converted by now. Of course, it would all be moot if the reset is moved away from the hwmod code into the drivers. I do think that moving that to driver code seems much better since all these customs reset code (I2C, DSS, USB...) does anyway require access to the device itself. The is driver responsibility to do that. So ideally it should not be in OMAP architecture code. Regards, Benoit -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [CFT 01/11] dmaengine: add OMAP DMA engine driver
On Thu, Jun 7, 2012 at 4:36 PM, Russell King rmk+ker...@arm.linux.org.uk wrote: Tested-by: Tony Lindgren t...@atomide.com Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/Kconfig | 6 + drivers/dma/Makefile | 1 + drivers/dma/omap-dma.c | 522 ++ include/linux/omap-dma.h | 24 ++ 4 files changed, 553 insertions(+), 0 deletions(-) create mode 100644 drivers/dma/omap-dma.c create mode 100644 include/linux/omap-dma.h diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index eb2b60e..8be3bf6 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -261,6 +261,12 @@ config DMA_SA11X0 SA-1110 SoCs. This DMA engine can only be used with on-chip devices. +config DMA_OMAP + tristate OMAP DMA support + depends on ARCH_OMAP + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + config DMA_ENGINE bool diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index fc05f7d..ddc291a 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -29,3 +29,4 @@ obj-$(CONFIG_PCH_DMA) += pch_dma.o obj-$(CONFIG_AMBA_PL08X) += amba-pl08x.o obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o +obj-$(CONFIG_DMA_OMAP) += omap-dma.o diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c new file mode 100644 index 000..500bc71 --- /dev/null +++ b/drivers/dma/omap-dma.c @@ -0,0 +1,522 @@ +/* + * OMAP DMAengine support + * + * 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. + */ +#include linux/dmaengine.h +#include linux/dma-mapping.h +#include linux/err.h +#include linux/init.h +#include linux/interrupt.h +#include linux/list.h +#include linux/module.h +#include linux/omap-dma.h +#include linux/platform_device.h +#include linux/slab.h +#include linux/spinlock.h + +#include virt-dma.h Russell, I applied your entire series on 3.5-rc1 and build fails as it can't find virt-dma.h Perhaps a missed git add ? +#include plat/dma.h + -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [CFT 09/11] mtd: omap2: add DMA engine support
On Thu, 2012-06-07 at 12:09 +0100, Russell King wrote: Add DMA engine support to the OMAP2 NAND driver. This supplements the private DMA API implementation contained within this driver, and the driver can be independently switched at build time between using DMA engine and the private DMA API. Tested-by: Grazvydas Ignotas nota...@gmail.com Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk I guess it is makes sense to make this stuff to go in via the OMAP tree. -- Best Regards, Artem Bityutskiy signature.asc Description: This is a digitally signed message part
Re: [CFT 01/11] dmaengine: add OMAP DMA engine driver
On Thu, Jun 7, 2012 at 6:10 PM, S, Venkatraman svenk...@ti.com wrote: On Thu, Jun 7, 2012 at 4:36 PM, Russell King rmk+ker...@arm.linux.org.uk wrote: Tested-by: Tony Lindgren t...@atomide.com Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk --- drivers/dma/Kconfig | 6 + drivers/dma/Makefile | 1 + drivers/dma/omap-dma.c | 522 ++ include/linux/omap-dma.h | 24 ++ 4 files changed, 553 insertions(+), 0 deletions(-) create mode 100644 drivers/dma/omap-dma.c create mode 100644 include/linux/omap-dma.h diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index eb2b60e..8be3bf6 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -261,6 +261,12 @@ config DMA_SA11X0 SA-1110 SoCs. This DMA engine can only be used with on-chip devices. +config DMA_OMAP + tristate OMAP DMA support + depends on ARCH_OMAP + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + config DMA_ENGINE bool diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index fc05f7d..ddc291a 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -29,3 +29,4 @@ obj-$(CONFIG_PCH_DMA) += pch_dma.o obj-$(CONFIG_AMBA_PL08X) += amba-pl08x.o obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o +obj-$(CONFIG_DMA_OMAP) += omap-dma.o diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c new file mode 100644 index 000..500bc71 --- /dev/null +++ b/drivers/dma/omap-dma.c @@ -0,0 +1,522 @@ +/* + * OMAP DMAengine support + * + * 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. + */ +#include linux/dmaengine.h +#include linux/dma-mapping.h +#include linux/err.h +#include linux/init.h +#include linux/interrupt.h +#include linux/list.h +#include linux/module.h +#include linux/omap-dma.h +#include linux/platform_device.h +#include linux/slab.h +#include linux/spinlock.h + +#include virt-dma.h Russell, I applied your entire series on 3.5-rc1 and build fails as it can't find virt-dma.h Perhaps a missed git add ? Ok I reread your messages again and these 11 are based on the generic dma-engine series. +#include plat/dma.h + -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [CFT 09/11] mtd: omap2: add DMA engine support
On Thu, Jun 07, 2012 at 03:49:35PM +0300, Artem Bityutskiy wrote: On Thu, 2012-06-07 at 12:09 +0100, Russell King wrote: Add DMA engine support to the OMAP2 NAND driver. This supplements the private DMA API implementation contained within this driver, and the driver can be independently switched at build time between using DMA engine and the private DMA API. Tested-by: Grazvydas Ignotas nota...@gmail.com Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk I guess it is makes sense to make this stuff to go in via the OMAP tree. No, it makes sense to get this stuff via a single tree all together, because, as you can see from the thread structure, it isn't purely an OMAP thing. The OMAP stuff depends on a core set, as does a bunch of PL08x and SA11x0 changes. We can't stuff all that through the OMAP tree, that wouldn't make any sense. What probably should happen is that the tip of the OMAP stuff gets pulled by Tony into his tree, and we share those commits between my tree and his - and then it doesn't matter what goes in when and by whom. -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [CFT 09/11] mtd: omap2: add DMA engine support
On Thu, 2012-06-07 at 14:11 +0100, Russell King - ARM Linux wrote: No, it makes sense to get this stuff via a single tree all together, because, as you can see from the thread structure, it isn't purely an OMAP thing. The OMAP stuff depends on a core set, as does a bunch of PL08x and SA11x0 changes. We can't stuff all that through the OMAP tree, that wouldn't make any sense. What probably should happen is that the tip of the OMAP stuff gets pulled by Tony into his tree, and we share those commits between my tree and his - and then it doesn't matter what goes in when and by whom. Oh, sure, sorry, I actually wanted to say that these to patches should _not_ got via the MTD tree. -- Best Regards, Artem Bityutskiy signature.asc Description: This is a digitally signed message part
RE: [PATCH 00/10] Prepare for GPMC driver conversion (w.r.t MTD)
Hi, On Mon, Jun 04, 2012 at 12:15:01, Mohammed, Afzal wrote: Hi, This series cleans up gpmc mtd interactions so that GPMC driver conversion which is going to happen shortly would happen smoothly by not creating much disturbance outside of arch/arm/*omap*/ This series, 1. provides the ability for OMAP NAND driver to configure GPMC-NAND registers by NAND driver itself instead of using exported GPMC symbols 2. modifies GPMC to provide OMAP ONENAND NAND drivers with GPMC allocated address space as resource 3. creates a fictitious GPMC interrupt chip and provide the clients with interrupts that could be handled using standard APIs (helps in removing the requirement for driver of peripheral connected to GPMC having the knowledge about GPMC interrupt handling). The only user is OMAP NAND driver, it has also been modified to take advantage of this This series has been made over 3.5-rc1 Ping Regards Afzal -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
how to specify dma_mask and coherent_dma_mask in hwmod
Hi While converting platform device registry to Hwmod for CPSW Ethernet driver which is present in AM335X (OMAP2+), I am not finding a way to specify dma_mask and coherent_dma_mask. Is there a way to specify dma_mask and coherent_dma_mask in hwmod? --- Regards, Mugunthan V N. -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [CFT 02/11] mmc: omap_hsmmc: add DMA engine support
* Russell King rmk+ker...@arm.linux.org.uk [120607 04:11]: Add DMA engine support to the OMAP HSMMC driver. This supplements the private DMA API implementation contained within this driver, and the driver can be switched at build time between using DMA engine and the private DMA API. Tested-by: Grazvydas Ignotas nota...@gmail.com Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk Gave this quick boot test on 2430sdp, zoom3, n900 and blaze: Tested-by: Tony Lindgren t...@atomide.com -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [CFT 03/11] mmc: omap_hsmmc: remove private DMA API implementation
* Russell King rmk+ker...@arm.linux.org.uk [120607 04:11]: Remove the private DMA API implementation from omap_hsmmc, making it use entirely the DMA engine API. Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk Tested-by: Tony Lindgren t...@atomide.com -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [CFT 05/11] mmc: omap: remove private DMA API implementation
* Russell King rmk+ker...@arm.linux.org.uk [120607 04:12]: Remove the private DMA API implementation from omap, making it use entirely the DMA engine API. Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk Tested-by: Tony Lindgren t...@atomide.com -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [CFT 06/11] ARM: omap: remove mmc platform data dma_mask and initialization
* Russell King rmk+ker...@arm.linux.org.uk [120607 04:12]: DMAengine uses the DMA engine device structure when mapping/unmapping memory for DMA, so the MMC devices do not need their DMA masks initialized (this reflects hardware: the MMC device is not the device doing DMA.) Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk Tested-by: Tony Lindgren t...@atomide.com -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [CFT 11/11] Add feature removal of old OMAP private DMA implementation
* Russell King rmk+ker...@arm.linux.org.uk [120607 04:14]: Acked-by: Linus Walleij linus.wall...@linaro.org Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk Acked-by: Tony Lindgren t...@atomide.com --- Documentation/feature-removal-schedule.txt | 11 +++ 1 files changed, 11 insertions(+), 0 deletions(-) diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 56000b3..1f7ba35 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -612,3 +612,14 @@ When:June 2013 Why: Unsupported/unmaintained/unused since 2.6 + +What:OMAP private DMA implementation +When:2013 +Why: We have a DMA engine implementation; all users should be updated + to use this rather than persisting with the old APIs. The old APIs + block merging the old DMA engine implementation into the DMA + engine driver. +Who: Russell King li...@arm.linux.org.uk, + Santosh Shilimkar santosh.shilim...@ti.com + + -- 1.7.4.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [CFT 09/11] mtd: omap2: add DMA engine support
* Artem Bityutskiy dedeki...@gmail.com [120607 06:28]: On Thu, 2012-06-07 at 14:11 +0100, Russell King - ARM Linux wrote: No, it makes sense to get this stuff via a single tree all together, because, as you can see from the thread structure, it isn't purely an OMAP thing. The OMAP stuff depends on a core set, as does a bunch of PL08x and SA11x0 changes. We can't stuff all that through the OMAP tree, that wouldn't make any sense. What probably should happen is that the tip of the OMAP stuff gets pulled by Tony into his tree, and we share those commits between my tree and his - and then it doesn't matter what goes in when and by whom. Oh, sure, sorry, I actually wanted to say that these to patches should _not_ got via the MTD tree. What Russell is suggesting works good for me. Regards, Tony -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [CFT 03/11] mmc: omap_hsmmc: remove private DMA API implementation
On Thu, Jun 7, 2012 at 4:37 PM, Russell King rmk+ker...@arm.linux.org.uk wrote: Remove the private DMA API implementation from omap_hsmmc, making it use entirely the DMA engine API. Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk Tested this on 4430SDP with rootfs usage, untarring the kernel source and compiling it natively. Tested-by: Venkatraman S svenk...@ti.com --- drivers/mmc/host/omap_hsmmc.c | 265 ++--- 1 files changed, 64 insertions(+), 201 deletions(-) -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
RE: [PATCH 05/11] ARM: OMAP2+: hwmod code/data: fix 32K sync timer
On Thu, Jun 07, 2012 at 12:38:50, Paul Walmsley wrote: Hi On Thu, 7 Jun 2012, Hiremath, Vaibhav wrote: Isn't this impact AM33xx devices, where we do not support smart idle mode??? Anyway, I will also test it on both OMAP3EVM and AM33xx platform now... Thanks, please let me know how your tests go. If it doesn't work, we'll go back to the flag-based approach in the patch I posted already. Paul, I couldn't finish my testing today, got into continuous meetings. Tomorrow, I will test it and update you on this. Thanks, Vaibhav -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html