linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 000/222] The *Full* Cubox-i series
@ 2014-04-25 11:29 Russell King - ARM Linux
  2014-04-25 11:31 ` [PATCH 001/222] ARM: l2c: remove outer_inv_all() method Russell King
                   ` (222 more replies)
  0 siblings, 223 replies; 232+ messages in thread
From: Russell King - ARM Linux @ 2014-04-25 11:29 UTC (permalink / raw)
  To: linux-arm-kernel

So that people can see what kind of a patch nightmare I'm in, and
hopefully start being more co-operative towards getting patches into
mainline, here is the *full* patch set for CuBox-i support that I'm
presently sitting on.

Anything that can be done to make this easier would be very helpful,
so I'm not spending lots of time tweaking some random patch and then
having to remerge all these different sub-series.

 .../DocBook/media/v4l/pixfmt-packed-rgb.xml        |   39 +
 .../devicetree/bindings/leds/leds-pwm.txt          |    2 +
 Documentation/devicetree/bindings/mmc/mmc.txt      |   11 +
 .../bindings/staging/imx-drm/fsl-imx-drm.txt       |    3 +-
 arch/arm/Kconfig                                   |   51 -
 arch/arm/boot/dts/imx6dl-hummingboard.dts          |   28 +
 arch/arm/boot/dts/imx6q-cubox-i.dts                |    4 +
 arch/arm/boot/dts/imx6qdl-cubox-i.dtsi             |   79 +-
 arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi     |   22 +-
 arch/arm/boot/dts/imx6qdl-microsom.dtsi            |   98 ++
 arch/arm/boot/dts/imx6qdl.dtsi                     |    2 +
 arch/arm/boot/dts/imx6sl.dtsi                      |    2 +
 arch/arm/boot/dts/marco.dtsi                       |    2 +-
 arch/arm/boot/dts/prima2.dtsi                      |    2 +-
 arch/arm/configs/imx_v6_v7_defconfig               |    1 +
 arch/arm/include/asm/hardware/cache-l2x0.h         |  104 +-
 arch/arm/include/asm/outercache.h                  |   67 +-
 arch/arm/mach-berlin/berlin.c                      |    2 +-
 arch/arm/mach-cns3xxx/core.c                       |   10 +-
 arch/arm/mach-exynos/common.h                      |    1 -
 arch/arm/mach-exynos/exynos.c                      |   15 +-
 arch/arm/mach-exynos/sleep.S                       |   30 +-
 arch/arm/mach-highbank/highbank.c                  |   18 +-
 arch/arm/mach-imx/clk-imx6q.c                      |   29 +-
 arch/arm/mach-imx/clk-pllv3.c                      |   27 +-
 arch/arm/mach-imx/mach-vf610.c                     |    2 +-
 arch/arm/mach-imx/suspend-imx6.S                   |   24 +-
 arch/arm/mach-imx/system.c                         |    8 +-
 arch/arm/mach-mvebu/board-v7.c                     |    2 +-
 arch/arm/mach-nomadik/cpu-8815.c                   |    2 +-
 arch/arm/mach-omap2/Kconfig                        |    1 +
 arch/arm/mach-omap2/common.h                       |    1 +
 arch/arm/mach-omap2/io.c                           |    2 +
 arch/arm/mach-omap2/omap-mpuss-lowpower.c          |   16 +-
 arch/arm/mach-omap2/omap4-common.c                 |   86 +-
 arch/arm/mach-prima2/l2x0.c                        |   34 +-
 arch/arm/mach-prima2/pm.c                          |    1 -
 arch/arm/mach-realview/realview_eb.c               |    9 +-
 arch/arm/mach-realview/realview_pb1176.c           |    8 +-
 arch/arm/mach-realview/realview_pb11mp.c           |    9 +-
 arch/arm/mach-realview/realview_pbx.c              |    4 +-
 arch/arm/mach-rockchip/rockchip.c                  |    2 +-
 .../board-armadillo800eva-reference.c              |    4 +-
 arch/arm/mach-shmobile/board-armadillo800eva.c     |    4 +-
 arch/arm/mach-shmobile/board-kzm9g-reference.c     |    4 +-
 arch/arm/mach-shmobile/board-kzm9g.c               |    4 +-
 arch/arm/mach-shmobile/setup-r8a7778.c             |    4 +-
 arch/arm/mach-shmobile/setup-r8a7779.c             |    4 +-
 arch/arm/mach-socfpga/socfpga.c                    |    2 +-
 arch/arm/mach-spear/platsmp.c                      |   19 +-
 arch/arm/mach-spear/spear13xx.c                    |    8 +-
 arch/arm/mach-sti/board-dt.c                       |   12 +-
 arch/arm/mach-tegra/pm.h                           |    2 -
 arch/arm/mach-tegra/reset-handler.S                |   11 +-
 arch/arm/mach-tegra/sleep.h                        |   31 -
 arch/arm/mach-tegra/tegra.c                        |   22 +-
 arch/arm/mach-ux500/cache-l2x0.c                   |   32 +-
 arch/arm/mach-vexpress/ct-ca9x4.c                  |   28 +-
 arch/arm/mach-zynq/common.c                        |    2 +-
 arch/arm/mm/Kconfig                                |   51 +
 arch/arm/mm/Makefile                               |    3 +-
 arch/arm/mm/cache-feroceon-l2.c                    |    1 -
 arch/arm/mm/cache-l2x0.c                           | 1564 +++++++++++++-------
 arch/arm/mm/l2c-common.c                           |   20 +
 arch/arm/mm/l2c-l2x0-resume.S                      |   58 +
 arch/arm/plat-samsung/s5p-sleep.S                  |    1 -
 drivers/Kconfig                                    |    2 +
 drivers/Makefile                                   |    1 +
 drivers/ata/ahci_imx.c                             |  184 ++-
 drivers/cec/Kconfig                                |   14 +
 drivers/cec/Makefile                               |    1 +
 drivers/cec/cec-dev.c                              |  384 +++++
 drivers/gpu/drm/drm_crtc_helper.c                  |    6 -
 drivers/leds/leds-pwm.c                            |  144 +-
 drivers/mmc/core/core.c                            |   42 +
 drivers/mmc/core/host.c                            |   68 +
 drivers/mmc/core/sdio_irq.c                        |   41 +-
 drivers/mmc/host/Kconfig                           |   63 +-
 drivers/mmc/host/dw_mmc.c                          |    2 +
 drivers/mmc/host/sdhci-acpi.c                      |    8 +
 drivers/mmc/host/sdhci-bcm-kona.c                  |    4 +
 drivers/mmc/host/sdhci-bcm2835.c                   |    4 +
 drivers/mmc/host/sdhci-cns3xxx.c                   |   13 +-
 drivers/mmc/host/sdhci-dove.c                      |    4 +
 drivers/mmc/host/sdhci-esdhc-imx.c                 |   82 +-
 drivers/mmc/host/sdhci-esdhc.h                     |    4 +-
 drivers/mmc/host/sdhci-of-arasan.c                 |    4 +
 drivers/mmc/host/sdhci-of-esdhc.c                  |   70 +-
 drivers/mmc/host/sdhci-of-hlwd.c                   |    4 +
 drivers/mmc/host/sdhci-pci.c                       |    9 +-
 drivers/mmc/host/sdhci-pltfm.c                     |    4 +
 drivers/mmc/host/sdhci-pxav2.c                     |   14 +-
 drivers/mmc/host/sdhci-pxav3.c                     |   13 +-
 drivers/mmc/host/sdhci-s3c.c                       |   36 +-
 drivers/mmc/host/sdhci-sirf.c                      |    4 +
 drivers/mmc/host/sdhci-spear.c                     |    5 +-
 drivers/mmc/host/sdhci-tegra.c                     |   27 +-
 drivers/mmc/host/sdhci.c                           |  728 +++++----
 drivers/mmc/host/sdhci.h                           |   20 +-
 drivers/net/ethernet/freescale/fec.h               |   62 +-
 drivers/net/ethernet/freescale/fec_main.c          | 1414 +++++++++++-------
 drivers/regulator/anatop-regulator.c               |    1 +
 drivers/regulator/core.c                           |    2 +-
 drivers/regulator/dummy.c                          |    1 +
 drivers/regulator/fixed.c                          |    4 +-
 drivers/staging/imx-drm/Kconfig                    |   18 +
 drivers/staging/imx-drm/Makefile                   |    3 +
 drivers/staging/imx-drm/drm-ddc-connector.c        |   92 ++
 drivers/staging/imx-drm/drm-ddc-connector.h        |   26 +
 drivers/staging/imx-drm/dw-hdmi-audio.c            |  654 ++++++++
 drivers/staging/imx-drm/dw-hdmi-audio.h            |   15 +
 drivers/staging/imx-drm/dw-hdmi-cec.c              |  205 +++
 drivers/staging/imx-drm/dw-hdmi-cec.h              |   16 +
 drivers/staging/imx-drm/imx-drm-core.c             |    7 +-
 drivers/staging/imx-drm/imx-hdmi.c                 |  178 ++-
 drivers/staging/imx-drm/imx-ldb.c                  |   21 +
 drivers/staging/imx-drm/imx-tve.c                  |   63 +-
 drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h        |    5 +
 drivers/staging/imx-drm/ipu-v3/ipu-common.c        |   41 +-
 drivers/staging/imx-drm/ipu-v3/ipu-dc.c            |   94 +-
 drivers/staging/imx-drm/ipu-v3/ipu-di.c            |    2 +-
 drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c          |   25 +-
 drivers/staging/imx-drm/ipu-v3/ipu-dp.c            |   71 +-
 drivers/staging/imx-drm/ipu-v3/ipu-prv.h           |    3 +
 drivers/staging/imx-drm/ipuv3-crtc.c               |   16 +-
 drivers/staging/imx-drm/ipuv3-plane.c              |    4 +
 drivers/staging/imx-drm/parallel-display.c         |    2 +
 include/linux/cec-dev.h                            |   69 +
 include/linux/mmc/host.h                           |    8 +
 include/linux/mmc/sdhci.h                          |   15 +-
 include/uapi/linux/cec-dev.h                       |   34 +
 include/uapi/linux/videodev2.h                     |    1 +
 sound/soc/fsl/imx-pcm-dma.c                        |    2 +-
 133 files changed, 5598 insertions(+), 2336 deletions(-)


-- 
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.

^ permalink raw reply	[flat|nested] 232+ messages in thread

* [PATCH 001/222] ARM: l2c: remove outer_inv_all() method
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
@ 2014-04-25 11:31 ` Russell King
  2014-04-25 11:31 ` [PATCH 002/222] ARM: l2c: remove unnecessary call to outer_flush_all() Russell King
                   ` (221 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:31 UTC (permalink / raw)
  To: linux-arm-kernel

No one ever calls this function anywhere in the kernel, so let's
completely remove it from the outer cache API and turn it into an
internal-only thing.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/include/asm/outercache.h | 8 --------
 arch/arm/mm/cache-feroceon-l2.c   | 1 -
 arch/arm/mm/cache-l2x0.c          | 5 -----
 3 files changed, 14 deletions(-)

diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h
index f94784f0e3a6..0e4420858990 100644
--- a/arch/arm/include/asm/outercache.h
+++ b/arch/arm/include/asm/outercache.h
@@ -28,7 +28,6 @@ struct outer_cache_fns {
 	void (*clean_range)(unsigned long, unsigned long);
 	void (*flush_range)(unsigned long, unsigned long);
 	void (*flush_all)(void);
-	void (*inv_all)(void);
 	void (*disable)(void);
 #ifdef CONFIG_OUTER_CACHE_SYNC
 	void (*sync)(void);
@@ -63,12 +62,6 @@ static inline void outer_flush_all(void)
 		outer_cache.flush_all();
 }
 
-static inline void outer_inv_all(void)
-{
-	if (outer_cache.inv_all)
-		outer_cache.inv_all();
-}
-
 static inline void outer_disable(void)
 {
 	if (outer_cache.disable)
@@ -90,7 +83,6 @@ static inline void outer_clean_range(phys_addr_t start, phys_addr_t end)
 static inline void outer_flush_range(phys_addr_t start, phys_addr_t end)
 { }
 static inline void outer_flush_all(void) { }
-static inline void outer_inv_all(void) { }
 static inline void outer_disable(void) { }
 static inline void outer_resume(void) { }
 
diff --git a/arch/arm/mm/cache-feroceon-l2.c b/arch/arm/mm/cache-feroceon-l2.c
index dc814a548056..e028a7f2ebcc 100644
--- a/arch/arm/mm/cache-feroceon-l2.c
+++ b/arch/arm/mm/cache-feroceon-l2.c
@@ -350,7 +350,6 @@ void __init feroceon_l2_init(int __l2_wt_override)
 	outer_cache.inv_range = feroceon_l2_inv_range;
 	outer_cache.clean_range = feroceon_l2_clean_range;
 	outer_cache.flush_range = feroceon_l2_flush_range;
-	outer_cache.inv_all = l2_inv_all;
 
 	enable_l2();
 
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 7abde2ce8973..f9985e5a208c 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -414,7 +414,6 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
 		outer_cache.flush_range = l2x0_flush_range;
 		outer_cache.sync = l2x0_cache_sync;
 		outer_cache.flush_all = l2x0_flush_all;
-		outer_cache.inv_all = l2x0_inv_all;
 		outer_cache.disable = l2x0_disable;
 	}
 
@@ -884,7 +883,6 @@ static const struct l2x0_of_data pl310_data = {
 		.flush_range = l2x0_flush_range,
 		.sync        = l2x0_cache_sync,
 		.flush_all   = l2x0_flush_all,
-		.inv_all     = l2x0_inv_all,
 		.disable     = l2x0_disable,
 	},
 };
@@ -899,7 +897,6 @@ static const struct l2x0_of_data l2x0_data = {
 		.flush_range = l2x0_flush_range,
 		.sync        = l2x0_cache_sync,
 		.flush_all   = l2x0_flush_all,
-		.inv_all     = l2x0_inv_all,
 		.disable     = l2x0_disable,
 	},
 };
@@ -914,7 +911,6 @@ static const struct l2x0_of_data aurora_with_outer_data = {
 		.flush_range = aurora_flush_range,
 		.sync        = l2x0_cache_sync,
 		.flush_all   = l2x0_flush_all,
-		.inv_all     = l2x0_inv_all,
 		.disable     = l2x0_disable,
 	},
 };
@@ -946,7 +942,6 @@ static const struct l2x0_of_data bcm_l2x0_data = {
 		.flush_range = bcm_flush_range,
 		.sync        = l2x0_cache_sync,
 		.flush_all   = l2x0_flush_all,
-		.inv_all     = l2x0_inv_all,
 		.disable     = l2x0_disable,
 	},
 };
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 002/222] ARM: l2c: remove unnecessary call to outer_flush_all()
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
  2014-04-25 11:31 ` [PATCH 001/222] ARM: l2c: remove outer_inv_all() method Russell King
@ 2014-04-25 11:31 ` Russell King
  2014-04-25 11:31 ` [PATCH 003/222] ARM: l2c: avoid calling outer_flush_all() unnecessarily (Spear) Russell King
                   ` (220 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:31 UTC (permalink / raw)
  To: linux-arm-kernel

outer_disable() is defined to safely turn the L2 cache off without data
loss: this means that outer_flush_all() should never be called unless
you need to implement some special L2 cache disabling, and even then
only from your replacement L2 cache disable function.

Acked-by: Shawn Guo <shawn.guo@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-prima2/pm.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/arch/arm/mach-prima2/pm.c b/arch/arm/mach-prima2/pm.c
index c4525a88e5da..96e9bc102117 100644
--- a/arch/arm/mach-prima2/pm.c
+++ b/arch/arm/mach-prima2/pm.c
@@ -71,7 +71,6 @@ static int sirfsoc_pm_enter(suspend_state_t state)
 	case PM_SUSPEND_MEM:
 		sirfsoc_pre_suspend_power_off();
 
-		outer_flush_all();
 		outer_disable();
 		/* go zzz */
 		cpu_suspend(0, sirfsoc_finish_suspend);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 003/222] ARM: l2c: avoid calling outer_flush_all() unnecessarily (Spear)
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
  2014-04-25 11:31 ` [PATCH 001/222] ARM: l2c: remove outer_inv_all() method Russell King
  2014-04-25 11:31 ` [PATCH 002/222] ARM: l2c: remove unnecessary call to outer_flush_all() Russell King
@ 2014-04-25 11:31 ` Russell King
  2014-04-25 11:31 ` [PATCH 004/222] ARM: l2c: omap2: remove ES1.0 support Russell King
                   ` (219 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:31 UTC (permalink / raw)
  To: linux-arm-kernel

Spear calls outer_flush_all() from it's SMP bringup function.  This
is potentially dangerous as the L2C set/way operations which implement
this don't take kindly to concurrent operations.  Besides, there's
better solutions to this, as implemented on other platforms.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-spear/platsmp.c | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/arch/arm/mach-spear/platsmp.c b/arch/arm/mach-spear/platsmp.c
index 5c4a19887b2b..eb9f2ef1e974 100644
--- a/arch/arm/mach-spear/platsmp.c
+++ b/arch/arm/mach-spear/platsmp.c
@@ -20,6 +20,18 @@
 #include <mach/spear.h>
 #include "generic.h"
 
+/*
+ * Write pen_release in a way that is guaranteed to be visible to all
+ * observers, irrespective of whether they're taking part in coherency
+ * or not.  This is necessary for the hotplug code to work reliably.
+ */
+static void write_pen_release(int val)
+{
+	pen_release = val;
+	smp_wmb();
+	sync_cache_w(&pen_release);
+}
+
 static DEFINE_SPINLOCK(boot_lock);
 
 static void __iomem *scu_base = IOMEM(VA_SCU_BASE);
@@ -30,8 +42,7 @@ static void spear13xx_secondary_init(unsigned int cpu)
 	 * let the primary processor know we're out of the
 	 * pen, then head off into the C entry point
 	 */
-	pen_release = -1;
-	smp_wmb();
+	write_pen_release(-1);
 
 	/*
 	 * Synchronise with the boot thread.
@@ -58,9 +69,7 @@ static int spear13xx_boot_secondary(unsigned int cpu, struct task_struct *idle)
 	 * Note that "pen_release" is the hardware CPU ID, whereas
 	 * "cpu" is Linux's internal ID.
 	 */
-	pen_release = cpu;
-	flush_cache_all();
-	outer_flush_all();
+	write_pen_release(cpu);
 
 	timeout = jiffies + (1 * HZ);
 	while (time_before(jiffies, timeout)) {
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 004/222] ARM: l2c: omap2: remove ES1.0 support
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (2 preceding siblings ...)
  2014-04-25 11:31 ` [PATCH 003/222] ARM: l2c: avoid calling outer_flush_all() unnecessarily (Spear) Russell King
@ 2014-04-25 11:31 ` Russell King
  2014-04-25 11:31 ` [PATCH 005/222] ARM: l2c: remove unnecessary UL-suffix to mask values Russell King
                   ` (218 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:31 UTC (permalink / raw)
  To: linux-arm-kernel

Santosh says:
> But we should kill all of that since we long back decided to remove
> ES1.0 related code. The mach-omap code alreasy has removed the ES1.0
> compatibility so feel free to remove any specific ES1.0
> related stuff. That silicon is long dead.

Acked-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-omap2/omap4-common.c | 25 ++++++++-----------------
 1 file changed, 8 insertions(+), 17 deletions(-)

diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c
index 95e171a055f3..48cf74d284ec 100644
--- a/arch/arm/mach-omap2/omap4-common.c
+++ b/arch/arm/mach-omap2/omap4-common.c
@@ -182,7 +182,7 @@ static void omap4_l2x0_set_debug(unsigned long val)
 
 static int __init omap_l2_cache_init(void)
 {
-	u32 aux_ctrl = 0;
+	u32 aux_ctrl;
 
 	/*
 	 * To avoid code running on other OMAPs in
@@ -196,27 +196,18 @@ static int __init omap_l2_cache_init(void)
 	if (WARN_ON(!l2cache_base))
 		return -ENOMEM;
 
-	/*
-	 * 16-way associativity, parity disabled
-	 * Way size - 32KB (es1.0)
-	 * Way size - 64KB (es2.0 +)
-	 */
-	aux_ctrl = ((1 << L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT) |
+	/* 16-way associativity, parity disabled, way size - 64KB (es2.0 +) */
+	aux_ctrl = (1 << L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT) |
 			(0x1 << 25) |
 			(0x1 << L2X0_AUX_CTRL_NS_LOCKDOWN_SHIFT) |
-			(0x1 << L2X0_AUX_CTRL_NS_INT_CTRL_SHIFT));
-
-	if (omap_rev() == OMAP4430_REV_ES1_0) {
-		aux_ctrl |= 0x2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT;
-	} else {
-		aux_ctrl |= ((0x3 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) |
+			(0x1 << L2X0_AUX_CTRL_NS_INT_CTRL_SHIFT)) |
+			(0x3 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) |
 			(1 << L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT) |
 			(1 << L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT) |
 			(1 << L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT) |
-			(1 << L2X0_AUX_CTRL_EARLY_BRESP_SHIFT));
-	}
-	if (omap_rev() != OMAP4430_REV_ES1_0)
-		omap_smc1(0x109, aux_ctrl);
+			(1 << L2X0_AUX_CTRL_EARLY_BRESP_SHIFT);
+
+	omap_smc1(0x109, aux_ctrl);
 
 	/* Enable PL310 L2 Cache controller */
 	omap_smc1(0x102, 0x1);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 005/222] ARM: l2c: remove unnecessary UL-suffix to mask values
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (3 preceding siblings ...)
  2014-04-25 11:31 ` [PATCH 004/222] ARM: l2c: omap2: remove ES1.0 support Russell King
@ 2014-04-25 11:31 ` Russell King
  2014-04-25 11:31 ` [PATCH 006/222] ARM: outer cache: add documentation of outer cache functions Russell King
                   ` (217 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:31 UTC (permalink / raw)
  To: linux-arm-kernel

They're u32, they're not unsigned long.  The UL suffix is not required
here.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-highbank/highbank.c | 2 +-
 arch/arm/mach-imx/mach-vf610.c    | 2 +-
 arch/arm/mach-imx/system.c        | 2 +-
 arch/arm/mach-mvebu/board-v7.c    | 2 +-
 arch/arm/mach-rockchip/rockchip.c | 2 +-
 arch/arm/mach-socfpga/socfpga.c   | 2 +-
 6 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/arch/arm/mach-highbank/highbank.c b/arch/arm/mach-highbank/highbank.c
index c7de89b263dd..38e1dc3b4c6e 100644
--- a/arch/arm/mach-highbank/highbank.c
+++ b/arch/arm/mach-highbank/highbank.c
@@ -69,7 +69,7 @@ static void __init highbank_init_irq(void)
 	if (IS_ENABLED(CONFIG_CACHE_L2X0) &&
 	    of_find_compatible_node(NULL, NULL, "arm,pl310-cache")) {
 		highbank_smc1(0x102, 0x1);
-		l2x0_of_init(0, ~0UL);
+		l2x0_of_init(0, ~0);
 		outer_cache.disable = highbank_l2x0_disable;
 	}
 }
diff --git a/arch/arm/mach-imx/mach-vf610.c b/arch/arm/mach-imx/mach-vf610.c
index 2d8aef5a6efa..6288a9690e78 100644
--- a/arch/arm/mach-imx/mach-vf610.c
+++ b/arch/arm/mach-imx/mach-vf610.c
@@ -22,7 +22,7 @@ static void __init vf610_init_machine(void)
 
 static void __init vf610_init_irq(void)
 {
-	l2x0_of_init(0, ~0UL);
+	l2x0_of_init(0, ~0);
 	irqchip_init();
 }
 
diff --git a/arch/arm/mach-imx/system.c b/arch/arm/mach-imx/system.c
index 5e3027d3692f..c6571f1de9fd 100644
--- a/arch/arm/mach-imx/system.c
+++ b/arch/arm/mach-imx/system.c
@@ -145,6 +145,6 @@ void __init imx_init_l2cache(void)
 	of_node_put(np);
 
 out:
-	l2x0_of_init(0, ~0UL);
+	l2x0_of_init(0, ~0);
 }
 #endif
diff --git a/arch/arm/mach-mvebu/board-v7.c b/arch/arm/mach-mvebu/board-v7.c
index 333fca8fdc41..c6bd79f64744 100644
--- a/arch/arm/mach-mvebu/board-v7.c
+++ b/arch/arm/mach-mvebu/board-v7.c
@@ -60,7 +60,7 @@ static void __init mvebu_timer_and_clk_init(void)
 	coherency_init();
 	BUG_ON(mvebu_mbus_dt_init());
 #ifdef CONFIG_CACHE_L2X0
-	l2x0_of_init(0, ~0UL);
+	l2x0_of_init(0, ~0);
 #endif
 
 	if (of_machine_is_compatible("marvell,armada375"))
diff --git a/arch/arm/mach-rockchip/rockchip.c b/arch/arm/mach-rockchip/rockchip.c
index d211d6fa0d98..d252efe3747b 100644
--- a/arch/arm/mach-rockchip/rockchip.c
+++ b/arch/arm/mach-rockchip/rockchip.c
@@ -26,7 +26,7 @@
 
 static void __init rockchip_dt_init(void)
 {
-	l2x0_of_init(0, ~0UL);
+	l2x0_of_init(0, ~0);
 	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
 }
 
diff --git a/arch/arm/mach-socfpga/socfpga.c b/arch/arm/mach-socfpga/socfpga.c
index d86231e11b34..9bbb8177f247 100644
--- a/arch/arm/mach-socfpga/socfpga.c
+++ b/arch/arm/mach-socfpga/socfpga.c
@@ -100,7 +100,7 @@ static void socfpga_cyclone5_restart(enum reboot_mode mode, const char *cmd)
 
 static void __init socfpga_cyclone5_init(void)
 {
-	l2x0_of_init(0, ~0UL);
+	l2x0_of_init(0, ~0);
 	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
 }
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 006/222] ARM: outer cache: add documentation of outer cache functions
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (4 preceding siblings ...)
  2014-04-25 11:31 ` [PATCH 005/222] ARM: l2c: remove unnecessary UL-suffix to mask values Russell King
@ 2014-04-25 11:31 ` Russell King
  2014-04-25 11:31 ` [PATCH 007/222] ARM: outer cache: add WARN_ON() to outer_disable() Russell King
                   ` (216 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:31 UTC (permalink / raw)
  To: linux-arm-kernel

Add some documentation to cover the outer cache functions so that their
requirements can be better understood.  Of particular note are the
flush_all() and disable() methods which must not be called except in
very specific circumstances.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/include/asm/outercache.h | 48 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 47 insertions(+), 1 deletion(-)

diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h
index 0e4420858990..2615b3d9e807 100644
--- a/arch/arm/include/asm/outercache.h
+++ b/arch/arm/include/asm/outercache.h
@@ -39,35 +39,75 @@ struct outer_cache_fns {
 extern struct outer_cache_fns outer_cache;
 
 #ifdef CONFIG_OUTER_CACHE
-
+/**
+ * outer_inv_range - invalidate range of outer cache lines
+ * @start: starting physical address, inclusive
+ * @end: end physical address, exclusive
+ */
 static inline void outer_inv_range(phys_addr_t start, phys_addr_t end)
 {
 	if (outer_cache.inv_range)
 		outer_cache.inv_range(start, end);
 }
+
+/**
+ * outer_clean_range - clean dirty outer cache lines
+ * @start: starting physical address, inclusive
+ * @end: end physical address, exclusive
+ */
 static inline void outer_clean_range(phys_addr_t start, phys_addr_t end)
 {
 	if (outer_cache.clean_range)
 		outer_cache.clean_range(start, end);
 }
+
+/**
+ * outer_flush_range - clean and invalidate outer cache lines
+ * @start: starting physical address, inclusive
+ * @end: end physical address, exclusive
+ */
 static inline void outer_flush_range(phys_addr_t start, phys_addr_t end)
 {
 	if (outer_cache.flush_range)
 		outer_cache.flush_range(start, end);
 }
 
+/**
+ * outer_flush_all - clean and invalidate all cache lines in the outer cache
+ *
+ * Note: depending on implementation, this may not be atomic - it must
+ * only be called with interrupts disabled and no other active outer
+ * cache masters.
+ *
+ * It is intended that this function is only used by implementations
+ * needing to override the outer_cache.disable() method due to security.
+ * (Some implementations perform this as a clean followed by an invalidate.)
+ */
 static inline void outer_flush_all(void)
 {
 	if (outer_cache.flush_all)
 		outer_cache.flush_all();
 }
 
+/**
+ * outer_disable - clean, invalidate and disable the outer cache
+ *
+ * Disable the outer cache, ensuring that any data contained in the outer
+ * cache is pushed out to lower levels of system memory.  The note and
+ * conditions above concerning outer_flush_all() applies here.
+ */
 static inline void outer_disable(void)
 {
 	if (outer_cache.disable)
 		outer_cache.disable();
 }
 
+/**
+ * outer_resume - restore the cache configuration and re-enable outer cache
+ *
+ * Restore any configuration that the cache had when previously enabled,
+ * and re-enable the outer cache.
+ */
 static inline void outer_resume(void)
 {
 	if (outer_cache.resume)
@@ -89,6 +129,12 @@ static inline void outer_resume(void) { }
 #endif
 
 #ifdef CONFIG_OUTER_CACHE_SYNC
+/**
+ * outer_sync - perform a sync point for outer cache
+ *
+ * Ensure that all outer cache operations are complete and any store
+ * buffers are drained.
+ */
 static inline void outer_sync(void)
 {
 	if (outer_cache.sync)
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 007/222] ARM: outer cache: add WARN_ON() to outer_disable()
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (5 preceding siblings ...)
  2014-04-25 11:31 ` [PATCH 006/222] ARM: outer cache: add documentation of outer cache functions Russell King
@ 2014-04-25 11:31 ` Russell King
  2014-04-25 11:31 ` [PATCH 008/222] ARM: l2c: add helper for L2 cache controller DT IDs Russell King
                   ` (215 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:31 UTC (permalink / raw)
  To: linux-arm-kernel

Add WARN_ON() conditions to outer_disable() to ensure that its
requirements aren't violated.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/include/asm/outercache.h |  7 ++-----
 arch/arm/mm/Makefile              |  1 +
 arch/arm/mm/l2c-common.c          | 20 ++++++++++++++++++++
 3 files changed, 23 insertions(+), 5 deletions(-)
 create mode 100644 arch/arm/mm/l2c-common.c

diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h
index 2615b3d9e807..e9a0797fe188 100644
--- a/arch/arm/include/asm/outercache.h
+++ b/arch/arm/include/asm/outercache.h
@@ -21,6 +21,7 @@
 #ifndef __ASM_OUTERCACHE_H
 #define __ASM_OUTERCACHE_H
 
+#include <linux/bug.h>
 #include <linux/types.h>
 
 struct outer_cache_fns {
@@ -96,11 +97,7 @@ static inline void outer_flush_all(void)
  * cache is pushed out to lower levels of system memory.  The note and
  * conditions above concerning outer_flush_all() applies here.
  */
-static inline void outer_disable(void)
-{
-	if (outer_cache.disable)
-		outer_cache.disable();
-}
+extern void outer_disable(void);
 
 /**
  * outer_resume - restore the cache configuration and re-enable outer cache
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index 7f39ce2f841f..de5a6a27081b 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -95,6 +95,7 @@ obj-$(CONFIG_CPU_V7M)		+= proc-v7m.o
 AFLAGS_proc-v6.o	:=-Wa,-march=armv6
 AFLAGS_proc-v7.o	:=-Wa,-march=armv7-a
 
+obj-$(CONFIG_OUTER_CACHE)	+= l2c-common.o
 obj-$(CONFIG_CACHE_FEROCEON_L2)	+= cache-feroceon-l2.o
 obj-$(CONFIG_CACHE_L2X0)	+= cache-l2x0.o
 obj-$(CONFIG_CACHE_XSC3L2)	+= cache-xsc3l2.o
diff --git a/arch/arm/mm/l2c-common.c b/arch/arm/mm/l2c-common.c
new file mode 100644
index 000000000000..10a3cf28c362
--- /dev/null
+++ b/arch/arm/mm/l2c-common.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2010 ARM Ltd.
+ * Written by Catalin Marinas <catalin.marinas@arm.com>
+ *
+ * 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/bug.h>
+#include <linux/smp.h>
+#include <asm/outercache.h>
+
+void outer_disable(void)
+{
+	WARN_ON(!irqs_disabled());
+	WARN_ON(num_online_cpus() > 1);
+
+	if (outer_cache.disable)
+		outer_cache.disable();
+}
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 008/222] ARM: l2c: add helper for L2 cache controller DT IDs
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (6 preceding siblings ...)
  2014-04-25 11:31 ` [PATCH 007/222] ARM: outer cache: add WARN_ON() to outer_disable() Russell King
@ 2014-04-25 11:31 ` Russell King
  2014-04-25 11:31 ` [PATCH 009/222] ARM: l2c: tidy up l2x0_of_data declarations Russell King
                   ` (214 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:31 UTC (permalink / raw)
  To: linux-arm-kernel

Make it easier to declare L2 cache controller DT IDs by using a macro.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 23 ++++++++++-------------
 1 file changed, 10 insertions(+), 13 deletions(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index f9985e5a208c..ac410b21edfb 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -946,20 +946,17 @@ static const struct l2x0_of_data bcm_l2x0_data = {
 	},
 };
 
+#define L2C_ID(name, fns) { .compatible = name, .data = (void *)&fns }
 static const struct of_device_id l2x0_ids[] __initconst = {
-	{ .compatible = "arm,l210-cache", .data = (void *)&l2x0_data },
-	{ .compatible = "arm,l220-cache", .data = (void *)&l2x0_data },
-	{ .compatible = "arm,pl310-cache", .data = (void *)&pl310_data },
-	{ .compatible = "bcm,bcm11351-a2-pl310-cache", /* deprecated name */
-	  .data = (void *)&bcm_l2x0_data},
-	{ .compatible = "brcm,bcm11351-a2-pl310-cache",
-	  .data = (void *)&bcm_l2x0_data},
-	{ .compatible = "marvell,aurora-outer-cache",
-	  .data = (void *)&aurora_with_outer_data},
-	{ .compatible = "marvell,aurora-system-cache",
-	  .data = (void *)&aurora_no_outer_data},
-	{ .compatible = "marvell,tauros3-cache",
-	  .data = (void *)&tauros3_data },
+	L2C_ID("arm,l210-cache", l2x0_data),
+	L2C_ID("arm,l220-cache", l2x0_data),
+	L2C_ID("arm,pl310-cache", pl310_data),
+	L2C_ID("brcm,bcm11351-a2-pl310-cache", bcm_l2x0_data),
+	L2C_ID("marvell,aurora-outer-cache", aurora_with_outer_data),
+	L2C_ID("marvell,aurora-system-cache", aurora_no_outer_data),
+	L2C_ID("marvell,tauros3-cache", tauros3_data),
+	/* Deprecated IDs */
+	L2C_ID("bcm,bcm11351-a2-pl310-cache", bcm_l2x0_data),
 	{}
 };
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 009/222] ARM: l2c: tidy up l2x0_of_data declarations
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (7 preceding siblings ...)
  2014-04-25 11:31 ` [PATCH 008/222] ARM: l2c: add helper for L2 cache controller DT IDs Russell King
@ 2014-04-25 11:31 ` Russell King
  2014-04-25 11:31 ` [PATCH 010/222] ARM: l2c: rename OF specific things, making l2x0_of_data available to all Russell King
                   ` (213 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:31 UTC (permalink / raw)
  To: linux-arm-kernel

Remove NULL initialisers, make these all __initconst structures, and
order their members in the same order as the structure declaration.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 30 ++++++++++++++----------------
 1 file changed, 14 insertions(+), 16 deletions(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index ac410b21edfb..063e1787e8c3 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -873,49 +873,48 @@ static void __init aurora_of_setup(const struct device_node *np,
 	*aux_mask &= ~mask;
 }
 
-static const struct l2x0_of_data pl310_data = {
+static const struct l2x0_of_data pl310_data __initconst = {
 	.setup = pl310_of_setup,
 	.save  = pl310_save,
 	.outer_cache = {
-		.resume      = pl310_resume,
 		.inv_range   = l2x0_inv_range,
 		.clean_range = l2x0_clean_range,
 		.flush_range = l2x0_flush_range,
-		.sync        = l2x0_cache_sync,
 		.flush_all   = l2x0_flush_all,
 		.disable     = l2x0_disable,
+		.sync        = l2x0_cache_sync,
+		.resume      = pl310_resume,
 	},
 };
 
-static const struct l2x0_of_data l2x0_data = {
+static const struct l2x0_of_data l2x0_data __initconst = {
 	.setup = l2x0_of_setup,
-	.save  = NULL,
 	.outer_cache = {
-		.resume      = l2x0_resume,
 		.inv_range   = l2x0_inv_range,
 		.clean_range = l2x0_clean_range,
 		.flush_range = l2x0_flush_range,
-		.sync        = l2x0_cache_sync,
 		.flush_all   = l2x0_flush_all,
 		.disable     = l2x0_disable,
+		.sync        = l2x0_cache_sync,
+		.resume      = l2x0_resume,
 	},
 };
 
-static const struct l2x0_of_data aurora_with_outer_data = {
+static const struct l2x0_of_data aurora_with_outer_data __initconst = {
 	.setup = aurora_of_setup,
 	.save  = aurora_save,
 	.outer_cache = {
-		.resume      = aurora_resume,
 		.inv_range   = aurora_inv_range,
 		.clean_range = aurora_clean_range,
 		.flush_range = aurora_flush_range,
-		.sync        = l2x0_cache_sync,
 		.flush_all   = l2x0_flush_all,
 		.disable     = l2x0_disable,
+		.sync        = l2x0_cache_sync,
+		.resume      = aurora_resume,
 	},
 };
 
-static const struct l2x0_of_data aurora_no_outer_data = {
+static const struct l2x0_of_data aurora_no_outer_data __initconst = {
 	.setup = aurora_of_setup,
 	.save  = aurora_save,
 	.outer_cache = {
@@ -923,8 +922,7 @@ static const struct l2x0_of_data aurora_no_outer_data = {
 	},
 };
 
-static const struct l2x0_of_data tauros3_data = {
-	.setup = NULL,
+static const struct l2x0_of_data tauros3_data __initconst = {
 	.save  = tauros3_save,
 	/* Tauros3 broadcasts L1 cache operations to L2 */
 	.outer_cache = {
@@ -932,17 +930,17 @@ static const struct l2x0_of_data tauros3_data = {
 	},
 };
 
-static const struct l2x0_of_data bcm_l2x0_data = {
+static const struct l2x0_of_data bcm_l2x0_data __initconst = {
 	.setup = pl310_of_setup,
 	.save  = pl310_save,
 	.outer_cache = {
-		.resume      = pl310_resume,
 		.inv_range   = bcm_inv_range,
 		.clean_range = bcm_clean_range,
 		.flush_range = bcm_flush_range,
-		.sync        = l2x0_cache_sync,
 		.flush_all   = l2x0_flush_all,
 		.disable     = l2x0_disable,
+		.sync        = l2x0_cache_sync,
+		.resume      = pl310_resume,
 	},
 };
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 010/222] ARM: l2c: rename OF specific things, making l2x0_of_data available to all
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (8 preceding siblings ...)
  2014-04-25 11:31 ` [PATCH 009/222] ARM: l2c: tidy up l2x0_of_data declarations Russell King
@ 2014-04-25 11:31 ` Russell King
  2014-04-25 11:31 ` [PATCH 011/222] ARM: l2c: provide generic function for calling set_debug method Russell King
                   ` (212 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:31 UTC (permalink / raw)
  To: linux-arm-kernel

Rename a few things to help distinguish their function(s):
 l2x0_of_data -> l2c_init_data
 setup -> of_parse
 add of_ prefix to OF specific data

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 64 ++++++++++++++++++++++++------------------------
 1 file changed, 32 insertions(+), 32 deletions(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 063e1787e8c3..d659c4ca46bb 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -28,6 +28,12 @@
 #include "cache-tauros3.h"
 #include "cache-aurora-l2.h"
 
+struct l2c_init_data {
+	void (*of_parse)(const struct device_node *, u32 *, u32 *);
+	void (*save)(void);
+	struct outer_cache_fns outer_cache;
+};
+
 #define CACHE_LINE_SIZE		32
 
 static void __iomem *l2x0_base;
@@ -42,12 +48,6 @@ static u32  cache_id_part_number_from_dt;
 
 struct l2x0_regs l2x0_saved_regs;
 
-struct l2x0_of_data {
-	void (*setup)(const struct device_node *, u32 *, u32 *);
-	void (*save)(void);
-	struct outer_cache_fns outer_cache;
-};
-
 static bool of_init = false;
 
 static inline void cache_wait_way(void __iomem *reg, unsigned long mask)
@@ -664,7 +664,7 @@ static void bcm_flush_range(unsigned long start, unsigned long end)
 		new_end);
 }
 
-static void __init l2x0_of_setup(const struct device_node *np,
+static void __init l2x0_of_parse(const struct device_node *np,
 				 u32 *aux_val, u32 *aux_mask)
 {
 	u32 data[2] = { 0, 0 };
@@ -698,7 +698,7 @@ static void __init l2x0_of_setup(const struct device_node *np,
 	*aux_mask &= ~mask;
 }
 
-static void __init pl310_of_setup(const struct device_node *np,
+static void __init pl310_of_parse(const struct device_node *np,
 				  u32 *aux_val, u32 *aux_mask)
 {
 	u32 data[3] = { 0, 0, 0 };
@@ -851,7 +851,7 @@ static void __init aurora_broadcast_l2_commands(void)
 	isb();
 }
 
-static void __init aurora_of_setup(const struct device_node *np,
+static void __init aurora_of_parse(const struct device_node *np,
 				u32 *aux_val, u32 *aux_mask)
 {
 	u32 val = AURORA_ACR_REPLACEMENT_TYPE_SEMIPLRU;
@@ -873,8 +873,8 @@ static void __init aurora_of_setup(const struct device_node *np,
 	*aux_mask &= ~mask;
 }
 
-static const struct l2x0_of_data pl310_data __initconst = {
-	.setup = pl310_of_setup,
+static const struct l2c_init_data of_pl310_data __initconst = {
+	.of_parse = pl310_of_parse,
 	.save  = pl310_save,
 	.outer_cache = {
 		.inv_range   = l2x0_inv_range,
@@ -887,8 +887,8 @@ static const struct l2x0_of_data pl310_data __initconst = {
 	},
 };
 
-static const struct l2x0_of_data l2x0_data __initconst = {
-	.setup = l2x0_of_setup,
+static const struct l2c_init_data of_l2x0_data __initconst = {
+	.of_parse = l2x0_of_parse,
 	.outer_cache = {
 		.inv_range   = l2x0_inv_range,
 		.clean_range = l2x0_clean_range,
@@ -900,8 +900,8 @@ static const struct l2x0_of_data l2x0_data __initconst = {
 	},
 };
 
-static const struct l2x0_of_data aurora_with_outer_data __initconst = {
-	.setup = aurora_of_setup,
+static const struct l2c_init_data of_aurora_with_outer_data __initconst = {
+	.of_parse = aurora_of_parse,
 	.save  = aurora_save,
 	.outer_cache = {
 		.inv_range   = aurora_inv_range,
@@ -914,15 +914,15 @@ static const struct l2x0_of_data aurora_with_outer_data __initconst = {
 	},
 };
 
-static const struct l2x0_of_data aurora_no_outer_data __initconst = {
-	.setup = aurora_of_setup,
+static const struct l2c_init_data of_aurora_no_outer_data __initconst = {
+	.of_parse = aurora_of_parse,
 	.save  = aurora_save,
 	.outer_cache = {
 		.resume      = aurora_resume,
 	},
 };
 
-static const struct l2x0_of_data tauros3_data __initconst = {
+static const struct l2c_init_data of_tauros3_data __initconst = {
 	.save  = tauros3_save,
 	/* Tauros3 broadcasts L1 cache operations to L2 */
 	.outer_cache = {
@@ -930,8 +930,8 @@ static const struct l2x0_of_data tauros3_data __initconst = {
 	},
 };
 
-static const struct l2x0_of_data bcm_l2x0_data __initconst = {
-	.setup = pl310_of_setup,
+static const struct l2c_init_data of_bcm_l2x0_data __initconst = {
+	.of_parse = pl310_of_parse,
 	.save  = pl310_save,
 	.outer_cache = {
 		.inv_range   = bcm_inv_range,
@@ -946,22 +946,22 @@ static const struct l2x0_of_data bcm_l2x0_data __initconst = {
 
 #define L2C_ID(name, fns) { .compatible = name, .data = (void *)&fns }
 static const struct of_device_id l2x0_ids[] __initconst = {
-	L2C_ID("arm,l210-cache", l2x0_data),
-	L2C_ID("arm,l220-cache", l2x0_data),
-	L2C_ID("arm,pl310-cache", pl310_data),
-	L2C_ID("brcm,bcm11351-a2-pl310-cache", bcm_l2x0_data),
-	L2C_ID("marvell,aurora-outer-cache", aurora_with_outer_data),
-	L2C_ID("marvell,aurora-system-cache", aurora_no_outer_data),
-	L2C_ID("marvell,tauros3-cache", tauros3_data),
+	L2C_ID("arm,l210-cache", of_l2x0_data),
+	L2C_ID("arm,l220-cache", of_l2x0_data),
+	L2C_ID("arm,pl310-cache", of_pl310_data),
+	L2C_ID("brcm,bcm11351-a2-pl310-cache", of_bcm_l2x0_data),
+	L2C_ID("marvell,aurora-outer-cache", of_aurora_with_outer_data),
+	L2C_ID("marvell,aurora-system-cache", of_aurora_no_outer_data),
+	L2C_ID("marvell,tauros3-cache", of_tauros3_data),
 	/* Deprecated IDs */
-	L2C_ID("bcm,bcm11351-a2-pl310-cache", bcm_l2x0_data),
+	L2C_ID("bcm,bcm11351-a2-pl310-cache", of_bcm_l2x0_data),
 	{}
 };
 
 int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
 {
+	const struct l2c_init_data *data;
 	struct device_node *np;
-	const struct l2x0_of_data *data;
 	struct resource res;
 
 	np = of_find_matching_node(NULL, l2x0_ids);
@@ -981,12 +981,12 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
 
 	/* L2 configuration can only be changed if the cache is disabled */
 	if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) {
-		if (data->setup)
-			data->setup(np, &aux_val, &aux_mask);
+		if (data->of_parse)
+			data->of_parse(np, &aux_val, &aux_mask);
 
 		/* For aurora cache in no outer mode select the
 		 * correct mode using the coprocessor*/
-		if (data == &aurora_no_outer_data)
+		if (data == &of_aurora_no_outer_data)
 			aurora_broadcast_l2_commands();
 	}
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 011/222] ARM: l2c: provide generic function for calling set_debug method
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (9 preceding siblings ...)
  2014-04-25 11:31 ` [PATCH 010/222] ARM: l2c: rename OF specific things, making l2x0_of_data available to all Russell King
@ 2014-04-25 11:31 ` Russell King
  2014-04-25 11:31 ` [PATCH 012/222] ARM: l2c: split out cache unlock code Russell King
                   ` (211 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:31 UTC (permalink / raw)
  To: linux-arm-kernel

Provide a generic function which always calls the set_debug method.
This will be used later in the series as some work-arounds require
that the debug register be written.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index d659c4ca46bb..595c50519e41 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -57,6 +57,16 @@ static inline void cache_wait_way(void __iomem *reg, unsigned long mask)
 		cpu_relax();
 }
 
+/*
+ * This should only be called when we have a requirement that the
+ * register be written due to a work-around, as platforms running
+ * in non-secure mode may not be able to access this register.
+ */
+static inline void l2c_set_debug(void __iomem *base, unsigned long val)
+{
+	outer_cache.set_debug(val);
+}
+
 #ifdef CONFIG_CACHE_PL310
 static inline void cache_wait(void __iomem *reg, unsigned long mask)
 {
@@ -92,7 +102,7 @@ static inline void l2x0_inv_line(unsigned long addr)
 static inline void debug_writel(unsigned long val)
 {
 	if (outer_cache.set_debug)
-		outer_cache.set_debug(val);
+		l2c_set_debug(l2x0_base, val);
 }
 
 static void pl310_set_debug(unsigned long val)
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 012/222] ARM: l2c: split out cache unlock code
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (10 preceding siblings ...)
  2014-04-25 11:31 ` [PATCH 011/222] ARM: l2c: provide generic function for calling set_debug method Russell King
@ 2014-04-25 11:31 ` Russell King
  2014-04-25 11:32 ` [PATCH 013/222] ARM: l2c: provide generic helper for way-based operations Russell King
                   ` (210 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:31 UTC (permalink / raw)
  To: linux-arm-kernel

Split the cache unlock code out of l2x0_unlock().  We want to be able
to re-use this functionality later.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 23 ++++++++++++++++-------
 1 file changed, 16 insertions(+), 7 deletions(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 595c50519e41..a1313d20f205 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -50,6 +50,9 @@ struct l2x0_regs l2x0_saved_regs;
 
 static bool of_init = false;
 
+/*
+ * Common code for all cache controllers.
+ */
 static inline void cache_wait_way(void __iomem *reg, unsigned long mask)
 {
 	/* wait for cache operation by line or way to complete */
@@ -67,6 +70,18 @@ static inline void l2c_set_debug(void __iomem *base, unsigned long val)
 	outer_cache.set_debug(val);
 }
 
+static inline void l2c_unlock(void __iomem *base, unsigned num)
+{
+	unsigned i;
+
+	for (i = 0; i < num; i++) {
+		writel_relaxed(0, base + L2X0_LOCKDOWN_WAY_D_BASE +
+			       i * L2X0_LOCKDOWN_STRIDE);
+		writel_relaxed(0, base + L2X0_LOCKDOWN_WAY_I_BASE +
+			       i * L2X0_LOCKDOWN_STRIDE);
+	}
+}
+
 #ifdef CONFIG_CACHE_PL310
 static inline void cache_wait(void __iomem *reg, unsigned long mask)
 {
@@ -308,7 +323,6 @@ static void l2x0_disable(void)
 static void l2x0_unlock(u32 cache_id)
 {
 	int lockregs;
-	int i;
 
 	switch (cache_id & L2X0_CACHE_ID_PART_MASK) {
 	case L2X0_CACHE_ID_PART_L310:
@@ -323,12 +337,7 @@ static void l2x0_unlock(u32 cache_id)
 		break;
 	}
 
-	for (i = 0; i < lockregs; i++) {
-		writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_D_BASE +
-			       i * L2X0_LOCKDOWN_STRIDE);
-		writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_I_BASE +
-			       i * L2X0_LOCKDOWN_STRIDE);
-	}
+	l2c_unlock(l2x0_base, lockregs);
 }
 
 void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 013/222] ARM: l2c: provide generic helper for way-based operations
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (11 preceding siblings ...)
  2014-04-25 11:31 ` [PATCH 012/222] ARM: l2c: split out cache unlock code Russell King
@ 2014-04-25 11:32 ` Russell King
  2014-04-25 11:32 ` [PATCH 014/222] ARM: l2c: rename cache_wait_way() Russell King
                   ` (209 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:32 UTC (permalink / raw)
  To: linux-arm-kernel

Provide a generic helper function for way based operations.  These are
always background operations, and thus have to be waited for before a
new operation is commenced.  This helper extracts that requirement from
several locations in the code.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index a1313d20f205..1c3a23318f53 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -70,6 +70,12 @@ static inline void l2c_set_debug(void __iomem *base, unsigned long val)
 	outer_cache.set_debug(val);
 }
 
+static void __l2c_op_way(void __iomem *reg)
+{
+	writel_relaxed(l2x0_way_mask, reg);
+	cache_wait_way(reg, l2x0_way_mask);
+}
+
 static inline void l2c_unlock(void __iomem *base, unsigned num)
 {
 	unsigned i;
@@ -166,8 +172,7 @@ static void l2x0_cache_sync(void)
 static void __l2x0_flush_all(void)
 {
 	debug_writel(0x03);
-	writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_INV_WAY);
-	cache_wait_way(l2x0_base + L2X0_CLEAN_INV_WAY, l2x0_way_mask);
+	__l2c_op_way(l2x0_base + L2X0_CLEAN_INV_WAY);
 	cache_sync();
 	debug_writel(0x00);
 }
@@ -188,8 +193,7 @@ static void l2x0_clean_all(void)
 
 	/* clean all ways */
 	raw_spin_lock_irqsave(&l2x0_lock, flags);
-	writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_WAY);
-	cache_wait_way(l2x0_base + L2X0_CLEAN_WAY, l2x0_way_mask);
+	__l2c_op_way(l2x0_base + L2X0_CLEAN_WAY);
 	cache_sync();
 	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
 }
@@ -202,8 +206,7 @@ static void l2x0_inv_all(void)
 	raw_spin_lock_irqsave(&l2x0_lock, flags);
 	/* Invalidating when L2 is enabled is a nono */
 	BUG_ON(readl(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN);
-	writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_INV_WAY);
-	cache_wait_way(l2x0_base + L2X0_INV_WAY, l2x0_way_mask);
+	__l2c_op_way(l2x0_base + L2X0_INV_WAY);
 	cache_sync();
 	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
 }
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 014/222] ARM: l2c: rename cache_wait_way()
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (12 preceding siblings ...)
  2014-04-25 11:32 ` [PATCH 013/222] ARM: l2c: provide generic helper for way-based operations Russell King
@ 2014-04-25 11:32 ` Russell King
  2014-04-25 11:32 ` [PATCH 015/222] ARM: l2c: add and use L2C revision constants Russell King
                   ` (208 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:32 UTC (permalink / raw)
  To: linux-arm-kernel

cache_wait_way() is actually used to wait for a particular mask to
report clear; it's not really got much to do with cache ways at all.
Indeed, it gets used to wait for the C bit to clear on older caches.
Rename this with a more generic function name which better reflects
its purpose: l2c_wait_mask().

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 1c3a23318f53..29ee7f692801 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -53,7 +53,7 @@ static bool of_init = false;
 /*
  * Common code for all cache controllers.
  */
-static inline void cache_wait_way(void __iomem *reg, unsigned long mask)
+static inline void l2c_wait_mask(void __iomem *reg, unsigned long mask)
 {
 	/* wait for cache operation by line or way to complete */
 	while (readl_relaxed(reg) & mask)
@@ -73,7 +73,7 @@ static inline void l2c_set_debug(void __iomem *base, unsigned long val)
 static void __l2c_op_way(void __iomem *reg)
 {
 	writel_relaxed(l2x0_way_mask, reg);
-	cache_wait_way(reg, l2x0_way_mask);
+	l2c_wait_mask(reg, l2x0_way_mask);
 }
 
 static inline void l2c_unlock(void __iomem *base, unsigned num)
@@ -94,7 +94,7 @@ static inline void cache_wait(void __iomem *reg, unsigned long mask)
 	/* cache operations by line are atomic on PL310 */
 }
 #else
-#define cache_wait	cache_wait_way
+#define cache_wait	l2c_wait_mask
 #endif
 
 static inline void cache_sync(void)
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 015/222] ARM: l2c: add and use L2C revision constants
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (13 preceding siblings ...)
  2014-04-25 11:32 ` [PATCH 014/222] ARM: l2c: rename cache_wait_way() Russell King
@ 2014-04-25 11:32 ` Russell King
  2014-04-25 11:32 ` [PATCH 016/222] ARM: l2c: clean up OF initialisation a bit Russell King
                   ` (207 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:32 UTC (permalink / raw)
  To: linux-arm-kernel

The revision namespace is specific to the L2 cache part, so don't name
these with generic identifiers, use a part specific identifier.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/include/asm/hardware/cache-l2x0.h | 22 ++++++++++++++++------
 arch/arm/mm/cache-l2x0.c                   | 10 +++++-----
 2 files changed, 21 insertions(+), 11 deletions(-)

diff --git a/arch/arm/include/asm/hardware/cache-l2x0.h b/arch/arm/include/asm/hardware/cache-l2x0.h
index 6795ff743b3d..3af45734b514 100644
--- a/arch/arm/include/asm/hardware/cache-l2x0.h
+++ b/arch/arm/include/asm/hardware/cache-l2x0.h
@@ -68,14 +68,24 @@
 /* Registers shifts and masks */
 #define L2X0_CACHE_ID_PART_MASK		(0xf << 6)
 #define L2X0_CACHE_ID_PART_L210		(1 << 6)
+#define L2X0_CACHE_ID_PART_L220		(2 << 6)
 #define L2X0_CACHE_ID_PART_L310		(3 << 6)
 #define L2X0_CACHE_ID_RTL_MASK          0x3f
-#define L2X0_CACHE_ID_RTL_R0P0          0x0
-#define L2X0_CACHE_ID_RTL_R1P0          0x2
-#define L2X0_CACHE_ID_RTL_R2P0          0x4
-#define L2X0_CACHE_ID_RTL_R3P0          0x5
-#define L2X0_CACHE_ID_RTL_R3P1          0x6
-#define L2X0_CACHE_ID_RTL_R3P2          0x8
+#define L210_CACHE_ID_RTL_R0P2_02	0x00
+#define L210_CACHE_ID_RTL_R0P1		0x01
+#define L210_CACHE_ID_RTL_R0P2_01	0x02
+#define L210_CACHE_ID_RTL_R0P3		0x03
+#define L210_CACHE_ID_RTL_R0P4		0x0b
+#define L210_CACHE_ID_RTL_R0P5		0x0f
+#define L220_CACHE_ID_RTL_R1P7_01REL0	0x06
+#define L310_CACHE_ID_RTL_R0P0		0x00
+#define L310_CACHE_ID_RTL_R1P0		0x02
+#define L310_CACHE_ID_RTL_R2P0		0x04
+#define L310_CACHE_ID_RTL_R3P0		0x05
+#define L310_CACHE_ID_RTL_R3P1		0x06
+#define L310_CACHE_ID_RTL_R3P1_50REL0	0x07
+#define L310_CACHE_ID_RTL_R3P2		0x08
+#define L310_CACHE_ID_RTL_R3P3		0x09
 
 #define L2X0_AUX_CTRL_MASK			0xc0000fff
 #define L2X0_AUX_CTRL_DATA_RD_LATENCY_SHIFT	0
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 29ee7f692801..c39602ef2cdd 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -374,7 +374,7 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
 		/* Unmapped register. */
 		sync_reg_offset = L2X0_DUMMY_REG;
 #endif
-		if ((cache_id & L2X0_CACHE_ID_RTL_MASK) <= L2X0_CACHE_ID_RTL_R3P0)
+		if ((cache_id & L2X0_CACHE_ID_RTL_MASK) <= L310_CACHE_ID_RTL_R3P0)
 			outer_cache.set_debug = pl310_set_debug;
 		break;
 	case L2X0_CACHE_ID_PART_L210:
@@ -768,7 +768,7 @@ static void __init pl310_save(void)
 	l2x0_saved_regs.filter_start = readl_relaxed(l2x0_base +
 		L2X0_ADDR_FILTER_START);
 
-	if (l2x0_revision >= L2X0_CACHE_ID_RTL_R2P0) {
+	if (l2x0_revision >= L310_CACHE_ID_RTL_R2P0) {
 		/*
 		 * From r2p0, there is Prefetch offset/control register
 		 */
@@ -777,7 +777,7 @@ static void __init pl310_save(void)
 		/*
 		 * From r3p0, there is Power control register
 		 */
-		if (l2x0_revision >= L2X0_CACHE_ID_RTL_R3P0)
+		if (l2x0_revision >= L310_CACHE_ID_RTL_R3P0)
 			l2x0_saved_regs.pwr_ctrl = readl_relaxed(l2x0_base +
 				L2X0_POWER_CTRL);
 	}
@@ -830,10 +830,10 @@ static void pl310_resume(void)
 		l2x0_revision = readl_relaxed(l2x0_base + L2X0_CACHE_ID) &
 			L2X0_CACHE_ID_RTL_MASK;
 
-		if (l2x0_revision >= L2X0_CACHE_ID_RTL_R2P0) {
+		if (l2x0_revision >= L310_CACHE_ID_RTL_R2P0) {
 			writel_relaxed(l2x0_saved_regs.prefetch_ctrl,
 				l2x0_base + L2X0_PREFETCH_CTRL);
-			if (l2x0_revision >= L2X0_CACHE_ID_RTL_R3P0)
+			if (l2x0_revision >= L310_CACHE_ID_RTL_R3P0)
 				writel_relaxed(l2x0_saved_regs.pwr_ctrl,
 					l2x0_base + L2X0_POWER_CTRL);
 		}
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 016/222] ARM: l2c: clean up OF initialisation a bit
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (14 preceding siblings ...)
  2014-04-25 11:32 ` [PATCH 015/222] ARM: l2c: add and use L2C revision constants Russell King
@ 2014-04-25 11:32 ` Russell King
  2014-04-25 11:32 ` [PATCH 017/222] ARM: l2c: pass iomem address into data->save function Russell King
                   ` (206 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:32 UTC (permalink / raw)
  To: linux-arm-kernel

Rather than having a boolean and other tricks to disable some bits of
l2x0_init(), split this function into two parts: a common part shared
between OF and non-OF, and the non-OF part.

The common part can take a block of function pointers, and the cache
ID (to cope with Aurora's DT specified ID.)  Eliminate the redundant
setting of l2x0_base in the OF case, moving it to the non-OF init
function.

This allows us to localise the OF-specific initialisation handling
from the non-OF handling.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 66 +++++++++++++++++++++++++++++-------------------
 1 file changed, 40 insertions(+), 26 deletions(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index c39602ef2cdd..0d83b24b7971 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -42,14 +42,8 @@ static u32 l2x0_way_mask;	/* Bitmask of active ways */
 static u32 l2x0_size;
 static unsigned long sync_reg_offset = L2X0_CACHE_SYNC;
 
-/* Aurora don't have the cache ID register available, so we have to
- * pass it though the device tree */
-static u32  cache_id_part_number_from_dt;
-
 struct l2x0_regs l2x0_saved_regs;
 
-static bool of_init = false;
-
 /*
  * Common code for all cache controllers.
  */
@@ -343,20 +337,26 @@ static void l2x0_unlock(u32 cache_id)
 	l2c_unlock(l2x0_base, lockregs);
 }
 
-void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
+static const struct l2c_init_data l2x0_init_fns __initconst = {
+	.outer_cache = {
+		.inv_range = l2x0_inv_range,
+		.clean_range = l2x0_clean_range,
+		.flush_range = l2x0_flush_range,
+		.flush_all = l2x0_flush_all,
+		.disable = l2x0_disable,
+		.sync = l2x0_cache_sync,
+	},
+};
+
+static void __init __l2c_init(const struct l2c_init_data *data,
+	u32 aux_val, u32 aux_mask, u32 cache_id)
 {
 	u32 aux;
-	u32 cache_id;
 	u32 way_size = 0;
 	int ways;
 	int way_size_shift = L2X0_WAY_SIZE_SHIFT;
 	const char *type;
 
-	l2x0_base = base;
-	if (cache_id_part_number_from_dt)
-		cache_id = cache_id_part_number_from_dt;
-	else
-		cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID);
 	aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
 
 	aux &= aux_mask;
@@ -374,8 +374,6 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
 		/* Unmapped register. */
 		sync_reg_offset = L2X0_DUMMY_REG;
 #endif
-		if ((cache_id & L2X0_CACHE_ID_RTL_MASK) <= L310_CACHE_ID_RTL_R3P0)
-			outer_cache.set_debug = pl310_set_debug;
 		break;
 	case L2X0_CACHE_ID_PART_L210:
 		ways = (aux >> 13) & 0xf;
@@ -430,23 +428,35 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
 	/* Save the value for resuming. */
 	l2x0_saved_regs.aux_ctrl = aux;
 
-	if (!of_init) {
-		outer_cache.inv_range = l2x0_inv_range;
-		outer_cache.clean_range = l2x0_clean_range;
-		outer_cache.flush_range = l2x0_flush_range;
-		outer_cache.sync = l2x0_cache_sync;
-		outer_cache.flush_all = l2x0_flush_all;
-		outer_cache.disable = l2x0_disable;
-	}
+	outer_cache = data->outer_cache;
+
+	if ((cache_id & L2X0_CACHE_ID_PART_MASK) == L2X0_CACHE_ID_PART_L310 &&
+	    (cache_id & L2X0_CACHE_ID_RTL_MASK) <= L310_CACHE_ID_RTL_R3P0)
+		outer_cache.set_debug = pl310_set_debug;
 
 	pr_info("%s cache controller enabled\n", type);
 	pr_info("l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x, Cache size: %d kB\n",
 		ways, cache_id, aux, l2x0_size >> 10);
 }
 
+void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
+{
+	u32 cache_id;
+
+	l2x0_base = base;
+
+	cache_id = readl_relaxed(base + L2X0_CACHE_ID);
+
+	__l2c_init(&l2x0_init_fns, aux_val, aux_mask, cache_id);
+}
+
 #ifdef CONFIG_OF
 static int l2_wt_override;
 
+/* Aurora don't have the cache ID register available, so we have to
+ * pass it though the device tree */
+static u32 cache_id_part_number_from_dt;
+
 /*
  * Note that the end addresses passed to Linux primitives are
  * noninclusive, while the hardware cache range operations use
@@ -985,6 +995,7 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
 	const struct l2c_init_data *data;
 	struct device_node *np;
 	struct resource res;
+	u32 cache_id;
 
 	np = of_find_matching_node(NULL, l2x0_ids);
 	if (!np)
@@ -1015,9 +1026,12 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
 	if (data->save)
 		data->save();
 
-	of_init = true;
-	memcpy(&outer_cache, &data->outer_cache, sizeof(outer_cache));
-	l2x0_init(l2x0_base, aux_val, aux_mask);
+	if (cache_id_part_number_from_dt)
+		cache_id = cache_id_part_number_from_dt;
+	else
+		cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID);
+
+	__l2c_init(data, aux_val, aux_mask, cache_id);
 
 	return 0;
 }
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 017/222] ARM: l2c: pass iomem address into data->save function
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (15 preceding siblings ...)
  2014-04-25 11:32 ` [PATCH 016/222] ARM: l2c: clean up OF initialisation a bit Russell King
@ 2014-04-25 11:32 ` Russell King
  2014-04-25 11:32 ` [PATCH 018/222] ARM: l2c: move l2c save function to __l2c_init() Russell King
                   ` (205 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:32 UTC (permalink / raw)
  To: linux-arm-kernel

Pass the iomem address into this function so we don't have to keep
accessing it from a global.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 32 ++++++++++++++++----------------
 1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 0d83b24b7971..08f9cade028a 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -30,7 +30,7 @@
 
 struct l2c_init_data {
 	void (*of_parse)(const struct device_node *, u32 *, u32 *);
-	void (*save)(void);
+	void (*save)(void __iomem *);
 	struct outer_cache_fns outer_cache;
 };
 
@@ -764,47 +764,47 @@ static void __init pl310_of_parse(const struct device_node *np,
 	}
 }
 
-static void __init pl310_save(void)
+static void __init pl310_save(void __iomem *base)
 {
-	u32 l2x0_revision = readl_relaxed(l2x0_base + L2X0_CACHE_ID) &
+	u32 l2x0_revision = readl_relaxed(base + L2X0_CACHE_ID) &
 		L2X0_CACHE_ID_RTL_MASK;
 
-	l2x0_saved_regs.tag_latency = readl_relaxed(l2x0_base +
+	l2x0_saved_regs.tag_latency = readl_relaxed(base +
 		L2X0_TAG_LATENCY_CTRL);
-	l2x0_saved_regs.data_latency = readl_relaxed(l2x0_base +
+	l2x0_saved_regs.data_latency = readl_relaxed(base +
 		L2X0_DATA_LATENCY_CTRL);
-	l2x0_saved_regs.filter_end = readl_relaxed(l2x0_base +
+	l2x0_saved_regs.filter_end = readl_relaxed(base +
 		L2X0_ADDR_FILTER_END);
-	l2x0_saved_regs.filter_start = readl_relaxed(l2x0_base +
+	l2x0_saved_regs.filter_start = readl_relaxed(base +
 		L2X0_ADDR_FILTER_START);
 
 	if (l2x0_revision >= L310_CACHE_ID_RTL_R2P0) {
 		/*
 		 * From r2p0, there is Prefetch offset/control register
 		 */
-		l2x0_saved_regs.prefetch_ctrl = readl_relaxed(l2x0_base +
+		l2x0_saved_regs.prefetch_ctrl = readl_relaxed(base +
 			L2X0_PREFETCH_CTRL);
 		/*
 		 * From r3p0, there is Power control register
 		 */
 		if (l2x0_revision >= L310_CACHE_ID_RTL_R3P0)
-			l2x0_saved_regs.pwr_ctrl = readl_relaxed(l2x0_base +
+			l2x0_saved_regs.pwr_ctrl = readl_relaxed(base +
 				L2X0_POWER_CTRL);
 	}
 }
 
-static void aurora_save(void)
+static void aurora_save(void __iomem *base)
 {
-	l2x0_saved_regs.ctrl = readl_relaxed(l2x0_base + L2X0_CTRL);
-	l2x0_saved_regs.aux_ctrl = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
+	l2x0_saved_regs.ctrl = readl_relaxed(base + L2X0_CTRL);
+	l2x0_saved_regs.aux_ctrl = readl_relaxed(base + L2X0_AUX_CTRL);
 }
 
-static void __init tauros3_save(void)
+static void __init tauros3_save(void __iomem *base)
 {
 	l2x0_saved_regs.aux2_ctrl =
-		readl_relaxed(l2x0_base + TAUROS3_AUX2_CTRL);
+		readl_relaxed(base + TAUROS3_AUX2_CTRL);
 	l2x0_saved_regs.prefetch_ctrl =
-		readl_relaxed(l2x0_base + L2X0_PREFETCH_CTRL);
+		readl_relaxed(base + L2X0_PREFETCH_CTRL);
 }
 
 static void l2x0_resume(void)
@@ -1024,7 +1024,7 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
 	}
 
 	if (data->save)
-		data->save();
+		data->save(l2x0_base);
 
 	if (cache_id_part_number_from_dt)
 		cache_id = cache_id_part_number_from_dt;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 018/222] ARM: l2c: move l2c save function to __l2c_init()
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (16 preceding siblings ...)
  2014-04-25 11:32 ` [PATCH 017/222] ARM: l2c: pass iomem address into data->save function Russell King
@ 2014-04-25 11:32 ` Russell King
  2014-04-25 11:32 ` [PATCH 019/222] ARM: l2c: group implementation specific code together Russell King
                   ` (204 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:32 UTC (permalink / raw)
  To: linux-arm-kernel

There's no reason this functionality should be specific to DT, so move
it into the common initialisation function.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 08f9cade028a..3b6213838054 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -357,6 +357,13 @@ static void __init __l2c_init(const struct l2c_init_data *data,
 	int way_size_shift = L2X0_WAY_SIZE_SHIFT;
 	const char *type;
 
+	/*
+	 * It is strange to save the register state before initialisation,
+	 * but hey, this is what the DT implementations decided to do.
+	 */
+	if (data->save)
+		data->save(l2x0_base);
+
 	aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
 
 	aux &= aux_mask;
@@ -1023,9 +1030,6 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
 			aurora_broadcast_l2_commands();
 	}
 
-	if (data->save)
-		data->save(l2x0_base);
-
 	if (cache_id_part_number_from_dt)
 		cache_id = cache_id_part_number_from_dt;
 	else
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 019/222] ARM: l2c: group implementation specific code together
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (17 preceding siblings ...)
  2014-04-25 11:32 ` [PATCH 018/222] ARM: l2c: move l2c save function to __l2c_init() Russell King
@ 2014-04-25 11:32 ` Russell King
  2014-04-25 11:32 ` [PATCH 020/222] ARM: l2c: provide enable method Russell King
                   ` (203 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:32 UTC (permalink / raw)
  To: linux-arm-kernel

Back in the mists of time, someone decided that it would be a good idea
to group like functions together - so all the save functions in one
place, all the resume functions in another, all the OF parsing functions
some place else.

This makes it difficult to get an overview on what a particular
implementation is doing - grouping an implementations specific functions
together makes more sense, because you can see what it's doing without
the clutter of other implementations.

Organise it according to implementation.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 502 +++++++++++++++++++++++------------------------
 1 file changed, 251 insertions(+), 251 deletions(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 3b6213838054..09fe0f5eada5 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -464,6 +464,175 @@ static int l2_wt_override;
  * pass it though the device tree */
 static u32 cache_id_part_number_from_dt;
 
+static void __init l2x0_of_parse(const struct device_node *np,
+				 u32 *aux_val, u32 *aux_mask)
+{
+	u32 data[2] = { 0, 0 };
+	u32 tag = 0;
+	u32 dirty = 0;
+	u32 val = 0, mask = 0;
+
+	of_property_read_u32(np, "arm,tag-latency", &tag);
+	if (tag) {
+		mask |= L2X0_AUX_CTRL_TAG_LATENCY_MASK;
+		val |= (tag - 1) << L2X0_AUX_CTRL_TAG_LATENCY_SHIFT;
+	}
+
+	of_property_read_u32_array(np, "arm,data-latency",
+				   data, ARRAY_SIZE(data));
+	if (data[0] && data[1]) {
+		mask |= L2X0_AUX_CTRL_DATA_RD_LATENCY_MASK |
+			L2X0_AUX_CTRL_DATA_WR_LATENCY_MASK;
+		val |= ((data[0] - 1) << L2X0_AUX_CTRL_DATA_RD_LATENCY_SHIFT) |
+		       ((data[1] - 1) << L2X0_AUX_CTRL_DATA_WR_LATENCY_SHIFT);
+	}
+
+	of_property_read_u32(np, "arm,dirty-latency", &dirty);
+	if (dirty) {
+		mask |= L2X0_AUX_CTRL_DIRTY_LATENCY_MASK;
+		val |= (dirty - 1) << L2X0_AUX_CTRL_DIRTY_LATENCY_SHIFT;
+	}
+
+	*aux_val &= ~mask;
+	*aux_val |= val;
+	*aux_mask &= ~mask;
+}
+
+static void l2x0_resume(void)
+{
+	if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) {
+		/* restore aux ctrl and enable l2 */
+		l2x0_unlock(readl_relaxed(l2x0_base + L2X0_CACHE_ID));
+
+		writel_relaxed(l2x0_saved_regs.aux_ctrl, l2x0_base +
+			L2X0_AUX_CTRL);
+
+		l2x0_inv_all();
+
+		writel_relaxed(L2X0_CTRL_EN, l2x0_base + L2X0_CTRL);
+	}
+}
+
+static const struct l2c_init_data of_l2x0_data __initconst = {
+	.of_parse = l2x0_of_parse,
+	.outer_cache = {
+		.inv_range   = l2x0_inv_range,
+		.clean_range = l2x0_clean_range,
+		.flush_range = l2x0_flush_range,
+		.flush_all   = l2x0_flush_all,
+		.disable     = l2x0_disable,
+		.sync        = l2x0_cache_sync,
+		.resume      = l2x0_resume,
+	},
+};
+
+static void __init pl310_of_parse(const struct device_node *np,
+				  u32 *aux_val, u32 *aux_mask)
+{
+	u32 data[3] = { 0, 0, 0 };
+	u32 tag[3] = { 0, 0, 0 };
+	u32 filter[2] = { 0, 0 };
+
+	of_property_read_u32_array(np, "arm,tag-latency", tag, ARRAY_SIZE(tag));
+	if (tag[0] && tag[1] && tag[2])
+		writel_relaxed(
+			((tag[0] - 1) << L2X0_LATENCY_CTRL_RD_SHIFT) |
+			((tag[1] - 1) << L2X0_LATENCY_CTRL_WR_SHIFT) |
+			((tag[2] - 1) << L2X0_LATENCY_CTRL_SETUP_SHIFT),
+			l2x0_base + L2X0_TAG_LATENCY_CTRL);
+
+	of_property_read_u32_array(np, "arm,data-latency",
+				   data, ARRAY_SIZE(data));
+	if (data[0] && data[1] && data[2])
+		writel_relaxed(
+			((data[0] - 1) << L2X0_LATENCY_CTRL_RD_SHIFT) |
+			((data[1] - 1) << L2X0_LATENCY_CTRL_WR_SHIFT) |
+			((data[2] - 1) << L2X0_LATENCY_CTRL_SETUP_SHIFT),
+			l2x0_base + L2X0_DATA_LATENCY_CTRL);
+
+	of_property_read_u32_array(np, "arm,filter-ranges",
+				   filter, ARRAY_SIZE(filter));
+	if (filter[1]) {
+		writel_relaxed(ALIGN(filter[0] + filter[1], SZ_1M),
+			       l2x0_base + L2X0_ADDR_FILTER_END);
+		writel_relaxed((filter[0] & ~(SZ_1M - 1)) | L2X0_ADDR_FILTER_EN,
+			       l2x0_base + L2X0_ADDR_FILTER_START);
+	}
+}
+
+static void __init pl310_save(void __iomem *base)
+{
+	u32 l2x0_revision = readl_relaxed(base + L2X0_CACHE_ID) &
+		L2X0_CACHE_ID_RTL_MASK;
+
+	l2x0_saved_regs.tag_latency = readl_relaxed(base +
+		L2X0_TAG_LATENCY_CTRL);
+	l2x0_saved_regs.data_latency = readl_relaxed(base +
+		L2X0_DATA_LATENCY_CTRL);
+	l2x0_saved_regs.filter_end = readl_relaxed(base +
+		L2X0_ADDR_FILTER_END);
+	l2x0_saved_regs.filter_start = readl_relaxed(base +
+		L2X0_ADDR_FILTER_START);
+
+	if (l2x0_revision >= L310_CACHE_ID_RTL_R2P0) {
+		/*
+		 * From r2p0, there is Prefetch offset/control register
+		 */
+		l2x0_saved_regs.prefetch_ctrl = readl_relaxed(base +
+			L2X0_PREFETCH_CTRL);
+		/*
+		 * From r3p0, there is Power control register
+		 */
+		if (l2x0_revision >= L310_CACHE_ID_RTL_R3P0)
+			l2x0_saved_regs.pwr_ctrl = readl_relaxed(base +
+				L2X0_POWER_CTRL);
+	}
+}
+
+static void pl310_resume(void)
+{
+	u32 l2x0_revision;
+
+	if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) {
+		/* restore pl310 setup */
+		writel_relaxed(l2x0_saved_regs.tag_latency,
+			l2x0_base + L2X0_TAG_LATENCY_CTRL);
+		writel_relaxed(l2x0_saved_regs.data_latency,
+			l2x0_base + L2X0_DATA_LATENCY_CTRL);
+		writel_relaxed(l2x0_saved_regs.filter_end,
+			l2x0_base + L2X0_ADDR_FILTER_END);
+		writel_relaxed(l2x0_saved_regs.filter_start,
+			l2x0_base + L2X0_ADDR_FILTER_START);
+
+		l2x0_revision = readl_relaxed(l2x0_base + L2X0_CACHE_ID) &
+			L2X0_CACHE_ID_RTL_MASK;
+
+		if (l2x0_revision >= L310_CACHE_ID_RTL_R2P0) {
+			writel_relaxed(l2x0_saved_regs.prefetch_ctrl,
+				l2x0_base + L2X0_PREFETCH_CTRL);
+			if (l2x0_revision >= L310_CACHE_ID_RTL_R3P0)
+				writel_relaxed(l2x0_saved_regs.pwr_ctrl,
+					l2x0_base + L2X0_POWER_CTRL);
+		}
+	}
+
+	l2x0_resume();
+}
+
+static const struct l2c_init_data of_pl310_data __initconst = {
+	.of_parse = pl310_of_parse,
+	.save  = pl310_save,
+	.outer_cache = {
+		.inv_range   = l2x0_inv_range,
+		.clean_range = l2x0_clean_range,
+		.flush_range = l2x0_flush_range,
+		.flush_all   = l2x0_flush_all,
+		.disable     = l2x0_disable,
+		.sync        = l2x0_cache_sync,
+		.resume      = pl310_resume,
+	},
+};
+
 /*
  * Note that the end addresses passed to Linux primitives are
  * noninclusive, while the hardware cache range operations use
@@ -562,6 +731,75 @@ static void aurora_flush_range(unsigned long start, unsigned long end)
 	}
 }
 
+static void aurora_save(void __iomem *base)
+{
+	l2x0_saved_regs.ctrl = readl_relaxed(base + L2X0_CTRL);
+	l2x0_saved_regs.aux_ctrl = readl_relaxed(base + L2X0_AUX_CTRL);
+}
+
+static void aurora_resume(void)
+{
+	if (!(readl(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) {
+		writel_relaxed(l2x0_saved_regs.aux_ctrl,
+				l2x0_base + L2X0_AUX_CTRL);
+		writel_relaxed(l2x0_saved_regs.ctrl, l2x0_base + L2X0_CTRL);
+	}
+}
+
+static void __init aurora_broadcast_l2_commands(void)
+{
+	__u32 u;
+	/* Enable Broadcasting of cache commands to L2*/
+	__asm__ __volatile__("mrc p15, 1, %0, c15, c2, 0" : "=r"(u));
+	u |= AURORA_CTRL_FW;		/* Set the FW bit */
+	__asm__ __volatile__("mcr p15, 1, %0, c15, c2, 0\n" : : "r"(u));
+	isb();
+}
+
+static void __init aurora_of_parse(const struct device_node *np,
+				u32 *aux_val, u32 *aux_mask)
+{
+	u32 val = AURORA_ACR_REPLACEMENT_TYPE_SEMIPLRU;
+	u32 mask =  AURORA_ACR_REPLACEMENT_MASK;
+
+	of_property_read_u32(np, "cache-id-part",
+			&cache_id_part_number_from_dt);
+
+	/* Determine and save the write policy */
+	l2_wt_override = of_property_read_bool(np, "wt-override");
+
+	if (l2_wt_override) {
+		val |= AURORA_ACR_FORCE_WRITE_THRO_POLICY;
+		mask |= AURORA_ACR_FORCE_WRITE_POLICY_MASK;
+	}
+
+	*aux_val &= ~mask;
+	*aux_val |= val;
+	*aux_mask &= ~mask;
+}
+
+static const struct l2c_init_data of_aurora_with_outer_data __initconst = {
+	.of_parse = aurora_of_parse,
+	.save  = aurora_save,
+	.outer_cache = {
+		.inv_range   = aurora_inv_range,
+		.clean_range = aurora_clean_range,
+		.flush_range = aurora_flush_range,
+		.flush_all   = l2x0_flush_all,
+		.disable     = l2x0_disable,
+		.sync        = l2x0_cache_sync,
+		.resume      = aurora_resume,
+	},
+};
+
+static const struct l2c_init_data of_aurora_no_outer_data __initconst = {
+	.of_parse = aurora_of_parse,
+	.save  = aurora_save,
+	.outer_cache = {
+		.resume      = aurora_resume,
+	},
+};
+
 /*
  * For certain Broadcom SoCs, depending on the address range, different offsets
  * need to be added to the address before passing it to L2 for
@@ -703,108 +941,19 @@ static void bcm_flush_range(unsigned long start, unsigned long end)
 		new_end);
 }
 
-static void __init l2x0_of_parse(const struct device_node *np,
-				 u32 *aux_val, u32 *aux_mask)
-{
-	u32 data[2] = { 0, 0 };
-	u32 tag = 0;
-	u32 dirty = 0;
-	u32 val = 0, mask = 0;
-
-	of_property_read_u32(np, "arm,tag-latency", &tag);
-	if (tag) {
-		mask |= L2X0_AUX_CTRL_TAG_LATENCY_MASK;
-		val |= (tag - 1) << L2X0_AUX_CTRL_TAG_LATENCY_SHIFT;
-	}
-
-	of_property_read_u32_array(np, "arm,data-latency",
-				   data, ARRAY_SIZE(data));
-	if (data[0] && data[1]) {
-		mask |= L2X0_AUX_CTRL_DATA_RD_LATENCY_MASK |
-			L2X0_AUX_CTRL_DATA_WR_LATENCY_MASK;
-		val |= ((data[0] - 1) << L2X0_AUX_CTRL_DATA_RD_LATENCY_SHIFT) |
-		       ((data[1] - 1) << L2X0_AUX_CTRL_DATA_WR_LATENCY_SHIFT);
-	}
-
-	of_property_read_u32(np, "arm,dirty-latency", &dirty);
-	if (dirty) {
-		mask |= L2X0_AUX_CTRL_DIRTY_LATENCY_MASK;
-		val |= (dirty - 1) << L2X0_AUX_CTRL_DIRTY_LATENCY_SHIFT;
-	}
-
-	*aux_val &= ~mask;
-	*aux_val |= val;
-	*aux_mask &= ~mask;
-}
-
-static void __init pl310_of_parse(const struct device_node *np,
-				  u32 *aux_val, u32 *aux_mask)
-{
-	u32 data[3] = { 0, 0, 0 };
-	u32 tag[3] = { 0, 0, 0 };
-	u32 filter[2] = { 0, 0 };
-
-	of_property_read_u32_array(np, "arm,tag-latency", tag, ARRAY_SIZE(tag));
-	if (tag[0] && tag[1] && tag[2])
-		writel_relaxed(
-			((tag[0] - 1) << L2X0_LATENCY_CTRL_RD_SHIFT) |
-			((tag[1] - 1) << L2X0_LATENCY_CTRL_WR_SHIFT) |
-			((tag[2] - 1) << L2X0_LATENCY_CTRL_SETUP_SHIFT),
-			l2x0_base + L2X0_TAG_LATENCY_CTRL);
-
-	of_property_read_u32_array(np, "arm,data-latency",
-				   data, ARRAY_SIZE(data));
-	if (data[0] && data[1] && data[2])
-		writel_relaxed(
-			((data[0] - 1) << L2X0_LATENCY_CTRL_RD_SHIFT) |
-			((data[1] - 1) << L2X0_LATENCY_CTRL_WR_SHIFT) |
-			((data[2] - 1) << L2X0_LATENCY_CTRL_SETUP_SHIFT),
-			l2x0_base + L2X0_DATA_LATENCY_CTRL);
-
-	of_property_read_u32_array(np, "arm,filter-ranges",
-				   filter, ARRAY_SIZE(filter));
-	if (filter[1]) {
-		writel_relaxed(ALIGN(filter[0] + filter[1], SZ_1M),
-			       l2x0_base + L2X0_ADDR_FILTER_END);
-		writel_relaxed((filter[0] & ~(SZ_1M - 1)) | L2X0_ADDR_FILTER_EN,
-			       l2x0_base + L2X0_ADDR_FILTER_START);
-	}
-}
-
-static void __init pl310_save(void __iomem *base)
-{
-	u32 l2x0_revision = readl_relaxed(base + L2X0_CACHE_ID) &
-		L2X0_CACHE_ID_RTL_MASK;
-
-	l2x0_saved_regs.tag_latency = readl_relaxed(base +
-		L2X0_TAG_LATENCY_CTRL);
-	l2x0_saved_regs.data_latency = readl_relaxed(base +
-		L2X0_DATA_LATENCY_CTRL);
-	l2x0_saved_regs.filter_end = readl_relaxed(base +
-		L2X0_ADDR_FILTER_END);
-	l2x0_saved_regs.filter_start = readl_relaxed(base +
-		L2X0_ADDR_FILTER_START);
-
-	if (l2x0_revision >= L310_CACHE_ID_RTL_R2P0) {
-		/*
-		 * From r2p0, there is Prefetch offset/control register
-		 */
-		l2x0_saved_regs.prefetch_ctrl = readl_relaxed(base +
-			L2X0_PREFETCH_CTRL);
-		/*
-		 * From r3p0, there is Power control register
-		 */
-		if (l2x0_revision >= L310_CACHE_ID_RTL_R3P0)
-			l2x0_saved_regs.pwr_ctrl = readl_relaxed(base +
-				L2X0_POWER_CTRL);
-	}
-}
-
-static void aurora_save(void __iomem *base)
-{
-	l2x0_saved_regs.ctrl = readl_relaxed(base + L2X0_CTRL);
-	l2x0_saved_regs.aux_ctrl = readl_relaxed(base + L2X0_AUX_CTRL);
-}
+static const struct l2c_init_data of_bcm_l2x0_data __initconst = {
+	.of_parse = pl310_of_parse,
+	.save  = pl310_save,
+	.outer_cache = {
+		.inv_range   = bcm_inv_range,
+		.clean_range = bcm_clean_range,
+		.flush_range = bcm_flush_range,
+		.flush_all   = l2x0_flush_all,
+		.disable     = l2x0_disable,
+		.sync        = l2x0_cache_sync,
+		.resume      = pl310_resume,
+	},
+};
 
 static void __init tauros3_save(void __iomem *base)
 {
@@ -814,60 +963,6 @@ static void __init tauros3_save(void __iomem *base)
 		readl_relaxed(base + L2X0_PREFETCH_CTRL);
 }
 
-static void l2x0_resume(void)
-{
-	if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) {
-		/* restore aux ctrl and enable l2 */
-		l2x0_unlock(readl_relaxed(l2x0_base + L2X0_CACHE_ID));
-
-		writel_relaxed(l2x0_saved_regs.aux_ctrl, l2x0_base +
-			L2X0_AUX_CTRL);
-
-		l2x0_inv_all();
-
-		writel_relaxed(L2X0_CTRL_EN, l2x0_base + L2X0_CTRL);
-	}
-}
-
-static void pl310_resume(void)
-{
-	u32 l2x0_revision;
-
-	if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) {
-		/* restore pl310 setup */
-		writel_relaxed(l2x0_saved_regs.tag_latency,
-			l2x0_base + L2X0_TAG_LATENCY_CTRL);
-		writel_relaxed(l2x0_saved_regs.data_latency,
-			l2x0_base + L2X0_DATA_LATENCY_CTRL);
-		writel_relaxed(l2x0_saved_regs.filter_end,
-			l2x0_base + L2X0_ADDR_FILTER_END);
-		writel_relaxed(l2x0_saved_regs.filter_start,
-			l2x0_base + L2X0_ADDR_FILTER_START);
-
-		l2x0_revision = readl_relaxed(l2x0_base + L2X0_CACHE_ID) &
-			L2X0_CACHE_ID_RTL_MASK;
-
-		if (l2x0_revision >= L310_CACHE_ID_RTL_R2P0) {
-			writel_relaxed(l2x0_saved_regs.prefetch_ctrl,
-				l2x0_base + L2X0_PREFETCH_CTRL);
-			if (l2x0_revision >= L310_CACHE_ID_RTL_R3P0)
-				writel_relaxed(l2x0_saved_regs.pwr_ctrl,
-					l2x0_base + L2X0_POWER_CTRL);
-		}
-	}
-
-	l2x0_resume();
-}
-
-static void aurora_resume(void)
-{
-	if (!(readl(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) {
-		writel_relaxed(l2x0_saved_regs.aux_ctrl,
-				l2x0_base + L2X0_AUX_CTRL);
-		writel_relaxed(l2x0_saved_regs.ctrl, l2x0_base + L2X0_CTRL);
-	}
-}
-
 static void tauros3_resume(void)
 {
 	if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) {
@@ -880,87 +975,6 @@ static void tauros3_resume(void)
 	l2x0_resume();
 }
 
-static void __init aurora_broadcast_l2_commands(void)
-{
-	__u32 u;
-	/* Enable Broadcasting of cache commands to L2*/
-	__asm__ __volatile__("mrc p15, 1, %0, c15, c2, 0" : "=r"(u));
-	u |= AURORA_CTRL_FW;		/* Set the FW bit */
-	__asm__ __volatile__("mcr p15, 1, %0, c15, c2, 0\n" : : "r"(u));
-	isb();
-}
-
-static void __init aurora_of_parse(const struct device_node *np,
-				u32 *aux_val, u32 *aux_mask)
-{
-	u32 val = AURORA_ACR_REPLACEMENT_TYPE_SEMIPLRU;
-	u32 mask =  AURORA_ACR_REPLACEMENT_MASK;
-
-	of_property_read_u32(np, "cache-id-part",
-			&cache_id_part_number_from_dt);
-
-	/* Determine and save the write policy */
-	l2_wt_override = of_property_read_bool(np, "wt-override");
-
-	if (l2_wt_override) {
-		val |= AURORA_ACR_FORCE_WRITE_THRO_POLICY;
-		mask |= AURORA_ACR_FORCE_WRITE_POLICY_MASK;
-	}
-
-	*aux_val &= ~mask;
-	*aux_val |= val;
-	*aux_mask &= ~mask;
-}
-
-static const struct l2c_init_data of_pl310_data __initconst = {
-	.of_parse = pl310_of_parse,
-	.save  = pl310_save,
-	.outer_cache = {
-		.inv_range   = l2x0_inv_range,
-		.clean_range = l2x0_clean_range,
-		.flush_range = l2x0_flush_range,
-		.flush_all   = l2x0_flush_all,
-		.disable     = l2x0_disable,
-		.sync        = l2x0_cache_sync,
-		.resume      = pl310_resume,
-	},
-};
-
-static const struct l2c_init_data of_l2x0_data __initconst = {
-	.of_parse = l2x0_of_parse,
-	.outer_cache = {
-		.inv_range   = l2x0_inv_range,
-		.clean_range = l2x0_clean_range,
-		.flush_range = l2x0_flush_range,
-		.flush_all   = l2x0_flush_all,
-		.disable     = l2x0_disable,
-		.sync        = l2x0_cache_sync,
-		.resume      = l2x0_resume,
-	},
-};
-
-static const struct l2c_init_data of_aurora_with_outer_data __initconst = {
-	.of_parse = aurora_of_parse,
-	.save  = aurora_save,
-	.outer_cache = {
-		.inv_range   = aurora_inv_range,
-		.clean_range = aurora_clean_range,
-		.flush_range = aurora_flush_range,
-		.flush_all   = l2x0_flush_all,
-		.disable     = l2x0_disable,
-		.sync        = l2x0_cache_sync,
-		.resume      = aurora_resume,
-	},
-};
-
-static const struct l2c_init_data of_aurora_no_outer_data __initconst = {
-	.of_parse = aurora_of_parse,
-	.save  = aurora_save,
-	.outer_cache = {
-		.resume      = aurora_resume,
-	},
-};
-
 static const struct l2c_init_data of_tauros3_data __initconst = {
 	.save  = tauros3_save,
 	/* Tauros3 broadcasts L1 cache operations to L2 */
@@ -969,20 +983,6 @@ static const struct l2c_init_data of_tauros3_data __initconst = {
 	},
 };
 
-static const struct l2c_init_data of_bcm_l2x0_data __initconst = {
-	.of_parse = pl310_of_parse,
-	.save  = pl310_save,
-	.outer_cache = {
-		.inv_range   = bcm_inv_range,
-		.clean_range = bcm_clean_range,
-		.flush_range = bcm_flush_range,
-		.flush_all   = l2x0_flush_all,
-		.disable     = l2x0_disable,
-		.sync        = l2x0_cache_sync,
-		.resume      = pl310_resume,
-	},
-};
-
 #define L2C_ID(name, fns) { .compatible = name, .data = (void *)&fns }
 static const struct of_device_id l2x0_ids[] __initconst = {
 	L2C_ID("arm,l210-cache", of_l2x0_data),
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 020/222] ARM: l2c: provide enable method
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (18 preceding siblings ...)
  2014-04-25 11:32 ` [PATCH 019/222] ARM: l2c: group implementation specific code together Russell King
@ 2014-04-25 11:32 ` Russell King
  2014-04-25 11:32 ` [PATCH 021/222] ARM: l2c: write auxctrl register before unlocking Russell King
                   ` (202 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:32 UTC (permalink / raw)
  To: linux-arm-kernel

Providing an enable method gives L2 cache controllers a chance to do
special handling at enable time.  This allows us to remove a hack in
l2x0_unlock() for Marvell Aurora L2 caches.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 80 +++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 62 insertions(+), 18 deletions(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 09fe0f5eada5..2adb82e7f4b3 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -29,7 +29,9 @@
 #include "cache-aurora-l2.h"
 
 struct l2c_init_data {
+	unsigned num_lock;
 	void (*of_parse)(const struct device_node *, u32 *, u32 *);
+	void (*enable)(void __iomem *, u32, unsigned);
 	void (*save)(void __iomem *);
 	struct outer_cache_fns outer_cache;
 };
@@ -82,6 +84,36 @@ static inline void l2c_unlock(void __iomem *base, unsigned num)
 	}
 }
 
+/*
+ * Enable the L2 cache controller.  This function must only be
+ * called when the cache controller is known to be disabled.
+ */
+static void l2c_enable(void __iomem *base, u32 aux, unsigned num_lock)
+{
+	unsigned long flags;
+
+	l2c_unlock(base, num_lock);
+
+	writel_relaxed(aux, base + L2X0_AUX_CTRL);
+
+	local_irq_save(flags);
+	__l2c_op_way(base + L2X0_INV_WAY);
+	writel_relaxed(0, base + sync_reg_offset);
+	l2c_wait_mask(base + sync_reg_offset, 1);
+	local_irq_restore(flags);
+
+	writel_relaxed(L2X0_CTRL_EN, base + L2X0_CTRL);
+}
+
+static void l2c_disable(void)
+{
+	void __iomem *base = l2x0_base;
+
+	outer_cache.flush_all();
+	writel_relaxed(0, base + L2X0_CTRL);
+	dsb(st);
+}
+
 #ifdef CONFIG_CACHE_PL310
 static inline void cache_wait(void __iomem *reg, unsigned long mask)
 {
@@ -325,9 +357,6 @@ static void l2x0_unlock(u32 cache_id)
 	case L2X0_CACHE_ID_PART_L310:
 		lockregs = 8;
 		break;
-	case AURORA_CACHE_ID:
-		lockregs = 4;
-		break;
 	default:
 		/* L210 and unknown types */
 		lockregs = 1;
@@ -337,7 +366,22 @@ static void l2x0_unlock(u32 cache_id)
 	l2c_unlock(l2x0_base, lockregs);
 }
 
+static void l2x0_enable(void __iomem *base, u32 aux, unsigned num_lock)
+{
+	/* Make sure that I&D is not locked down when starting */
+	l2x0_unlock(readl_relaxed(base + L2X0_CACHE_ID));
+
+	/* l2x0 controller is disabled */
+	writel_relaxed(aux, base + L2X0_AUX_CTRL);
+
+	l2x0_inv_all();
+
+	/* enable L2X0 */
+	writel_relaxed(L2X0_CTRL_EN, base + L2X0_CTRL);
+}
+
 static const struct l2c_init_data l2x0_init_fns __initconst = {
+	.enable = l2x0_enable,
 	.outer_cache = {
 		.inv_range = l2x0_inv_range,
 		.clean_range = l2x0_clean_range,
@@ -412,22 +456,11 @@ static void __init __l2c_init(const struct l2c_init_data *data,
 	l2x0_size = ways * way_size * SZ_1K;
 
 	/*
-	 * Check if l2x0 controller is already enabled.
-	 * If you are booting from non-secure mode
-	 * accessing the below registers will fault.
+	 * Check if l2x0 controller is already enabled.  If we are booting
+	 * in non-secure mode accessing the below registers will fault.
 	 */
-	if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) {
-		/* Make sure that I&D is not locked down when starting */
-		l2x0_unlock(cache_id);
-
-		/* l2x0 controller is disabled */
-		writel_relaxed(aux, l2x0_base + L2X0_AUX_CTRL);
-
-		l2x0_inv_all();
-
-		/* enable L2X0 */
-		writel_relaxed(L2X0_CTRL_EN, l2x0_base + L2X0_CTRL);
-	}
+	if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN))
+		data->enable(l2x0_base, aux, data->num_lock);
 
 	/* Re-read it in case some bits are reserved. */
 	aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
@@ -515,6 +548,7 @@ static void l2x0_resume(void)
 
 static const struct l2c_init_data of_l2x0_data __initconst = {
 	.of_parse = l2x0_of_parse,
+	.enable = l2x0_enable,
 	.outer_cache = {
 		.inv_range   = l2x0_inv_range,
 		.clean_range = l2x0_clean_range,
@@ -620,7 +654,9 @@ static void pl310_resume(void)
 }
 
 static const struct l2c_init_data of_pl310_data __initconst = {
+	.num_lock = 8,
 	.of_parse = pl310_of_parse,
+	.enable = l2c_enable,
 	.save  = pl310_save,
 	.outer_cache = {
 		.inv_range   = l2x0_inv_range,
@@ -779,7 +815,9 @@ static void __init aurora_of_parse(const struct device_node *np,
 }
 
 static const struct l2c_init_data of_aurora_with_outer_data __initconst = {
+	.num_lock = 4,
 	.of_parse = aurora_of_parse,
+	.enable = l2c_enable,
 	.save  = aurora_save,
 	.outer_cache = {
 		.inv_range   = aurora_inv_range,
@@ -793,7 +831,9 @@ static const struct l2c_init_data of_aurora_with_outer_data __initconst = {
 };
 
 static const struct l2c_init_data of_aurora_no_outer_data __initconst = {
+	.num_lock = 4,
 	.of_parse = aurora_of_parse,
+	.enable = l2c_enable,
 	.save  = aurora_save,
 	.outer_cache = {
 		.resume      = aurora_resume,
@@ -942,7 +982,9 @@ static void bcm_flush_range(unsigned long start, unsigned long end)
 }
 
 static const struct l2c_init_data of_bcm_l2x0_data __initconst = {
+	.num_lock = 8,
 	.of_parse = pl310_of_parse,
+	.enable = l2c_enable,
 	.save  = pl310_save,
 	.outer_cache = {
 		.inv_range   = bcm_inv_range,
@@ -976,6 +1018,8 @@ static void tauros3_resume(void)
 }
 
 static const struct l2c_init_data of_tauros3_data __initconst = {
+	.num_lock = 8,
+	.enable = l2c_enable,
 	.save  = tauros3_save,
 	/* Tauros3 broadcasts L1 cache operations to L2 */
 	.outer_cache = {
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 021/222] ARM: l2c: write auxctrl register before unlocking
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (19 preceding siblings ...)
  2014-04-25 11:32 ` [PATCH 020/222] ARM: l2c: provide enable method Russell King
@ 2014-04-25 11:32 ` Russell King
  2014-04-25 11:32 ` [PATCH 022/222] ARM: l2c: only write the auxiliary control register if required Russell King
                   ` (201 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:32 UTC (permalink / raw)
  To: linux-arm-kernel

We should write the auxillary control register before unlocking: the
write may be necessary to enable non-secure access to the lock
registers.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 2adb82e7f4b3..fc609550b7fa 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -92,10 +92,10 @@ static void l2c_enable(void __iomem *base, u32 aux, unsigned num_lock)
 {
 	unsigned long flags;
 
-	l2c_unlock(base, num_lock);
-
 	writel_relaxed(aux, base + L2X0_AUX_CTRL);
 
+	l2c_unlock(base, num_lock);
+
 	local_irq_save(flags);
 	__l2c_op_way(base + L2X0_INV_WAY);
 	writel_relaxed(0, base + sync_reg_offset);
@@ -368,12 +368,12 @@ static void l2x0_unlock(u32 cache_id)
 
 static void l2x0_enable(void __iomem *base, u32 aux, unsigned num_lock)
 {
-	/* Make sure that I&D is not locked down when starting */
-	l2x0_unlock(readl_relaxed(base + L2X0_CACHE_ID));
-
 	/* l2x0 controller is disabled */
 	writel_relaxed(aux, base + L2X0_AUX_CTRL);
 
+	/* Make sure that I&D is not locked down when starting */
+	l2x0_unlock(readl_relaxed(base + L2X0_CACHE_ID));
+
 	l2x0_inv_all();
 
 	/* enable L2X0 */
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 022/222] ARM: l2c: only write the auxiliary control register if required
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (20 preceding siblings ...)
  2014-04-25 11:32 ` [PATCH 021/222] ARM: l2c: write auxctrl register before unlocking Russell King
@ 2014-04-25 11:32 ` Russell King
  2014-04-25 11:32 ` [PATCH 023/222] ARM: l2c: move aurora broadcast setup to enable function Russell King
                   ` (200 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:32 UTC (permalink / raw)
  To: linux-arm-kernel

Avoid unnecessary writes to the auxiliary control register if the
register already contains the required value.  This allows us to
avoid invoking the platforms secure monitor code unnecessarily.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index fc609550b7fa..1c947b4c7f05 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -92,7 +92,9 @@ static void l2c_enable(void __iomem *base, u32 aux, unsigned num_lock)
 {
 	unsigned long flags;
 
-	writel_relaxed(aux, base + L2X0_AUX_CTRL);
+	/* Only write the aux register if it needs changing */
+	if (readl_relaxed(base + L2X0_AUX_CTRL) != aux)
+		writel_relaxed(aux, base + L2X0_AUX_CTRL);
 
 	l2c_unlock(base, num_lock);
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 023/222] ARM: l2c: move aurora broadcast setup to enable function
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (21 preceding siblings ...)
  2014-04-25 11:32 ` [PATCH 022/222] ARM: l2c: only write the auxiliary control register if required Russell King
@ 2014-04-25 11:32 ` Russell King
  2014-04-25 11:32 ` [PATCH 024/222] ARM: l2c: implement fixups for L2 cache controller quirks/errata Russell King
                   ` (199 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:32 UTC (permalink / raw)
  To: linux-arm-kernel

Rather than having this hacked into the OF initialiation function, we
can handle this via the enable function instead.  While here, clean
up that code and comments a little.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 28 +++++++++++++++-------------
 1 file changed, 15 insertions(+), 13 deletions(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 1c947b4c7f05..5f381af1a7a4 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -784,14 +784,22 @@ static void aurora_resume(void)
 	}
 }
 
-static void __init aurora_broadcast_l2_commands(void)
+/*
+ * For Aurora cache in no outer mode, enable via the CP15 coprocessor
+ * broadcasting of cache commands to L2.
+ */
+static void __init aurora_enable_no_outer(void __iomem *base, u32 aux,
+	unsigned num_lock)
 {
-	__u32 u;
-	/* Enable Broadcasting of cache commands to L2*/
-	__asm__ __volatile__("mrc p15, 1, %0, c15, c2, 0" : "=r"(u));
+	u32 u;
+
+	asm volatile("mrc p15, 1, %0, c15, c2, 0" : "=r" (u));
 	u |= AURORA_CTRL_FW;		/* Set the FW bit */
-	__asm__ __volatile__("mcr p15, 1, %0, c15, c2, 0\n" : : "r"(u));
+	asm volatile("mcr p15, 1, %0, c15, c2, 0" : : "r" (u));
+
 	isb();
+
+	l2c_enable(base, aux, num_lock);
 }
 
 static void __init aurora_of_parse(const struct device_node *np,
@@ -835,7 +843,7 @@ static const struct l2c_init_data of_aurora_with_outer_data __initconst = {
 static const struct l2c_init_data of_aurora_no_outer_data __initconst = {
 	.num_lock = 4,
 	.of_parse = aurora_of_parse,
-	.enable = l2c_enable,
+	.enable = aurora_enable_no_outer,
 	.save  = aurora_save,
 	.outer_cache = {
 		.resume      = aurora_resume,
@@ -1066,16 +1074,10 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
 	data = of_match_node(l2x0_ids, np)->data;
 
 	/* L2 configuration can only be changed if the cache is disabled */
-	if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) {
+	if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN))
 		if (data->of_parse)
 			data->of_parse(np, &aux_val, &aux_mask);
 
-		/* For aurora cache in no outer mode select the
-		 * correct mode using the coprocessor*/
-		if (data == &of_aurora_no_outer_data)
-			aurora_broadcast_l2_commands();
-	}
-
 	if (cache_id_part_number_from_dt)
 		cache_id = cache_id_part_number_from_dt;
 	else
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 024/222] ARM: l2c: implement fixups for L2 cache controller quirks/errata
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (22 preceding siblings ...)
  2014-04-25 11:32 ` [PATCH 023/222] ARM: l2c: move aurora broadcast setup to enable function Russell King
@ 2014-04-25 11:32 ` Russell King
  2014-04-25 11:33 ` [PATCH 025/222] ARM: l2c: clean up L2 cache initialisation messages Russell King
                   ` (198 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:32 UTC (permalink / raw)
  To: linux-arm-kernel

Rather than putting quirk handling in __l2c_init(), move it out to a
separate function which individual implementations can specify.  This
helps to localise the quirks to those implementations which require
them.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 112 ++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 101 insertions(+), 11 deletions(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 5f381af1a7a4..a544f19c448f 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -32,6 +32,7 @@ struct l2c_init_data {
 	unsigned num_lock;
 	void (*of_parse)(const struct device_node *, u32 *, u32 *);
 	void (*enable)(void __iomem *, u32, unsigned);
+	void (*fixup)(void __iomem *, u32, struct outer_cache_fns *);
 	void (*save)(void __iomem *);
 	struct outer_cache_fns outer_cache;
 };
@@ -394,9 +395,80 @@ static const struct l2c_init_data l2x0_init_fns __initconst = {
 	},
 };
 
+/*
+ * L2C-310 specific code.
+ *
+ * Errata:
+ * 588369: PL310 R0P0->R1P0, fixed R2P0.
+ *	Affects: all clean+invalidate operations
+ *	clean and invalidate skips the invalidate step, so we need to issue
+ *	separate operations.  We also require the above debug workaround
+ *	enclosing this code fragment on affected parts.  On unaffected parts,
+ *	we must not use this workaround without the debug register writes
+ *	to avoid exposing a problem similar to 727915.
+ *
+ * 727915: PL310 R2P0->R3P0, fixed R3P1.
+ *	Affects: clean+invalidate by way
+ *	clean and invalidate by way runs in the background, and a store can
+ *	hit the line between the clean operation and invalidate operation,
+ *	resulting in the store being lost.
+ *
+ * 753970: PL310 R3P0, fixed R3P1.
+ *	Affects: sync
+ *	prevents merging writes after the sync operation, until another L2C
+ *	operation is performed (or a number of other conditions.)
+ *
+ * 769419: PL310 R0P0->R3P1, fixed R3P2.
+ *	Affects: store buffer
+ *	store buffer is not automatically drained.
+ */
+static void __init l2c310_fixup(void __iomem *base, u32 cache_id,
+	struct outer_cache_fns *fns)
+{
+	unsigned revision = cache_id & L2X0_CACHE_ID_RTL_MASK;
+	const char *errata[4];
+	unsigned n = 0;
+
+	if (revision <= L310_CACHE_ID_RTL_R3P0)
+		fns->set_debug = pl310_set_debug;
+
+	if (IS_ENABLED(CONFIG_PL310_ERRATA_753970) &&
+	    revision == L310_CACHE_ID_RTL_R3P0) {
+		sync_reg_offset = L2X0_DUMMY_REG;
+		errata[n++] = "753970";
+	}
+
+	if (IS_ENABLED(CONFIG_PL310_ERRATA_769419))
+		errata[n++] = "769419";
+
+	if (n) {
+		unsigned i;
+
+		pr_info("L2C-310 errat%s", n > 1 ? "a" : "um");
+		for (i = 0; i < n; i++)
+			pr_cont(" %s", errata[i]);
+		pr_cont(" enabled\n");
+	}
+}
+
+static const struct l2c_init_data l2c310_init_fns __initconst = {
+	.num_lock = 8,
+	.enable = l2c_enable,
+	.fixup = l2c310_fixup,
+	.outer_cache = {
+		.inv_range = l2x0_inv_range,
+		.clean_range = l2x0_clean_range,
+		.flush_range = l2x0_flush_range,
+		.flush_all = l2x0_flush_all,
+		.disable = l2x0_disable,
+		.sync = l2x0_cache_sync,
+	},
+};
+
 static void __init __l2c_init(const struct l2c_init_data *data,
 	u32 aux_val, u32 aux_mask, u32 cache_id)
 {
+	struct outer_cache_fns fns;
 	u32 aux;
 	u32 way_size = 0;
 	int ways;
@@ -423,23 +495,20 @@ static void __init __l2c_init(const struct l2c_init_data *data,
 		else
 			ways = 8;
 		type = "L310";
-#ifdef CONFIG_PL310_ERRATA_753970
-		/* Unmapped register. */
-		sync_reg_offset = L2X0_DUMMY_REG;
-#endif
 		break;
+
 	case L2X0_CACHE_ID_PART_L210:
 		ways = (aux >> 13) & 0xf;
 		type = "L210";
 		break;
 
 	case AURORA_CACHE_ID:
-		sync_reg_offset = AURORA_SYNC_REG;
 		ways = (aux >> 13) & 0xf;
 		ways = 2 << ((ways + 1) >> 2);
 		way_size_shift = AURORA_WAY_SIZE_SHIFT;
 		type = "Aurora";
 		break;
+
 	default:
 		/* Assume unknown chips have 8 ways */
 		ways = 8;
@@ -457,6 +526,10 @@ static void __init __l2c_init(const struct l2c_init_data *data,
 
 	l2x0_size = ways * way_size * SZ_1K;
 
+	fns = data->outer_cache;
+	if (data->fixup)
+		data->fixup(l2x0_base, cache_id, &fns);
+
 	/*
 	 * Check if l2x0 controller is already enabled.  If we are booting
 	 * in non-secure mode accessing the below registers will fault.
@@ -470,11 +543,7 @@ static void __init __l2c_init(const struct l2c_init_data *data,
 	/* Save the value for resuming. */
 	l2x0_saved_regs.aux_ctrl = aux;
 
-	outer_cache = data->outer_cache;
-
-	if ((cache_id & L2X0_CACHE_ID_PART_MASK) == L2X0_CACHE_ID_PART_L310 &&
-	    (cache_id & L2X0_CACHE_ID_RTL_MASK) <= L310_CACHE_ID_RTL_R3P0)
-		outer_cache.set_debug = pl310_set_debug;
+	outer_cache = fns;
 
 	pr_info("%s cache controller enabled\n", type);
 	pr_info("l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x, Cache size: %d kB\n",
@@ -483,13 +552,24 @@ static void __init __l2c_init(const struct l2c_init_data *data,
 
 void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
 {
+	const struct l2c_init_data *data;
 	u32 cache_id;
 
 	l2x0_base = base;
 
 	cache_id = readl_relaxed(base + L2X0_CACHE_ID);
 
-	__l2c_init(&l2x0_init_fns, aux_val, aux_mask, cache_id);
+	switch (cache_id & L2X0_CACHE_ID_PART_MASK) {
+	default:
+		data = &l2x0_init_fns;
+		break;
+
+	case L2X0_CACHE_ID_PART_L310:
+		data = &l2c310_init_fns;
+		break;
+	}
+
+	__l2c_init(data, aux_val, aux_mask, cache_id);
 }
 
 #ifdef CONFIG_OF
@@ -659,6 +739,7 @@ static const struct l2c_init_data of_pl310_data __initconst = {
 	.num_lock = 8,
 	.of_parse = pl310_of_parse,
 	.enable = l2c_enable,
+	.fixup = l2c310_fixup,
 	.save  = pl310_save,
 	.outer_cache = {
 		.inv_range   = l2x0_inv_range,
@@ -802,6 +883,12 @@ static void __init aurora_enable_no_outer(void __iomem *base, u32 aux,
 	l2c_enable(base, aux, num_lock);
 }
 
+static void __init aurora_fixup(void __iomem *base, u32 cache_id,
+	struct outer_cache_fns *fns)
+{
+	sync_reg_offset = AURORA_SYNC_REG;
+}
+
 static void __init aurora_of_parse(const struct device_node *np,
 				u32 *aux_val, u32 *aux_mask)
 {
@@ -828,6 +915,7 @@ static const struct l2c_init_data of_aurora_with_outer_data __initconst = {
 	.num_lock = 4,
 	.of_parse = aurora_of_parse,
 	.enable = l2c_enable,
+	.fixup = aurora_fixup,
 	.save  = aurora_save,
 	.outer_cache = {
 		.inv_range   = aurora_inv_range,
@@ -844,6 +932,7 @@ static const struct l2c_init_data of_aurora_no_outer_data __initconst = {
 	.num_lock = 4,
 	.of_parse = aurora_of_parse,
 	.enable = aurora_enable_no_outer,
+	.fixup = aurora_fixup,
 	.save  = aurora_save,
 	.outer_cache = {
 		.resume      = aurora_resume,
@@ -995,6 +1084,7 @@ static const struct l2c_init_data of_bcm_l2x0_data __initconst = {
 	.num_lock = 8,
 	.of_parse = pl310_of_parse,
 	.enable = l2c_enable,
+	.fixup = l2c310_fixup,
 	.save  = pl310_save,
 	.outer_cache = {
 		.inv_range   = bcm_inv_range,
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 025/222] ARM: l2c: clean up L2 cache initialisation messages
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (23 preceding siblings ...)
  2014-04-25 11:32 ` [PATCH 024/222] ARM: l2c: implement fixups for L2 cache controller quirks/errata Russell King
@ 2014-04-25 11:33 ` Russell King
  2014-04-25 11:33 ` [PATCH 026/222] ARM: l2c: move and add ARM L2C-2x0/L2C-310 save/resume code to non-OF Russell King
                   ` (197 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:33 UTC (permalink / raw)
  To: linux-arm-kernel

Make one of them purely "English", and the other purely technical.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index a544f19c448f..713cdcef25d1 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -545,9 +545,10 @@ static void __init __l2c_init(const struct l2c_init_data *data,
 
 	outer_cache = fns;
 
-	pr_info("%s cache controller enabled\n", type);
-	pr_info("l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x, Cache size: %d kB\n",
-		ways, cache_id, aux, l2x0_size >> 10);
+	pr_info("%s cache controller enabled, %d ways, %d kB\n",
+		type, ways, l2x0_size >> 10);
+	pr_info("%s: CACHE_ID 0x%08x, AUX_CTRL 0x%08x\n",
+		type, cache_id, aux);
 }
 
 void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 026/222] ARM: l2c: move and add ARM L2C-2x0/L2C-310 save/resume code to non-OF
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (24 preceding siblings ...)
  2014-04-25 11:33 ` [PATCH 025/222] ARM: l2c: clean up L2 cache initialisation messages Russell King
@ 2014-04-25 11:33 ` Russell King
  2014-04-25 11:33 ` [PATCH 027/222] ARM: l2c: clean up save/resume functions Russell King
                   ` (196 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:33 UTC (permalink / raw)
  To: linux-arm-kernel

Add the save/resume code hooks to the non-OF implementations as well.
There's no reason for the non-OF implementations to be any different
from the OF implementations.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 151 ++++++++++++++++++++++++-----------------------
 1 file changed, 77 insertions(+), 74 deletions(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 713cdcef25d1..4d985c17291c 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -383,6 +383,21 @@ static void l2x0_enable(void __iomem *base, u32 aux, unsigned num_lock)
 	writel_relaxed(L2X0_CTRL_EN, base + L2X0_CTRL);
 }
 
+static void l2x0_resume(void)
+{
+	if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) {
+		/* restore aux ctrl and enable l2 */
+		l2x0_unlock(readl_relaxed(l2x0_base + L2X0_CACHE_ID));
+
+		writel_relaxed(l2x0_saved_regs.aux_ctrl, l2x0_base +
+			L2X0_AUX_CTRL);
+
+		l2x0_inv_all();
+
+		writel_relaxed(L2X0_CTRL_EN, l2x0_base + L2X0_CTRL);
+	}
+}
+
 static const struct l2c_init_data l2x0_init_fns __initconst = {
 	.enable = l2x0_enable,
 	.outer_cache = {
@@ -392,6 +407,7 @@ static const struct l2c_init_data l2x0_init_fns __initconst = {
 		.flush_all = l2x0_flush_all,
 		.disable = l2x0_disable,
 		.sync = l2x0_cache_sync,
+		.resume = l2x0_resume,
 	},
 };
 
@@ -422,6 +438,65 @@ static const struct l2c_init_data l2x0_init_fns __initconst = {
  *	Affects: store buffer
  *	store buffer is not automatically drained.
  */
+static void __init pl310_save(void __iomem *base)
+{
+	u32 l2x0_revision = readl_relaxed(base + L2X0_CACHE_ID) &
+		L2X0_CACHE_ID_RTL_MASK;
+
+	l2x0_saved_regs.tag_latency = readl_relaxed(base +
+		L2X0_TAG_LATENCY_CTRL);
+	l2x0_saved_regs.data_latency = readl_relaxed(base +
+		L2X0_DATA_LATENCY_CTRL);
+	l2x0_saved_regs.filter_end = readl_relaxed(base +
+		L2X0_ADDR_FILTER_END);
+	l2x0_saved_regs.filter_start = readl_relaxed(base +
+		L2X0_ADDR_FILTER_START);
+
+	if (l2x0_revision >= L310_CACHE_ID_RTL_R2P0) {
+		/*
+		 * From r2p0, there is Prefetch offset/control register
+		 */
+		l2x0_saved_regs.prefetch_ctrl = readl_relaxed(base +
+			L2X0_PREFETCH_CTRL);
+		/*
+		 * From r3p0, there is Power control register
+		 */
+		if (l2x0_revision >= L310_CACHE_ID_RTL_R3P0)
+			l2x0_saved_regs.pwr_ctrl = readl_relaxed(base +
+				L2X0_POWER_CTRL);
+	}
+}
+
+static void pl310_resume(void)
+{
+	u32 l2x0_revision;
+
+	if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) {
+		/* restore pl310 setup */
+		writel_relaxed(l2x0_saved_regs.tag_latency,
+			l2x0_base + L2X0_TAG_LATENCY_CTRL);
+		writel_relaxed(l2x0_saved_regs.data_latency,
+			l2x0_base + L2X0_DATA_LATENCY_CTRL);
+		writel_relaxed(l2x0_saved_regs.filter_end,
+			l2x0_base + L2X0_ADDR_FILTER_END);
+		writel_relaxed(l2x0_saved_regs.filter_start,
+			l2x0_base + L2X0_ADDR_FILTER_START);
+
+		l2x0_revision = readl_relaxed(l2x0_base + L2X0_CACHE_ID) &
+			L2X0_CACHE_ID_RTL_MASK;
+
+		if (l2x0_revision >= L310_CACHE_ID_RTL_R2P0) {
+			writel_relaxed(l2x0_saved_regs.prefetch_ctrl,
+				l2x0_base + L2X0_PREFETCH_CTRL);
+			if (l2x0_revision >= L310_CACHE_ID_RTL_R3P0)
+				writel_relaxed(l2x0_saved_regs.pwr_ctrl,
+					l2x0_base + L2X0_POWER_CTRL);
+		}
+	}
+
+	l2x0_resume();
+}
+
 static void __init l2c310_fixup(void __iomem *base, u32 cache_id,
 	struct outer_cache_fns *fns)
 {
@@ -455,6 +530,7 @@ static const struct l2c_init_data l2c310_init_fns __initconst = {
 	.num_lock = 8,
 	.enable = l2c_enable,
 	.fixup = l2c310_fixup,
+	.save = pl310_save,
 	.outer_cache = {
 		.inv_range = l2x0_inv_range,
 		.clean_range = l2x0_clean_range,
@@ -462,6 +538,7 @@ static const struct l2c_init_data l2c310_init_fns __initconst = {
 		.flush_all = l2x0_flush_all,
 		.disable = l2x0_disable,
 		.sync = l2x0_cache_sync,
+		.resume = pl310_resume,
 	},
 };
 
@@ -614,21 +691,6 @@ static void __init l2x0_of_parse(const struct device_node *np,
 	*aux_mask &= ~mask;
 }
 
-static void l2x0_resume(void)
-{
-	if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) {
-		/* restore aux ctrl and enable l2 */
-		l2x0_unlock(readl_relaxed(l2x0_base + L2X0_CACHE_ID));
-
-		writel_relaxed(l2x0_saved_regs.aux_ctrl, l2x0_base +
-			L2X0_AUX_CTRL);
-
-		l2x0_inv_all();
-
-		writel_relaxed(L2X0_CTRL_EN, l2x0_base + L2X0_CTRL);
-	}
-}
-
 static const struct l2c_init_data of_l2x0_data __initconst = {
 	.of_parse = l2x0_of_parse,
 	.enable = l2x0_enable,
@@ -677,65 +739,6 @@ static void __init pl310_of_parse(const struct device_node *np,
 	}
 }
 
-static void __init pl310_save(void __iomem *base)
-{
-	u32 l2x0_revision = readl_relaxed(base + L2X0_CACHE_ID) &
-		L2X0_CACHE_ID_RTL_MASK;
-
-	l2x0_saved_regs.tag_latency = readl_relaxed(base +
-		L2X0_TAG_LATENCY_CTRL);
-	l2x0_saved_regs.data_latency = readl_relaxed(base +
-		L2X0_DATA_LATENCY_CTRL);
-	l2x0_saved_regs.filter_end = readl_relaxed(base +
-		L2X0_ADDR_FILTER_END);
-	l2x0_saved_regs.filter_start = readl_relaxed(base +
-		L2X0_ADDR_FILTER_START);
-
-	if (l2x0_revision >= L310_CACHE_ID_RTL_R2P0) {
-		/*
-		 * From r2p0, there is Prefetch offset/control register
-		 */
-		l2x0_saved_regs.prefetch_ctrl = readl_relaxed(base +
-			L2X0_PREFETCH_CTRL);
-		/*
-		 * From r3p0, there is Power control register
-		 */
-		if (l2x0_revision >= L310_CACHE_ID_RTL_R3P0)
-			l2x0_saved_regs.pwr_ctrl = readl_relaxed(base +
-				L2X0_POWER_CTRL);
-	}
-}
-
-static void pl310_resume(void)
-{
-	u32 l2x0_revision;
-
-	if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) {
-		/* restore pl310 setup */
-		writel_relaxed(l2x0_saved_regs.tag_latency,
-			l2x0_base + L2X0_TAG_LATENCY_CTRL);
-		writel_relaxed(l2x0_saved_regs.data_latency,
-			l2x0_base + L2X0_DATA_LATENCY_CTRL);
-		writel_relaxed(l2x0_saved_regs.filter_end,
-			l2x0_base + L2X0_ADDR_FILTER_END);
-		writel_relaxed(l2x0_saved_regs.filter_start,
-			l2x0_base + L2X0_ADDR_FILTER_START);
-
-		l2x0_revision = readl_relaxed(l2x0_base + L2X0_CACHE_ID) &
-			L2X0_CACHE_ID_RTL_MASK;
-
-		if (l2x0_revision >= L310_CACHE_ID_RTL_R2P0) {
-			writel_relaxed(l2x0_saved_regs.prefetch_ctrl,
-				l2x0_base + L2X0_PREFETCH_CTRL);
-			if (l2x0_revision >= L310_CACHE_ID_RTL_R3P0)
-				writel_relaxed(l2x0_saved_regs.pwr_ctrl,
-					l2x0_base + L2X0_POWER_CTRL);
-		}
-	}
-
-	l2x0_resume();
-}
-
 static const struct l2c_init_data of_pl310_data __initconst = {
 	.num_lock = 8,
 	.of_parse = pl310_of_parse,
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 027/222] ARM: l2c: clean up save/resume functions
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (25 preceding siblings ...)
  2014-04-25 11:33 ` [PATCH 026/222] ARM: l2c: move and add ARM L2C-2x0/L2C-310 save/resume code to non-OF Russell King
@ 2014-04-25 11:33 ` Russell King
  2014-04-25 11:33 ` [PATCH 028/222] ARM: l2c: simplify l2x0 unlocking code Russell King
                   ` (195 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:33 UTC (permalink / raw)
  To: linux-arm-kernel

Rename the pl310 save/resume functions to have a l2c310 prefix - this
is it's official name.  Use a local cached copy of the l2x0_base
virtual address, and also realise that many of the resume function
tails are the same as the enable functions, so make a call to the
enable function instead of duplicating that code.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 109 ++++++++++++++++++++++-------------------------
 1 file changed, 52 insertions(+), 57 deletions(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 4d985c17291c..e3f4fcbcc88b 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -385,17 +385,10 @@ static void l2x0_enable(void __iomem *base, u32 aux, unsigned num_lock)
 
 static void l2x0_resume(void)
 {
-	if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) {
-		/* restore aux ctrl and enable l2 */
-		l2x0_unlock(readl_relaxed(l2x0_base + L2X0_CACHE_ID));
-
-		writel_relaxed(l2x0_saved_regs.aux_ctrl, l2x0_base +
-			L2X0_AUX_CTRL);
-
-		l2x0_inv_all();
+	void __iomem *base = l2x0_base;
 
-		writel_relaxed(L2X0_CTRL_EN, l2x0_base + L2X0_CTRL);
-	}
+	if (!(readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN))
+		l2x0_enable(base, l2x0_saved_regs.aux_ctrl, 0);
 }
 
 static const struct l2c_init_data l2x0_init_fns __initconst = {
@@ -438,10 +431,9 @@ static const struct l2c_init_data l2x0_init_fns __initconst = {
  *	Affects: store buffer
  *	store buffer is not automatically drained.
  */
-static void __init pl310_save(void __iomem *base)
+static void __init l2c310_save(void __iomem *base)
 {
-	u32 l2x0_revision = readl_relaxed(base + L2X0_CACHE_ID) &
-		L2X0_CACHE_ID_RTL_MASK;
+	unsigned revision;
 
 	l2x0_saved_regs.tag_latency = readl_relaxed(base +
 		L2X0_TAG_LATENCY_CTRL);
@@ -452,49 +444,49 @@ static void __init pl310_save(void __iomem *base)
 	l2x0_saved_regs.filter_start = readl_relaxed(base +
 		L2X0_ADDR_FILTER_START);
 
-	if (l2x0_revision >= L310_CACHE_ID_RTL_R2P0) {
-		/*
-		 * From r2p0, there is Prefetch offset/control register
-		 */
+	revision = readl_relaxed(base + L2X0_CACHE_ID) &
+			L2X0_CACHE_ID_RTL_MASK;
+
+	/* From r2p0, there is Prefetch offset/control register */
+	if (revision >= L310_CACHE_ID_RTL_R2P0)
 		l2x0_saved_regs.prefetch_ctrl = readl_relaxed(base +
-			L2X0_PREFETCH_CTRL);
-		/*
-		 * From r3p0, there is Power control register
-		 */
-		if (l2x0_revision >= L310_CACHE_ID_RTL_R3P0)
-			l2x0_saved_regs.pwr_ctrl = readl_relaxed(base +
-				L2X0_POWER_CTRL);
-	}
+							L2X0_PREFETCH_CTRL);
+
+	/* From r3p0, there is Power control register */
+	if (revision >= L310_CACHE_ID_RTL_R3P0)
+		l2x0_saved_regs.pwr_ctrl = readl_relaxed(base +
+							L2X0_POWER_CTRL);
 }
 
-static void pl310_resume(void)
+static void l2c310_resume(void)
 {
-	u32 l2x0_revision;
+	void __iomem *base = l2x0_base;
+
+	if (!(readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN)) {
+		unsigned revision;
 
-	if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) {
 		/* restore pl310 setup */
 		writel_relaxed(l2x0_saved_regs.tag_latency,
-			l2x0_base + L2X0_TAG_LATENCY_CTRL);
+			       base + L2X0_TAG_LATENCY_CTRL);
 		writel_relaxed(l2x0_saved_regs.data_latency,
-			l2x0_base + L2X0_DATA_LATENCY_CTRL);
+			       base + L2X0_DATA_LATENCY_CTRL);
 		writel_relaxed(l2x0_saved_regs.filter_end,
-			l2x0_base + L2X0_ADDR_FILTER_END);
+			       base + L2X0_ADDR_FILTER_END);
 		writel_relaxed(l2x0_saved_regs.filter_start,
-			l2x0_base + L2X0_ADDR_FILTER_START);
+			       base + L2X0_ADDR_FILTER_START);
 
-		l2x0_revision = readl_relaxed(l2x0_base + L2X0_CACHE_ID) &
-			L2X0_CACHE_ID_RTL_MASK;
+		revision = readl_relaxed(base + L2X0_CACHE_ID) &
+				L2X0_CACHE_ID_RTL_MASK;
 
-		if (l2x0_revision >= L310_CACHE_ID_RTL_R2P0) {
+		if (revision >= L310_CACHE_ID_RTL_R2P0)
 			writel_relaxed(l2x0_saved_regs.prefetch_ctrl,
-				l2x0_base + L2X0_PREFETCH_CTRL);
-			if (l2x0_revision >= L310_CACHE_ID_RTL_R3P0)
-				writel_relaxed(l2x0_saved_regs.pwr_ctrl,
-					l2x0_base + L2X0_POWER_CTRL);
-		}
-	}
+				       base + L2X0_PREFETCH_CTRL);
+		if (revision >= L310_CACHE_ID_RTL_R3P0)
+			writel_relaxed(l2x0_saved_regs.pwr_ctrl,
+				       base + L2X0_POWER_CTRL);
 
-	l2x0_resume();
+		l2c_enable(base, l2x0_saved_regs.aux_ctrl, 8);
+	}
 }
 
 static void __init l2c310_fixup(void __iomem *base, u32 cache_id,
@@ -530,7 +522,7 @@ static const struct l2c_init_data l2c310_init_fns __initconst = {
 	.num_lock = 8,
 	.enable = l2c_enable,
 	.fixup = l2c310_fixup,
-	.save = pl310_save,
+	.save = l2c310_save,
 	.outer_cache = {
 		.inv_range = l2x0_inv_range,
 		.clean_range = l2x0_clean_range,
@@ -538,7 +530,7 @@ static const struct l2c_init_data l2c310_init_fns __initconst = {
 		.flush_all = l2x0_flush_all,
 		.disable = l2x0_disable,
 		.sync = l2x0_cache_sync,
-		.resume = pl310_resume,
+		.resume = l2c310_resume,
 	},
 };
 
@@ -744,7 +736,7 @@ static const struct l2c_init_data of_pl310_data __initconst = {
 	.of_parse = pl310_of_parse,
 	.enable = l2c_enable,
 	.fixup = l2c310_fixup,
-	.save  = pl310_save,
+	.save  = l2c310_save,
 	.outer_cache = {
 		.inv_range   = l2x0_inv_range,
 		.clean_range = l2x0_clean_range,
@@ -752,7 +744,7 @@ static const struct l2c_init_data of_pl310_data __initconst = {
 		.flush_all   = l2x0_flush_all,
 		.disable     = l2x0_disable,
 		.sync        = l2x0_cache_sync,
-		.resume      = pl310_resume,
+		.resume      = l2c310_resume,
 	},
 };
 
@@ -862,10 +854,11 @@ static void aurora_save(void __iomem *base)
 
 static void aurora_resume(void)
 {
-	if (!(readl(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) {
-		writel_relaxed(l2x0_saved_regs.aux_ctrl,
-				l2x0_base + L2X0_AUX_CTRL);
-		writel_relaxed(l2x0_saved_regs.ctrl, l2x0_base + L2X0_CTRL);
+	void __iomem *base = l2x0_base;
+
+	if (!(readl(base + L2X0_CTRL) & L2X0_CTRL_EN)) {
+		writel_relaxed(l2x0_saved_regs.aux_ctrl, base + L2X0_AUX_CTRL);
+		writel_relaxed(l2x0_saved_regs.ctrl, base + L2X0_CTRL);
 	}
 }
 
@@ -1089,7 +1082,7 @@ static const struct l2c_init_data of_bcm_l2x0_data __initconst = {
 	.of_parse = pl310_of_parse,
 	.enable = l2c_enable,
 	.fixup = l2c310_fixup,
-	.save  = pl310_save,
+	.save  = l2c310_save,
 	.outer_cache = {
 		.inv_range   = bcm_inv_range,
 		.clean_range = bcm_clean_range,
@@ -1097,7 +1090,7 @@ static const struct l2c_init_data of_bcm_l2x0_data __initconst = {
 		.flush_all   = l2x0_flush_all,
 		.disable     = l2x0_disable,
 		.sync        = l2x0_cache_sync,
-		.resume      = pl310_resume,
+		.resume      = l2c310_resume,
 	},
 };
 
@@ -1111,14 +1104,16 @@ static void __init tauros3_save(void __iomem *base)
 
 static void tauros3_resume(void)
 {
-	if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) {
+	void __iomem *base = l2x0_base;
+
+	if (!(readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN)) {
 		writel_relaxed(l2x0_saved_regs.aux2_ctrl,
-			       l2x0_base + TAUROS3_AUX2_CTRL);
+			       base + TAUROS3_AUX2_CTRL);
 		writel_relaxed(l2x0_saved_regs.prefetch_ctrl,
-			       l2x0_base + L2X0_PREFETCH_CTRL);
-	}
+			       base + L2X0_PREFETCH_CTRL);
 
-	l2x0_resume();
+		l2c_enable(base, l2x0_saved_regs.aux_ctrl, 8);
+	}
 }
 
 static const struct l2c_init_data of_tauros3_data __initconst = {
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 028/222] ARM: l2c: simplify l2x0 unlocking code
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (26 preceding siblings ...)
  2014-04-25 11:33 ` [PATCH 027/222] ARM: l2c: clean up save/resume functions Russell King
@ 2014-04-25 11:33 ` Russell King
  2014-04-25 11:33 ` [PATCH 029/222] ARM: l2c: move pl310_set_debug() into l2c-310 code Russell King
                   ` (194 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:33 UTC (permalink / raw)
  To: linux-arm-kernel

The l2x0 unlocking code is only called from l2x0_enable() now, so move
the logic entirely into that function and simplify it.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 25 ++++++++-----------------
 1 file changed, 8 insertions(+), 17 deletions(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index e3f4fcbcc88b..157fd7ae331a 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -352,30 +352,21 @@ static void l2x0_disable(void)
 	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
 }
 
-static void l2x0_unlock(u32 cache_id)
+static void l2x0_enable(void __iomem *base, u32 aux, unsigned num_lock)
 {
-	int lockregs;
+	unsigned id;
 
-	switch (cache_id & L2X0_CACHE_ID_PART_MASK) {
-	case L2X0_CACHE_ID_PART_L310:
-		lockregs = 8;
-		break;
-	default:
-		/* L210 and unknown types */
-		lockregs = 1;
-		break;
-	}
-
-	l2c_unlock(l2x0_base, lockregs);
-}
+	id = readl_relaxed(base + L2X0_CACHE_ID) & L2X0_CACHE_ID_PART_MASK;
+	if (id == L2X0_CACHE_ID_PART_L310)
+		num_lock = 8;
+	else
+		num_lock = 1;
 
-static void l2x0_enable(void __iomem *base, u32 aux, unsigned num_lock)
-{
 	/* l2x0 controller is disabled */
 	writel_relaxed(aux, base + L2X0_AUX_CTRL);
 
 	/* Make sure that I&D is not locked down when starting */
-	l2x0_unlock(readl_relaxed(base + L2X0_CACHE_ID));
+	l2c_unlock(base, num_lock);
 
 	l2x0_inv_all();
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 029/222] ARM: l2c: move pl310_set_debug() into l2c-310 code
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (27 preceding siblings ...)
  2014-04-25 11:33 ` [PATCH 028/222] ARM: l2c: simplify l2x0 unlocking code Russell King
@ 2014-04-25 11:33 ` Russell King
  2014-04-25 11:33 ` [PATCH 030/222] ARM: l2c: add L2C-210 specific handlers Russell King
                   ` (193 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:33 UTC (permalink / raw)
  To: linux-arm-kernel

Move the pl310_set_debug() into the l2c-310 code area, and don't hide
it with ifdefs.  Rename it to l2c310_set_debug().

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 157fd7ae331a..9586be73ca4f 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -154,18 +154,11 @@ static inline void debug_writel(unsigned long val)
 	if (outer_cache.set_debug)
 		l2c_set_debug(l2x0_base, val);
 }
-
-static void pl310_set_debug(unsigned long val)
-{
-	writel_relaxed(val, l2x0_base + L2X0_DEBUG_CTRL);
-}
 #else
 /* Optimised out for non-errata case */
 static inline void debug_writel(unsigned long val)
 {
 }
-
-#define pl310_set_debug	NULL
 #endif
 
 #ifdef CONFIG_PL310_ERRATA_588369
@@ -422,6 +415,11 @@ static const struct l2c_init_data l2x0_init_fns __initconst = {
  *	Affects: store buffer
  *	store buffer is not automatically drained.
  */
+static void l2c310_set_debug(unsigned long val)
+{
+	writel_relaxed(val, l2x0_base + L2X0_DEBUG_CTRL);
+}
+
 static void __init l2c310_save(void __iomem *base)
 {
 	unsigned revision;
@@ -488,7 +486,7 @@ static void __init l2c310_fixup(void __iomem *base, u32 cache_id,
 	unsigned n = 0;
 
 	if (revision <= L310_CACHE_ID_RTL_R3P0)
-		fns->set_debug = pl310_set_debug;
+		fns->set_debug = l2c310_set_debug;
 
 	if (IS_ENABLED(CONFIG_PL310_ERRATA_753970) &&
 	    revision == L310_CACHE_ID_RTL_R3P0) {
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 030/222] ARM: l2c: add L2C-210 specific handlers
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (28 preceding siblings ...)
  2014-04-25 11:33 ` [PATCH 029/222] ARM: l2c: move pl310_set_debug() into l2c-310 code Russell King
@ 2014-04-25 11:33 ` Russell King
  2014-04-25 11:33 ` [PATCH 031/222] ARM: l2c: implement L2C-310 erratum 727915 as a method override Russell King
                   ` (192 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:33 UTC (permalink / raw)
  To: linux-arm-kernel

Add L2C-210 specific cache operation handlers.  These are tailored to
the requirements of the L2C-210 cache controller, which doesn't
require any workarounds.  We avoid using the way operations during
normal operation, which means we can avoid locking: the only time
we use the way operations are during initialisation, and when
disabling the cache.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 122 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 9586be73ca4f..d07fa4fc95a3 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -389,6 +389,108 @@ static const struct l2c_init_data l2x0_init_fns __initconst = {
 };
 
 /*
+ * L2C-210 specific code.
+ *
+ * The L2C-2x0 PA, set/way and sync operations are atomic, but we must
+ * ensure that no background operation is running.  The way operations
+ * are all background tasks.
+ *
+ * While a background operation is in progress, any new operation is
+ * ignored (unspecified whether this causes an error.)  Thankfully, not
+ * used on SMP.
+ *
+ * Never has a different sync register other than L2X0_CACHE_SYNC, but
+ * we use sync_reg_offset here so we can share some of this with L2C-310.
+ */
+static void __l2c210_cache_sync(void __iomem *base)
+{
+	writel_relaxed(0, base + sync_reg_offset);
+}
+
+static void __l2c210_op_pa_range(void __iomem *reg, unsigned long start,
+	unsigned long end)
+{
+	while (start < end) {
+		writel_relaxed(start, reg);
+		start += CACHE_LINE_SIZE;
+	}
+}
+
+static void l2c210_inv_range(unsigned long start, unsigned long end)
+{
+	void __iomem *base = l2x0_base;
+
+	if (start & (CACHE_LINE_SIZE - 1)) {
+		start &= ~(CACHE_LINE_SIZE - 1);
+		writel_relaxed(start, base + L2X0_CLEAN_INV_LINE_PA);
+		start += CACHE_LINE_SIZE;
+	}
+
+	if (end & (CACHE_LINE_SIZE - 1)) {
+		end &= ~(CACHE_LINE_SIZE - 1);
+		writel_relaxed(end, base + L2X0_CLEAN_INV_LINE_PA);
+	}
+
+	__l2c210_op_pa_range(base + L2X0_INV_LINE_PA, start, end);
+	__l2c210_cache_sync(base);
+}
+
+static void l2c210_clean_range(unsigned long start, unsigned long end)
+{
+	void __iomem *base = l2x0_base;
+
+	start &= ~(CACHE_LINE_SIZE - 1);
+	__l2c210_op_pa_range(base + L2X0_CLEAN_LINE_PA, start, end);
+	__l2c210_cache_sync(base);
+}
+
+static void l2c210_flush_range(unsigned long start, unsigned long end)
+{
+	void __iomem *base = l2x0_base;
+
+	start &= ~(CACHE_LINE_SIZE - 1);
+	__l2c210_op_pa_range(base + L2X0_CLEAN_INV_LINE_PA, start, end);
+	__l2c210_cache_sync(base);
+}
+
+static void l2c210_flush_all(void)
+{
+	void __iomem *base = l2x0_base;
+
+	BUG_ON(!irqs_disabled());
+
+	__l2c_op_way(base + L2X0_CLEAN_INV_WAY);
+	__l2c210_cache_sync(base);
+}
+
+static void l2c210_sync(void)
+{
+	__l2c210_cache_sync(l2x0_base);
+}
+
+static void l2c210_resume(void)
+{
+	void __iomem *base = l2x0_base;
+
+	if (!(readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN))
+		l2c_enable(base, l2x0_saved_regs.aux_ctrl, 1);
+}
+
+static const struct l2c_init_data l2c210_data __initconst = {
+	.num_lock = 1,
+	.enable = l2c_enable,
+	.outer_cache = {
+		.inv_range = l2c210_inv_range,
+		.clean_range = l2c210_clean_range,
+		.flush_range = l2c210_flush_range,
+		.flush_all = l2c210_flush_all,
+		.disable = l2c_disable,
+		.sync = l2c210_sync,
+		.resume = l2c210_resume,
+	},
+};
+
+/*
  * L2C-310 specific code.
  *
  * Errata:
@@ -623,6 +725,10 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
 		data = &l2x0_init_fns;
 		break;
 
+	case L2X0_CACHE_ID_PART_L210:
+		data = &l2c210_data;
+		break;
+
 	case L2X0_CACHE_ID_PART_L310:
 		data = &l2c310_init_fns;
 		break;
@@ -672,6 +778,21 @@ static void __init l2x0_of_parse(const struct device_node *np,
 	*aux_mask &= ~mask;
 }
 
+static const struct l2c_init_data of_l2c210_data __initconst = {
+	.num_lock = 1,
+	.of_parse = l2x0_of_parse,
+	.enable = l2c_enable,
+	.outer_cache = {
+		.inv_range   = l2c210_inv_range,
+		.clean_range = l2c210_clean_range,
+		.flush_range = l2c210_flush_range,
+		.flush_all   = l2c210_flush_all,
+		.disable     = l2c_disable,
+		.sync        = l2c210_sync,
+		.resume      = l2c210_resume,
+	},
+};
+
 static const struct l2c_init_data of_l2x0_data __initconst = {
 	.of_parse = l2x0_of_parse,
 	.enable = l2x0_enable,
@@ -1117,7 +1238,7 @@ static const struct l2c_init_data of_tauros3_data __initconst = {
 
 #define L2C_ID(name, fns) { .compatible = name, .data = (void *)&fns }
 static const struct of_device_id l2x0_ids[] __initconst = {
-	L2C_ID("arm,l210-cache", of_l2x0_data),
+	L2C_ID("arm,l210-cache", of_l2c210_data),
 	L2C_ID("arm,l220-cache", of_l2x0_data),
 	L2C_ID("arm,pl310-cache", of_pl310_data),
 	L2C_ID("brcm,bcm11351-a2-pl310-cache", of_bcm_l2x0_data),
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 031/222] ARM: l2c: implement L2C-310 erratum 727915 as a method override
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (29 preceding siblings ...)
  2014-04-25 11:33 ` [PATCH 030/222] ARM: l2c: add L2C-210 specific handlers Russell King
@ 2014-04-25 11:33 ` Russell King
  2014-04-25 11:33 ` [PATCH 032/222] ARM: l2c: implement L2C-310 erratum 588369 " Russell King
                   ` (191 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:33 UTC (permalink / raw)
  To: linux-arm-kernel

Implement L2C-310 erratum 727915 by overriding the flush_all method
in the outer_cache operations structure.  This allows us to sensibly
contain the erratum code in one place without affecting other
locations or implementations.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index d07fa4fc95a3..6161232c8a85 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -522,6 +522,19 @@ static void l2c310_set_debug(unsigned long val)
 	writel_relaxed(val, l2x0_base + L2X0_DEBUG_CTRL);
 }
 
+static void l2c310_flush_all_erratum(void)
+{
+	void __iomem *base = l2x0_base;
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&l2x0_lock, flags);
+	l2c_set_debug(base, 0x03);
+	__l2c_op_way(base + L2X0_CLEAN_INV_WAY);
+	l2c_set_debug(base, 0x00);
+	__l2c210_cache_sync(base);
+	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
+}
+
 static void __init l2c310_save(void __iomem *base)
 {
 	unsigned revision;
@@ -590,6 +603,13 @@ static void __init l2c310_fixup(void __iomem *base, u32 cache_id,
 	if (revision <= L310_CACHE_ID_RTL_R3P0)
 		fns->set_debug = l2c310_set_debug;
 
+	if (IS_ENABLED(CONFIG_PL310_ERRATA_727915) &&
+	    revision >= L310_CACHE_ID_RTL_R2P0 &&
+	    revision < L310_CACHE_ID_RTL_R3P1) {
+		fns->flush_all = l2c310_flush_all_erratum;
+		errata[n++] = "727915";
+	}
+
 	if (IS_ENABLED(CONFIG_PL310_ERRATA_753970) &&
 	    revision == L310_CACHE_ID_RTL_R3P0) {
 		sync_reg_offset = L2X0_DUMMY_REG;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 032/222] ARM: l2c: implement L2C-310 erratum 588369 as a method override
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (30 preceding siblings ...)
  2014-04-25 11:33 ` [PATCH 031/222] ARM: l2c: implement L2C-310 erratum 727915 as a method override Russell King
@ 2014-04-25 11:33 ` Russell King
  2014-04-25 11:33 ` [PATCH 033/222] ARM: l2c: use L2C-210 handlers for L2C-310 errata-less implementations Russell King
                   ` (190 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:33 UTC (permalink / raw)
  To: linux-arm-kernel

Implement L2C-310 erratum 588369 by overriding the invalidate range
and flush range methods in the outer_cache operations structure.
This allows us to sensibly contain the erratum code in one place
without affecting other locations/implemetations.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 6161232c8a85..79ff08db204d 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -522,6 +522,65 @@ static void l2c310_set_debug(unsigned long val)
 	writel_relaxed(val, l2x0_base + L2X0_DEBUG_CTRL);
 }
 
+static void l2c310_inv_range_erratum(unsigned long start, unsigned long end)
+{
+	void __iomem *base = l2x0_base;
+
+	if ((start | end) & (CACHE_LINE_SIZE - 1)) {
+		unsigned long flags;
+
+		/* Erratum 588369 for both clean+invalidate operations */
+		raw_spin_lock_irqsave(&l2x0_lock, flags);
+		l2c_set_debug(base, 0x03);
+
+		if (start & (CACHE_LINE_SIZE - 1)) {
+			start &= ~(CACHE_LINE_SIZE - 1);
+			writel_relaxed(start, base + L2X0_CLEAN_LINE_PA);
+			writel_relaxed(start, base + L2X0_INV_LINE_PA);
+			start += CACHE_LINE_SIZE;
+		}
+
+		if (end & (CACHE_LINE_SIZE - 1)) {
+			end &= ~(CACHE_LINE_SIZE - 1);
+			writel_relaxed(end, base + L2X0_CLEAN_LINE_PA);
+			writel_relaxed(end, base + L2X0_INV_LINE_PA);
+		}
+
+		l2c_set_debug(base, 0x00);
+		raw_spin_unlock_irqrestore(&l2x0_lock, flags);
+	}
+
+	__l2c210_op_pa_range(base + L2X0_INV_LINE_PA, start, end);
+	__l2c210_cache_sync(base);
+}
+
+static void l2c310_flush_range_erratum(unsigned long start, unsigned long end)
+{
+	raw_spinlock_t *lock = &l2x0_lock;
+	unsigned long flags;
+	void __iomem *base = l2x0_base;
+
+	raw_spin_lock_irqsave(lock, flags);
+	while (start < end) {
+		unsigned long blk_end = start + min(end - start, 4096UL);
+
+		l2c_set_debug(base, 0x03);
+		while (start < blk_end) {
+			writel_relaxed(start, base + L2X0_CLEAN_LINE_PA);
+			writel_relaxed(start, base + L2X0_INV_LINE_PA);
+			start += CACHE_LINE_SIZE;
+		}
+		l2c_set_debug(base, 0x00);
+
+		if (blk_end < end) {
+			raw_spin_unlock_irqrestore(lock, flags);
+			raw_spin_lock_irqsave(lock, flags);
+		}
+	}
+	raw_spin_unlock_irqrestore(lock, flags);
+	__l2c210_cache_sync(base);
+}
+
 static void l2c310_flush_all_erratum(void)
 {
 	void __iomem *base = l2x0_base;
@@ -600,9 +659,19 @@ static void __init l2c310_fixup(void __iomem *base, u32 cache_id,
 	const char *errata[4];
 	unsigned n = 0;
 
+	/* For compatibility */
 	if (revision <= L310_CACHE_ID_RTL_R3P0)
 		fns->set_debug = l2c310_set_debug;
 
+	if (IS_ENABLED(CONFIG_PL310_ERRATA_588369) &&
+	    revision < L310_CACHE_ID_RTL_R2P0 &&
+	    /* For bcm compatibility */
+	    fns->inv_range == l2x0_inv_range) {
+		fns->inv_range = l2c310_inv_range_erratum;
+		fns->flush_range = l2c310_flush_range_erratum;
+		errata[n++] = "588369";
+	}
+
 	if (IS_ENABLED(CONFIG_PL310_ERRATA_727915) &&
 	    revision >= L310_CACHE_ID_RTL_R2P0 &&
 	    revision < L310_CACHE_ID_RTL_R3P1) {
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 033/222] ARM: l2c: use L2C-210 handlers for L2C-310 errata-less implementations
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (31 preceding siblings ...)
  2014-04-25 11:33 ` [PATCH 032/222] ARM: l2c: implement L2C-310 erratum 588369 " Russell King
@ 2014-04-25 11:33 ` Russell King
  2014-04-25 11:33 ` [PATCH 034/222] ARM: l2c: add L2C-220 specific handlers Russell King
                   ` (189 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:33 UTC (permalink / raw)
  To: linux-arm-kernel

Where no errata affect the L2C-310 handlers, they are functionally
equivalent to L2C-210.  Re-use the L2C-210 handlers for the L2C-310
part.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 58 ++++++++++++++++++++++++++++++------------------
 1 file changed, 36 insertions(+), 22 deletions(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 79ff08db204d..49ddff972cb3 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -493,6 +493,18 @@ static const struct l2c_init_data l2c210_data __initconst = {
 /*
  * L2C-310 specific code.
  *
+ * Very similar to L2C-210, the PA, set/way and sync operations are atomic,
+ * and the way operations are all background tasks.  However, issuing an
+ * operation while a background operation is in progress results in a
+ * SLVERR response.  We can reuse:
+ *
+ *  __l2c210_cache_sync (using sync_reg_offset)
+ *  l2c210_sync
+ *  l2c210_inv_range (if 588369 is not applicable)
+ *  l2c210_clean_range
+ *  l2c210_flush_range (if 588369 is not applicable)
+ *  l2c210_flush_all (if 727915 is not applicable)
+ *
  * Errata:
  * 588369: PL310 R0P0->R1P0, fixed R2P0.
  *	Affects: all clean+invalidate operations
@@ -666,7 +678,7 @@ static void __init l2c310_fixup(void __iomem *base, u32 cache_id,
 	if (IS_ENABLED(CONFIG_PL310_ERRATA_588369) &&
 	    revision < L310_CACHE_ID_RTL_R2P0 &&
 	    /* For bcm compatibility */
-	    fns->inv_range == l2x0_inv_range) {
+	    fns->inv_range == l2c210_inv_range) {
 		fns->inv_range = l2c310_inv_range_erratum;
 		fns->flush_range = l2c310_flush_range_erratum;
 		errata[n++] = "588369";
@@ -704,12 +716,13 @@ static const struct l2c_init_data l2c310_init_fns __initconst = {
 	.fixup = l2c310_fixup,
 	.save = l2c310_save,
 	.outer_cache = {
-		.inv_range = l2x0_inv_range,
-		.clean_range = l2x0_clean_range,
-		.flush_range = l2x0_flush_range,
-		.flush_all = l2x0_flush_all,
-		.disable = l2x0_disable,
-		.sync = l2x0_cache_sync,
+		.inv_range = l2c210_inv_range,
+		.clean_range = l2c210_clean_range,
+		.flush_range = l2c210_flush_range,
+		.flush_all = l2c210_flush_all,
+		.disable = l2c_disable,
+		.sync = l2c210_sync,
+		.set_debug = l2c310_set_debug,
 		.resume = l2c310_resume,
 	},
 };
@@ -896,8 +909,8 @@ static const struct l2c_init_data of_l2x0_data __initconst = {
 	},
 };
 
-static void __init pl310_of_parse(const struct device_node *np,
-				  u32 *aux_val, u32 *aux_mask)
+static void __init l2c310_of_parse(const struct device_node *np,
+	u32 *aux_val, u32 *aux_mask)
 {
 	u32 data[3] = { 0, 0, 0 };
 	u32 tag[3] = { 0, 0, 0 };
@@ -930,19 +943,20 @@ static void __init pl310_of_parse(const struct device_node *np,
 	}
 }
 
-static const struct l2c_init_data of_pl310_data __initconst = {
+static const struct l2c_init_data of_l2c310_data __initconst = {
 	.num_lock = 8,
-	.of_parse = pl310_of_parse,
+	.of_parse = l2c310_of_parse,
 	.enable = l2c_enable,
 	.fixup = l2c310_fixup,
 	.save  = l2c310_save,
 	.outer_cache = {
-		.inv_range   = l2x0_inv_range,
-		.clean_range = l2x0_clean_range,
-		.flush_range = l2x0_flush_range,
-		.flush_all   = l2x0_flush_all,
-		.disable     = l2x0_disable,
-		.sync        = l2x0_cache_sync,
+		.inv_range   = l2c210_inv_range,
+		.clean_range = l2c210_clean_range,
+		.flush_range = l2c210_flush_range,
+		.flush_all   = l2c210_flush_all,
+		.disable     = l2c_disable,
+		.sync        = l2c210_sync,
+		.set_debug   = l2c310_set_debug,
 		.resume      = l2c310_resume,
 	},
 };
@@ -1278,7 +1292,7 @@ static void bcm_flush_range(unsigned long start, unsigned long end)
 
 static const struct l2c_init_data of_bcm_l2x0_data __initconst = {
 	.num_lock = 8,
-	.of_parse = pl310_of_parse,
+	.of_parse = l2c310_of_parse,
 	.enable = l2c_enable,
 	.fixup = l2c310_fixup,
 	.save  = l2c310_save,
@@ -1286,9 +1300,9 @@ static const struct l2c_init_data of_bcm_l2x0_data __initconst = {
 		.inv_range   = bcm_inv_range,
 		.clean_range = bcm_clean_range,
 		.flush_range = bcm_flush_range,
-		.flush_all   = l2x0_flush_all,
-		.disable     = l2x0_disable,
-		.sync        = l2x0_cache_sync,
+		.flush_all   = l2c210_flush_all,
+		.disable     = l2c_disable,
+		.sync        = l2c210_sync,
 		.resume      = l2c310_resume,
 	},
 };
@@ -1329,7 +1343,7 @@ static const struct l2c_init_data of_tauros3_data __initconst = {
 static const struct of_device_id l2x0_ids[] __initconst = {
 	L2C_ID("arm,l210-cache", of_l2c210_data),
 	L2C_ID("arm,l220-cache", of_l2x0_data),
-	L2C_ID("arm,pl310-cache", of_pl310_data),
+	L2C_ID("arm,pl310-cache", of_l2c310_data),
 	L2C_ID("brcm,bcm11351-a2-pl310-cache", of_bcm_l2x0_data),
 	L2C_ID("marvell,aurora-outer-cache", of_aurora_with_outer_data),
 	L2C_ID("marvell,aurora-system-cache", of_aurora_no_outer_data),
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 034/222] ARM: l2c: add L2C-220 specific handlers
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (32 preceding siblings ...)
  2014-04-25 11:33 ` [PATCH 033/222] ARM: l2c: use L2C-210 handlers for L2C-310 errata-less implementations Russell King
@ 2014-04-25 11:33 ` Russell King
  2014-04-25 11:33 ` [PATCH 035/222] ARM: l2c: convert Broadcom L2C-310 to new code Russell King
                   ` (188 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:33 UTC (permalink / raw)
  To: linux-arm-kernel

The L2C-220 is different from the L2C-210 and L2C-310 in that every
operation is a background operation: this means we have to use
spinlocks to protect all operations, and we have to wait for every
operation to complete.

Should a second operation be attempted while a previous operation
is in progress, the response will be an imprecise abort.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 167 ++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 157 insertions(+), 10 deletions(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 49ddff972cb3..751c3d7a22b3 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -491,6 +491,148 @@ static const struct l2c_init_data l2c210_data __initconst = {
 };
 
 /*
+ * L2C-220 specific code.
+ *
+ * All operations are background operations: they have to be waited for.
+ * Conflicting requests generate a slave error (which will cause an
+ * imprecise abort.)  Never uses sync_reg_offset, so we hard-code the
+ * sync register here.
+ *
+ * However, we can re-use the l2c210_resume call.
+ */
+static inline void __l2c220_cache_sync(void __iomem *base)
+{
+	writel_relaxed(0, base + L2X0_CACHE_SYNC);
+	l2c_wait_mask(base + L2X0_CACHE_SYNC, 1);
+}
+
+static void l2c220_op_way(void __iomem *base, unsigned reg)
+{
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&l2x0_lock, flags);
+	__l2c_op_way(base + reg);
+	__l2c220_cache_sync(base);
+	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
+}
+
+static unsigned long l2c220_op_pa_range(void __iomem *reg, unsigned long start,
+	unsigned long end, unsigned long flags)
+{
+	raw_spinlock_t *lock = &l2x0_lock;
+
+	while (start < end) {
+		unsigned long blk_end = start + min(end - start, 4096UL);
+
+		while (start < blk_end) {
+			l2c_wait_mask(reg, 1);
+			writel_relaxed(start, reg);
+			start += CACHE_LINE_SIZE;
+		}
+
+		if (blk_end < end) {
+			raw_spin_unlock_irqrestore(lock, flags);
+			raw_spin_lock_irqsave(lock, flags);
+		}
+	}
+
+	return flags;
+}
+
+static void l2c220_inv_range(unsigned long start, unsigned long end)
+{
+	void __iomem *base = l2x0_base;
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&l2x0_lock, flags);
+	if ((start | end) & (CACHE_LINE_SIZE - 1)) {
+		if (start & (CACHE_LINE_SIZE - 1)) {
+			start &= ~(CACHE_LINE_SIZE - 1);
+			writel_relaxed(start, base + L2X0_CLEAN_INV_LINE_PA);
+			start += CACHE_LINE_SIZE;
+		}
+
+		if (end & (CACHE_LINE_SIZE - 1)) {
+			end &= ~(CACHE_LINE_SIZE - 1);
+			l2c_wait_mask(base + L2X0_CLEAN_INV_LINE_PA, 1);
+			writel_relaxed(end, base + L2X0_CLEAN_INV_LINE_PA);
+		}
+	}
+
+	flags = l2c220_op_pa_range(base + L2X0_INV_LINE_PA,
+				   start, end, flags);
+	l2c_wait_mask(base + L2X0_INV_LINE_PA, 1);
+	__l2c220_cache_sync(base);
+	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
+}
+
+static void l2c220_clean_range(unsigned long start, unsigned long end)
+{
+	void __iomem *base = l2x0_base;
+	unsigned long flags;
+
+	start &= ~(CACHE_LINE_SIZE - 1);
+	if ((end - start) >= l2x0_size) {
+		l2c220_op_way(base, L2X0_CLEAN_WAY);
+		return;
+	}
+
+	raw_spin_lock_irqsave(&l2x0_lock, flags);
+	flags = l2c220_op_pa_range(base + L2X0_CLEAN_LINE_PA,
+				   start, end, flags);
+	l2c_wait_mask(base + L2X0_CLEAN_INV_LINE_PA, 1);
+	__l2c220_cache_sync(base);
+	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
+}
+
+static void l2c220_flush_range(unsigned long start, unsigned long end)
+{
+	void __iomem *base = l2x0_base;
+	unsigned long flags;
+
+	start &= ~(CACHE_LINE_SIZE - 1);
+	if ((end - start) >= l2x0_size) {
+		l2c220_op_way(base, L2X0_CLEAN_INV_WAY);
+		return;
+	}
+
+	raw_spin_lock_irqsave(&l2x0_lock, flags);
+	flags = l2c220_op_pa_range(base + L2X0_CLEAN_INV_LINE_PA,
+				   start, end, flags);
+	l2c_wait_mask(base + L2X0_CLEAN_INV_LINE_PA, 1);
+	__l2c220_cache_sync(base);
+	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
+}
+
+static void l2c220_flush_all(void)
+{
+	l2c220_op_way(l2x0_base, L2X0_CLEAN_INV_WAY);
+}
+
+static void l2c220_sync(void)
+{
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&l2x0_lock, flags);
+	__l2c220_cache_sync(l2x0_base);
+	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
+}
+
+static const struct l2c_init_data l2c220_data = {
+	.num_lock = 1,
+	.enable = l2c_enable,
+	.outer_cache = {
+		.inv_range = l2c220_inv_range,
+		.clean_range = l2c220_clean_range,
+		.flush_range = l2c220_flush_range,
+		.flush_all = l2c220_flush_all,
+		.disable = l2c_disable,
+		.sync = l2c220_sync,
+		.resume = l2c210_resume,
+	},
+};
+
+/*
  * L2C-310 specific code.
  *
  * Very similar to L2C-210, the PA, set/way and sync operations are atomic,
@@ -831,6 +973,10 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
 		data = &l2c210_data;
 		break;
 
+	case L2X0_CACHE_ID_PART_L220:
+		data = &l2c220_data;
+		break;
+
 	case L2X0_CACHE_ID_PART_L310:
 		data = &l2c310_init_fns;
 		break;
@@ -895,17 +1041,18 @@ static const struct l2c_init_data of_l2c210_data __initconst = {
 	},
 };
 
-static const struct l2c_init_data of_l2x0_data __initconst = {
+static const struct l2c_init_data of_l2c220_data __initconst = {
+	.num_lock = 1,
 	.of_parse = l2x0_of_parse,
-	.enable = l2x0_enable,
+	.enable = l2c_enable,
 	.outer_cache = {
-		.inv_range   = l2x0_inv_range,
-		.clean_range = l2x0_clean_range,
-		.flush_range = l2x0_flush_range,
-		.flush_all   = l2x0_flush_all,
-		.disable     = l2x0_disable,
-		.sync        = l2x0_cache_sync,
-		.resume      = l2x0_resume,
+		.inv_range   = l2c220_inv_range,
+		.clean_range = l2c220_clean_range,
+		.flush_range = l2c220_flush_range,
+		.flush_all   = l2c220_flush_all,
+		.disable     = l2c_disable,
+		.sync        = l2c220_sync,
+		.resume      = l2c210_resume,
 	},
 };
 
@@ -1342,7 +1489,7 @@ static const struct l2c_init_data of_tauros3_data __initconst = {
 #define L2C_ID(name, fns) { .compatible = name, .data = (void *)&fns }
 static const struct of_device_id l2x0_ids[] __initconst = {
 	L2C_ID("arm,l210-cache", of_l2c210_data),
-	L2C_ID("arm,l220-cache", of_l2x0_data),
+	L2C_ID("arm,l220-cache", of_l2c220_data),
 	L2C_ID("arm,pl310-cache", of_l2c310_data),
 	L2C_ID("brcm,bcm11351-a2-pl310-cache", of_bcm_l2x0_data),
 	L2C_ID("marvell,aurora-outer-cache", of_aurora_with_outer_data),
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 035/222] ARM: l2c: convert Broadcom L2C-310 to new code
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (33 preceding siblings ...)
  2014-04-25 11:33 ` [PATCH 034/222] ARM: l2c: add L2C-220 specific handlers Russell King
@ 2014-04-25 11:33 ` Russell King
  2014-04-25 11:34 ` [PATCH 036/222] ARM: l2c: remove obsolete l2x0 ops for non-OF init Russell King
                   ` (187 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:33 UTC (permalink / raw)
  To: linux-arm-kernel

The Broadcom L2C-310 devices use ARMs L2C-310 R2P3 or later.  These
require no errata workarounds, and so we can directly call the l2c210
functions from their methods.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 27 +++++++++++----------------
 1 file changed, 11 insertions(+), 16 deletions(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 751c3d7a22b3..57680e03da84 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -1360,16 +1360,16 @@ static void bcm_inv_range(unsigned long start, unsigned long end)
 
 	/* normal case, no cross section between start and end */
 	if (likely(bcm_addr_is_sys_emi(end) || !bcm_addr_is_sys_emi(start))) {
-		l2x0_inv_range(new_start, new_end);
+		l2c210_inv_range(new_start, new_end);
 		return;
 	}
 
 	/* They cross sections, so it can only be a cross from section
 	 * 2 to section 3
 	 */
-	l2x0_inv_range(new_start,
+	l2c210_inv_range(new_start,
 		bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR-1));
-	l2x0_inv_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR),
+	l2c210_inv_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR),
 		new_end);
 }
 
@@ -1382,26 +1382,21 @@ static void bcm_clean_range(unsigned long start, unsigned long end)
 	if (unlikely(end <= start))
 		return;
 
-	if ((end - start) >= l2x0_size) {
-		l2x0_clean_all();
-		return;
-	}
-
 	new_start = bcm_l2_phys_addr(start);
 	new_end = bcm_l2_phys_addr(end);
 
 	/* normal case, no cross section between start and end */
 	if (likely(bcm_addr_is_sys_emi(end) || !bcm_addr_is_sys_emi(start))) {
-		l2x0_clean_range(new_start, new_end);
+		l2c210_clean_range(new_start, new_end);
 		return;
 	}
 
 	/* They cross sections, so it can only be a cross from section
 	 * 2 to section 3
 	 */
-	l2x0_clean_range(new_start,
+	l2c210_clean_range(new_start,
 		bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR-1));
-	l2x0_clean_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR),
+	l2c210_clean_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR),
 		new_end);
 }
 
@@ -1415,7 +1410,7 @@ static void bcm_flush_range(unsigned long start, unsigned long end)
 		return;
 
 	if ((end - start) >= l2x0_size) {
-		l2x0_flush_all();
+		outer_cache.flush_all();
 		return;
 	}
 
@@ -1424,24 +1419,24 @@ static void bcm_flush_range(unsigned long start, unsigned long end)
 
 	/* normal case, no cross section between start and end */
 	if (likely(bcm_addr_is_sys_emi(end) || !bcm_addr_is_sys_emi(start))) {
-		l2x0_flush_range(new_start, new_end);
+		l2c210_flush_range(new_start, new_end);
 		return;
 	}
 
 	/* They cross sections, so it can only be a cross from section
 	 * 2 to section 3
 	 */
-	l2x0_flush_range(new_start,
+	l2c210_flush_range(new_start,
 		bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR-1));
-	l2x0_flush_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR),
+	l2c210_flush_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR),
 		new_end);
 }
 
+/* Broadcom L2C-310 start from ARMs R3P2 or later, and require no fixups */
 static const struct l2c_init_data of_bcm_l2x0_data __initconst = {
 	.num_lock = 8,
 	.of_parse = l2c310_of_parse,
 	.enable = l2c_enable,
-	.fixup = l2c310_fixup,
 	.save  = l2c310_save,
 	.outer_cache = {
 		.inv_range   = bcm_inv_range,
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 036/222] ARM: l2c: remove obsolete l2x0 ops for non-OF init
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (34 preceding siblings ...)
  2014-04-25 11:33 ` [PATCH 035/222] ARM: l2c: convert Broadcom L2C-310 to new code Russell King
@ 2014-04-25 11:34 ` Russell King
  2014-04-25 11:34 ` [PATCH 037/222] ARM: l2c: move type string into l2c_init_data structure Russell King
                   ` (186 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:34 UTC (permalink / raw)
  To: linux-arm-kernel

non-OF initialisation has never been used with any cache controller
which isn't an ARM cache controller, so we can safely get rid of the
old (and buggy) l2x0_*-based operations structure.

This is also the last reference to:
- l2x0_clean_line()
- l2x0_inv_line()
- l2x0_flush_line()
- l2x0_flush_all()
- l2x0_clean_all()
- l2x0_inv_all()
- l2x0_inv_range()
- l2x0_clean_range()
- l2x0_flush_range()
- l2x0_enable()
- l2x0_resume()
so kill those functions too.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 206 -----------------------------------------------
 1 file changed, 206 deletions(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 57680e03da84..c5d754912f96 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -134,20 +134,6 @@ static inline void cache_sync(void)
 	cache_wait(base + L2X0_CACHE_SYNC, 1);
 }
 
-static inline void l2x0_clean_line(unsigned long addr)
-{
-	void __iomem *base = l2x0_base;
-	cache_wait(base + L2X0_CLEAN_LINE_PA, 1);
-	writel_relaxed(addr, base + L2X0_CLEAN_LINE_PA);
-}
-
-static inline void l2x0_inv_line(unsigned long addr)
-{
-	void __iomem *base = l2x0_base;
-	cache_wait(base + L2X0_INV_LINE_PA, 1);
-	writel_relaxed(addr, base + L2X0_INV_LINE_PA);
-}
-
 #if defined(CONFIG_PL310_ERRATA_588369) || defined(CONFIG_PL310_ERRATA_727915)
 static inline void debug_writel(unsigned long val)
 {
@@ -161,27 +147,6 @@ static inline void debug_writel(unsigned long val)
 }
 #endif
 
-#ifdef CONFIG_PL310_ERRATA_588369
-static inline void l2x0_flush_line(unsigned long addr)
-{
-	void __iomem *base = l2x0_base;
-
-	/* Clean by PA followed by Invalidate by PA */
-	cache_wait(base + L2X0_CLEAN_LINE_PA, 1);
-	writel_relaxed(addr, base + L2X0_CLEAN_LINE_PA);
-	cache_wait(base + L2X0_INV_LINE_PA, 1);
-	writel_relaxed(addr, base + L2X0_INV_LINE_PA);
-}
-#else
-
-static inline void l2x0_flush_line(unsigned long addr)
-{
-	void __iomem *base = l2x0_base;
-	cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1);
-	writel_relaxed(addr, base + L2X0_CLEAN_INV_LINE_PA);
-}
-#endif
-
 static void l2x0_cache_sync(void)
 {
 	unsigned long flags;
@@ -209,131 +174,6 @@ static void l2x0_flush_all(void)
 	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
 }
 
-static void l2x0_clean_all(void)
-{
-	unsigned long flags;
-
-	/* clean all ways */
-	raw_spin_lock_irqsave(&l2x0_lock, flags);
-	__l2c_op_way(l2x0_base + L2X0_CLEAN_WAY);
-	cache_sync();
-	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
-}
-
-static void l2x0_inv_all(void)
-{
-	unsigned long flags;
-
-	/* invalidate all ways */
-	raw_spin_lock_irqsave(&l2x0_lock, flags);
-	/* Invalidating when L2 is enabled is a nono */
-	BUG_ON(readl(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN);
-	__l2c_op_way(l2x0_base + L2X0_INV_WAY);
-	cache_sync();
-	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
-}
-
-static void l2x0_inv_range(unsigned long start, unsigned long end)
-{
-	void __iomem *base = l2x0_base;
-	unsigned long flags;
-
-	raw_spin_lock_irqsave(&l2x0_lock, flags);
-	if (start & (CACHE_LINE_SIZE - 1)) {
-		start &= ~(CACHE_LINE_SIZE - 1);
-		debug_writel(0x03);
-		l2x0_flush_line(start);
-		debug_writel(0x00);
-		start += CACHE_LINE_SIZE;
-	}
-
-	if (end & (CACHE_LINE_SIZE - 1)) {
-		end &= ~(CACHE_LINE_SIZE - 1);
-		debug_writel(0x03);
-		l2x0_flush_line(end);
-		debug_writel(0x00);
-	}
-
-	while (start < end) {
-		unsigned long blk_end = start + min(end - start, 4096UL);
-
-		while (start < blk_end) {
-			l2x0_inv_line(start);
-			start += CACHE_LINE_SIZE;
-		}
-
-		if (blk_end < end) {
-			raw_spin_unlock_irqrestore(&l2x0_lock, flags);
-			raw_spin_lock_irqsave(&l2x0_lock, flags);
-		}
-	}
-	cache_wait(base + L2X0_INV_LINE_PA, 1);
-	cache_sync();
-	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
-}
-
-static void l2x0_clean_range(unsigned long start, unsigned long end)
-{
-	void __iomem *base = l2x0_base;
-	unsigned long flags;
-
-	if ((end - start) >= l2x0_size) {
-		l2x0_clean_all();
-		return;
-	}
-
-	raw_spin_lock_irqsave(&l2x0_lock, flags);
-	start &= ~(CACHE_LINE_SIZE - 1);
-	while (start < end) {
-		unsigned long blk_end = start + min(end - start, 4096UL);
-
-		while (start < blk_end) {
-			l2x0_clean_line(start);
-			start += CACHE_LINE_SIZE;
-		}
-
-		if (blk_end < end) {
-			raw_spin_unlock_irqrestore(&l2x0_lock, flags);
-			raw_spin_lock_irqsave(&l2x0_lock, flags);
-		}
-	}
-	cache_wait(base + L2X0_CLEAN_LINE_PA, 1);
-	cache_sync();
-	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
-}
-
-static void l2x0_flush_range(unsigned long start, unsigned long end)
-{
-	void __iomem *base = l2x0_base;
-	unsigned long flags;
-
-	if ((end - start) >= l2x0_size) {
-		l2x0_flush_all();
-		return;
-	}
-
-	raw_spin_lock_irqsave(&l2x0_lock, flags);
-	start &= ~(CACHE_LINE_SIZE - 1);
-	while (start < end) {
-		unsigned long blk_end = start + min(end - start, 4096UL);
-
-		debug_writel(0x03);
-		while (start < blk_end) {
-			l2x0_flush_line(start);
-			start += CACHE_LINE_SIZE;
-		}
-		debug_writel(0x00);
-
-		if (blk_end < end) {
-			raw_spin_unlock_irqrestore(&l2x0_lock, flags);
-			raw_spin_lock_irqsave(&l2x0_lock, flags);
-		}
-	}
-	cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1);
-	cache_sync();
-	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
-}
-
 static void l2x0_disable(void)
 {
 	unsigned long flags;
@@ -345,49 +185,6 @@ static void l2x0_disable(void)
 	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
 }
 
-static void l2x0_enable(void __iomem *base, u32 aux, unsigned num_lock)
-{
-	unsigned id;
-
-	id = readl_relaxed(base + L2X0_CACHE_ID) & L2X0_CACHE_ID_PART_MASK;
-	if (id == L2X0_CACHE_ID_PART_L310)
-		num_lock = 8;
-	else
-		num_lock = 1;
-
-	/* l2x0 controller is disabled */
-	writel_relaxed(aux, base + L2X0_AUX_CTRL);
-
-	/* Make sure that I&D is not locked down when starting */
-	l2c_unlock(base, num_lock);
-
-	l2x0_inv_all();
-
-	/* enable L2X0 */
-	writel_relaxed(L2X0_CTRL_EN, base + L2X0_CTRL);
-}
-
-static void l2x0_resume(void)
-{
-	void __iomem *base = l2x0_base;
-
-	if (!(readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN))
-		l2x0_enable(base, l2x0_saved_regs.aux_ctrl, 0);
-}
-
-static const struct l2c_init_data l2x0_init_fns __initconst = {
-	.enable = l2x0_enable,
-	.outer_cache = {
-		.inv_range = l2x0_inv_range,
-		.clean_range = l2x0_clean_range,
-		.flush_range = l2x0_flush_range,
-		.flush_all = l2x0_flush_all,
-		.disable = l2x0_disable,
-		.sync = l2x0_cache_sync,
-		.resume = l2x0_resume,
-	},
-};
-
 /*
  * L2C-210 specific code.
  *
@@ -966,9 +763,6 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
 
 	switch (cache_id & L2X0_CACHE_ID_PART_MASK) {
 	default:
-		data = &l2x0_init_fns;
-		break;
-
 	case L2X0_CACHE_ID_PART_L210:
 		data = &l2c210_data;
 		break;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 037/222] ARM: l2c: move type string into l2c_init_data structure
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (35 preceding siblings ...)
  2014-04-25 11:34 ` [PATCH 036/222] ARM: l2c: remove obsolete l2x0 ops for non-OF init Russell King
@ 2014-04-25 11:34 ` Russell King
  2014-04-25 11:34 ` [PATCH 038/222] ARM: l2c: add decode for L2C-220 cache ways Russell King
                   ` (185 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:34 UTC (permalink / raw)
  To: linux-arm-kernel

Rather than decoding this from the ID register, store it in the
l2c_init_data structure.  This simplifies things some more, and
allows us to better provide further details as to how we're
driving the cache.  We print the cache ID value anyway should we
need to precisely identify the cache hardware.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index c5d754912f96..b4dd2f4b491b 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -29,6 +29,7 @@
 #include "cache-aurora-l2.h"
 
 struct l2c_init_data {
+	const char *type;
 	unsigned num_lock;
 	void (*of_parse)(const struct device_node *, u32 *, u32 *);
 	void (*enable)(void __iomem *, u32, unsigned);
@@ -274,6 +275,7 @@ static void l2c210_resume(void)
 }
 
 static const struct l2c_init_data l2c210_data __initconst = {
+	.type = "L2C-210",
 	.num_lock = 1,
 	.enable = l2c_enable,
 	.outer_cache = {
@@ -416,6 +418,7 @@ static void l2c220_sync(void)
 }
 
 static const struct l2c_init_data l2c220_data = {
+	.type = "L2C-220",
 	.num_lock = 1,
 	.enable = l2c_enable,
 	.outer_cache = {
@@ -650,6 +653,7 @@ static void __init l2c310_fixup(void __iomem *base, u32 cache_id,
 }
 
 static const struct l2c_init_data l2c310_init_fns __initconst = {
+	.type = "L2C-310",
 	.num_lock = 8,
 	.enable = l2c_enable,
 	.fixup = l2c310_fixup,
@@ -674,7 +678,6 @@ static void __init __l2c_init(const struct l2c_init_data *data,
 	u32 way_size = 0;
 	int ways;
 	int way_size_shift = L2X0_WAY_SIZE_SHIFT;
-	const char *type;
 
 	/*
 	 * It is strange to save the register state before initialisation,
@@ -695,25 +698,21 @@ static void __init __l2c_init(const struct l2c_init_data *data,
 			ways = 16;
 		else
 			ways = 8;
-		type = "L310";
 		break;
 
 	case L2X0_CACHE_ID_PART_L210:
 		ways = (aux >> 13) & 0xf;
-		type = "L210";
 		break;
 
 	case AURORA_CACHE_ID:
 		ways = (aux >> 13) & 0xf;
 		ways = 2 << ((ways + 1) >> 2);
 		way_size_shift = AURORA_WAY_SIZE_SHIFT;
-		type = "Aurora";
 		break;
 
 	default:
 		/* Assume unknown chips have 8 ways */
 		ways = 8;
-		type = "L2x0 series";
 		break;
 	}
 
@@ -747,9 +746,9 @@ static void __init __l2c_init(const struct l2c_init_data *data,
 	outer_cache = fns;
 
 	pr_info("%s cache controller enabled, %d ways, %d kB\n",
-		type, ways, l2x0_size >> 10);
+		data->type, ways, l2x0_size >> 10);
 	pr_info("%s: CACHE_ID 0x%08x, AUX_CTRL 0x%08x\n",
-		type, cache_id, aux);
+		data->type, cache_id, aux);
 }
 
 void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
@@ -821,6 +820,7 @@ static void __init l2x0_of_parse(const struct device_node *np,
 }
 
 static const struct l2c_init_data of_l2c210_data __initconst = {
+	.type = "L2C-210",
 	.num_lock = 1,
 	.of_parse = l2x0_of_parse,
 	.enable = l2c_enable,
@@ -836,6 +836,7 @@ static const struct l2c_init_data of_l2c210_data __initconst = {
 };
 
 static const struct l2c_init_data of_l2c220_data __initconst = {
+	.type = "L2C-220",
 	.num_lock = 1,
 	.of_parse = l2x0_of_parse,
 	.enable = l2c_enable,
@@ -885,6 +886,7 @@ static void __init l2c310_of_parse(const struct device_node *np,
 }
 
 static const struct l2c_init_data of_l2c310_data __initconst = {
+	.type = "L2C-310",
 	.num_lock = 8,
 	.of_parse = l2c310_of_parse,
 	.enable = l2c_enable,
@@ -1063,6 +1065,7 @@ static void __init aurora_of_parse(const struct device_node *np,
 }
 
 static const struct l2c_init_data of_aurora_with_outer_data __initconst = {
+	.type = "Aurora",
 	.num_lock = 4,
 	.of_parse = aurora_of_parse,
 	.enable = l2c_enable,
@@ -1080,6 +1083,7 @@ static const struct l2c_init_data of_aurora_with_outer_data __initconst = {
 };
 
 static const struct l2c_init_data of_aurora_no_outer_data __initconst = {
+	.type = "Aurora",
 	.num_lock = 4,
 	.of_parse = aurora_of_parse,
 	.enable = aurora_enable_no_outer,
@@ -1228,6 +1232,7 @@ static void bcm_flush_range(unsigned long start, unsigned long end)
 
 /* Broadcom L2C-310 start from ARMs R3P2 or later, and require no fixups */
 static const struct l2c_init_data of_bcm_l2x0_data __initconst = {
+	.type = "BCM-L2C-310",
 	.num_lock = 8,
 	.of_parse = l2c310_of_parse,
 	.enable = l2c_enable,
@@ -1266,6 +1271,7 @@ static void tauros3_resume(void)
 }
 
 static const struct l2c_init_data of_tauros3_data __initconst = {
+	.type = "Tauros3",
 	.num_lock = 8,
 	.enable = l2c_enable,
 	.save  = tauros3_save,
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 038/222] ARM: l2c: add decode for L2C-220 cache ways
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (36 preceding siblings ...)
  2014-04-25 11:34 ` [PATCH 037/222] ARM: l2c: move type string into l2c_init_data structure Russell King
@ 2014-04-25 11:34 ` Russell King
  2014-04-25 11:34 ` [PATCH 039/222] ARM: l2c: move way size calculation data into l2c_init_data Russell King
                   ` (184 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:34 UTC (permalink / raw)
  To: linux-arm-kernel

Rather than assuming these are always 8-way, it can be decoded from the
auxillary register in the same manner as L2C-210.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index b4dd2f4b491b..69a18316b239 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -701,6 +701,7 @@ static void __init __l2c_init(const struct l2c_init_data *data,
 		break;
 
 	case L2X0_CACHE_ID_PART_L210:
+	case L2X0_CACHE_ID_PART_L220:
 		ways = (aux >> 13) & 0xf;
 		break;
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 039/222] ARM: l2c: move way size calculation data into l2c_init_data
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (37 preceding siblings ...)
  2014-04-25 11:34 ` [PATCH 038/222] ARM: l2c: add decode for L2C-220 cache ways Russell King
@ 2014-04-25 11:34 ` Russell King
  2014-04-25 11:34 ` [PATCH 040/222] ARM: l2c: move errata configuration options to arch/arm/mm/Kconfig Russell King
                   ` (183 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:34 UTC (permalink / raw)
  To: linux-arm-kernel

Move the way size calculation data (base of way size) out of the
switch statement into the provided initialisation data.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 29 ++++++++++++++++++++---------
 1 file changed, 20 insertions(+), 9 deletions(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 69a18316b239..b4d373ab1a5c 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -30,6 +30,7 @@
 
 struct l2c_init_data {
 	const char *type;
+	unsigned way_size_0;
 	unsigned num_lock;
 	void (*of_parse)(const struct device_node *, u32 *, u32 *);
 	void (*enable)(void __iomem *, u32, unsigned);
@@ -276,6 +277,7 @@ static void l2c210_resume(void)
 
 static const struct l2c_init_data l2c210_data __initconst = {
 	.type = "L2C-210",
+	.way_size_0 = SZ_8K,
 	.num_lock = 1,
 	.enable = l2c_enable,
 	.outer_cache = {
@@ -419,6 +421,7 @@ static void l2c220_sync(void)
 
 static const struct l2c_init_data l2c220_data = {
 	.type = "L2C-220",
+	.way_size_0 = SZ_8K,
 	.num_lock = 1,
 	.enable = l2c_enable,
 	.outer_cache = {
@@ -654,6 +657,7 @@ static void __init l2c310_fixup(void __iomem *base, u32 cache_id,
 
 static const struct l2c_init_data l2c310_init_fns __initconst = {
 	.type = "L2C-310",
+	.way_size_0 = SZ_8K,
 	.num_lock = 8,
 	.enable = l2c_enable,
 	.fixup = l2c310_fixup,
@@ -674,10 +678,8 @@ static void __init __l2c_init(const struct l2c_init_data *data,
 	u32 aux_val, u32 aux_mask, u32 cache_id)
 {
 	struct outer_cache_fns fns;
+	unsigned way_size_bits, ways;
 	u32 aux;
-	u32 way_size = 0;
-	int ways;
-	int way_size_shift = L2X0_WAY_SIZE_SHIFT;
 
 	/*
 	 * It is strange to save the register state before initialisation,
@@ -708,7 +710,6 @@ static void __init __l2c_init(const struct l2c_init_data *data,
 	case AURORA_CACHE_ID:
 		ways = (aux >> 13) & 0xf;
 		ways = 2 << ((ways + 1) >> 2);
-		way_size_shift = AURORA_WAY_SIZE_SHIFT;
 		break;
 
 	default:
@@ -720,12 +721,15 @@ static void __init __l2c_init(const struct l2c_init_data *data,
 	l2x0_way_mask = (1 << ways) - 1;
 
 	/*
-	 * L2 cache Size =  Way size * Number of ways
+	 * way_size_0 is the size that a way_size value of zero would be
+	 * given the calculation: way_size = way_size_0 << way_size_bits.
+	 * So, if way_size_bits=0 is reserved, but way_size_bits=1 is 16k,
+	 * then way_size_0 would be 8k.
+	 *
+	 * L2 cache size = number of ways * way size.
 	 */
-	way_size = (aux & L2X0_AUX_CTRL_WAY_SIZE_MASK) >> 17;
-	way_size = 1 << (way_size + way_size_shift);
-
-	l2x0_size = ways * way_size * SZ_1K;
+	way_size_bits = (aux & L2X0_AUX_CTRL_WAY_SIZE_MASK) >> 17;
+	l2x0_size = ways * (data->way_size_0 << way_size_bits);
 
 	fns = data->outer_cache;
 	if (data->fixup)
@@ -822,6 +826,7 @@ static void __init l2x0_of_parse(const struct device_node *np,
 
 static const struct l2c_init_data of_l2c210_data __initconst = {
 	.type = "L2C-210",
+	.way_size_0 = SZ_8K,
 	.num_lock = 1,
 	.of_parse = l2x0_of_parse,
 	.enable = l2c_enable,
@@ -838,6 +843,7 @@ static const struct l2c_init_data of_l2c210_data __initconst = {
 
 static const struct l2c_init_data of_l2c220_data __initconst = {
 	.type = "L2C-220",
+	.way_size_0 = SZ_8K,
 	.num_lock = 1,
 	.of_parse = l2x0_of_parse,
 	.enable = l2c_enable,
@@ -888,6 +894,7 @@ static void __init l2c310_of_parse(const struct device_node *np,
 
 static const struct l2c_init_data of_l2c310_data __initconst = {
 	.type = "L2C-310",
+	.way_size_0 = SZ_8K,
 	.num_lock = 8,
 	.of_parse = l2c310_of_parse,
 	.enable = l2c_enable,
@@ -1067,6 +1074,7 @@ static void __init aurora_of_parse(const struct device_node *np,
 
 static const struct l2c_init_data of_aurora_with_outer_data __initconst = {
 	.type = "Aurora",
+	.way_size_0 = SZ_4K,
 	.num_lock = 4,
 	.of_parse = aurora_of_parse,
 	.enable = l2c_enable,
@@ -1085,6 +1093,7 @@ static const struct l2c_init_data of_aurora_with_outer_data __initconst = {
 
 static const struct l2c_init_data of_aurora_no_outer_data __initconst = {
 	.type = "Aurora",
+	.way_size_0 = SZ_4K,
 	.num_lock = 4,
 	.of_parse = aurora_of_parse,
 	.enable = aurora_enable_no_outer,
@@ -1234,6 +1243,7 @@ static void bcm_flush_range(unsigned long start, unsigned long end)
 /* Broadcom L2C-310 start from ARMs R3P2 or later, and require no fixups */
 static const struct l2c_init_data of_bcm_l2x0_data __initconst = {
 	.type = "BCM-L2C-310",
+	.way_size_0 = SZ_8K,
 	.num_lock = 8,
 	.of_parse = l2c310_of_parse,
 	.enable = l2c_enable,
@@ -1273,6 +1283,7 @@ static void tauros3_resume(void)
 
 static const struct l2c_init_data of_tauros3_data __initconst = {
 	.type = "Tauros3",
+	.way_size_0 = SZ_8K,
 	.num_lock = 8,
 	.enable = l2c_enable,
 	.save  = tauros3_save,
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 040/222] ARM: l2c: move errata configuration options to arch/arm/mm/Kconfig
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (38 preceding siblings ...)
  2014-04-25 11:34 ` [PATCH 039/222] ARM: l2c: move way size calculation data into l2c_init_data Russell King
@ 2014-04-25 11:34 ` Russell King
  2014-04-25 11:34 ` [PATCH 041/222] ARM: l2c: provide generic hook to intercept writes to secure registers Russell King
                   ` (182 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:34 UTC (permalink / raw)
  To: linux-arm-kernel

Move the L2C-310 errata configuration options to arch/arm/mm/Kconfig
along side the option which enables support for this device.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/Kconfig    | 51 ---------------------------------------------------
 arch/arm/mm/Kconfig | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 51 insertions(+), 51 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index ab438cb5af55..b22f990bdd06 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1229,19 +1229,6 @@ config ARM_ERRATA_742231
 	  register of the Cortex-A9 which reduces the linefill issuing
 	  capabilities of the processor.
 
-config PL310_ERRATA_588369
-	bool "PL310 errata: Clean & Invalidate maintenance operations do not invalidate clean lines"
-	depends on CACHE_L2X0
-	help
-	   The PL310 L2 cache controller implements three types of Clean &
-	   Invalidate maintenance operations: by Physical Address
-	   (offset 0x7F0), by Index/Way (0x7F8) and by Way (0x7FC).
-	   They are architecturally defined to behave as the execution of a
-	   clean operation followed immediately by an invalidate operation,
-	   both performing to the same memory location. This functionality
-	   is not correctly implemented in PL310 as clean lines are not
-	   invalidated as a result of these operations.
-
 config ARM_ERRATA_643719
 	bool "ARM errata: LoUIS bit field in CLIDR register is incorrect"
 	depends on CPU_V7 && SMP
@@ -1264,17 +1251,6 @@ config ARM_ERRATA_720789
 	  tables. The workaround changes the TLB flushing routines to invalidate
 	  entries regardless of the ASID.
 
-config PL310_ERRATA_727915
-	bool "PL310 errata: Background Clean & Invalidate by Way operation can cause data corruption"
-	depends on CACHE_L2X0
-	help
-	  PL310 implements the Clean & Invalidate by Way L2 cache maintenance
-	  operation (offset 0x7FC). This operation runs in background so that
-	  PL310 can handle normal accesses while it is in progress. Under very
-	  rare circumstances, due to this erratum, write data can be lost when
-	  PL310 treats a cacheable write transaction during a Clean &
-	  Invalidate by Way operation.
-
 config ARM_ERRATA_743622
 	bool "ARM errata: Faulty hazard checking in the Store Buffer may lead to data corruption"
 	depends on CPU_V7
@@ -1300,21 +1276,6 @@ config ARM_ERRATA_751472
 	  operation is received by a CPU before the ICIALLUIS has completed,
 	  potentially leading to corrupted entries in the cache or TLB.
 
-config PL310_ERRATA_753970
-	bool "PL310 errata: cache sync operation may be faulty"
-	depends on CACHE_PL310
-	help
-	  This option enables the workaround for the 753970 PL310 (r3p0) erratum.
-
-	  Under some condition the effect of cache sync operation on
-	  the store buffer still remains when the operation completes.
-	  This means that the store buffer is always asked to drain and
-	  this prevents it from merging any further writes. The workaround
-	  is to replace the normal offset of cache sync operation (0x730)
-	  by another offset targeting an unmapped PL310 register 0x740.
-	  This has the same effect as the cache sync operation: store buffer
-	  drain and waiting for all buffers empty.
-
 config ARM_ERRATA_754322
 	bool "ARM errata: possible faulty MMU translations following an ASID switch"
 	depends on CPU_V7
@@ -1363,18 +1324,6 @@ config ARM_ERRATA_764369
 	  relevant cache maintenance functions and sets a specific bit
 	  in the diagnostic control register of the SCU.
 
-config PL310_ERRATA_769419
-	bool "PL310 errata: no automatic Store Buffer drain"
-	depends on CACHE_L2X0
-	help
-	  On revisions of the PL310 prior to r3p2, the Store Buffer does
-	  not automatically drain. This can cause normal, non-cacheable
-	  writes to be retained when the memory system is idle, leading
-	  to suboptimal I/O performance for drivers using coherent DMA.
-	  This option adds a write barrier to the cpu_idle loop so that,
-	  on systems with an outer cache, the store buffer is drained
-	  explicitly.
-
 config ARM_ERRATA_775420
        bool "ARM errata: A data cache maintenance operation which aborts, might lead to deadlock"
        depends on CPU_V7
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index f5ad9ee70426..6fe3e4ced342 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -897,6 +897,57 @@ config CACHE_PL310
 	  This option enables optimisations for the PL310 cache
 	  controller.
 
+config PL310_ERRATA_588369
+	bool "PL310 errata: Clean & Invalidate maintenance operations do not invalidate clean lines"
+	depends on CACHE_L2X0
+	help
+	   The PL310 L2 cache controller implements three types of Clean &
+	   Invalidate maintenance operations: by Physical Address
+	   (offset 0x7F0), by Index/Way (0x7F8) and by Way (0x7FC).
+	   They are architecturally defined to behave as the execution of a
+	   clean operation followed immediately by an invalidate operation,
+	   both performing to the same memory location. This functionality
+	   is not correctly implemented in PL310 as clean lines are not
+	   invalidated as a result of these operations.
+
+config PL310_ERRATA_727915
+	bool "PL310 errata: Background Clean & Invalidate by Way operation can cause data corruption"
+	depends on CACHE_L2X0
+	help
+	  PL310 implements the Clean & Invalidate by Way L2 cache maintenance
+	  operation (offset 0x7FC). This operation runs in background so that
+	  PL310 can handle normal accesses while it is in progress. Under very
+	  rare circumstances, due to this erratum, write data can be lost when
+	  PL310 treats a cacheable write transaction during a Clean &
+	  Invalidate by Way operation.
+
+config PL310_ERRATA_753970
+	bool "PL310 errata: cache sync operation may be faulty"
+	depends on CACHE_PL310
+	help
+	  This option enables the workaround for the 753970 PL310 (r3p0) erratum.
+
+	  Under some condition the effect of cache sync operation on
+	  the store buffer still remains when the operation completes.
+	  This means that the store buffer is always asked to drain and
+	  this prevents it from merging any further writes. The workaround
+	  is to replace the normal offset of cache sync operation (0x730)
+	  by another offset targeting an unmapped PL310 register 0x740.
+	  This has the same effect as the cache sync operation: store buffer
+	  drain and waiting for all buffers empty.
+
+config PL310_ERRATA_769419
+	bool "PL310 errata: no automatic Store Buffer drain"
+	depends on CACHE_L2X0
+	help
+	  On revisions of the PL310 prior to r3p2, the Store Buffer does
+	  not automatically drain. This can cause normal, non-cacheable
+	  writes to be retained when the memory system is idle, leading
+	  to suboptimal I/O performance for drivers using coherent DMA.
+	  This option adds a write barrier to the cpu_idle loop so that,
+	  on systems with an outer cache, the store buffer is drained
+	  explicitly.
+
 config CACHE_TAUROS2
 	bool "Enable the Tauros2 L2 cache controller"
 	depends on (ARCH_DOVE || ARCH_MMP || CPU_PJ4)
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 041/222] ARM: l2c: provide generic hook to intercept writes to secure registers
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (39 preceding siblings ...)
  2014-04-25 11:34 ` [PATCH 040/222] ARM: l2c: move errata configuration options to arch/arm/mm/Kconfig Russell King
@ 2014-04-25 11:34 ` Russell King
  2014-04-25 11:34 ` [PATCH 042/222] ARM: l2c: omap2: implement new write_sec method Russell King
                   ` (181 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:34 UTC (permalink / raw)
  To: linux-arm-kernel

When Linux is running in the non-secure world, any write to a secure
L2C register will generate an abort.  Platforms normally have to call
firmware to work around this.  Provide a hook for them to intercept
any L2C secure register write.

l2c_write_sec() avoids writes to secure registers which are already set
to the appropriate value, thus avoiding the overhead of needlessly
calling into the secure monitor.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/include/asm/outercache.h |  5 ++++-
 arch/arm/mm/cache-l2x0.c          | 42 ++++++++++++++++++++++++++++-----------
 2 files changed, 34 insertions(+), 13 deletions(-)

diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h
index e9a0797fe188..5066fa2f73ab 100644
--- a/arch/arm/include/asm/outercache.h
+++ b/arch/arm/include/asm/outercache.h
@@ -33,8 +33,11 @@ struct outer_cache_fns {
 #ifdef CONFIG_OUTER_CACHE_SYNC
 	void (*sync)(void);
 #endif
-	void (*set_debug)(unsigned long);
 	void (*resume)(void);
+
+	/* This is an ARM L2C thing */
+	void (*set_debug)(unsigned long);
+	void (*write_sec)(unsigned long, unsigned);
 };
 
 extern struct outer_cache_fns outer_cache;
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index b4d373ab1a5c..369a9d01d94f 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -60,13 +60,30 @@ static inline void l2c_wait_mask(void __iomem *reg, unsigned long mask)
 }
 
 /*
+ * By default, we write directly to secure registers.  Platforms must
+ * override this if they are running non-secure.
+ */
+static void l2c_write_sec(unsigned long val, void __iomem *base, unsigned reg)
+{
+	if (val == readl_relaxed(base + reg))
+		return;
+	if (outer_cache.write_sec)
+		outer_cache.write_sec(val, reg);
+	else
+		writel_relaxed(val, base + reg);
+}
+
+/*
  * This should only be called when we have a requirement that the
  * register be written due to a work-around, as platforms running
  * in non-secure mode may not be able to access this register.
  */
 static inline void l2c_set_debug(void __iomem *base, unsigned long val)
 {
-	outer_cache.set_debug(val);
+	if (outer_cache.set_debug)
+		outer_cache.set_debug(val);
+	else
+		l2c_write_sec(val, base, L2X0_DEBUG_CTRL);
 }
 
 static void __l2c_op_way(void __iomem *reg)
@@ -95,9 +112,7 @@ static void l2c_enable(void __iomem *base, u32 aux, unsigned num_lock)
 {
 	unsigned long flags;
 
-	/* Only write the aux register if it needs changing */
-	if (readl_relaxed(base + L2X0_AUX_CTRL) != aux)
-		writel_relaxed(aux, base + L2X0_AUX_CTRL);
+	l2c_write_sec(aux, base, L2X0_AUX_CTRL);
 
 	l2c_unlock(base, num_lock);
 
@@ -107,7 +122,7 @@ static void l2c_enable(void __iomem *base, u32 aux, unsigned num_lock)
 	l2c_wait_mask(base + sync_reg_offset, 1);
 	local_irq_restore(flags);
 
-	writel_relaxed(L2X0_CTRL_EN, base + L2X0_CTRL);
+	l2c_write_sec(L2X0_CTRL_EN, base, L2X0_CTRL);
 }
 
 static void l2c_disable(void)
@@ -115,7 +130,7 @@ static void l2c_disable(void)
 	void __iomem *base = l2x0_base;
 
 	outer_cache.flush_all();
-	writel_relaxed(0, base + L2X0_CTRL);
+	l2c_write_sec(0, base, L2X0_CTRL);
 	dsb(st);
 }
 
@@ -139,7 +154,7 @@ static inline void cache_sync(void)
 #if defined(CONFIG_PL310_ERRATA_588369) || defined(CONFIG_PL310_ERRATA_727915)
 static inline void debug_writel(unsigned long val)
 {
-	if (outer_cache.set_debug)
+	if (outer_cache.set_debug || outer_cache.write_sec)
 		l2c_set_debug(l2x0_base, val);
 }
 #else
@@ -182,7 +197,7 @@ static void l2x0_disable(void)
 
 	raw_spin_lock_irqsave(&l2x0_lock, flags);
 	__l2x0_flush_all();
-	writel_relaxed(0, l2x0_base + L2X0_CTRL);
+	l2c_write_sec(0, l2x0_base, L2X0_CTRL);
 	dsb(st);
 	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
 }
@@ -599,11 +614,11 @@ static void l2c310_resume(void)
 				L2X0_CACHE_ID_RTL_MASK;
 
 		if (revision >= L310_CACHE_ID_RTL_R2P0)
-			writel_relaxed(l2x0_saved_regs.prefetch_ctrl,
-				       base + L2X0_PREFETCH_CTRL);
+			l2c_write_sec(l2x0_saved_regs.prefetch_ctrl, base,
+				      L2X0_PREFETCH_CTRL);
 		if (revision >= L310_CACHE_ID_RTL_R3P0)
-			writel_relaxed(l2x0_saved_regs.pwr_ctrl,
-				       base + L2X0_POWER_CTRL);
+			l2c_write_sec(l2x0_saved_regs.pwr_ctrl, base,
+				      L2X0_POWER_CTRL);
 
 		l2c_enable(base, l2x0_saved_regs.aux_ctrl, 8);
 	}
@@ -732,8 +747,11 @@ static void __init __l2c_init(const struct l2c_init_data *data,
 	l2x0_size = ways * (data->way_size_0 << way_size_bits);
 
 	fns = data->outer_cache;
+	fns.write_sec = outer_cache.write_sec;
 	if (data->fixup)
 		data->fixup(l2x0_base, cache_id, &fns);
+	if (fns.write_sec)
+		fns.set_debug = NULL;
 
 	/*
 	 * Check if l2x0 controller is already enabled.  If we are booting
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 042/222] ARM: l2c: omap2: implement new write_sec method
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (40 preceding siblings ...)
  2014-04-25 11:34 ` [PATCH 041/222] ARM: l2c: provide generic hook to intercept writes to secure registers Russell King
@ 2014-04-25 11:34 ` Russell King
  2014-04-25 11:34 ` [PATCH 043/222] ARM: l2c: omap2: remove explicit SMI calls to enable L2 cache Russell King
                   ` (180 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:34 UTC (permalink / raw)
  To: linux-arm-kernel

With the write_sec method, we no longer need to override the default
L2C disable method, and we no longer need the L2C set_debug method.
Both of these can be handled via the write_sec method.

Acked-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-omap2/omap4-common.c | 42 +++++++++++++++++++++++---------------
 1 file changed, 26 insertions(+), 16 deletions(-)

diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c
index 48cf74d284ec..a51501ad7e83 100644
--- a/arch/arm/mach-omap2/omap4-common.c
+++ b/arch/arm/mach-omap2/omap4-common.c
@@ -167,17 +167,33 @@ void __iomem *omap4_get_l2cache_base(void)
 	return l2cache_base;
 }
 
-static void omap4_l2x0_disable(void)
+static void omap4_l2c310_write_sec(unsigned long val, unsigned reg)
 {
-	outer_flush_all();
-	/* Disable PL310 L2 Cache controller */
-	omap_smc1(0x102, 0x0);
-}
+	unsigned smc_op;
 
-static void omap4_l2x0_set_debug(unsigned long val)
-{
-	/* Program PL310 L2 Cache controller debug register */
-	omap_smc1(0x100, val);
+	switch (reg) {
+	case L2X0_CTRL:
+		smc_op = OMAP4_MON_L2X0_CTRL_INDEX;
+		break;
+
+	case L2X0_AUX_CTRL:
+		smc_op = OMAP4_MON_L2X0_AUXCTRL_INDEX;
+		break;
+
+	case L2X0_DEBUG_CTRL:
+		smc_op = OMAP4_MON_L2X0_DBG_CTRL_INDEX;
+		break;
+
+	case L310_PREFETCH_CTRL:
+		smc_op = OMAP4_MON_L2X0_PREFETCH_INDEX;
+		break;
+
+	default:
+		WARN_ONCE(1, "OMAP L2C310: ignoring write to reg 0x%x\n", reg);
+		return;
+	}
+
+	omap_smc1(smc_op, val);
 }
 
 static int __init omap_l2_cache_init(void)
@@ -212,18 +228,12 @@ static int __init omap_l2_cache_init(void)
 	/* Enable PL310 L2 Cache controller */
 	omap_smc1(0x102, 0x1);
 
+	outer_cache.write_sec = omap4_l2c310_write_sec;
 	if (of_have_populated_dt())
 		l2x0_of_init(aux_ctrl, L2X0_AUX_CTRL_MASK);
 	else
 		l2x0_init(l2cache_base, aux_ctrl, L2X0_AUX_CTRL_MASK);
 
-	/*
-	 * Override default outer_cache.disable with a OMAP4
-	 * specific one
-	*/
-	outer_cache.disable = omap4_l2x0_disable;
-	outer_cache.set_debug = omap4_l2x0_set_debug;
-
 	return 0;
 }
 omap_early_initcall(omap_l2_cache_init);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 043/222] ARM: l2c: omap2: remove explicit SMI calls to enable L2 cache
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (41 preceding siblings ...)
  2014-04-25 11:34 ` [PATCH 042/222] ARM: l2c: omap2: implement new write_sec method Russell King
@ 2014-04-25 11:34 ` Russell King
  2014-04-25 11:34 ` [PATCH 044/222] ARM: l2c: highbank: implement new write_sec method Russell King
                   ` (179 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:34 UTC (permalink / raw)
  To: linux-arm-kernel

Now that OMAP2 uses the write_sec method, we don't need to enable the L2
cache in OMAP2 specific code; this can be done via the normal mechanisms
in the L2C code.  Remove the OMAP2 specific code.

Acked-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-omap2/omap4-common.c | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c
index a51501ad7e83..46dac72aaa4c 100644
--- a/arch/arm/mach-omap2/omap4-common.c
+++ b/arch/arm/mach-omap2/omap4-common.c
@@ -223,11 +223,6 @@ static int __init omap_l2_cache_init(void)
 			(1 << L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT) |
 			(1 << L2X0_AUX_CTRL_EARLY_BRESP_SHIFT);
 
-	omap_smc1(0x109, aux_ctrl);
-
-	/* Enable PL310 L2 Cache controller */
-	omap_smc1(0x102, 0x1);
-
 	outer_cache.write_sec = omap4_l2c310_write_sec;
 	if (of_have_populated_dt())
 		l2x0_of_init(aux_ctrl, L2X0_AUX_CTRL_MASK);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 044/222] ARM: l2c: highbank: implement new write_sec method
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (42 preceding siblings ...)
  2014-04-25 11:34 ` [PATCH 043/222] ARM: l2c: omap2: remove explicit SMI calls to enable L2 cache Russell King
@ 2014-04-25 11:34 ` Russell King
  2014-04-25 11:34 ` [PATCH 045/222] ARM: l2c: highbank: remove explicit SMI call in L2 cache initialisation Russell King
                   ` (178 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:34 UTC (permalink / raw)
  To: linux-arm-kernel

With the write_sec method, we no longer need to override the default L2C
disable method.  This can be handled via the write_sec method instead.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-highbank/highbank.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/arch/arm/mach-highbank/highbank.c b/arch/arm/mach-highbank/highbank.c
index 38e1dc3b4c6e..4712aed3d9f6 100644
--- a/arch/arm/mach-highbank/highbank.c
+++ b/arch/arm/mach-highbank/highbank.c
@@ -51,11 +51,13 @@ static void __init highbank_scu_map_io(void)
 }
 
 
-static void highbank_l2x0_disable(void)
+static void highbank_l2c310_write_sec(unsigned long val, unsigned reg)
 {
-	outer_flush_all();
-	/* Disable PL310 L2 Cache controller */
-	highbank_smc1(0x102, 0x0);
+	if (reg == L2X0_CTRL)
+		highbank_smc1(0x102, val);
+	else
+		WARN_ONCE(1, "Highbank L2C310: ignoring write to reg 0x%x\n",
+			  reg);
 }
 
 static void __init highbank_init_irq(void)
@@ -69,8 +71,8 @@ static void __init highbank_init_irq(void)
 	if (IS_ENABLED(CONFIG_CACHE_L2X0) &&
 	    of_find_compatible_node(NULL, NULL, "arm,pl310-cache")) {
 		highbank_smc1(0x102, 0x1);
+		outer_cache.write_sec = highbank_l2c310_write_sec;
 		l2x0_of_init(0, ~0);
-		outer_cache.disable = highbank_l2x0_disable;
 	}
 }
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 045/222] ARM: l2c: highbank: remove explicit SMI call in L2 cache initialisation
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (43 preceding siblings ...)
  2014-04-25 11:34 ` [PATCH 044/222] ARM: l2c: highbank: implement new write_sec method Russell King
@ 2014-04-25 11:34 ` Russell King
  2014-04-25 11:34 ` [PATCH 046/222] ARM: l2c: ux500: implement dummy write_sec method Russell King
                   ` (177 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:34 UTC (permalink / raw)
  To: linux-arm-kernel

Now that highbank uses the write_sec method, we don't need to enable
the L2 cache in SoC specific code; this can be done via the normal
mechanisms in the L2C code.

Checking with Rob Herring:
> > Can we kill the "highbank_smc1(0x102, 0x1);" here?	That means
> > l2x0_of_init() will see the L2 cache disabled, and will try to enable
> > it via the write_sec hook, so it should do the right thing.
>
> Yes, that should work. You should be able to just call l2x0_of_init
> unconditionally. The condition was really to just avoid the smc on
> Midway which does get handled on h/w, but not if running virtualized.

So also drop the DT check too.  I'm leaving the config check in place
so that if L2 is disabled, the write_sec hook can be optimised away.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-highbank/highbank.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/arch/arm/mach-highbank/highbank.c b/arch/arm/mach-highbank/highbank.c
index 4712aed3d9f6..245e588859ec 100644
--- a/arch/arm/mach-highbank/highbank.c
+++ b/arch/arm/mach-highbank/highbank.c
@@ -68,9 +68,7 @@ static void __init highbank_init_irq(void)
 		highbank_scu_map_io();
 
 	/* Enable PL310 L2 Cache controller */
-	if (IS_ENABLED(CONFIG_CACHE_L2X0) &&
-	    of_find_compatible_node(NULL, NULL, "arm,pl310-cache")) {
-		highbank_smc1(0x102, 0x1);
+	if (IS_ENABLED(CONFIG_CACHE_L2X0)) {
 		outer_cache.write_sec = highbank_l2c310_write_sec;
 		l2x0_of_init(0, ~0);
 	}
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 046/222] ARM: l2c: ux500: implement dummy write_sec method
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (44 preceding siblings ...)
  2014-04-25 11:34 ` [PATCH 045/222] ARM: l2c: highbank: remove explicit SMI call in L2 cache initialisation Russell King
@ 2014-04-25 11:34 ` Russell King
  2014-04-25 11:34 ` [PATCH 047/222] ARM: l2c: remove old .set_debug method Russell King
                   ` (176 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:34 UTC (permalink / raw)
  To: linux-arm-kernel

ux500 can't write to any of the secure registers on the L2C controllers,
so provide a dummy handler which ignores all writes.

Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-ux500/cache-l2x0.c | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/arch/arm/mach-ux500/cache-l2x0.c b/arch/arm/mach-ux500/cache-l2x0.c
index 264f894c0e3d..5cc7e3625d8c 100644
--- a/arch/arm/mach-ux500/cache-l2x0.c
+++ b/arch/arm/mach-ux500/cache-l2x0.c
@@ -35,6 +35,14 @@ static int __init ux500_l2x0_unlock(void)
 	return 0;
 }
 
+static void ux500_l2c310_write_sec(unsigned long val, unsigned reg)
+{
+	/*
+	 * We can't write to secure registers as we are in non-secure
+	 * mode, until we have some SMI service available.
+	 */
+}
+
 static int __init ux500_l2x0_init(void)
 {
 	u32 aux_val = 0x3e000000;
@@ -56,21 +64,14 @@ static int __init ux500_l2x0_init(void)
 		/* 64KB way size */
 		aux_val |= (0x3 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT);
 
+	outer_cache.write_sec = ux500_l2c310_write_sec;
+
 	/* 64KB way size, 8 way associativity, force WA */
 	if (of_have_populated_dt())
 		l2x0_of_init(aux_val, 0xc0000fff);
 	else
 		l2x0_init(l2x0_base, aux_val, 0xc0000fff);
 
-	/*
-	 * We can't disable l2 as we are in non secure mode, currently
-	 * this seems be called only during kexec path. So let's
-	 * override outer.disable with nasty assignment until we have
-	 * some SMI service available.
-	 */
-	outer_cache.disable = NULL;
-	outer_cache.set_debug = NULL;
-
 	return 0;
 }
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 047/222] ARM: l2c: remove old .set_debug method
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (45 preceding siblings ...)
  2014-04-25 11:34 ` [PATCH 046/222] ARM: l2c: ux500: implement dummy write_sec method Russell King
@ 2014-04-25 11:34 ` Russell King
  2014-04-25 11:35 ` [PATCH 048/222] ARM: l2c: implement L2C-310 erratum 752271 in core L2C code Russell King
                   ` (175 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:34 UTC (permalink / raw)
  To: linux-arm-kernel

We no longer need or require the .set_debug method; we handle everything
it used to do via the .write_sec method instead.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/include/asm/outercache.h |  1 -
 arch/arm/mm/cache-l2x0.c          | 21 ++-------------------
 2 files changed, 2 insertions(+), 20 deletions(-)

diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h
index 5066fa2f73ab..eaa8a28c6871 100644
--- a/arch/arm/include/asm/outercache.h
+++ b/arch/arm/include/asm/outercache.h
@@ -36,7 +36,6 @@ struct outer_cache_fns {
 	void (*resume)(void);
 
 	/* This is an ARM L2C thing */
-	void (*set_debug)(unsigned long);
 	void (*write_sec)(unsigned long, unsigned);
 };
 
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 369a9d01d94f..b13276c9971b 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -80,10 +80,7 @@ static void l2c_write_sec(unsigned long val, void __iomem *base, unsigned reg)
  */
 static inline void l2c_set_debug(void __iomem *base, unsigned long val)
 {
-	if (outer_cache.set_debug)
-		outer_cache.set_debug(val);
-	else
-		l2c_write_sec(val, base, L2X0_DEBUG_CTRL);
+	l2c_write_sec(val, base, L2X0_DEBUG_CTRL);
 }
 
 static void __l2c_op_way(void __iomem *reg)
@@ -154,8 +151,7 @@ static inline void cache_sync(void)
 #if defined(CONFIG_PL310_ERRATA_588369) || defined(CONFIG_PL310_ERRATA_727915)
 static inline void debug_writel(unsigned long val)
 {
-	if (outer_cache.set_debug || outer_cache.write_sec)
-		l2c_set_debug(l2x0_base, val);
+	l2c_set_debug(l2x0_base, val);
 }
 #else
 /* Optimised out for non-errata case */
@@ -489,11 +485,6 @@ static const struct l2c_init_data l2c220_data = {
  *	Affects: store buffer
  *	store buffer is not automatically drained.
  */
-static void l2c310_set_debug(unsigned long val)
-{
-	writel_relaxed(val, l2x0_base + L2X0_DEBUG_CTRL);
-}
-
 static void l2c310_inv_range_erratum(unsigned long start, unsigned long end)
 {
 	void __iomem *base = l2x0_base;
@@ -631,10 +622,6 @@ static void __init l2c310_fixup(void __iomem *base, u32 cache_id,
 	const char *errata[4];
 	unsigned n = 0;
 
-	/* For compatibility */
-	if (revision <= L310_CACHE_ID_RTL_R3P0)
-		fns->set_debug = l2c310_set_debug;
-
 	if (IS_ENABLED(CONFIG_PL310_ERRATA_588369) &&
 	    revision < L310_CACHE_ID_RTL_R2P0 &&
 	    /* For bcm compatibility */
@@ -684,7 +671,6 @@ static const struct l2c_init_data l2c310_init_fns __initconst = {
 		.flush_all = l2c210_flush_all,
 		.disable = l2c_disable,
 		.sync = l2c210_sync,
-		.set_debug = l2c310_set_debug,
 		.resume = l2c310_resume,
 	},
 };
@@ -750,8 +736,6 @@ static void __init __l2c_init(const struct l2c_init_data *data,
 	fns.write_sec = outer_cache.write_sec;
 	if (data->fixup)
 		data->fixup(l2x0_base, cache_id, &fns);
-	if (fns.write_sec)
-		fns.set_debug = NULL;
 
 	/*
 	 * Check if l2x0 controller is already enabled.  If we are booting
@@ -925,7 +909,6 @@ static const struct l2c_init_data of_l2c310_data __initconst = {
 		.flush_all   = l2c210_flush_all,
 		.disable     = l2c_disable,
 		.sync        = l2c210_sync,
-		.set_debug   = l2c310_set_debug,
 		.resume      = l2c310_resume,
 	},
 };
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 048/222] ARM: l2c: implement L2C-310 erratum 752271 in core L2C code
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (46 preceding siblings ...)
  2014-04-25 11:34 ` [PATCH 047/222] ARM: l2c: remove old .set_debug method Russell King
@ 2014-04-25 11:35 ` Russell King
  2014-04-25 11:35 ` [PATCH 049/222] ARM: l2c: fix register naming Russell King
                   ` (174 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:35 UTC (permalink / raw)
  To: linux-arm-kernel

Rather than having SoCs work around L2C erratum themselves, move them
into core code.  This erratum affects the double linefill feature which
needs to be disabled for r3p0 to r3p1-50rel0.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index b13276c9971b..b1fa825c133f 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -476,6 +476,11 @@ static const struct l2c_init_data l2c220_data = {
  *	hit the line between the clean operation and invalidate operation,
  *	resulting in the store being lost.
  *
+ * 752271: PL310 R3P0->R3P1-50REL0, fixed R3P2.
+ *	Affects: 8x64-bit (double fill) line fetches
+ *	double fill line fetches can fail to cause dirty data to be evicted
+ *	from the cache before the new data overwrites the second line.
+ *
  * 753970: PL310 R3P0, fixed R3P1.
  *	Affects: sync
  *	prevents merging writes after the sync operation, until another L2C
@@ -619,7 +624,7 @@ static void __init l2c310_fixup(void __iomem *base, u32 cache_id,
 	struct outer_cache_fns *fns)
 {
 	unsigned revision = cache_id & L2X0_CACHE_ID_RTL_MASK;
-	const char *errata[4];
+	const char *errata[8];
 	unsigned n = 0;
 
 	if (IS_ENABLED(CONFIG_PL310_ERRATA_588369) &&
@@ -638,6 +643,17 @@ static void __init l2c310_fixup(void __iomem *base, u32 cache_id,
 		errata[n++] = "727915";
 	}
 
+	if (revision >= L310_CACHE_ID_RTL_R3P0 &&
+	    revision < L310_CACHE_ID_RTL_R3P2) {
+		u32 val = readl_relaxed(base + L2X0_PREFETCH_CTRL);
+		/* I don't think bit23 is required here... but iMX6 does so */
+		if (val & (BIT(30) | BIT(23))) {
+			val &= ~(BIT(30) | BIT(23));
+			l2c_write_sec(val, base, L2X0_PREFETCH_CTRL);
+			errata[n++] = "752271";
+		}
+	}
+
 	if (IS_ENABLED(CONFIG_PL310_ERRATA_753970) &&
 	    revision == L310_CACHE_ID_RTL_R3P0) {
 		sync_reg_offset = L2X0_DUMMY_REG;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 049/222] ARM: l2c: fix register naming
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (47 preceding siblings ...)
  2014-04-25 11:35 ` [PATCH 048/222] ARM: l2c: implement L2C-310 erratum 752271 in core L2C code Russell King
@ 2014-04-25 11:35 ` Russell King
  2014-04-25 11:35 ` [PATCH 050/222] ARM: l2c: add automatic enable of early BRESP Russell King
                   ` (173 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:35 UTC (permalink / raw)
  To: linux-arm-kernel

We have a mixture of different devices with different register layouts,
but we group all the bits together in an opaque mess.  Split them out
into those which are L2C-310 specific and ones which refer to earlier
devices.  Provide full auxiliary control register definitions.

Acked-by: Tony Lindgren <tony@atomide.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/include/asm/hardware/cache-l2x0.h | 73 ++++++++++++++++++++----------
 arch/arm/mach-cns3xxx/core.c               |  8 ++--
 arch/arm/mach-exynos/sleep.S               |  8 ++--
 arch/arm/mach-imx/system.c                 |  8 ++--
 arch/arm/mach-omap2/omap-mpuss-lowpower.c  |  2 +-
 arch/arm/mach-omap2/omap4-common.c         | 18 ++++----
 arch/arm/mach-prima2/l2x0.c                |  5 +-
 arch/arm/mach-realview/realview_pbx.c      |  4 +-
 arch/arm/mach-spear/spear13xx.c            |  6 +--
 arch/arm/mach-sti/board-dt.c               |  8 ++--
 arch/arm/mach-tegra/sleep.h                |  8 ++--
 arch/arm/mach-ux500/cache-l2x0.c           |  4 +-
 arch/arm/mach-vexpress/ct-ca9x4.c          |  4 +-
 arch/arm/mm/cache-l2x0.c                   | 57 +++++++++++------------
 14 files changed, 118 insertions(+), 95 deletions(-)

diff --git a/arch/arm/include/asm/hardware/cache-l2x0.h b/arch/arm/include/asm/hardware/cache-l2x0.h
index 3af45734b514..b3ee122c6f24 100644
--- a/arch/arm/include/asm/hardware/cache-l2x0.h
+++ b/arch/arm/include/asm/hardware/cache-l2x0.h
@@ -26,8 +26,8 @@
 #define L2X0_CACHE_TYPE			0x004
 #define L2X0_CTRL			0x100
 #define L2X0_AUX_CTRL			0x104
-#define L2X0_TAG_LATENCY_CTRL		0x108
-#define L2X0_DATA_LATENCY_CTRL		0x10C
+#define L310_TAG_LATENCY_CTRL		0x108
+#define L310_DATA_LATENCY_CTRL		0x10C
 #define L2X0_EVENT_CNT_CTRL		0x200
 #define L2X0_EVENT_CNT1_CFG		0x204
 #define L2X0_EVENT_CNT0_CFG		0x208
@@ -54,16 +54,16 @@
 #define L2X0_LOCKDOWN_WAY_D_BASE	0x900
 #define L2X0_LOCKDOWN_WAY_I_BASE	0x904
 #define L2X0_LOCKDOWN_STRIDE		0x08
-#define L2X0_ADDR_FILTER_START		0xC00
-#define L2X0_ADDR_FILTER_END		0xC04
+#define L310_ADDR_FILTER_START		0xC00
+#define L310_ADDR_FILTER_END		0xC04
 #define L2X0_TEST_OPERATION		0xF00
 #define L2X0_LINE_DATA			0xF10
 #define L2X0_LINE_TAG			0xF30
 #define L2X0_DEBUG_CTRL			0xF40
-#define L2X0_PREFETCH_CTRL		0xF60
-#define L2X0_POWER_CTRL			0xF80
-#define   L2X0_DYNAMIC_CLK_GATING_EN	(1 << 1)
-#define   L2X0_STNDBY_MODE_EN		(1 << 0)
+#define L310_PREFETCH_CTRL		0xF60
+#define L310_POWER_CTRL			0xF80
+#define   L310_DYNAMIC_CLK_GATING_EN	(1 << 1)
+#define   L310_STNDBY_MODE_EN		(1 << 0)
 
 /* Registers shifts and masks */
 #define L2X0_CACHE_ID_PART_MASK		(0xf << 6)
@@ -88,29 +88,52 @@
 #define L310_CACHE_ID_RTL_R3P3		0x09
 
 #define L2X0_AUX_CTRL_MASK			0xc0000fff
+/* L2C auxiliary control register - bits common to L2C-210/220/310 */
+#define L2C_AUX_CTRL_WAY_SIZE_SHIFT		17
+#define L2C_AUX_CTRL_WAY_SIZE_MASK		(7 << 17)
+#define L2C_AUX_CTRL_WAY_SIZE(n)		((n) << 17)
+#define L2C_AUX_CTRL_EVTMON_ENABLE		BIT(20)
+#define L2C_AUX_CTRL_PARITY_ENABLE		BIT(21)
+#define L2C_AUX_CTRL_SHARED_OVERRIDE		BIT(22)
+/* L2C-210/220 common bits */
 #define L2X0_AUX_CTRL_DATA_RD_LATENCY_SHIFT	0
-#define L2X0_AUX_CTRL_DATA_RD_LATENCY_MASK	0x7
+#define L2X0_AUX_CTRL_DATA_RD_LATENCY_MASK	(7 << 0)
 #define L2X0_AUX_CTRL_DATA_WR_LATENCY_SHIFT	3
-#define L2X0_AUX_CTRL_DATA_WR_LATENCY_MASK	(0x7 << 3)
+#define L2X0_AUX_CTRL_DATA_WR_LATENCY_MASK	(7 << 3)
 #define L2X0_AUX_CTRL_TAG_LATENCY_SHIFT		6
-#define L2X0_AUX_CTRL_TAG_LATENCY_MASK		(0x7 << 6)
+#define L2X0_AUX_CTRL_TAG_LATENCY_MASK		(7 << 6)
 #define L2X0_AUX_CTRL_DIRTY_LATENCY_SHIFT	9
-#define L2X0_AUX_CTRL_DIRTY_LATENCY_MASK	(0x7 << 9)
-#define L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT	16
-#define L2X0_AUX_CTRL_WAY_SIZE_SHIFT		17
-#define L2X0_AUX_CTRL_WAY_SIZE_MASK		(0x7 << 17)
-#define L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT	22
-#define L2X0_AUX_CTRL_NS_LOCKDOWN_SHIFT		26
-#define L2X0_AUX_CTRL_NS_INT_CTRL_SHIFT		27
-#define L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT	28
-#define L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT	29
-#define L2X0_AUX_CTRL_EARLY_BRESP_SHIFT		30
+#define L2X0_AUX_CTRL_DIRTY_LATENCY_MASK	(7 << 9)
+#define L2X0_AUX_CTRL_ASSOC_SHIFT		13
+#define L2X0_AUX_CTRL_ASSOC_MASK		(15 << 13)
+/* L2C-210 specific bits */
+#define L210_AUX_CTRL_WRAP_DISABLE		BIT(12)
+#define L210_AUX_CTRL_WA_OVERRIDE		BIT(23)
+#define L210_AUX_CTRL_EXCLUSIVE_ABORT		BIT(24)
+/* L2C-220 specific bits */
+#define L220_AUX_CTRL_EXCLUSIVE_CACHE		BIT(12)
+#define L220_AUX_CTRL_FWA_SHIFT			23
+#define L220_AUX_CTRL_FWA_MASK			(3 << 23)
+#define L220_AUX_CTRL_NS_LOCKDOWN		BIT(26)
+#define L220_AUX_CTRL_NS_INT_CTRL		BIT(27)
+/* L2C-310 specific bits */
+#define L310_AUX_CTRL_FULL_LINE_ZERO		BIT(0)	/* R2P0+ */
+#define L310_AUX_CTRL_HIGHPRIO_SO_DEV		BIT(10)	/* R2P0+ */
+#define L310_AUX_CTRL_STORE_LIMITATION		BIT(11)	/* R2P0+ */
+#define L310_AUX_CTRL_EXCLUSIVE_CACHE		BIT(12)
+#define L310_AUX_CTRL_ASSOCIATIVITY_16		BIT(16)
+#define L310_AUX_CTRL_CACHE_REPLACE_RR		BIT(25)	/* R2P0+ */
+#define L310_AUX_CTRL_NS_LOCKDOWN		BIT(26)
+#define L310_AUX_CTRL_NS_INT_CTRL		BIT(27)
+#define L310_AUX_CTRL_DATA_PREFETCH		BIT(28)
+#define L310_AUX_CTRL_INSTR_PREFETCH		BIT(29)
+#define L310_AUX_CTRL_EARLY_BRESP		BIT(30)	/* R2P0+ */
 
-#define L2X0_LATENCY_CTRL_SETUP_SHIFT	0
-#define L2X0_LATENCY_CTRL_RD_SHIFT	4
-#define L2X0_LATENCY_CTRL_WR_SHIFT	8
+#define L310_LATENCY_CTRL_SETUP(n)		((n) << 0)
+#define L310_LATENCY_CTRL_RD(n)			((n) << 4)
+#define L310_LATENCY_CTRL_WR(n)			((n) << 8)
 
-#define L2X0_ADDR_FILTER_EN		1
+#define L310_ADDR_FILTER_EN		1
 
 #define L2X0_CTRL_EN			1
 
diff --git a/arch/arm/mach-cns3xxx/core.c b/arch/arm/mach-cns3xxx/core.c
index 2ae28a69e3e5..5c31b2638c01 100644
--- a/arch/arm/mach-cns3xxx/core.c
+++ b/arch/arm/mach-cns3xxx/core.c
@@ -272,9 +272,9 @@ void __init cns3xxx_l2x0_init(void)
 	 *
 	 * 1 cycle of latency for setup, read and write accesses
 	 */
-	val = readl(base + L2X0_TAG_LATENCY_CTRL);
+	val = readl(base + L310_TAG_LATENCY_CTRL);
 	val &= 0xfffff888;
-	writel(val, base + L2X0_TAG_LATENCY_CTRL);
+	writel(val, base + L310_TAG_LATENCY_CTRL);
 
 	/*
 	 * Data RAM Control register
@@ -285,9 +285,9 @@ void __init cns3xxx_l2x0_init(void)
 	 *
 	 * 1 cycle of latency for setup, read and write accesses
 	 */
-	val = readl(base + L2X0_DATA_LATENCY_CTRL);
+	val = readl(base + L310_DATA_LATENCY_CTRL);
 	val &= 0xfffff888;
-	writel(val, base + L2X0_DATA_LATENCY_CTRL);
+	writel(val, base + L310_DATA_LATENCY_CTRL);
 
 	/* 32 KiB, 8-way, parity disable */
 	l2x0_init(base, 0x00540000, 0xfe000fff);
diff --git a/arch/arm/mach-exynos/sleep.S b/arch/arm/mach-exynos/sleep.S
index a2613e944e10..7e0af530511e 100644
--- a/arch/arm/mach-exynos/sleep.S
+++ b/arch/arm/mach-exynos/sleep.S
@@ -65,13 +65,13 @@ ENTRY(exynos_cpu_resume)
 	ldr	r2, [r0, #L2X0_R_AUX_CTRL]
 	str	r2, [r1, #L2X0_AUX_CTRL]
 	ldr	r2, [r0, #L2X0_R_TAG_LATENCY]
-	str	r2, [r1, #L2X0_TAG_LATENCY_CTRL]
+	str	r2, [r1, #L310_TAG_LATENCY_CTRL]
 	ldr	r2, [r0, #L2X0_R_DATA_LATENCY]
-	str	r2, [r1, #L2X0_DATA_LATENCY_CTRL]
+	str	r2, [r1, #L310_DATA_LATENCY_CTRL]
 	ldr	r2, [r0, #L2X0_R_PREFETCH_CTRL]
-	str	r2, [r1, #L2X0_PREFETCH_CTRL]
+	str	r2, [r1, #L310_PREFETCH_CTRL]
 	ldr	r2, [r0, #L2X0_R_PWR_CTRL]
-	str	r2, [r1, #L2X0_POWER_CTRL]
+	str	r2, [r1, #L310_POWER_CTRL]
 	mov	r2, #1
 	str	r2, [r1, #L2X0_CTRL]
 skip_l2_resume:
diff --git a/arch/arm/mach-imx/system.c b/arch/arm/mach-imx/system.c
index c6571f1de9fd..59013a81107b 100644
--- a/arch/arm/mach-imx/system.c
+++ b/arch/arm/mach-imx/system.c
@@ -124,7 +124,7 @@ void __init imx_init_l2cache(void)
 	}
 
 	/* Configure the L2 PREFETCH and POWER registers */
-	val = readl_relaxed(l2x0_base + L2X0_PREFETCH_CTRL);
+	val = readl_relaxed(l2x0_base + L310_PREFETCH_CTRL);
 	val |= 0x70800000;
 	/*
 	 * The L2 cache controller(PL310) version on the i.MX6D/Q is r3p1-50rel0
@@ -137,9 +137,9 @@ void __init imx_init_l2cache(void)
 	 */
 	if (cpu_is_imx6q())
 		val &= ~(1 << 30 | 1 << 23);
-	writel_relaxed(val, l2x0_base + L2X0_PREFETCH_CTRL);
-	val = L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN;
-	writel_relaxed(val, l2x0_base + L2X0_POWER_CTRL);
+	writel_relaxed(val, l2x0_base + L310_PREFETCH_CTRL);
+	val = L310_DYNAMIC_CLK_GATING_EN | L310_STNDBY_MODE_EN;
+	writel_relaxed(val, l2x0_base + L310_POWER_CTRL);
 
 	iounmap(l2x0_base);
 	of_node_put(np);
diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
index 667915d236f3..ba43f49fbb59 100644
--- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c
+++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
@@ -194,7 +194,7 @@ static void save_l2x0_context(void)
 	if (l2x0_base) {
 		val = __raw_readl(l2x0_base + L2X0_AUX_CTRL);
 		__raw_writel(val, sar_base + L2X0_AUXCTRL_OFFSET);
-		val = __raw_readl(l2x0_base + L2X0_PREFETCH_CTRL);
+		val = __raw_readl(l2x0_base + L310_PREFETCH_CTRL);
 		__raw_writel(val, sar_base + L2X0_PREFETCH_CTRL_OFFSET);
 	}
 }
diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c
index 46dac72aaa4c..dc9844a55443 100644
--- a/arch/arm/mach-omap2/omap4-common.c
+++ b/arch/arm/mach-omap2/omap4-common.c
@@ -213,15 +213,15 @@ static int __init omap_l2_cache_init(void)
 		return -ENOMEM;
 
 	/* 16-way associativity, parity disabled, way size - 64KB (es2.0 +) */
-	aux_ctrl = (1 << L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT) |
-			(0x1 << 25) |
-			(0x1 << L2X0_AUX_CTRL_NS_LOCKDOWN_SHIFT) |
-			(0x1 << L2X0_AUX_CTRL_NS_INT_CTRL_SHIFT)) |
-			(0x3 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) |
-			(1 << L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT) |
-			(1 << L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT) |
-			(1 << L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT) |
-			(1 << L2X0_AUX_CTRL_EARLY_BRESP_SHIFT);
+	aux_ctrl = L310_AUX_CTRL_ASSOCIATIVITY_16 |
+		   L310_AUX_CTRL_CACHE_REPLACE_RR |
+		   L310_AUX_CTRL_NS_LOCKDOWN |
+		   L310_AUX_CTRL_NS_INT_CTRL |
+		   L2C_AUX_CTRL_WAY_SIZE(3) |
+		   L2C_AUX_CTRL_SHARED_OVERRIDE |
+		   L310_AUX_CTRL_DATA_PREFETCH |
+		   L310_AUX_CTRL_INSTR_PREFETCH |
+		   L310_AUX_CTRL_EARLY_BRESP;
 
 	outer_cache.write_sec = omap4_l2c310_write_sec;
 	if (of_have_populated_dt())
diff --git a/arch/arm/mach-prima2/l2x0.c b/arch/arm/mach-prima2/l2x0.c
index c7102539c0b0..2db82742fb74 100644
--- a/arch/arm/mach-prima2/l2x0.c
+++ b/arch/arm/mach-prima2/l2x0.c
@@ -17,13 +17,12 @@ struct l2x0_aux {
 };
 
 static const struct l2x0_aux prima2_l2x0_aux __initconst = {
-	.val = 2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT,
+	.val = L2C_AUX_CTRL_WAY_SIZE(2),
 	.mask =	0,
 };
 
 static const struct l2x0_aux marco_l2x0_aux __initconst = {
-	.val = (2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) |
-		(1 << L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT),
+	.val = L2C_AUX_CTRL_WAY_SIZE(2) | L310_AUX_CTRL_ASSOCIATIVITY_16,
 	.mask = L2X0_AUX_CTRL_MASK,
 };
 
diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c
index 9d75493e3f0c..f0cfd7e7e569 100644
--- a/arch/arm/mach-realview/realview_pbx.c
+++ b/arch/arm/mach-realview/realview_pbx.c
@@ -370,8 +370,8 @@ static void __init realview_pbx_init(void)
 			__io_address(REALVIEW_PBX_TILE_L220_BASE);
 
 		/* set RAM latencies to 1 cycle for eASIC */
-		writel(0, l2x0_base + L2X0_TAG_LATENCY_CTRL);
-		writel(0, l2x0_base + L2X0_DATA_LATENCY_CTRL);
+		writel(0, l2x0_base + L310_TAG_LATENCY_CTRL);
+		writel(0, l2x0_base + L310_DATA_LATENCY_CTRL);
 
 		/* 16KB way size, 8-way associativity, parity disabled
 		 * Bits:  .. 0 0 0 0 1 00 1 0 1 001 0 000 0 .... .... .... */
diff --git a/arch/arm/mach-spear/spear13xx.c b/arch/arm/mach-spear/spear13xx.c
index 7aa6e8cf830f..92860fa01668 100644
--- a/arch/arm/mach-spear/spear13xx.c
+++ b/arch/arm/mach-spear/spear13xx.c
@@ -38,14 +38,14 @@ void __init spear13xx_l2x0_init(void)
 	if (!IS_ENABLED(CONFIG_CACHE_L2X0))
 		return;
 
-	writel_relaxed(0x06, VA_L2CC_BASE + L2X0_PREFETCH_CTRL);
+	writel_relaxed(0x06, VA_L2CC_BASE + L310_PREFETCH_CTRL);
 
 	/*
 	 * Program following latencies in order to make
 	 * SPEAr1340 work@600 MHz
 	 */
-	writel_relaxed(0x221, VA_L2CC_BASE + L2X0_TAG_LATENCY_CTRL);
-	writel_relaxed(0x441, VA_L2CC_BASE + L2X0_DATA_LATENCY_CTRL);
+	writel_relaxed(0x221, VA_L2CC_BASE + L310_TAG_LATENCY_CTRL);
+	writel_relaxed(0x441, VA_L2CC_BASE + L310_DATA_LATENCY_CTRL);
 	l2x0_init(VA_L2CC_BASE, 0x70A60001, 0xfe00ffff);
 }
 
diff --git a/arch/arm/mach-sti/board-dt.c b/arch/arm/mach-sti/board-dt.c
index 1217fb598cfd..dc8669efc12d 100644
--- a/arch/arm/mach-sti/board-dt.c
+++ b/arch/arm/mach-sti/board-dt.c
@@ -19,10 +19,10 @@ void __init stih41x_l2x0_init(void)
 	u32 way_size = 0x4;
 	u32 aux_ctrl;
 	/* may be this can be encoded in macros like BIT*() */
-	aux_ctrl = (0x1 << L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT) |
-		(0x1 << L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT) |
-		(0x1 << L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT) |
-		(way_size << L2X0_AUX_CTRL_WAY_SIZE_SHIFT);
+	aux_ctrl = L2C_AUX_CTRL_SHARED_OVERRIDE |
+		   L310_AUX_CTRL_DATA_PREFETCH |
+		   L310_AUX_CTRL_INSTR_PREFETCH |
+		   L2C_AUX_CTRL_WAY_SIZE(way_size);
 
 	l2x0_of_init(aux_ctrl, L2X0_AUX_CTRL_MASK);
 }
diff --git a/arch/arm/mach-tegra/sleep.h b/arch/arm/mach-tegra/sleep.h
index a4edbb3abd3d..a032820d2fac 100644
--- a/arch/arm/mach-tegra/sleep.h
+++ b/arch/arm/mach-tegra/sleep.h
@@ -134,13 +134,13 @@
 	tst	\tmp3, #L2X0_CTRL_EN
 	bne	exit_l2_resume
 	ldr	\tmp3, [\tmp1, #L2X0_R_TAG_LATENCY]
-	str	\tmp3, [\tmp2, #L2X0_TAG_LATENCY_CTRL]
+	str	\tmp3, [\tmp2, #L310_TAG_LATENCY_CTRL]
 	ldr	\tmp3, [\tmp1, #L2X0_R_DATA_LATENCY]
-	str	\tmp3, [\tmp2, #L2X0_DATA_LATENCY_CTRL]
+	str	\tmp3, [\tmp2, #L310_DATA_LATENCY_CTRL]
 	ldr	\tmp3, [\tmp1, #L2X0_R_PREFETCH_CTRL]
-	str	\tmp3, [\tmp2, #L2X0_PREFETCH_CTRL]
+	str	\tmp3, [\tmp2, #L310_PREFETCH_CTRL]
 	ldr	\tmp3, [\tmp1, #L2X0_R_PWR_CTRL]
-	str	\tmp3, [\tmp2, #L2X0_POWER_CTRL]
+	str	\tmp3, [\tmp2, #L310_POWER_CTRL]
 	ldr	\tmp3, [\tmp1, #L2X0_R_AUX_CTRL]
 	str	\tmp3, [\tmp2, #L2X0_AUX_CTRL]
 	mov	\tmp3, #L2X0_CTRL_EN
diff --git a/arch/arm/mach-ux500/cache-l2x0.c b/arch/arm/mach-ux500/cache-l2x0.c
index 5cc7e3625d8c..067c37a054fb 100644
--- a/arch/arm/mach-ux500/cache-l2x0.c
+++ b/arch/arm/mach-ux500/cache-l2x0.c
@@ -59,10 +59,10 @@ static int __init ux500_l2x0_init(void)
 	/* DBx540's L2 has 128KB way size */
 	if (cpu_is_ux540_family())
 		/* 128KB way size */
-		aux_val |= (0x4 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT);
+		aux_val |= L2C_AUX_CTRL_WAY_SIZE(4);
 	else
 		/* 64KB way size */
-		aux_val |= (0x3 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT);
+		aux_val |= L2C_AUX_CTRL_WAY_SIZE(3);
 
 	outer_cache.write_sec = ux500_l2c310_write_sec;
 
diff --git a/arch/arm/mach-vexpress/ct-ca9x4.c b/arch/arm/mach-vexpress/ct-ca9x4.c
index 6f34497a4245..6c4ffb6c5ad8 100644
--- a/arch/arm/mach-vexpress/ct-ca9x4.c
+++ b/arch/arm/mach-vexpress/ct-ca9x4.c
@@ -145,8 +145,8 @@ static void __init ct_ca9x4_init(void)
 	void __iomem *l2x0_base = ioremap(CT_CA9X4_L2CC, SZ_4K);
 
 	/* set RAM latencies to 1 cycle for this core tile. */
-	writel(0, l2x0_base + L2X0_TAG_LATENCY_CTRL);
-	writel(0, l2x0_base + L2X0_DATA_LATENCY_CTRL);
+	writel(0, l2x0_base + L310_TAG_LATENCY_CTRL);
+	writel(0, l2x0_base + L310_DATA_LATENCY_CTRL);
 
 	l2x0_init(l2x0_base, 0x00400000, 0xfe0fffff);
 #endif
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index b1fa825c133f..3e2c22a12d87 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -567,13 +567,13 @@ static void __init l2c310_save(void __iomem *base)
 	unsigned revision;
 
 	l2x0_saved_regs.tag_latency = readl_relaxed(base +
-		L2X0_TAG_LATENCY_CTRL);
+		L310_TAG_LATENCY_CTRL);
 	l2x0_saved_regs.data_latency = readl_relaxed(base +
-		L2X0_DATA_LATENCY_CTRL);
+		L310_DATA_LATENCY_CTRL);
 	l2x0_saved_regs.filter_end = readl_relaxed(base +
-		L2X0_ADDR_FILTER_END);
+		L310_ADDR_FILTER_END);
 	l2x0_saved_regs.filter_start = readl_relaxed(base +
-		L2X0_ADDR_FILTER_START);
+		L310_ADDR_FILTER_START);
 
 	revision = readl_relaxed(base + L2X0_CACHE_ID) &
 			L2X0_CACHE_ID_RTL_MASK;
@@ -581,12 +581,12 @@ static void __init l2c310_save(void __iomem *base)
 	/* From r2p0, there is Prefetch offset/control register */
 	if (revision >= L310_CACHE_ID_RTL_R2P0)
 		l2x0_saved_regs.prefetch_ctrl = readl_relaxed(base +
-							L2X0_PREFETCH_CTRL);
+							L310_PREFETCH_CTRL);
 
 	/* From r3p0, there is Power control register */
 	if (revision >= L310_CACHE_ID_RTL_R3P0)
 		l2x0_saved_regs.pwr_ctrl = readl_relaxed(base +
-							L2X0_POWER_CTRL);
+							L310_POWER_CTRL);
 }
 
 static void l2c310_resume(void)
@@ -598,23 +598,23 @@ static void l2c310_resume(void)
 
 		/* restore pl310 setup */
 		writel_relaxed(l2x0_saved_regs.tag_latency,
-			       base + L2X0_TAG_LATENCY_CTRL);
+			       base + L310_TAG_LATENCY_CTRL);
 		writel_relaxed(l2x0_saved_regs.data_latency,
-			       base + L2X0_DATA_LATENCY_CTRL);
+			       base + L310_DATA_LATENCY_CTRL);
 		writel_relaxed(l2x0_saved_regs.filter_end,
-			       base + L2X0_ADDR_FILTER_END);
+			       base + L310_ADDR_FILTER_END);
 		writel_relaxed(l2x0_saved_regs.filter_start,
-			       base + L2X0_ADDR_FILTER_START);
+			       base + L310_ADDR_FILTER_START);
 
 		revision = readl_relaxed(base + L2X0_CACHE_ID) &
 				L2X0_CACHE_ID_RTL_MASK;
 
 		if (revision >= L310_CACHE_ID_RTL_R2P0)
 			l2c_write_sec(l2x0_saved_regs.prefetch_ctrl, base,
-				      L2X0_PREFETCH_CTRL);
+				      L310_PREFETCH_CTRL);
 		if (revision >= L310_CACHE_ID_RTL_R3P0)
 			l2c_write_sec(l2x0_saved_regs.pwr_ctrl, base,
-				      L2X0_POWER_CTRL);
+				      L310_POWER_CTRL);
 
 		l2c_enable(base, l2x0_saved_regs.aux_ctrl, 8);
 	}
@@ -645,11 +645,11 @@ static void __init l2c310_fixup(void __iomem *base, u32 cache_id,
 
 	if (revision >= L310_CACHE_ID_RTL_R3P0 &&
 	    revision < L310_CACHE_ID_RTL_R3P2) {
-		u32 val = readl_relaxed(base + L2X0_PREFETCH_CTRL);
+		u32 val = readl_relaxed(base + L310_PREFETCH_CTRL);
 		/* I don't think bit23 is required here... but iMX6 does so */
 		if (val & (BIT(30) | BIT(23))) {
 			val &= ~(BIT(30) | BIT(23));
-			l2c_write_sec(val, base, L2X0_PREFETCH_CTRL);
+			l2c_write_sec(val, base, L310_PREFETCH_CTRL);
 			errata[n++] = "752271";
 		}
 	}
@@ -745,7 +745,8 @@ static void __init __l2c_init(const struct l2c_init_data *data,
 	 *
 	 * L2 cache size = number of ways * way size.
 	 */
-	way_size_bits = (aux & L2X0_AUX_CTRL_WAY_SIZE_MASK) >> 17;
+	way_size_bits = (aux & L2C_AUX_CTRL_WAY_SIZE_MASK) >>
+			L2C_AUX_CTRL_WAY_SIZE_SHIFT;
 	l2x0_size = ways * (data->way_size_0 << way_size_bits);
 
 	fns = data->outer_cache;
@@ -886,27 +887,27 @@ static void __init l2c310_of_parse(const struct device_node *np,
 	of_property_read_u32_array(np, "arm,tag-latency", tag, ARRAY_SIZE(tag));
 	if (tag[0] && tag[1] && tag[2])
 		writel_relaxed(
-			((tag[0] - 1) << L2X0_LATENCY_CTRL_RD_SHIFT) |
-			((tag[1] - 1) << L2X0_LATENCY_CTRL_WR_SHIFT) |
-			((tag[2] - 1) << L2X0_LATENCY_CTRL_SETUP_SHIFT),
-			l2x0_base + L2X0_TAG_LATENCY_CTRL);
+			L310_LATENCY_CTRL_RD(tag[0] - 1) |
+			L310_LATENCY_CTRL_WR(tag[1] - 1) |
+			L310_LATENCY_CTRL_SETUP(tag[2] - 1),
+			l2x0_base + L310_TAG_LATENCY_CTRL);
 
 	of_property_read_u32_array(np, "arm,data-latency",
 				   data, ARRAY_SIZE(data));
 	if (data[0] && data[1] && data[2])
 		writel_relaxed(
-			((data[0] - 1) << L2X0_LATENCY_CTRL_RD_SHIFT) |
-			((data[1] - 1) << L2X0_LATENCY_CTRL_WR_SHIFT) |
-			((data[2] - 1) << L2X0_LATENCY_CTRL_SETUP_SHIFT),
-			l2x0_base + L2X0_DATA_LATENCY_CTRL);
+			L310_LATENCY_CTRL_RD(data[0] - 1) |
+			L310_LATENCY_CTRL_WR(data[1] - 1) |
+			L310_LATENCY_CTRL_SETUP(data[2] - 1),
+			l2x0_base + L310_DATA_LATENCY_CTRL);
 
 	of_property_read_u32_array(np, "arm,filter-ranges",
 				   filter, ARRAY_SIZE(filter));
 	if (filter[1]) {
 		writel_relaxed(ALIGN(filter[0] + filter[1], SZ_1M),
-			       l2x0_base + L2X0_ADDR_FILTER_END);
-		writel_relaxed((filter[0] & ~(SZ_1M - 1)) | L2X0_ADDR_FILTER_EN,
-			       l2x0_base + L2X0_ADDR_FILTER_START);
+			       l2x0_base + L310_ADDR_FILTER_END);
+		writel_relaxed((filter[0] & ~(SZ_1M - 1)) | L310_ADDR_FILTER_EN,
+			       l2x0_base + L310_ADDR_FILTER_START);
 	}
 }
 
@@ -1281,7 +1282,7 @@ static void __init tauros3_save(void __iomem *base)
 	l2x0_saved_regs.aux2_ctrl =
 		readl_relaxed(base + TAUROS3_AUX2_CTRL);
 	l2x0_saved_regs.prefetch_ctrl =
-		readl_relaxed(base + L2X0_PREFETCH_CTRL);
+		readl_relaxed(base + L310_PREFETCH_CTRL);
 }
 
 static void tauros3_resume(void)
@@ -1292,7 +1293,7 @@ static void tauros3_resume(void)
 		writel_relaxed(l2x0_saved_regs.aux2_ctrl,
 			       base + TAUROS3_AUX2_CTRL);
 		writel_relaxed(l2x0_saved_regs.prefetch_ctrl,
-			       base + L2X0_PREFETCH_CTRL);
+			       base + L310_PREFETCH_CTRL);
 
 		l2c_enable(base, l2x0_saved_regs.aux_ctrl, 8);
 	}
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 050/222] ARM: l2c: add automatic enable of early BRESP
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (48 preceding siblings ...)
  2014-04-25 11:35 ` [PATCH 049/222] ARM: l2c: fix register naming Russell King
@ 2014-04-25 11:35 ` Russell King
  2014-04-25 11:35 ` [PATCH 051/222] ARM: l2c: remove platforms/SoCs setting " Russell King
                   ` (172 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:35 UTC (permalink / raw)
  To: linux-arm-kernel

The AXI bus protocol requires that a write response should only be
sent back to the master when the last write has been accepted.  Early
BRESP allows the L2C-310 to send the write response as soon as the
store buffer accepts the write address.

Cortex-A9 processors can signal to the L2C-310 that they wish to be
notified early, and if this optimisation is enabled, the L2C-310 can
signal an early write response.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 25 ++++++++++++++++++++++---
 1 file changed, 22 insertions(+), 3 deletions(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 3e2c22a12d87..db3f18a968b2 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -24,6 +24,7 @@
 #include <linux/of_address.h>
 
 #include <asm/cacheflush.h>
+#include <asm/cputype.h>
 #include <asm/hardware/cache-l2x0.h>
 #include "cache-tauros3.h"
 #include "cache-aurora-l2.h"
@@ -620,6 +621,24 @@ static void l2c310_resume(void)
 	}
 }
 
+static void __init l2c310_enable(void __iomem *base, u32 aux, unsigned num_lock)
+{
+	unsigned rev = readl_relaxed(base + L2X0_CACHE_ID) & L2X0_CACHE_ID_PART_MASK;
+	bool cortex_a9 = read_cpuid_part_number() == ARM_CPU_PART_CORTEX_A9;
+
+	if (rev >= L310_CACHE_ID_RTL_R2P0) {
+		if (cortex_a9) {
+			aux |= L310_AUX_CTRL_EARLY_BRESP;
+			pr_info("L2C-310 enabling early BRESP for Cortex-A9\n");
+		} else if (aux & L310_AUX_CTRL_EARLY_BRESP) {
+			pr_warn("L2C-310 early BRESP only supported with Cortex-A9\n");
+			aux &= ~L310_AUX_CTRL_EARLY_BRESP;
+		}
+	}
+
+	l2c_enable(base, aux, num_lock);
+}
+
 static void __init l2c310_fixup(void __iomem *base, u32 cache_id,
 	struct outer_cache_fns *fns)
 {
@@ -677,7 +696,7 @@ static const struct l2c_init_data l2c310_init_fns __initconst = {
 	.type = "L2C-310",
 	.way_size_0 = SZ_8K,
 	.num_lock = 8,
-	.enable = l2c_enable,
+	.enable = l2c310_enable,
 	.fixup = l2c310_fixup,
 	.save = l2c310_save,
 	.outer_cache = {
@@ -916,7 +935,7 @@ static const struct l2c_init_data of_l2c310_data __initconst = {
 	.way_size_0 = SZ_8K,
 	.num_lock = 8,
 	.of_parse = l2c310_of_parse,
-	.enable = l2c_enable,
+	.enable = l2c310_enable,
 	.fixup = l2c310_fixup,
 	.save  = l2c310_save,
 	.outer_cache = {
@@ -1264,7 +1283,7 @@ static const struct l2c_init_data of_bcm_l2x0_data __initconst = {
 	.way_size_0 = SZ_8K,
 	.num_lock = 8,
 	.of_parse = l2c310_of_parse,
-	.enable = l2c_enable,
+	.enable = l2c310_enable,
 	.save  = l2c310_save,
 	.outer_cache = {
 		.inv_range   = bcm_inv_range,
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 051/222] ARM: l2c: remove platforms/SoCs setting early BRESP
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (49 preceding siblings ...)
  2014-04-25 11:35 ` [PATCH 050/222] ARM: l2c: add automatic enable of early BRESP Russell King
@ 2014-04-25 11:35 ` Russell King
  2014-04-25 11:35 ` [PATCH 052/222] ARM: l2c: tegra: remove associativity and way size from aux_ctrl Russell King
                   ` (171 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:35 UTC (permalink / raw)
  To: linux-arm-kernel

Since we now automatically enable early BRESP in core L2C-310 code when
we detect a Cortex-A9, we don't need platforms/SoCs to set this bit
explicitly.  Instead, they should seek to preserve the value of bit 30
in the auxiliary control register.

Acked-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-berlin/berlin.c                            | 2 +-
 arch/arm/mach-exynos/exynos.c                            | 4 ++--
 arch/arm/mach-omap2/omap4-common.c                       | 3 +--
 arch/arm/mach-shmobile/board-armadillo800eva-reference.c | 4 ++--
 arch/arm/mach-shmobile/board-armadillo800eva.c           | 4 ++--
 arch/arm/mach-shmobile/board-kzm9g-reference.c           | 4 ++--
 arch/arm/mach-shmobile/board-kzm9g.c                     | 4 ++--
 arch/arm/mach-shmobile/setup-r8a7778.c                   | 4 ++--
 arch/arm/mach-shmobile/setup-r8a7779.c                   | 4 ++--
 arch/arm/mach-spear/spear13xx.c                          | 2 +-
 arch/arm/mach-tegra/tegra.c                              | 4 ++--
 11 files changed, 19 insertions(+), 20 deletions(-)

diff --git a/arch/arm/mach-berlin/berlin.c b/arch/arm/mach-berlin/berlin.c
index 025bcb5473eb..6709d2a6bec8 100644
--- a/arch/arm/mach-berlin/berlin.c
+++ b/arch/arm/mach-berlin/berlin.c
@@ -24,7 +24,7 @@ static void __init berlin_init_machine(void)
 	 * with DT probing for L2CCs, berlin_init_machine can be removed.
 	 * Note: 88DE3005 (Armada 1500-mini) uses pl310 l2cc
 	 */
-	l2x0_of_init(0x70c00000, 0xfeffffff);
+	l2x0_of_init(0x30c00000, 0xfeffffff);
 	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
 }
 
diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c
index b32a907d021d..e6828fb46034 100644
--- a/arch/arm/mach-exynos/exynos.c
+++ b/arch/arm/mach-exynos/exynos.c
@@ -32,8 +32,8 @@
 #include "mfc.h"
 #include "regs-pmu.h"
 
-#define L2_AUX_VAL 0x7C470001
-#define L2_AUX_MASK 0xC200ffff
+#define L2_AUX_VAL 0x3c470001
+#define L2_AUX_MASK 0xc200ffff
 
 static struct map_desc exynos4_iodesc[] __initdata = {
 	{
diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c
index dc9844a55443..9ce52548a484 100644
--- a/arch/arm/mach-omap2/omap4-common.c
+++ b/arch/arm/mach-omap2/omap4-common.c
@@ -220,8 +220,7 @@ static int __init omap_l2_cache_init(void)
 		   L2C_AUX_CTRL_WAY_SIZE(3) |
 		   L2C_AUX_CTRL_SHARED_OVERRIDE |
 		   L310_AUX_CTRL_DATA_PREFETCH |
-		   L310_AUX_CTRL_INSTR_PREFETCH |
-		   L310_AUX_CTRL_EARLY_BRESP;
+		   L310_AUX_CTRL_INSTR_PREFETCH;
 
 	outer_cache.write_sec = omap4_l2c310_write_sec;
 	if (of_have_populated_dt())
diff --git a/arch/arm/mach-shmobile/board-armadillo800eva-reference.c b/arch/arm/mach-shmobile/board-armadillo800eva-reference.c
index 57d1a78367b6..34e7f3c17dd2 100644
--- a/arch/arm/mach-shmobile/board-armadillo800eva-reference.c
+++ b/arch/arm/mach-shmobile/board-armadillo800eva-reference.c
@@ -164,8 +164,8 @@ static void __init eva_init(void)
 	r8a7740_meram_workaround();
 
 #ifdef CONFIG_CACHE_L2X0
-	/* Early BRESP enable, Shared attribute override enable, 32K*8way */
-	l2x0_init(IOMEM(0xf0002000), 0x40440000, 0x82000fff);
+	/* Shared attribute override enable, 32K*8way */
+	l2x0_init(IOMEM(0xf0002000), 0x00440000, 0xc2000fff);
 #endif
 
 	r8a7740_add_standard_devices_dt();
diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c
index 2858f380beae..7688990edd3a 100644
--- a/arch/arm/mach-shmobile/board-armadillo800eva.c
+++ b/arch/arm/mach-shmobile/board-armadillo800eva.c
@@ -1270,8 +1270,8 @@ static void __init eva_init(void)
 
 
 #ifdef CONFIG_CACHE_L2X0
-	/* Early BRESP enable, Shared attribute override enable, 32K*8way */
-	l2x0_init(IOMEM(0xf0002000), 0x40440000, 0x82000fff);
+	/* Shared attribute override enable, 32K*8way */
+	l2x0_init(IOMEM(0xf0002000), 0x00440000, 0xc2000fff);
 #endif
 
 	i2c_register_board_info(0, i2c0_devices, ARRAY_SIZE(i2c0_devices));
diff --git a/arch/arm/mach-shmobile/board-kzm9g-reference.c b/arch/arm/mach-shmobile/board-kzm9g-reference.c
index 598e32488410..85873f186d77 100644
--- a/arch/arm/mach-shmobile/board-kzm9g-reference.c
+++ b/arch/arm/mach-shmobile/board-kzm9g-reference.c
@@ -36,8 +36,8 @@ static void __init kzm_init(void)
 	sh73a0_add_standard_devices_dt();
 
 #ifdef CONFIG_CACHE_L2X0
-	/* Early BRESP enable, Shared attribute override enable, 64K*8way */
-	l2x0_init(IOMEM(0xf0100000), 0x40460000, 0x82000fff);
+	/* Shared attribute override enable, 64K*8way */
+	l2x0_init(IOMEM(0xf0100000), 0x00460000, 0xc2000fff);
 #endif
 }
 
diff --git a/arch/arm/mach-shmobile/board-kzm9g.c b/arch/arm/mach-shmobile/board-kzm9g.c
index 03dc3ac84502..ea9bf39fdc10 100644
--- a/arch/arm/mach-shmobile/board-kzm9g.c
+++ b/arch/arm/mach-shmobile/board-kzm9g.c
@@ -876,8 +876,8 @@ static void __init kzm_init(void)
 	gpio_request_one(223, GPIOF_IN, NULL); /* IRQ8 */
 
 #ifdef CONFIG_CACHE_L2X0
-	/* Early BRESP enable, Shared attribute override enable, 64K*8way */
-	l2x0_init(IOMEM(0xf0100000), 0x40460000, 0x82000fff);
+	/* Shared attribute override enable, 64K*8way */
+	l2x0_init(IOMEM(0xf0100000), 0x00460000, 0xc2000fff);
 #endif
 
 	i2c_register_board_info(0, i2c0_devices, ARRAY_SIZE(i2c0_devices));
diff --git a/arch/arm/mach-shmobile/setup-r8a7778.c b/arch/arm/mach-shmobile/setup-r8a7778.c
index 6d694526e4ca..3a8e5316671e 100644
--- a/arch/arm/mach-shmobile/setup-r8a7778.c
+++ b/arch/arm/mach-shmobile/setup-r8a7778.c
@@ -298,10 +298,10 @@ void __init r8a7778_add_dt_devices(void)
 	void __iomem *base = ioremap_nocache(0xf0100000, 0x1000);
 	if (base) {
 		/*
-		 * Early BRESP enable, Shared attribute override enable, 64K*16way
+		 * Shared attribute override enable, 64K*16way
 		 * don't call iounmap(base)
 		 */
-		l2x0_init(base, 0x40470000, 0x82000fff);
+		l2x0_init(base, 0x00470000, 0xc2000fff);
 	}
 #endif
 
diff --git a/arch/arm/mach-shmobile/setup-r8a7779.c b/arch/arm/mach-shmobile/setup-r8a7779.c
index 8e860b36997a..91c90bf0ae83 100644
--- a/arch/arm/mach-shmobile/setup-r8a7779.c
+++ b/arch/arm/mach-shmobile/setup-r8a7779.c
@@ -700,8 +700,8 @@ static struct platform_device *r8a7779_standard_devices[] __initdata = {
 void __init r8a7779_add_standard_devices(void)
 {
 #ifdef CONFIG_CACHE_L2X0
-	/* Early BRESP enable, Shared attribute override enable, 64K*16way */
-	l2x0_init(IOMEM(0xf0100000), 0x40470000, 0x82000fff);
+	/* Shared attribute override enable, 64K*16way */
+	l2x0_init(IOMEM(0xf0100000), 0x00470000, 0xc2000fff);
 #endif
 	r8a7779_pm_init();
 
diff --git a/arch/arm/mach-spear/spear13xx.c b/arch/arm/mach-spear/spear13xx.c
index 92860fa01668..dcb300443b66 100644
--- a/arch/arm/mach-spear/spear13xx.c
+++ b/arch/arm/mach-spear/spear13xx.c
@@ -46,7 +46,7 @@ void __init spear13xx_l2x0_init(void)
 	 */
 	writel_relaxed(0x221, VA_L2CC_BASE + L310_TAG_LATENCY_CTRL);
 	writel_relaxed(0x441, VA_L2CC_BASE + L310_DATA_LATENCY_CTRL);
-	l2x0_init(VA_L2CC_BASE, 0x70A60001, 0xfe00ffff);
+	l2x0_init(VA_L2CC_BASE, 0x30a60001, 0xfe00ffff);
 }
 
 /*
diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c
index 6191603379e1..ecbb5411a104 100644
--- a/arch/arm/mach-tegra/tegra.c
+++ b/arch/arm/mach-tegra/tegra.c
@@ -89,9 +89,9 @@ static void __init tegra_init_cache(void)
 
 	cache_type = readl(p + L2X0_CACHE_TYPE);
 	aux_ctrl = (cache_type & 0x700) << (17-8);
-	aux_ctrl |= 0x7C400001;
+	aux_ctrl |= 0x3c400001;
 
-	ret = l2x0_of_init(aux_ctrl, 0x8200c3fe);
+	ret = l2x0_of_init(aux_ctrl, 0xc200c3fe);
 	if (!ret)
 		l2x0_saved_regs_addr = virt_to_phys(&l2x0_saved_regs);
 #endif
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 052/222] ARM: l2c: tegra: remove associativity and way size from aux_ctrl
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (50 preceding siblings ...)
  2014-04-25 11:35 ` [PATCH 051/222] ARM: l2c: remove platforms/SoCs setting " Russell King
@ 2014-04-25 11:35 ` Russell King
  2014-04-25 11:35 ` [PATCH 053/222] ARM: l2c: ux500: " Russell King
                   ` (170 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:35 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-tegra/tegra.c | 18 +-----------------
 1 file changed, 1 insertion(+), 17 deletions(-)

diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c
index ecbb5411a104..fb802e24b647 100644
--- a/arch/arm/mach-tegra/tegra.c
+++ b/arch/arm/mach-tegra/tegra.c
@@ -73,25 +73,9 @@ u32 tegra_uart_config[3] = {
 static void __init tegra_init_cache(void)
 {
 #ifdef CONFIG_CACHE_L2X0
-	static const struct of_device_id pl310_ids[] __initconst = {
-		{ .compatible = "arm,pl310-cache",  },
-		{}
-	};
-
-	struct device_node *np;
 	int ret;
-	void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000;
-	u32 aux_ctrl, cache_type;
-
-	np = of_find_matching_node(NULL, pl310_ids);
-	if (!np)
-		return;
-
-	cache_type = readl(p + L2X0_CACHE_TYPE);
-	aux_ctrl = (cache_type & 0x700) << (17-8);
-	aux_ctrl |= 0x3c400001;
 
-	ret = l2x0_of_init(aux_ctrl, 0xc200c3fe);
+	ret = l2x0_of_init(0x3c400001, 0xc20fc3fe);
 	if (!ret)
 		l2x0_saved_regs_addr = virt_to_phys(&l2x0_saved_regs);
 #endif
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 053/222] ARM: l2c: ux500: remove associativity and way size from aux_ctrl
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (51 preceding siblings ...)
  2014-04-25 11:35 ` [PATCH 052/222] ARM: l2c: tegra: remove associativity and way size from aux_ctrl Russell King
@ 2014-04-25 11:35 ` Russell King
  2014-04-25 11:35 ` [PATCH 054/222] ARM: l2c: ux500: don't try to change the L2 cache auxiliary control register Russell King
                   ` (169 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:35 UTC (permalink / raw)
  To: linux-arm-kernel

Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-ux500/cache-l2x0.c | 15 ++-------------
 1 file changed, 2 insertions(+), 13 deletions(-)

diff --git a/arch/arm/mach-ux500/cache-l2x0.c b/arch/arm/mach-ux500/cache-l2x0.c
index 067c37a054fb..5b891d051054 100644
--- a/arch/arm/mach-ux500/cache-l2x0.c
+++ b/arch/arm/mach-ux500/cache-l2x0.c
@@ -45,8 +45,6 @@ static void ux500_l2c310_write_sec(unsigned long val, unsigned reg)
 
 static int __init ux500_l2x0_init(void)
 {
-	u32 aux_val = 0x3e000000;
-
 	if (cpu_is_u8500_family() || cpu_is_ux540_family())
 		l2x0_base = __io_address(U8500_L2CC_BASE);
 	else
@@ -56,21 +54,12 @@ static int __init ux500_l2x0_init(void)
 	/* Unlock before init */
 	ux500_l2x0_unlock();
 
-	/* DBx540's L2 has 128KB way size */
-	if (cpu_is_ux540_family())
-		/* 128KB way size */
-		aux_val |= L2C_AUX_CTRL_WAY_SIZE(4);
-	else
-		/* 64KB way size */
-		aux_val |= L2C_AUX_CTRL_WAY_SIZE(3);
-
 	outer_cache.write_sec = ux500_l2c310_write_sec;
 
-	/* 64KB way size, 8 way associativity, force WA */
 	if (of_have_populated_dt())
-		l2x0_of_init(aux_val, 0xc0000fff);
+		l2x0_of_init(0x3e000000, 0xc00f0fff);
 	else
-		l2x0_init(l2x0_base, aux_val, 0xc0000fff);
+		l2x0_init(l2x0_base, 0x3e000000, 0xc00f0fff);
 
 	return 0;
 }
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 054/222] ARM: l2c: ux500: don't try to change the L2 cache auxiliary control register
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (52 preceding siblings ...)
  2014-04-25 11:35 ` [PATCH 053/222] ARM: l2c: ux500: " Russell King
@ 2014-04-25 11:35 ` Russell King
  2014-04-25 11:35 ` [PATCH 055/222] ARM: l2c: cns3xxx: remove cache size override Russell King
                   ` (168 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:35 UTC (permalink / raw)
  To: linux-arm-kernel

ux500 can't change the auxiliary control register, so there's no point
passing values to try and modify it to the l2x0 init functions.

Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-ux500/cache-l2x0.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-ux500/cache-l2x0.c b/arch/arm/mach-ux500/cache-l2x0.c
index 5b891d051054..842ebedbdd1c 100644
--- a/arch/arm/mach-ux500/cache-l2x0.c
+++ b/arch/arm/mach-ux500/cache-l2x0.c
@@ -57,9 +57,9 @@ static int __init ux500_l2x0_init(void)
 	outer_cache.write_sec = ux500_l2c310_write_sec;
 
 	if (of_have_populated_dt())
-		l2x0_of_init(0x3e000000, 0xc00f0fff);
+		l2x0_of_init(0, ~0);
 	else
-		l2x0_init(l2x0_base, 0x3e000000, 0xc00f0fff);
+		l2x0_init(l2x0_base, 0, ~0);
 
 	return 0;
 }
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 055/222] ARM: l2c: cns3xxx: remove cache size override
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (53 preceding siblings ...)
  2014-04-25 11:35 ` [PATCH 054/222] ARM: l2c: ux500: don't try to change the L2 cache auxiliary control register Russell King
@ 2014-04-25 11:35 ` Russell King
  2014-04-25 11:35 ` [PATCH 056/222] ARM: l2c: exynos: " Russell King
                   ` (167 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:35 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-cns3xxx/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/mach-cns3xxx/core.c b/arch/arm/mach-cns3xxx/core.c
index 5c31b2638c01..f85449a6accd 100644
--- a/arch/arm/mach-cns3xxx/core.c
+++ b/arch/arm/mach-cns3xxx/core.c
@@ -290,7 +290,7 @@ void __init cns3xxx_l2x0_init(void)
 	writel(val, base + L310_DATA_LATENCY_CTRL);
 
 	/* 32 KiB, 8-way, parity disable */
-	l2x0_init(base, 0x00540000, 0xfe000fff);
+	l2x0_init(base, 0x00500000, 0xfe0f0fff);
 }
 
 #endif /* CONFIG_CACHE_L2X0 */
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 056/222] ARM: l2c: exynos: remove cache size override
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (54 preceding siblings ...)
  2014-04-25 11:35 ` [PATCH 055/222] ARM: l2c: cns3xxx: remove cache size override Russell King
@ 2014-04-25 11:35 ` Russell King
  2014-04-25 11:35 ` [PATCH 057/222] ARM: l2c: nomadik: " Russell King
                   ` (166 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:35 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-exynos/exynos.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c
index e6828fb46034..a51bf25e7523 100644
--- a/arch/arm/mach-exynos/exynos.c
+++ b/arch/arm/mach-exynos/exynos.c
@@ -32,9 +32,6 @@
 #include "mfc.h"
 #include "regs-pmu.h"
 
-#define L2_AUX_VAL 0x3c470001
-#define L2_AUX_MASK 0xc200ffff
-
 static struct map_desc exynos4_iodesc[] __initdata = {
 	{
 		.virtual	= (unsigned long)S3C_VA_SYS,
@@ -323,7 +320,7 @@ static int __init exynos4_l2x0_cache_init(void)
 {
 	int ret;
 
-	ret = l2x0_of_init(L2_AUX_VAL, L2_AUX_MASK);
+	ret = l2x0_of_init(0x3c400001, 0xc20fffff);
 	if (ret)
 		return ret;
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 057/222] ARM: l2c: nomadik: remove cache size override
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (55 preceding siblings ...)
  2014-04-25 11:35 ` [PATCH 056/222] ARM: l2c: exynos: " Russell King
@ 2014-04-25 11:35 ` Russell King
  2014-04-25 11:35 ` [PATCH 058/222] ARM: l2c: omap2: " Russell King
                   ` (165 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:35 UTC (permalink / raw)
  To: linux-arm-kernel

Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-nomadik/cpu-8815.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/mach-nomadik/cpu-8815.c b/arch/arm/mach-nomadik/cpu-8815.c
index 4a1065e41e9c..0f245bcc6b7e 100644
--- a/arch/arm/mach-nomadik/cpu-8815.c
+++ b/arch/arm/mach-nomadik/cpu-8815.c
@@ -147,7 +147,7 @@ static void __init cpu8815_init_of(void)
 {
 #ifdef CONFIG_CACHE_L2X0
 	/* At full speed latency must be >=2, so 0x249 in low bits */
-	l2x0_of_init(0x00730249, 0xfe000fff);
+	l2x0_of_init(0x00700249, 0xfe0fefff);
 #endif
 	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
 }
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 058/222] ARM: l2c: omap2: remove cache size override
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (56 preceding siblings ...)
  2014-04-25 11:35 ` [PATCH 057/222] ARM: l2c: nomadik: " Russell King
@ 2014-04-25 11:35 ` Russell King
  2014-04-25 11:35 ` [PATCH 059/222] ARM: l2c: prima2: " Russell King
                   ` (164 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:35 UTC (permalink / raw)
  To: linux-arm-kernel

Acked-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-omap2/omap4-common.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c
index 9ce52548a484..06c6a181d6ad 100644
--- a/arch/arm/mach-omap2/omap4-common.c
+++ b/arch/arm/mach-omap2/omap4-common.c
@@ -213,20 +213,18 @@ static int __init omap_l2_cache_init(void)
 		return -ENOMEM;
 
 	/* 16-way associativity, parity disabled, way size - 64KB (es2.0 +) */
-	aux_ctrl = L310_AUX_CTRL_ASSOCIATIVITY_16 |
-		   L310_AUX_CTRL_CACHE_REPLACE_RR |
+	aux_ctrl = L310_AUX_CTRL_CACHE_REPLACE_RR |
 		   L310_AUX_CTRL_NS_LOCKDOWN |
 		   L310_AUX_CTRL_NS_INT_CTRL |
-		   L2C_AUX_CTRL_WAY_SIZE(3) |
 		   L2C_AUX_CTRL_SHARED_OVERRIDE |
 		   L310_AUX_CTRL_DATA_PREFETCH |
 		   L310_AUX_CTRL_INSTR_PREFETCH;
 
 	outer_cache.write_sec = omap4_l2c310_write_sec;
 	if (of_have_populated_dt())
-		l2x0_of_init(aux_ctrl, L2X0_AUX_CTRL_MASK);
+		l2x0_of_init(aux_ctrl, 0xc19fffff);
 	else
-		l2x0_init(l2cache_base, aux_ctrl, L2X0_AUX_CTRL_MASK);
+		l2x0_init(l2cache_base, aux_ctrl, 0xc19fffff);
 
 	return 0;
 }
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 059/222] ARM: l2c: prima2: remove cache size override
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (57 preceding siblings ...)
  2014-04-25 11:35 ` [PATCH 058/222] ARM: l2c: omap2: " Russell King
@ 2014-04-25 11:35 ` Russell King
  2014-04-25 11:36 ` [PATCH 060/222] ARM: l2c: shmobile: " Russell King
                   ` (163 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:35 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/boot/dts/marco.dtsi  |  2 +-
 arch/arm/boot/dts/prima2.dtsi |  2 +-
 arch/arm/mach-prima2/l2x0.c   | 33 +--------------------------------
 3 files changed, 3 insertions(+), 34 deletions(-)

diff --git a/arch/arm/boot/dts/marco.dtsi b/arch/arm/boot/dts/marco.dtsi
index 0c9647d28765..fb354225740a 100644
--- a/arch/arm/boot/dts/marco.dtsi
+++ b/arch/arm/boot/dts/marco.dtsi
@@ -36,7 +36,7 @@
 		ranges = <0x40000000 0x40000000 0xa0000000>;
 
 		l2-cache-controller at c0030000 {
-			compatible = "sirf,marco-pl310-cache", "arm,pl310-cache";
+			compatible = "arm,pl310-cache";
 			reg = <0xc0030000 0x1000>;
 			interrupts = <0 59 0>;
 			arm,tag-latency = <1 1 1>;
diff --git a/arch/arm/boot/dts/prima2.dtsi b/arch/arm/boot/dts/prima2.dtsi
index 1e82571d6823..0d6588d549bf 100644
--- a/arch/arm/boot/dts/prima2.dtsi
+++ b/arch/arm/boot/dts/prima2.dtsi
@@ -48,7 +48,7 @@
 		ranges = <0x40000000 0x40000000 0x80000000>;
 
 		l2-cache-controller at 80040000 {
-			compatible = "arm,pl310-cache", "sirf,prima2-pl310-cache";
+			compatible = "arm,pl310-cache";
 			reg = <0x80040000 0x1000>;
 			interrupts = <59>;
 			arm,tag-latency = <1 1 1>;
diff --git a/arch/arm/mach-prima2/l2x0.c b/arch/arm/mach-prima2/l2x0.c
index 2db82742fb74..09f68f046830 100644
--- a/arch/arm/mach-prima2/l2x0.c
+++ b/arch/arm/mach-prima2/l2x0.c
@@ -8,41 +8,10 @@
 
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/of.h>
 #include <asm/hardware/cache-l2x0.h>
 
-struct l2x0_aux {
-	u32 val;
-	u32 mask;
-};
-
-static const struct l2x0_aux prima2_l2x0_aux __initconst = {
-	.val = L2C_AUX_CTRL_WAY_SIZE(2),
-	.mask =	0,
-};
-
-static const struct l2x0_aux marco_l2x0_aux __initconst = {
-	.val = L2C_AUX_CTRL_WAY_SIZE(2) | L310_AUX_CTRL_ASSOCIATIVITY_16,
-	.mask = L2X0_AUX_CTRL_MASK,
-};
-
-static const struct of_device_id sirf_l2x0_ids[] __initconst = {
-	{ .compatible = "sirf,prima2-pl310-cache", .data = &prima2_l2x0_aux, },
-	{ .compatible = "sirf,marco-pl310-cache", .data = &marco_l2x0_aux, },
-	{},
-};
-
 static int __init sirfsoc_l2x0_init(void)
 {
-	struct device_node *np;
-	const struct l2x0_aux *aux;
-
-	np = of_find_matching_node(NULL, sirf_l2x0_ids);
-	if (np) {
-		aux = of_match_node(sirf_l2x0_ids, np)->data;
-		return l2x0_of_init(aux->val, aux->mask);
-	}
-
-	return 0;
+	return l2x0_of_init(0, ~0);
 }
 early_initcall(sirfsoc_l2x0_init);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 060/222] ARM: l2c: shmobile: remove cache size override
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (58 preceding siblings ...)
  2014-04-25 11:35 ` [PATCH 059/222] ARM: l2c: prima2: " Russell King
@ 2014-04-25 11:36 ` Russell King
  2014-04-25 11:36 ` [PATCH 061/222] ARM: l2c: spear13xx: " Russell King
                   ` (162 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:36 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-shmobile/board-armadillo800eva-reference.c | 2 +-
 arch/arm/mach-shmobile/board-armadillo800eva.c           | 2 +-
 arch/arm/mach-shmobile/board-kzm9g-reference.c           | 2 +-
 arch/arm/mach-shmobile/board-kzm9g.c                     | 2 +-
 arch/arm/mach-shmobile/setup-r8a7778.c                   | 2 +-
 arch/arm/mach-shmobile/setup-r8a7779.c                   | 2 +-
 6 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/arch/arm/mach-shmobile/board-armadillo800eva-reference.c b/arch/arm/mach-shmobile/board-armadillo800eva-reference.c
index 34e7f3c17dd2..39e11f48e8bc 100644
--- a/arch/arm/mach-shmobile/board-armadillo800eva-reference.c
+++ b/arch/arm/mach-shmobile/board-armadillo800eva-reference.c
@@ -165,7 +165,7 @@ static void __init eva_init(void)
 
 #ifdef CONFIG_CACHE_L2X0
 	/* Shared attribute override enable, 32K*8way */
-	l2x0_init(IOMEM(0xf0002000), 0x00440000, 0xc2000fff);
+	l2x0_init(IOMEM(0xf0002000), 0x00400000, 0xc20f0fff);
 #endif
 
 	r8a7740_add_standard_devices_dt();
diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c
index 7688990edd3a..b0b9435a71ff 100644
--- a/arch/arm/mach-shmobile/board-armadillo800eva.c
+++ b/arch/arm/mach-shmobile/board-armadillo800eva.c
@@ -1271,7 +1271,7 @@ static void __init eva_init(void)
 
 #ifdef CONFIG_CACHE_L2X0
 	/* Shared attribute override enable, 32K*8way */
-	l2x0_init(IOMEM(0xf0002000), 0x00440000, 0xc2000fff);
+	l2x0_init(IOMEM(0xf0002000), 0x00400000, 0xc20f0fff);
 #endif
 
 	i2c_register_board_info(0, i2c0_devices, ARRAY_SIZE(i2c0_devices));
diff --git a/arch/arm/mach-shmobile/board-kzm9g-reference.c b/arch/arm/mach-shmobile/board-kzm9g-reference.c
index 85873f186d77..a735a1d80c28 100644
--- a/arch/arm/mach-shmobile/board-kzm9g-reference.c
+++ b/arch/arm/mach-shmobile/board-kzm9g-reference.c
@@ -37,7 +37,7 @@ static void __init kzm_init(void)
 
 #ifdef CONFIG_CACHE_L2X0
 	/* Shared attribute override enable, 64K*8way */
-	l2x0_init(IOMEM(0xf0100000), 0x00460000, 0xc2000fff);
+	l2x0_init(IOMEM(0xf0100000), 0x00400000, 0xc20f0fff);
 #endif
 }
 
diff --git a/arch/arm/mach-shmobile/board-kzm9g.c b/arch/arm/mach-shmobile/board-kzm9g.c
index ea9bf39fdc10..f94ec8ca42c1 100644
--- a/arch/arm/mach-shmobile/board-kzm9g.c
+++ b/arch/arm/mach-shmobile/board-kzm9g.c
@@ -877,7 +877,7 @@ static void __init kzm_init(void)
 
 #ifdef CONFIG_CACHE_L2X0
 	/* Shared attribute override enable, 64K*8way */
-	l2x0_init(IOMEM(0xf0100000), 0x00460000, 0xc2000fff);
+	l2x0_init(IOMEM(0xf0100000), 0x00400000, 0xc20f0fff);
 #endif
 
 	i2c_register_board_info(0, i2c0_devices, ARRAY_SIZE(i2c0_devices));
diff --git a/arch/arm/mach-shmobile/setup-r8a7778.c b/arch/arm/mach-shmobile/setup-r8a7778.c
index 3a8e5316671e..6dd7ddf88741 100644
--- a/arch/arm/mach-shmobile/setup-r8a7778.c
+++ b/arch/arm/mach-shmobile/setup-r8a7778.c
@@ -301,7 +301,7 @@ void __init r8a7778_add_dt_devices(void)
 		 * Shared attribute override enable, 64K*16way
 		 * don't call iounmap(base)
 		 */
-		l2x0_init(base, 0x00470000, 0xc2000fff);
+		l2x0_init(base, 0x00400000, 0xc20f0fff);
 	}
 #endif
 
diff --git a/arch/arm/mach-shmobile/setup-r8a7779.c b/arch/arm/mach-shmobile/setup-r8a7779.c
index 91c90bf0ae83..a6630fccfc45 100644
--- a/arch/arm/mach-shmobile/setup-r8a7779.c
+++ b/arch/arm/mach-shmobile/setup-r8a7779.c
@@ -701,7 +701,7 @@ void __init r8a7779_add_standard_devices(void)
 {
 #ifdef CONFIG_CACHE_L2X0
 	/* Shared attribute override enable, 64K*16way */
-	l2x0_init(IOMEM(0xf0100000), 0x00470000, 0xc2000fff);
+	l2x0_init(IOMEM(0xf0100000), 0x00400000, 0xc20f0fff);
 #endif
 	r8a7779_pm_init();
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 061/222] ARM: l2c: spear13xx: remove cache size override
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (59 preceding siblings ...)
  2014-04-25 11:36 ` [PATCH 060/222] ARM: l2c: shmobile: " Russell King
@ 2014-04-25 11:36 ` Russell King
  2014-04-25 11:36 ` [PATCH 062/222] ARM: l2c: sti: " Russell King
                   ` (161 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:36 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-spear/spear13xx.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/mach-spear/spear13xx.c b/arch/arm/mach-spear/spear13xx.c
index dcb300443b66..c9897ea38980 100644
--- a/arch/arm/mach-spear/spear13xx.c
+++ b/arch/arm/mach-spear/spear13xx.c
@@ -46,7 +46,7 @@ void __init spear13xx_l2x0_init(void)
 	 */
 	writel_relaxed(0x221, VA_L2CC_BASE + L310_TAG_LATENCY_CTRL);
 	writel_relaxed(0x441, VA_L2CC_BASE + L310_DATA_LATENCY_CTRL);
-	l2x0_init(VA_L2CC_BASE, 0x30a60001, 0xfe00ffff);
+	l2x0_init(VA_L2CC_BASE, 0x30a00001, 0xfe0fffff);
 }
 
 /*
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 062/222] ARM: l2c: sti: remove cache size override
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (60 preceding siblings ...)
  2014-04-25 11:36 ` [PATCH 061/222] ARM: l2c: spear13xx: " Russell King
@ 2014-04-25 11:36 ` Russell King
  2014-04-25 11:36 ` [PATCH 063/222] ARM: l2c: zynq: " Russell King
                   ` (160 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:36 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-sti/board-dt.c | 12 +++---------
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/arch/arm/mach-sti/board-dt.c b/arch/arm/mach-sti/board-dt.c
index dc8669efc12d..cf716ae10726 100644
--- a/arch/arm/mach-sti/board-dt.c
+++ b/arch/arm/mach-sti/board-dt.c
@@ -16,15 +16,9 @@
 
 void __init stih41x_l2x0_init(void)
 {
-	u32 way_size = 0x4;
-	u32 aux_ctrl;
-	/* may be this can be encoded in macros like BIT*() */
-	aux_ctrl = L2C_AUX_CTRL_SHARED_OVERRIDE |
-		   L310_AUX_CTRL_DATA_PREFETCH |
-		   L310_AUX_CTRL_INSTR_PREFETCH |
-		   L2C_AUX_CTRL_WAY_SIZE(way_size);
-
-	l2x0_of_init(aux_ctrl, L2X0_AUX_CTRL_MASK);
+	l2x0_of_init(L2C_AUX_CTRL_SHARED_OVERRIDE |
+		     L310_AUX_CTRL_DATA_PREFETCH |
+		     L310_AUX_CTRL_INSTR_PREFETCH, 0xc00f0fff);
 }
 
 static void __init stih41x_machine_init(void)
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 063/222] ARM: l2c: zynq: remove cache size override
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (61 preceding siblings ...)
  2014-04-25 11:36 ` [PATCH 062/222] ARM: l2c: sti: " Russell King
@ 2014-04-25 11:36 ` Russell King
  2014-04-25 11:36 ` [PATCH 064/222] ARM: l2c: realview: improve commentry about the L2 cache requirements Russell King
                   ` (159 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:36 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-zynq/common.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c
index 6fcc584c1a11..1e617a6dedc3 100644
--- a/arch/arm/mach-zynq/common.c
+++ b/arch/arm/mach-zynq/common.c
@@ -70,7 +70,7 @@ static void __init zynq_init_machine(void)
 	/*
 	 * 64KB way size, 8-way associativity, parity disabled
 	 */
-	l2x0_of_init(0x02060000, 0xF0F0FFFF);
+	l2x0_of_init(0x02000000, 0xf0ffffff);
 
 	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 064/222] ARM: l2c: realview: improve commentry about the L2 cache requirements
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (62 preceding siblings ...)
  2014-04-25 11:36 ` [PATCH 063/222] ARM: l2c: zynq: " Russell King
@ 2014-04-25 11:36 ` Russell King
  2014-04-25 11:36 ` [PATCH 065/222] ARM: l2c: kill L2X0_AUX_CTRL_MASK before anyone else makes use of this Russell King
                   ` (158 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:36 UTC (permalink / raw)
  To: linux-arm-kernel

Add better commentry about the L2 cache requirements on these platforms.
Unfortunately, the auxiliary control register is not pre-set to indicate
the correct cache parameters, so we have to manually program these.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-realview/realview_eb.c     | 9 +++++++--
 arch/arm/mach-realview/realview_pb1176.c | 8 +++++++-
 arch/arm/mach-realview/realview_pb11mp.c | 9 +++++++--
 3 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c
index c85ddb2a0ad0..b575895037b8 100644
--- a/arch/arm/mach-realview/realview_eb.c
+++ b/arch/arm/mach-realview/realview_eb.c
@@ -442,8 +442,13 @@ static void __init realview_eb_init(void)
 		realview_eb11mp_fixup();
 
 #ifdef CONFIG_CACHE_L2X0
-		/* 1MB (128KB/way), 8-way associativity, evmon/parity/share enabled
-		 * Bits:  .... ...0 0111 1001 0000 .... .... .... */
+		/*
+		 * The PL220 needs to be manually configured as the hardware
+		 * doesn't report the correct sizes.
+		 * 1MB (128KB/way), 8-way associativity, event monitor and
+		 * parity enabled, ignore share bit, no force write allocate
+		 * Bits:  .... ...0 0111 1001 0000 .... .... ....
+		 */
 		l2x0_init(__io_address(REALVIEW_EB11MP_L220_BASE), 0x00790000, 0xfe000fff);
 #endif
 		platform_device_register(&pmu_device);
diff --git a/arch/arm/mach-realview/realview_pb1176.c b/arch/arm/mach-realview/realview_pb1176.c
index c5eade76461b..e3bddb5ab10f 100644
--- a/arch/arm/mach-realview/realview_pb1176.c
+++ b/arch/arm/mach-realview/realview_pb1176.c
@@ -355,7 +355,13 @@ static void __init realview_pb1176_init(void)
 	int i;
 
 #ifdef CONFIG_CACHE_L2X0
-	/* 128Kb (16Kb/way) 8-way associativity. evmon/parity/share enabled. */
+	/*
+	 * The PL220 needs to be manually configured as the hardware
+	 * doesn't report the correct sizes.
+	 * 128kB (16kB/way), 8-way associativity, event monitor and
+	 * parity enabled, ignore share bit, no force write allocate
+	 * Bits:  .... ...0 0111 0011 0000 .... .... ....
+	 */
 	l2x0_init(__io_address(REALVIEW_PB1176_L220_BASE), 0x00730000, 0xfe000fff);
 #endif
 
diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c
index f4b0962578fe..101deaf2630b 100644
--- a/arch/arm/mach-realview/realview_pb11mp.c
+++ b/arch/arm/mach-realview/realview_pb11mp.c
@@ -337,8 +337,13 @@ static void __init realview_pb11mp_init(void)
 	int i;
 
 #ifdef CONFIG_CACHE_L2X0
-	/* 1MB (128KB/way), 8-way associativity, evmon/parity/share enabled
-	 * Bits:  .... ...0 0111 1001 0000 .... .... .... */
+	/*
+	 * The PL220 needs to be manually configured as the hardware
+	 * doesn't report the correct sizes.
+	 * 1MB (128KB/way), 8-way associativity, event monitor and
+	 * parity enabled, ignore share bit, no force write allocate
+	 * Bits:  .... ...0 0111 1001 0000 .... .... ....
+	 */
 	l2x0_init(__io_address(REALVIEW_TC11MP_L220_BASE), 0x00790000, 0xfe000fff);
 #endif
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 065/222] ARM: l2c: kill L2X0_AUX_CTRL_MASK before anyone else makes use of this
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (63 preceding siblings ...)
  2014-04-25 11:36 ` [PATCH 064/222] ARM: l2c: realview: improve commentry about the L2 cache requirements Russell King
@ 2014-04-25 11:36 ` Russell King
  2014-04-25 11:36 ` [PATCH 066/222] ARM: l2c: print a warning with L2C-310 caches if the cache size is modified Russell King
                   ` (157 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:36 UTC (permalink / raw)
  To: linux-arm-kernel

L2X0_AUX_CTRL_MASK is not useful for PL310s.  It would be better if
people thought about their value for this rather than cargo-cult
programming.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/include/asm/hardware/cache-l2x0.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/arch/arm/include/asm/hardware/cache-l2x0.h b/arch/arm/include/asm/hardware/cache-l2x0.h
index b3ee122c6f24..84bbd31b8910 100644
--- a/arch/arm/include/asm/hardware/cache-l2x0.h
+++ b/arch/arm/include/asm/hardware/cache-l2x0.h
@@ -87,7 +87,6 @@
 #define L310_CACHE_ID_RTL_R3P2		0x08
 #define L310_CACHE_ID_RTL_R3P3		0x09
 
-#define L2X0_AUX_CTRL_MASK			0xc0000fff
 /* L2C auxiliary control register - bits common to L2C-210/220/310 */
 #define L2C_AUX_CTRL_WAY_SIZE_SHIFT		17
 #define L2C_AUX_CTRL_WAY_SIZE_MASK		(7 << 17)
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 066/222] ARM: l2c: print a warning with L2C-310 caches if the cache size is modified
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (64 preceding siblings ...)
  2014-04-25 11:36 ` [PATCH 065/222] ARM: l2c: kill L2X0_AUX_CTRL_MASK before anyone else makes use of this Russell King
@ 2014-04-25 11:36 ` Russell King
  2014-04-25 11:36 ` [PATCH 067/222] ARM: l2c: vexpress ca9x4: move L2 cache initialisation earlier Russell King
                   ` (156 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:36 UTC (permalink / raw)
  To: linux-arm-kernel

As we have now removed all instances of the L2C-310 having its cache
size "modified" via platform/SoC code, discourage new cases showing
up by printing a warning.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index db3f18a968b2..48b826e759cb 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -732,6 +732,8 @@ static void __init __l2c_init(const struct l2c_init_data *data,
 	/* Determine the number of ways */
 	switch (cache_id & L2X0_CACHE_ID_PART_MASK) {
 	case L2X0_CACHE_ID_PART_L310:
+		if ((aux_val | ~aux_mask) & (L2C_AUX_CTRL_WAY_SIZE_MASK | L310_AUX_CTRL_ASSOCIATIVITY_16))
+			pr_warn("L2C: DT/platform tries to modify or specify cache size\n");
 		if (aux & (1 << 16))
 			ways = 16;
 		else
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 067/222] ARM: l2c: vexpress ca9x4: move L2 cache initialisation earlier
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (65 preceding siblings ...)
  2014-04-25 11:36 ` [PATCH 066/222] ARM: l2c: print a warning with L2C-310 caches if the cache size is modified Russell King
@ 2014-04-25 11:36 ` Russell King
  2014-04-25 11:36 ` [PATCH 068/222] ARM: l2c: add L2C-310 power control DT properties Russell King
                   ` (155 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:36 UTC (permalink / raw)
  To: linux-arm-kernel

It is beneficial to have the L2 cache up and running earlier in the
system boot.  Not only will this allow for simpler code when we come to
enable some features, but it also means that we get a more accurate
bogomips value for the udelay() loop.  Calibrating the loop with the
L2 cache off, and then running with the L2 cache on is not the best
idea.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-vexpress/ct-ca9x4.c | 28 ++++++++++++++++++----------
 1 file changed, 18 insertions(+), 10 deletions(-)

diff --git a/arch/arm/mach-vexpress/ct-ca9x4.c b/arch/arm/mach-vexpress/ct-ca9x4.c
index 6c4ffb6c5ad8..204038ef3795 100644
--- a/arch/arm/mach-vexpress/ct-ca9x4.c
+++ b/arch/arm/mach-vexpress/ct-ca9x4.c
@@ -45,6 +45,23 @@ static void __init ct_ca9x4_map_io(void)
 	iotable_init(ct_ca9x4_io_desc, ARRAY_SIZE(ct_ca9x4_io_desc));
 }
 
+static void __init ca9x4_l2_init(void)
+{
+#ifdef CONFIG_CACHE_L2X0
+	void __iomem *l2x0_base = ioremap(CT_CA9X4_L2CC, SZ_4K);
+
+	if (l2x0_base) {
+		/* set RAM latencies to 1 cycle for this core tile. */
+		writel(0, l2x0_base + L310_TAG_LATENCY_CTRL);
+		writel(0, l2x0_base + L310_DATA_LATENCY_CTRL);
+
+		l2x0_init(l2x0_base, 0x00400000, 0xfe0fffff);
+	} else {
+		pr_err("L2C: unable to map L2 cache controller\n");
+	}
+#endif
+}
+
 #ifdef CONFIG_HAVE_ARM_TWD
 static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, A9_MPCORE_TWD, IRQ_LOCALTIMER);
 
@@ -63,6 +80,7 @@ static void __init ct_ca9x4_init_irq(void)
 	gic_init(0, 29, ioremap(A9_MPCORE_GIC_DIST, SZ_4K),
 		 ioremap(A9_MPCORE_GIC_CPU, SZ_256));
 	ca9x4_twd_init();
+	ca9x4_l2_init();
 }
 
 static int ct_ca9x4_clcd_setup(struct clcd_fb *fb)
@@ -141,16 +159,6 @@ static void __init ct_ca9x4_init(void)
 {
 	int i;
 
-#ifdef CONFIG_CACHE_L2X0
-	void __iomem *l2x0_base = ioremap(CT_CA9X4_L2CC, SZ_4K);
-
-	/* set RAM latencies to 1 cycle for this core tile. */
-	writel(0, l2x0_base + L310_TAG_LATENCY_CTRL);
-	writel(0, l2x0_base + L310_DATA_LATENCY_CTRL);
-
-	l2x0_init(l2x0_base, 0x00400000, 0xfe0fffff);
-#endif
-
 	for (i = 0; i < ARRAY_SIZE(ct_ca9x4_amba_devs); i++)
 		amba_device_register(ct_ca9x4_amba_devs[i], &iomem_resource);
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 068/222] ARM: l2c: add L2C-310 power control DT properties
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (66 preceding siblings ...)
  2014-04-25 11:36 ` [PATCH 067/222] ARM: l2c: vexpress ca9x4: move L2 cache initialisation earlier Russell King
@ 2014-04-25 11:36 ` Russell King
  2014-04-25 11:36 ` [PATCH 069/222] ARM: l2c: check that DT files specify the required "cache-unified" property Russell King
                   ` (154 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:36 UTC (permalink / raw)
  To: linux-arm-kernel

Add two new properties for setting thte L3 power control register.  Two
new properties are added:

	arm,dynamic-clk-gating
	arm,standby-mode

iMX6 sets both these, add the properties there.

Acked-by: Shawn Guo <shawn.guo@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 Documentation/devicetree/bindings/arm/l2cc.txt |  2 ++
 arch/arm/boot/dts/imx6qdl.dtsi                 |  2 ++
 arch/arm/boot/dts/imx6sl.dtsi                  |  2 ++
 arch/arm/mm/cache-l2x0.c                       | 10 ++++++++++
 4 files changed, 16 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/l2cc.txt b/Documentation/devicetree/bindings/arm/l2cc.txt
index b513cb8196fe..e0dd400ecea6 100644
--- a/Documentation/devicetree/bindings/arm/l2cc.txt
+++ b/Documentation/devicetree/bindings/arm/l2cc.txt
@@ -40,6 +40,8 @@ implementations of the L2 cache controller with compatible programming models.
 - arm,filter-ranges : <start length> Starting address and length of window to
   filter. Addresses in the filter window are directed to the M1 port. Other
   addresses will go to the M0 port.
+- arm,dynamic-clk-gating : Enables dynamic clock gating (PL310)
+- arm,standby-mode : Enables standby mode (PL310)
 - interrupts : 1 combined interrupt.
 - cache-id-part: cache id part number to be used if it is not present
   on hardware
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index 55cb926fa3f7..1bde76683017 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -125,6 +125,8 @@
 			cache-level = <2>;
 			arm,tag-latency = <4 2 3>;
 			arm,data-latency = <4 2 3>;
+			arm,dynamic-clk-gating;
+			arm,standby-mode;
 		};
 
 		pcie: pcie at 0x01000000 {
diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi
index 3cb4941afeef..691832f26453 100644
--- a/arch/arm/boot/dts/imx6sl.dtsi
+++ b/arch/arm/boot/dts/imx6sl.dtsi
@@ -111,6 +111,8 @@
 			cache-level = <2>;
 			arm,tag-latency = <4 2 3>;
 			arm,data-latency = <4 2 3>;
+			arm,dynamic-clk-gating;
+			arm,standby-mode;
 		};
 
 		pmu {
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 48b826e759cb..8a5110deb657 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -904,6 +904,7 @@ static void __init l2c310_of_parse(const struct device_node *np,
 	u32 data[3] = { 0, 0, 0 };
 	u32 tag[3] = { 0, 0, 0 };
 	u32 filter[2] = { 0, 0 };
+	u32 val;
 
 	of_property_read_u32_array(np, "arm,tag-latency", tag, ARRAY_SIZE(tag));
 	if (tag[0] && tag[1] && tag[2])
@@ -930,6 +931,15 @@ static void __init l2c310_of_parse(const struct device_node *np,
 		writel_relaxed((filter[0] & ~(SZ_1M - 1)) | L310_ADDR_FILTER_EN,
 			       l2x0_base + L310_ADDR_FILTER_START);
 	}
+
+	val = 0;
+	if (of_property_read_bool(np, "arm,dynamic-clk-gating"))
+		val |= L310_DYNAMIC_CLK_GATING_EN;
+	if (of_property_read_bool(np, "arm,standby-mode"))
+		val |= L310_STNDBY_MODE_EN;
+
+	if (val)
+		l2c_write_sec(val, l2x0_base, L310_POWER_CTRL);
 }
 
 static const struct l2c_init_data of_l2c310_data __initconst = {
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 069/222] ARM: l2c: check that DT files specify the required "cache-unified" property
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (67 preceding siblings ...)
  2014-04-25 11:36 ` [PATCH 068/222] ARM: l2c: add L2C-310 power control DT properties Russell King
@ 2014-04-25 11:36 ` Russell King
  2014-04-25 11:36 ` [PATCH 070/222] ARM: l2c: add warnings for stuff modifying aux_ctrl register values Russell King
                   ` (153 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:36 UTC (permalink / raw)
  To: linux-arm-kernel

This is a required property, and should always be specified.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 8a5110deb657..96a1374127de 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -1378,6 +1378,10 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
 
 	data = of_match_node(l2x0_ids, np)->data;
 
+	/* All L2 caches are unified, so this property should be specified */
+	if (!of_property_read_bool(np, "cache-unified"))
+		pr_err("L2C: device tree omits to specify unified cache\n");
+
 	/* L2 configuration can only be changed if the cache is disabled */
 	if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN))
 		if (data->of_parse)
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 070/222] ARM: l2c: add warnings for stuff modifying aux_ctrl register values
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (68 preceding siblings ...)
  2014-04-25 11:36 ` [PATCH 069/222] ARM: l2c: check that DT files specify the required "cache-unified" property Russell King
@ 2014-04-25 11:36 ` Russell King
  2014-04-25 11:36 ` [PATCH 071/222] net:fec: remove unnecessary ip stack includes Russell King
                   ` (152 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:36 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 27 +++++++++++++++++++++++----
 1 file changed, 23 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 96a1374127de..5de7f6c56306 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -715,7 +715,15 @@ static void __init __l2c_init(const struct l2c_init_data *data,
 {
 	struct outer_cache_fns fns;
 	unsigned way_size_bits, ways;
-	u32 aux;
+	u32 aux, old_aux;
+
+	/*
+	 * Sanity check the aux values.  aux_mask is the bits we preserve
+	 * from reading the hardware register, and aux_val is the bits we
+	 * set.
+	 */
+	if (aux_val & aux_mask)
+		pr_alert("L2C: platform provided aux values permit register corruption.\n");
 
 	/*
 	 * It is strange to save the register state before initialisation,
@@ -724,11 +732,14 @@ static void __init __l2c_init(const struct l2c_init_data *data,
 	if (data->save)
 		data->save(l2x0_base);
 
-	aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
-
+	old_aux = aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
 	aux &= aux_mask;
 	aux |= aux_val;
 
+	if (old_aux != aux)
+		pr_warn("L2C: DT/platform modifies aux control register: 0x%08x -> 0x%08x\n",
+		        old_aux, aux);
+
 	/* Determine the number of ways */
 	switch (cache_id & L2X0_CACHE_ID_PART_MASK) {
 	case L2X0_CACHE_ID_PART_L310:
@@ -1361,7 +1372,7 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
 	const struct l2c_init_data *data;
 	struct device_node *np;
 	struct resource res;
-	u32 cache_id;
+	u32 cache_id, old_aux;
 
 	np = of_find_matching_node(NULL, l2x0_ids);
 	if (!np)
@@ -1378,6 +1389,14 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
 
 	data = of_match_node(l2x0_ids, np)->data;
 
+	old_aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
+	if (old_aux != ((old_aux & aux_mask) | aux_val)) {
+		pr_warn("L2C: platform modifies aux control register: 0x%08x -> 0x%08x\n",
+		        old_aux, (old_aux & aux_mask) | aux_val);
+	} else if (aux_mask != ~0U && aux_val != 0) {
+		pr_alert("L2C: platform provided aux values match the hardware, so have no effect.  Please remove them.\n");
+	}
+
 	/* All L2 caches are unified, so this property should be specified */
 	if (!of_property_read_bool(np, "cache-unified"))
 		pr_err("L2C: device tree omits to specify unified cache\n");
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 071/222] net:fec: remove unnecessary ip stack includes
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (69 preceding siblings ...)
  2014-04-25 11:36 ` [PATCH 070/222] ARM: l2c: add warnings for stuff modifying aux_ctrl register values Russell King
@ 2014-04-25 11:36 ` Russell King
  2014-04-28 18:36   ` Frank Li
  2014-04-25 11:37 ` [PATCH 072/222] net:fec: reorder ethtool ops to match order in struct declaration Russell King
                   ` (151 subsequent siblings)
  222 siblings, 1 reply; 232+ messages in thread
From: Russell King @ 2014-04-25 11:36 UTC (permalink / raw)
  To: linux-arm-kernel

Commit 4c09eed9dc42 (net: fec: Enable imx6 enet checksum acceleration.)
added support for hardware checksum support, adding six new includes
for things like tcp, udp, ip, icmp, but never made use of anything
provided by those header files.  Let's remove this bloat.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 8d69e439f0c5..b151eaf3b500 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -33,12 +33,6 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <net/ip.h>
-#include <linux/tcp.h>
-#include <linux/udp.h>
-#include <linux/icmp.h>
 #include <linux/spinlock.h>
 #include <linux/workqueue.h>
 #include <linux/bitops.h>
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 072/222] net:fec: reorder ethtool ops to match order in struct declaration
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (70 preceding siblings ...)
  2014-04-25 11:36 ` [PATCH 071/222] net:fec: remove unnecessary ip stack includes Russell King
@ 2014-04-25 11:37 ` Russell King
  2014-04-25 11:37 ` [PATCH 073/222] net:fec: remove checking for NULL phy_dev in fec_enet_close() Russell King
                   ` (150 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:37 UTC (permalink / raw)
  To: linux-arm-kernel

This allows us to merge two separate preprocessor conditionals together.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index b151eaf3b500..875c0ca55c5a 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1639,21 +1639,19 @@ static int fec_enet_nway_reset(struct net_device *dev)
 }
 
 static const struct ethtool_ops fec_enet_ethtool_ops = {
-#if !defined(CONFIG_M5272)
-	.get_pauseparam		= fec_enet_get_pauseparam,
-	.set_pauseparam		= fec_enet_set_pauseparam,
-#endif
 	.get_settings		= fec_enet_get_settings,
 	.set_settings		= fec_enet_set_settings,
 	.get_drvinfo		= fec_enet_get_drvinfo,
-	.get_link		= ethtool_op_get_link,
-	.get_ts_info		= fec_enet_get_ts_info,
 	.nway_reset		= fec_enet_nway_reset,
+	.get_link		= ethtool_op_get_link,
 #ifndef CONFIG_M5272
-	.get_ethtool_stats	= fec_enet_get_ethtool_stats,
+	.get_pauseparam		= fec_enet_get_pauseparam,
+	.set_pauseparam		= fec_enet_set_pauseparam,
 	.get_strings		= fec_enet_get_strings,
+	.get_ethtool_stats	= fec_enet_get_ethtool_stats,
 	.get_sset_count		= fec_enet_get_sset_count,
 #endif
+	.get_ts_info		= fec_enet_get_ts_info,
 };
 
 static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 073/222] net:fec: remove checking for NULL phy_dev in fec_enet_close()
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (71 preceding siblings ...)
  2014-04-25 11:37 ` [PATCH 072/222] net:fec: reorder ethtool ops to match order in struct declaration Russell King
@ 2014-04-25 11:37 ` Russell King
  2014-04-25 11:37 ` [PATCH 074/222] net:fec: ensure that a disconnected phy isn't configured Russell King
                   ` (149 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:37 UTC (permalink / raw)
  To: linux-arm-kernel

fep->phy_dev can not be NULL here for two reasons:
- fec_enet_open() will have successfully connected the phy, or will have
  failed.
- fec_enet_open() will have called phy_start(fep->phy_dev), which
  unconditionally dereferences this pointer.

If it were to be NULL here, then fec_enet_open() will have already
oopsed.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 875c0ca55c5a..b7a5614b874d 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1798,10 +1798,8 @@ fec_enet_close(struct net_device *ndev)
 	netif_stop_queue(ndev);
 	fec_stop(ndev);
 
-	if (fep->phy_dev) {
-		phy_stop(fep->phy_dev);
-		phy_disconnect(fep->phy_dev);
-	}
+	phy_stop(fep->phy_dev);
+	phy_disconnect(fep->phy_dev);
 
 	fec_enet_free_buffers(ndev);
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 074/222] net:fec: ensure that a disconnected phy isn't configured
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (72 preceding siblings ...)
  2014-04-25 11:37 ` [PATCH 073/222] net:fec: remove checking for NULL phy_dev in fec_enet_close() Russell King
@ 2014-04-25 11:37 ` Russell King
  2014-04-25 11:37 ` [PATCH 075/222] net:fec: add support for dumping transmit ring on timeout Russell King
                   ` (148 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:37 UTC (permalink / raw)
  To: linux-arm-kernel

When we disconnect from a phy, we should forget our pointer to it so we
don't accidentally try to configure it.  We handle a NULL phy pointer
correctly in most places, except fec_enet_set_pauseparam().  Fix this
too.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index b7a5614b874d..9de899eb9f8e 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1496,6 +1496,9 @@ static int fec_enet_set_pauseparam(struct net_device *ndev,
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 
+	if (!fep->phy_dev)
+		return -ENODEV;
+
 	if (pause->tx_pause != pause->rx_pause) {
 		netdev_info(ndev,
 			"hardware only support enable/disable both tx and rx");
@@ -1800,6 +1803,7 @@ fec_enet_close(struct net_device *ndev)
 
 	phy_stop(fep->phy_dev);
 	phy_disconnect(fep->phy_dev);
+	fep->phy_dev = NULL;
 
 	fec_enet_free_buffers(ndev);
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 075/222] net:fec: add support for dumping transmit ring on timeout
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (73 preceding siblings ...)
  2014-04-25 11:37 ` [PATCH 074/222] net:fec: ensure that a disconnected phy isn't configured Russell King
@ 2014-04-25 11:37 ` Russell King
  2014-04-25 11:37 ` [PATCH 076/222] net:fec: use netif_tx_disable() rather than netif_stop_queue() Russell King
                   ` (147 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:37 UTC (permalink / raw)
  To: linux-arm-kernel

When we timeout on transmit, it would be useful to dump the transmit
ring, so we can see the ring state.  This can be helpful to diagnose
the cause of transmit timeouts.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 9de899eb9f8e..7d506ae2dbba 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -291,6 +291,27 @@ static void *swap_buffer(void *bufaddr, int len)
 	return bufaddr;
 }
 
+static void fec_dump(struct net_device *ndev)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+	struct bufdesc *bdp = fep->tx_bd_base;
+	unsigned index = 0;
+
+	netdev_info(ndev, "TX ring dump\n");
+	pr_info("Nr     SC     addr       len  SKB\n");
+
+	do {
+		pr_info("%3u %c%c 0x%04x 0x%08lx %4u %p\n",
+			index,
+			bdp == fep->cur_tx ? 'S' : ' ',
+			bdp == fep->dirty_tx ? 'H' : ' ',
+			bdp->cbd_sc, bdp->cbd_bufaddr, bdp->cbd_datlen,
+			fep->tx_skbuff[index]);
+		bdp = fec_enet_get_nextdesc(bdp, fep);
+		index++;
+	} while (bdp != fep->tx_bd_base);
+}
+
 static int
 fec_enet_clear_csum(struct sk_buff *skb, struct net_device *ndev)
 {
@@ -717,6 +738,8 @@ fec_timeout(struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 
+	fec_dump(ndev);
+
 	ndev->stats.tx_errors++;
 
 	fep->delay_work.timeout = true;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 076/222] net:fec: use netif_tx_disable() rather than netif_stop_queue()
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (74 preceding siblings ...)
  2014-04-25 11:37 ` [PATCH 075/222] net:fec: add support for dumping transmit ring on timeout Russell King
@ 2014-04-25 11:37 ` Russell King
  2014-04-25 11:37 ` [PATCH 077/222] net:fec: iMX6 FEC does not support half-duplex gigabit Russell King
                   ` (146 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:37 UTC (permalink / raw)
  To: linux-arm-kernel

We use netif_stop_queue() in several places where we want to ensure that
the start_xmit function is not running.  netif_stop_queue() is not
sufficient to achieve that - it merely sets a flag to indicate that the
transmit queue(s) should not be run.

netif_tx_disable() gives this guarantee, since it takes the transmit
queue lock while marking the queue stopped.  This will wait for the
transmit function to complete before returning.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 7d506ae2dbba..1c84f3a6f3a7 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -522,7 +522,7 @@ fec_restart(struct net_device *ndev, int duplex)
 	if (netif_running(ndev)) {
 		netif_device_detach(ndev);
 		napi_disable(&fep->napi);
-		netif_stop_queue(ndev);
+		netif_tx_disable(ndev);
 		netif_tx_lock_bh(ndev);
 	}
 
@@ -1821,7 +1821,7 @@ fec_enet_close(struct net_device *ndev)
 	/* Don't know what to do yet. */
 	napi_disable(&fep->napi);
 	fep->opened = 0;
-	netif_stop_queue(ndev);
+	netif_tx_disable(ndev);
 	fec_stop(ndev);
 
 	phy_stop(fep->phy_dev);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 077/222] net:fec: iMX6 FEC does not support half-duplex gigabit
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (75 preceding siblings ...)
  2014-04-25 11:37 ` [PATCH 076/222] net:fec: use netif_tx_disable() rather than netif_stop_queue() Russell King
@ 2014-04-25 11:37 ` Russell King
  2014-04-25 11:37 ` [PATCH 078/222] net:fec: clean up transmit descriptor setup Russell King
                   ` (145 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:37 UTC (permalink / raw)
  To: linux-arm-kernel

The iMX6 gigabit FEC does not support half-duplex gigabit operation.
Phys attacked to the FEC may support this, and we currently do nothing
to disable this feature.  This may result in an invalid configuration.
Mask out phy support for gigabit half-duplex operation.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 1c84f3a6f3a7..d9109acc934d 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1316,6 +1316,7 @@ static int fec_enet_mii_probe(struct net_device *ndev)
 	/* mask with MAC supported features */
 	if (id_entry->driver_data & FEC_QUIRK_HAS_GBIT) {
 		phy_dev->supported &= PHY_GBIT_FEATURES;
+		phy_dev->supported &= ~SUPPORTED_1000baseT_Half;
 #if !defined(CONFIG_M5272)
 		phy_dev->supported |= SUPPORTED_Pause;
 #endif
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 078/222] net:fec: clean up transmit descriptor setup
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (76 preceding siblings ...)
  2014-04-25 11:37 ` [PATCH 077/222] net:fec: iMX6 FEC does not support half-duplex gigabit Russell King
@ 2014-04-25 11:37 ` Russell King
  2014-04-25 11:37 ` [PATCH 079/222] net:fec: make rx skb allocation/map more robust Russell King
                   ` (144 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:37 UTC (permalink / raw)
  To: linux-arm-kernel

Avoid writing any state until we're certain we can proceed with the
transmission: this avoids writing mapping error address values to the
descriptors, or setting the skbuff pointer until we have successfully
mapped the skb.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 32 +++++++++++++++----------------
 1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index d9109acc934d..45cb558bb227 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -337,6 +337,8 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	void *bufaddr;
 	unsigned short	status;
 	unsigned int index;
+	unsigned length;
+	dma_addr_t addr;
 
 	/* Fill in a Tx ring entry */
 	bdp = fep->cur_tx;
@@ -362,7 +364,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 
 	/* Set buffer length and buffer pointer */
 	bufaddr = skb->data;
-	bdp->cbd_datlen = skb->len;
+	length = skb->len;
 
 	/*
 	 * On some FEC implementations data must be aligned on
@@ -376,7 +378,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 		index = bdp - fep->tx_bd_base;
 
 	if (((unsigned long) bufaddr) & FEC_ALIGNMENT) {
-		memcpy(fep->tx_bounce[index], skb->data, skb->len);
+		memcpy(fep->tx_bounce[index], skb->data, length);
 		bufaddr = fep->tx_bounce[index];
 	}
 
@@ -386,25 +388,23 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	 * swap every frame going to and coming from the controller.
 	 */
 	if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
-		swap_buffer(bufaddr, skb->len);
+		swap_buffer(bufaddr, length);
 
-	/* Save skb pointer */
-	fep->tx_skbuff[index] = skb;
-
-	/* Push the data cache so the CPM does not get stale memory
-	 * data.
-	 */
-	bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, bufaddr,
-			skb->len, DMA_TO_DEVICE);
-	if (dma_mapping_error(&fep->pdev->dev, bdp->cbd_bufaddr)) {
-		bdp->cbd_bufaddr = 0;
-		fep->tx_skbuff[index] = NULL;
+	/* Push the data cache so the CPM does not get stale memory data. */
+	addr = dma_map_single(&fep->pdev->dev, bufaddr, length, DMA_TO_DEVICE);
+	if (dma_mapping_error(&fep->pdev->dev, addr)) {
 		dev_kfree_skb_any(skb);
 		if (net_ratelimit())
 			netdev_err(ndev, "Tx DMA memory map failed\n");
 		return NETDEV_TX_OK;
 	}
 
+	/* Save skb pointer */
+	fep->tx_skbuff[index] = skb;
+
+	bdp->cbd_datlen = length;
+	bdp->cbd_bufaddr = addr;
+
 	if (fep->bufdesc_ex) {
 
 		struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
@@ -489,7 +489,7 @@ static void fec_enet_bd_init(struct net_device *dev)
 
 		/* Initialize the BD for every fragment in the page. */
 		bdp->cbd_sc = 0;
-		if (bdp->cbd_bufaddr && fep->tx_skbuff[i]) {
+		if (fep->tx_skbuff[i]) {
 			dev_kfree_skb_any(fep->tx_skbuff[i]);
 			fep->tx_skbuff[i] = NULL;
 		}
@@ -793,6 +793,7 @@ fec_enet_tx(struct net_device *ndev)
 			index = bdp - fep->tx_bd_base;
 
 		skb = fep->tx_skbuff[index];
+		fep->tx_skbuff[index] = NULL;
 		dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, skb->len,
 				DMA_TO_DEVICE);
 		bdp->cbd_bufaddr = 0;
@@ -842,7 +843,6 @@ fec_enet_tx(struct net_device *ndev)
 
 		/* Free the sk buffer associated with this last transmit */
 		dev_kfree_skb_any(skb);
-		fep->tx_skbuff[index] = NULL;
 
 		fep->dirty_tx = bdp;
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 079/222] net:fec: make rx skb allocation/map more robust
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (77 preceding siblings ...)
  2014-04-25 11:37 ` [PATCH 078/222] net:fec: clean up transmit descriptor setup Russell King
@ 2014-04-25 11:37 ` Russell King
  2014-04-25 11:37 ` [PATCH 080/222] net:fec: ensure fec_enet_free_buffers() properly cleans the rings Russell King
                   ` (143 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:37 UTC (permalink / raw)
  To: linux-arm-kernel

Allocate, and then map the receive skb before writing any data to the
ring descriptor or storing the skb.  This means we have ring data in
one of two states: either fully setup, or not setup.  This simplifies
the cleanup, which could end up calling dma_unmap_single() on a DMA
error value.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 45cb558bb227..f98ddb0923a3 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1712,12 +1712,11 @@ static void fec_enet_free_buffers(struct net_device *ndev)
 	bdp = fep->rx_bd_base;
 	for (i = 0; i < fep->rx_ring_size; i++) {
 		skb = fep->rx_skbuff[i];
-
-		if (bdp->cbd_bufaddr)
+		if (skb) {
 			dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
 					FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
-		if (skb)
 			dev_kfree_skb(skb);
+		}
 		bdp = fec_enet_get_nextdesc(bdp, fep);
 	}
 
@@ -1735,21 +1734,26 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
 
 	bdp = fep->rx_bd_base;
 	for (i = 0; i < fep->rx_ring_size; i++) {
+		dma_addr_t addr;
+
 		skb = netdev_alloc_skb(ndev, FEC_ENET_RX_FRSIZE);
 		if (!skb) {
 			fec_enet_free_buffers(ndev);
 			return -ENOMEM;
 		}
-		fep->rx_skbuff[i] = skb;
 
-		bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, skb->data,
+		addr = dma_map_single(&fep->pdev->dev, skb->data,
 				FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
-		if (dma_mapping_error(&fep->pdev->dev, bdp->cbd_bufaddr)) {
+		if (dma_mapping_error(&fep->pdev->dev, addr)) {
+			dev_kfree_skb(skb);
 			fec_enet_free_buffers(ndev);
 			if (net_ratelimit())
 				netdev_err(ndev, "Rx DMA memory map failed\n");
 			return -ENOMEM;
 		}
+
+		fep->rx_skbuff[i] = skb;
+		bdp->cbd_bufaddr = addr;
 		bdp->cbd_sc = BD_ENET_RX_EMPTY;
 
 		if (fep->bufdesc_ex) {
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 080/222] net:fec: ensure fec_enet_free_buffers() properly cleans the rings
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (78 preceding siblings ...)
  2014-04-25 11:37 ` [PATCH 079/222] net:fec: make rx skb allocation/map more robust Russell King
@ 2014-04-25 11:37 ` Russell King
  2014-04-25 11:37 ` [PATCH 081/222] net:fec: fix missing kmalloc() failure check in fec_enet_alloc_buffers() Russell King
                   ` (142 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:37 UTC (permalink / raw)
  To: linux-arm-kernel

Ensure that we do not double-free any allocations, and that any transmit
skbuffs are properly freed when we clean up the rings.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index f98ddb0923a3..08a5004970c9 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1712,6 +1712,7 @@ static void fec_enet_free_buffers(struct net_device *ndev)
 	bdp = fep->rx_bd_base;
 	for (i = 0; i < fep->rx_ring_size; i++) {
 		skb = fep->rx_skbuff[i];
+		fep->rx_skbuff[i] = NULL;
 		if (skb) {
 			dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
 					FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
@@ -1721,8 +1722,14 @@ static void fec_enet_free_buffers(struct net_device *ndev)
 	}
 
 	bdp = fep->tx_bd_base;
-	for (i = 0; i < fep->tx_ring_size; i++)
+	for (i = 0; i < fep->tx_ring_size; i++) {
 		kfree(fep->tx_bounce[i]);
+		fep->tx_bounce[i] = NULL;
+		skb = fep->tx_skbuff[i];
+		fep->tx_skbuff[i] = NULL;
+		if (skb)
+			dev_kfree_skb(skb);
+	}
 }
 
 static int fec_enet_alloc_buffers(struct net_device *ndev)
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 081/222] net:fec: fix missing kmalloc() failure check in fec_enet_alloc_buffers()
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (79 preceding siblings ...)
  2014-04-25 11:37 ` [PATCH 080/222] net:fec: ensure fec_enet_free_buffers() properly cleans the rings Russell King
@ 2014-04-25 11:37 ` Russell King
  2014-04-25 11:37 ` [PATCH 082/222] net:fec: ensure that we dma unmap the transmit descriptors Russell King
                   ` (141 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:37 UTC (permalink / raw)
  To: linux-arm-kernel

fec_enet_alloc_buffers() appears to assume that kmalloc() will never
fail.  This is an unreasonable assumption.  Add a proper check and
failure cleanup path.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 08a5004970c9..7f7d9dcb485e 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1744,19 +1744,16 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
 		dma_addr_t addr;
 
 		skb = netdev_alloc_skb(ndev, FEC_ENET_RX_FRSIZE);
-		if (!skb) {
-			fec_enet_free_buffers(ndev);
-			return -ENOMEM;
-		}
+		if (!skb)
+			goto err_alloc;
 
 		addr = dma_map_single(&fep->pdev->dev, skb->data,
 				FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
 		if (dma_mapping_error(&fep->pdev->dev, addr)) {
 			dev_kfree_skb(skb);
-			fec_enet_free_buffers(ndev);
 			if (net_ratelimit())
 				netdev_err(ndev, "Rx DMA memory map failed\n");
-			return -ENOMEM;
+			goto err_alloc;
 		}
 
 		fep->rx_skbuff[i] = skb;
@@ -1778,6 +1775,8 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
 	bdp = fep->tx_bd_base;
 	for (i = 0; i < fep->tx_ring_size; i++) {
 		fep->tx_bounce[i] = kmalloc(FEC_ENET_TX_FRSIZE, GFP_KERNEL);
+		if (!fep->tx_bounce[i])
+			goto err_alloc;
 
 		bdp->cbd_sc = 0;
 		bdp->cbd_bufaddr = 0;
@@ -1795,6 +1794,10 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
 	bdp->cbd_sc |= BD_SC_WRAP;
 
 	return 0;
+
+ err_alloc:
+	fec_enet_free_buffers(ndev);
+	return -ENOMEM;
 }
 
 static int
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 082/222] net:fec: ensure that we dma unmap the transmit descriptors
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (80 preceding siblings ...)
  2014-04-25 11:37 ` [PATCH 081/222] net:fec: fix missing kmalloc() failure check in fec_enet_alloc_buffers() Russell King
@ 2014-04-25 11:37 ` Russell King
  2014-04-25 11:38 ` [PATCH 083/222] net:fec: remove useless fep->opened Russell King
                   ` (140 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:37 UTC (permalink / raw)
  To: linux-arm-kernel

On transmit timeout or close, dirty transmit descriptors were not being
correctly cleaned: the only time that DMA mappings are cleaned is when
scanning the TX ring after a transmit interrupt.  Fix this.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 7f7d9dcb485e..94861870e741 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -327,6 +327,17 @@ fec_enet_clear_csum(struct sk_buff *skb, struct net_device *ndev)
 	return 0;
 }
 
+static void
+fec_enet_tx_unmap(struct bufdesc *bdp, struct fec_enet_private *fep)
+{
+	dma_addr_t addr = bdp->cbd_bufaddr;
+	unsigned length = bdp->cbd_datlen;
+
+	bdp->cbd_bufaddr = 0;
+
+	dma_unmap_single(&fep->pdev->dev, addr, length, DMA_TO_DEVICE);
+}
+
 static netdev_tx_t
 fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
@@ -489,11 +500,12 @@ static void fec_enet_bd_init(struct net_device *dev)
 
 		/* Initialize the BD for every fragment in the page. */
 		bdp->cbd_sc = 0;
+		if (bdp->cbd_bufaddr)
+			fec_enet_tx_unmap(bdp, fep);
 		if (fep->tx_skbuff[i]) {
 			dev_kfree_skb_any(fep->tx_skbuff[i]);
 			fep->tx_skbuff[i] = NULL;
 		}
-		bdp->cbd_bufaddr = 0;
 		bdp = fec_enet_get_nextdesc(bdp, fep);
 	}
 
@@ -792,11 +804,10 @@ fec_enet_tx(struct net_device *ndev)
 		else
 			index = bdp - fep->tx_bd_base;
 
+		fec_enet_tx_unmap(bdp, fep);
+
 		skb = fep->tx_skbuff[index];
 		fep->tx_skbuff[index] = NULL;
-		dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, skb->len,
-				DMA_TO_DEVICE);
-		bdp->cbd_bufaddr = 0;
 
 		/* Check for errors. */
 		if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC |
@@ -1723,6 +1734,8 @@ static void fec_enet_free_buffers(struct net_device *ndev)
 
 	bdp = fep->tx_bd_base;
 	for (i = 0; i < fep->tx_ring_size; i++) {
+		if (bdp->cbd_bufaddr)
+			fec_enet_tx_unmap(bdp, fep);
 		kfree(fep->tx_bounce[i]);
 		fep->tx_bounce[i] = NULL;
 		skb = fep->tx_skbuff[i];
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 083/222] net:fec: remove useless fep->opened
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (81 preceding siblings ...)
  2014-04-25 11:37 ` [PATCH 082/222] net:fec: ensure that we dma unmap the transmit descriptors Russell King
@ 2014-04-25 11:38 ` Russell King
  2014-04-25 11:38 ` [PATCH 084/222] net:fec: stop the phy before shutting down the MAC Russell King
                   ` (139 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:38 UTC (permalink / raw)
  To: linux-arm-kernel

napi_disable() waits until the NAPI processing has completed, and then
prevents any further polls.  At this point, the driver then clears
fep->opened.  The NAPI poll function uses this to stop processing in
the receive path.  Hence, it will never see this variable cleared,
because the NAPI poll has to complete before it will be cleared.

Therefore, this variable serves no purpose, so let's remove it.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec.h      | 1 -
 drivers/net/ethernet/freescale/fec_main.c | 5 -----
 2 files changed, 6 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 3b8d6d19ff05..88ef53b18ae7 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -301,7 +301,6 @@ struct fec_enet_private {
 
 	struct	platform_device *pdev;
 
-	int	opened;
 	int	dev_id;
 
 	/* Phylib and MDIO interface */
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 94861870e741..634046c73734 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -914,9 +914,6 @@ fec_enet_rx(struct net_device *ndev, int budget)
 		if ((status & BD_ENET_RX_LAST) == 0)
 			netdev_err(ndev, "rcv is not +last\n");
 
-		if (!fep->opened)
-			goto rx_processing_done;
-
 		/* Check for errors. */
 		if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
 			   BD_ENET_RX_CR | BD_ENET_RX_OV)) {
@@ -1837,7 +1834,6 @@ fec_enet_open(struct net_device *ndev)
 	napi_enable(&fep->napi);
 	phy_start(fep->phy_dev);
 	netif_start_queue(ndev);
-	fep->opened = 1;
 	return 0;
 }
 
@@ -1848,7 +1844,6 @@ fec_enet_close(struct net_device *ndev)
 
 	/* Don't know what to do yet. */
 	napi_disable(&fep->napi);
-	fep->opened = 0;
 	netif_tx_disable(ndev);
 	fec_stop(ndev);
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 084/222] net:fec: stop the phy before shutting down the MAC
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (82 preceding siblings ...)
  2014-04-25 11:38 ` [PATCH 083/222] net:fec: remove useless fep->opened Russell King
@ 2014-04-25 11:38 ` Russell King
  2014-04-25 11:38 ` [PATCH 085/222] net:fec: improve safety of suspend/resume/transmit timeout paths Russell King
                   ` (138 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:38 UTC (permalink / raw)
  To: linux-arm-kernel

When the network interface goes down, stop the phy to prevent further
link up status changes before taking the MAC or netif sections down.
This prevents further reception of link up events which could
potentially call fec_restart().

Since phy_stop() takes the mutex which adjust_link() runs under, we
also ensure that adjust_link() will not already be processing a link
up event.

We also need to do this when suspending as well - we don't want a
mis-timed phy state change to restart the MAC after we have stopped
it for suspend, and thus need to restart the phy when resuming.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 634046c73734..765ea90b99ed 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1842,12 +1842,13 @@ fec_enet_close(struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 
+	phy_stop(fep->phy_dev);
+
 	/* Don't know what to do yet. */
 	napi_disable(&fep->napi);
 	netif_tx_disable(ndev);
 	fec_stop(ndev);
 
-	phy_stop(fep->phy_dev);
 	phy_disconnect(fep->phy_dev);
 	fep->phy_dev = NULL;
 
@@ -2333,6 +2334,7 @@ fec_suspend(struct device *dev)
 	struct fec_enet_private *fep = netdev_priv(ndev);
 
 	if (netif_running(ndev)) {
+		phy_stop(fep->phy_dev);
 		fec_stop(ndev);
 		netif_device_detach(ndev);
 	}
@@ -2385,6 +2387,7 @@ fec_resume(struct device *dev)
 	if (netif_running(ndev)) {
 		fec_restart(ndev, fep->full_duplex);
 		netif_device_attach(ndev);
+		phy_start(fep->phy_dev);
 	}
 
 	return 0;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 085/222] net:fec: improve safety of suspend/resume/transmit timeout paths
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (83 preceding siblings ...)
  2014-04-25 11:38 ` [PATCH 084/222] net:fec: stop the phy before shutting down the MAC Russell King
@ 2014-04-25 11:38 ` Russell King
  2014-04-25 11:38 ` [PATCH 086/222] net:fec: ensure fec_enet_close() copes with resume failure Russell King
                   ` (137 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:38 UTC (permalink / raw)
  To: linux-arm-kernel

We need to hold the rtnl lock while suspending, resuming or processing
the transmit timeout to ensure that netif_running() will not change
state beneath us while we bring up, take down or restart the hardware.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 765ea90b99ed..843721aa44bd 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -767,8 +767,10 @@ static void fec_enet_work(struct work_struct *work)
 
 	if (fep->delay_work.timeout) {
 		fep->delay_work.timeout = false;
+		rtnl_lock();
 		fec_restart(fep->netdev, fep->full_duplex);
 		netif_wake_queue(fep->netdev);
+		rtnl_unlock();
 	}
 
 	if (fep->delay_work.trig_tx) {
@@ -2333,11 +2335,14 @@ fec_suspend(struct device *dev)
 	struct net_device *ndev = dev_get_drvdata(dev);
 	struct fec_enet_private *fep = netdev_priv(ndev);
 
+	rtnl_lock();
 	if (netif_running(ndev)) {
 		phy_stop(fep->phy_dev);
 		fec_stop(ndev);
 		netif_device_detach(ndev);
 	}
+	rtnl_unlock();
+
 	if (fep->clk_ptp)
 		clk_disable_unprepare(fep->clk_ptp);
 	if (fep->clk_enet_out)
@@ -2384,11 +2389,13 @@ fec_resume(struct device *dev)
 			goto failed_clk_ptp;
 	}
 
+	rtnl_lock();
 	if (netif_running(ndev)) {
 		fec_restart(ndev, fep->full_duplex);
 		netif_device_attach(ndev);
 		phy_start(fep->phy_dev);
 	}
+	rtnl_unlock();
 
 	return 0;
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 086/222] net:fec: ensure fec_enet_close() copes with resume failure
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (84 preceding siblings ...)
  2014-04-25 11:38 ` [PATCH 085/222] net:fec: improve safety of suspend/resume/transmit timeout paths Russell King
@ 2014-04-25 11:38 ` Russell King
  2014-04-25 11:38 ` [PATCH 087/222] net:fec: only run a restart or stop if the device is present and running Russell King
                   ` (136 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:38 UTC (permalink / raw)
  To: linux-arm-kernel

When the FEC is suspended, the device is detached.  Upon resume failure,
the device is left in detached mode, possibly with some of the required
clocks not running.  We don't want to be poking the device in that state
because as it may cause bus errors.

If the device is marked detached, avoid calling fec_stop().

This depends upon: "net:fec: improve safety of suspend/resume paths"

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 843721aa44bd..f65c1f1d8770 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1846,10 +1846,10 @@ fec_enet_close(struct net_device *ndev)
 
 	phy_stop(fep->phy_dev);
 
-	/* Don't know what to do yet. */
 	napi_disable(&fep->napi);
 	netif_tx_disable(ndev);
-	fec_stop(ndev);
+	if (netif_device_present(ndev))
+		fec_stop(ndev);
 
 	phy_disconnect(fep->phy_dev);
 	fep->phy_dev = NULL;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 087/222] net:fec: only run a restart or stop if the device is present and running
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (85 preceding siblings ...)
  2014-04-25 11:38 ` [PATCH 086/222] net:fec: ensure fec_enet_close() copes with resume failure Russell King
@ 2014-04-25 11:38 ` Russell King
  2014-04-25 11:38 ` [PATCH 088/222] net:fec: move calls to quiesce/resume packet processing out of fec_restart() Russell King
                   ` (135 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:38 UTC (permalink / raw)
  To: linux-arm-kernel

Avoid calling fec_restart() or fec_stop() while the device is down
or not present (iow suspended.)

Although the ndo_timeout method will only be called if the device is
present and running, we defer this to a work queue.  The work queue
can run independently, and so needs to repeat these checks to ensure
that a restart doesn't occur after the device has been taken down or
detached for suspend.  In this case, we call fec_restart() in the
resume path, so nothing is lost.

For fec_set_features, we add a call to fec_restart() in fec_enet_open()
to ensure that the hardware is appropriate programmed when the interface
is opened.  fec_set_features() call should not occur while we're
suspended, so we don't have to worry about that case.

The adjust_link needs similar treatment - this also is called from a
work queue, which may be run independently after we have taken the
device down and detached it.  In this case, we just mark the link
down and take no further action.  We will reset things appropriately
once the device is up and running again, at which point we will receive
another adjust_link callback.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index f65c1f1d8770..723a645dfeb3 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -764,12 +764,15 @@ static void fec_enet_work(struct work_struct *work)
 		container_of(work,
 			     struct fec_enet_private,
 			     delay_work.delay_work.work);
+	struct net_device *ndev = fep->netdev;
 
 	if (fep->delay_work.timeout) {
 		fep->delay_work.timeout = false;
 		rtnl_lock();
-		fec_restart(fep->netdev, fep->full_duplex);
-		netif_wake_queue(fep->netdev);
+		if (netif_device_present(ndev) || netif_running(ndev)) {
+			fec_restart(ndev, fep->full_duplex);
+			netif_wake_queue(ndev);
+		}
 		rtnl_unlock();
 	}
 
@@ -1200,7 +1203,14 @@ static void fec_enet_adjust_link(struct net_device *ndev)
 		return;
 	}
 
-	if (phy_dev->link) {
+	/*
+	 * If the netdev is down, or is going down, we're not interested
+	 * in link state events, so just mark our idea of the link as down
+	 * and ignore the event.
+	 */
+	if (!netif_running(ndev) || !netif_device_present(ndev)) {
+		fep->link = 0;
+	} else if (phy_dev->link) {
 		if (!fep->link) {
 			fep->link = phy_dev->link;
 			status_change = 1;
@@ -1833,6 +1843,7 @@ fec_enet_open(struct net_device *ndev)
 		return ret;
 	}
 
+	fec_restart(ndev, fep->full_duplex);
 	napi_enable(&fep->napi);
 	phy_start(fep->phy_dev);
 	netif_start_queue(ndev);
@@ -1997,8 +2008,6 @@ static int fec_set_features(struct net_device *netdev,
 			fec_stop(netdev);
 			fec_restart(netdev, fep->phy_dev->duplex);
 			netif_wake_queue(netdev);
-		} else {
-			fec_restart(netdev, fep->phy_dev->duplex);
 		}
 	}
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 088/222] net:fec: move calls to quiesce/resume packet processing out of fec_restart()
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (86 preceding siblings ...)
  2014-04-25 11:38 ` [PATCH 087/222] net:fec: only run a restart or stop if the device is present and running Russell King
@ 2014-04-25 11:38 ` Russell King
  2014-04-25 11:38 ` [PATCH 089/222] net:fec: remove inappropriate calls around fec_restart() Russell King
                   ` (134 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:38 UTC (permalink / raw)
  To: linux-arm-kernel

Move the calls to quiesce and resume packet processing out of
fec_restart() to its call sites.  This is the first step in a two stage
clean up of this code, where we just move the calls out of fec_restart()
without changing them.  Not everywhere needs to issue these calls, and
not everywhere needs all of these calls to be issued.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 64 ++++++++++++++++++++++---------
 1 file changed, 45 insertions(+), 19 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 723a645dfeb3..1da67d4fdd0a 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -515,9 +515,10 @@ static void fec_enet_bd_init(struct net_device *dev)
 	fep->dirty_tx = bdp;
 }
 
-/* This function is called to start or restart the FEC during a link
- * change.  This only happens when switching between half and full
- * duplex.
+/*
+ * This function is called to start or restart the FEC during a link
+ * change, transmit timeout, or to reconfigure the FEC.  The network
+ * packet processing for this device must be stopped before this call.
  */
 static void
 fec_restart(struct net_device *ndev, int duplex)
@@ -531,13 +532,6 @@ fec_restart(struct net_device *ndev, int duplex)
 	u32 rcntl = OPT_FRAME_SIZE | 0x04;
 	u32 ecntl = 0x2; /* ETHEREN */
 
-	if (netif_running(ndev)) {
-		netif_device_detach(ndev);
-		napi_disable(&fep->napi);
-		netif_tx_disable(ndev);
-		netif_tx_lock_bh(ndev);
-	}
-
 	/* Whack a reset.  We should wait for this. */
 	writel(1, fep->hwp + FEC_ECNTRL);
 	udelay(10);
@@ -706,13 +700,6 @@ fec_restart(struct net_device *ndev, int duplex)
 
 	/* Enable interrupts we wish to service */
 	writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
-
-	if (netif_running(ndev)) {
-		netif_tx_unlock_bh(ndev);
-		netif_wake_queue(ndev);
-		napi_enable(&fep->napi);
-		netif_device_attach(ndev);
-	}
 }
 
 static void
@@ -770,8 +757,15 @@ static void fec_enet_work(struct work_struct *work)
 		fep->delay_work.timeout = false;
 		rtnl_lock();
 		if (netif_device_present(ndev) || netif_running(ndev)) {
+			netif_device_detach(ndev);
+			napi_disable(&fep->napi);
+			netif_tx_disable(ndev);
+			netif_tx_lock_bh(ndev);
 			fec_restart(ndev, fep->full_duplex);
+			netif_tx_unlock_bh(ndev);
 			netif_wake_queue(ndev);
+			napi_enable(&fep->napi);
+			netif_device_attach(ndev);
 		}
 		rtnl_unlock();
 	}
@@ -1225,8 +1219,17 @@ static void fec_enet_adjust_link(struct net_device *ndev)
 		}
 
 		/* if any of the above changed restart the FEC */
-		if (status_change)
+		if (status_change) {
+			netif_device_detach(ndev);
+			napi_disable(&fep->napi);
+			netif_tx_disable(ndev);
+			netif_tx_lock_bh(ndev);
 			fec_restart(ndev, phy_dev->duplex);
+			netif_tx_unlock_bh(ndev);
+			netif_wake_queue(ndev);
+			napi_enable(&fep->napi);
+			netif_device_attach(ndev);
+		}
 	} else {
 		if (fep->link) {
 			fec_stop(ndev);
@@ -1568,8 +1571,17 @@ static int fec_enet_set_pauseparam(struct net_device *ndev,
 			fec_stop(ndev);
 		phy_start_aneg(fep->phy_dev);
 	}
-	if (netif_running(ndev))
+	if (netif_running(ndev)) {
+		netif_device_detach(ndev);
+		napi_disable(&fep->napi);
+		netif_tx_disable(ndev);
+		netif_tx_lock_bh(ndev);
 		fec_restart(ndev, 0);
+		netif_tx_unlock_bh(ndev);
+		netif_wake_queue(ndev);
+		napi_enable(&fep->napi);
+		netif_device_attach(ndev);
+	}
 
 	return 0;
 }
@@ -2006,8 +2018,15 @@ static int fec_set_features(struct net_device *netdev,
 
 		if (netif_running(netdev)) {
 			fec_stop(netdev);
+			netif_device_detach(netdev);
+			napi_disable(&fep->napi);
+			netif_tx_disable(netdev);
+			netif_tx_lock_bh(netdev);
 			fec_restart(netdev, fep->phy_dev->duplex);
+			netif_tx_unlock_bh(netdev);
 			netif_wake_queue(netdev);
+			napi_enable(&fep->napi);
+			netif_device_attach(netdev);
 		}
 	}
 
@@ -2400,7 +2419,14 @@ fec_resume(struct device *dev)
 
 	rtnl_lock();
 	if (netif_running(ndev)) {
+		netif_device_detach(ndev);
+		napi_disable(&fep->napi);
+		netif_tx_disable(ndev);
+		netif_tx_lock_bh(ndev);
 		fec_restart(ndev, fep->full_duplex);
+		netif_tx_unlock_bh(ndev);
+		netif_wake_queue(ndev);
+		napi_enable(&fep->napi);
 		netif_device_attach(ndev);
 		phy_start(fep->phy_dev);
 	}
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 089/222] net:fec: remove inappropriate calls around fec_restart()
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (87 preceding siblings ...)
  2014-04-25 11:38 ` [PATCH 088/222] net:fec: move calls to quiesce/resume packet processing out of fec_restart() Russell King
@ 2014-04-25 11:38 ` Russell King
  2014-04-25 11:38 ` [PATCH 090/222] net:fec: quiesce packet processing before stopping device in fec_suspend() Russell King
                   ` (133 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:38 UTC (permalink / raw)
  To: linux-arm-kernel

This is the second stage to "move calls to quiesce/resume packet
processing out of fec_restart()", where we remove calls which are not
appropriate to the call site.

In the majority of cases, there is no need to detach and reattach the
interface as we are holding the queue xmit lock across the reset.  The
exception to that is in fec_resume(), where we are already detached by
the suspend function.  Here, we can remove the call to detach the
interface.

We also do not need to stop the transmit queue.  Holding the xmit lock
is enough to ensure that the transmit packet processing is not running
while we perform our task.  However, since fec_restart() always cleans
the rings, we call netif_wake_queue() (or netif_device_attach() in the
case of resume) just before dropping the xmit lock.  This prevents the
watchdog firing.

Lastly, always call napi_enable() after the device has been reattached
in the resume path so that we know that the transmit packet processing
is already in an enabled state, so we don't call netif_wake_queue()
while detached.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 26 ++++++--------------------
 1 file changed, 6 insertions(+), 20 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 1da67d4fdd0a..02e121a19d87 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -757,15 +757,12 @@ static void fec_enet_work(struct work_struct *work)
 		fep->delay_work.timeout = false;
 		rtnl_lock();
 		if (netif_device_present(ndev) || netif_running(ndev)) {
-			netif_device_detach(ndev);
 			napi_disable(&fep->napi);
-			netif_tx_disable(ndev);
 			netif_tx_lock_bh(ndev);
 			fec_restart(ndev, fep->full_duplex);
-			netif_tx_unlock_bh(ndev);
 			netif_wake_queue(ndev);
+			netif_tx_unlock_bh(ndev);
 			napi_enable(&fep->napi);
-			netif_device_attach(ndev);
 		}
 		rtnl_unlock();
 	}
@@ -1220,15 +1217,12 @@ static void fec_enet_adjust_link(struct net_device *ndev)
 
 		/* if any of the above changed restart the FEC */
 		if (status_change) {
-			netif_device_detach(ndev);
 			napi_disable(&fep->napi);
-			netif_tx_disable(ndev);
 			netif_tx_lock_bh(ndev);
 			fec_restart(ndev, phy_dev->duplex);
-			netif_tx_unlock_bh(ndev);
 			netif_wake_queue(ndev);
+			netif_tx_unlock_bh(ndev);
 			napi_enable(&fep->napi);
-			netif_device_attach(ndev);
 		}
 	} else {
 		if (fep->link) {
@@ -1572,15 +1566,12 @@ static int fec_enet_set_pauseparam(struct net_device *ndev,
 		phy_start_aneg(fep->phy_dev);
 	}
 	if (netif_running(ndev)) {
-		netif_device_detach(ndev);
 		napi_disable(&fep->napi);
-		netif_tx_disable(ndev);
 		netif_tx_lock_bh(ndev);
 		fec_restart(ndev, 0);
-		netif_tx_unlock_bh(ndev);
 		netif_wake_queue(ndev);
+		netif_tx_unlock_bh(ndev);
 		napi_enable(&fep->napi);
-		netif_device_attach(ndev);
 	}
 
 	return 0;
@@ -2018,15 +2009,12 @@ static int fec_set_features(struct net_device *netdev,
 
 		if (netif_running(netdev)) {
 			fec_stop(netdev);
-			netif_device_detach(netdev);
 			napi_disable(&fep->napi);
-			netif_tx_disable(netdev);
 			netif_tx_lock_bh(netdev);
 			fec_restart(netdev, fep->phy_dev->duplex);
-			netif_tx_unlock_bh(netdev);
 			netif_wake_queue(netdev);
+			netif_tx_unlock_bh(netdev);
 			napi_enable(&fep->napi);
-			netif_device_attach(netdev);
 		}
 	}
 
@@ -2419,15 +2407,13 @@ fec_resume(struct device *dev)
 
 	rtnl_lock();
 	if (netif_running(ndev)) {
-		netif_device_detach(ndev);
 		napi_disable(&fep->napi);
-		netif_tx_disable(ndev);
 		netif_tx_lock_bh(ndev);
 		fec_restart(ndev, fep->full_duplex);
+		netif_device_attach(ndev);
 		netif_tx_unlock_bh(ndev);
-		netif_wake_queue(ndev);
-		napi_enable(&fep->napi);
 		netif_device_attach(ndev);
+		napi_enable(&fep->napi);
 		phy_start(fep->phy_dev);
 	}
 	rtnl_unlock();
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 090/222] net:fec: quiesce packet processing before stopping device in fec_suspend()
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (88 preceding siblings ...)
  2014-04-25 11:38 ` [PATCH 089/222] net:fec: remove inappropriate calls around fec_restart() Russell King
@ 2014-04-25 11:38 ` Russell King
  2014-04-25 11:38 ` [PATCH 091/222] net:fec: quiesce packet processing before stopping device in fec_set_features() Russell King
                   ` (132 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:38 UTC (permalink / raw)
  To: linux-arm-kernel

fec_suspend() calls fec_stop() to stop the transmit ring while the
transmit packet processing is still active.  This can lead to the
transmit queue being restarted by an intervening packet queued for
transmission, or by the tx quirk timer expiring. Fix this by moving the
call to fec_enet_netif_quiesce() before fec_stop().  We must remove the
corresponding call to fec_enet_netif_quiesce() from the resume path.

We also need to avoid calling fec_enet_netif_quiesce() inside
fec_enet_close() to cover the failed resume scenario otherwise
fec_enet_close() will hang in napi_disable().

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 02e121a19d87..927c283e43b1 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1860,10 +1860,11 @@ fec_enet_close(struct net_device *ndev)
 
 	phy_stop(fep->phy_dev);
 
-	napi_disable(&fep->napi);
-	netif_tx_disable(ndev);
-	if (netif_device_present(ndev))
+	if (netif_device_present(ndev)) {
+		napi_disable(&fep->napi);
+		netif_tx_disable(ndev);
 		fec_stop(ndev);
+	}
 
 	phy_disconnect(fep->phy_dev);
 	fep->phy_dev = NULL;
@@ -2354,8 +2355,11 @@ fec_suspend(struct device *dev)
 	rtnl_lock();
 	if (netif_running(ndev)) {
 		phy_stop(fep->phy_dev);
-		fec_stop(ndev);
+		napi_disable(&fep->napi);
+		netif_tx_lock_bh(ndev);
 		netif_device_detach(ndev);
+		netif_tx_unlock_bh(ndev);
+		fec_stop(ndev);
 	}
 	rtnl_unlock();
 
@@ -2407,12 +2411,10 @@ fec_resume(struct device *dev)
 
 	rtnl_lock();
 	if (netif_running(ndev)) {
-		napi_disable(&fep->napi);
-		netif_tx_lock_bh(ndev);
 		fec_restart(ndev, fep->full_duplex);
+		netif_tx_lock_bh(ndev);
 		netif_device_attach(ndev);
 		netif_tx_unlock_bh(ndev);
-		netif_device_attach(ndev);
 		napi_enable(&fep->napi);
 		phy_start(fep->phy_dev);
 	}
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 091/222] net:fec: quiesce packet processing before stopping device in fec_set_features()
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (89 preceding siblings ...)
  2014-04-25 11:38 ` [PATCH 090/222] net:fec: quiesce packet processing before stopping device in fec_suspend() Russell King
@ 2014-04-25 11:38 ` Russell King
  2014-04-25 11:38 ` [PATCH 092/222] net:fec: quiesce packet processing before changing features Russell King
                   ` (131 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:38 UTC (permalink / raw)
  To: linux-arm-kernel

fec_set_features() calls fec_stop() to stop the transmit ring while the
transmit queue is still active.  This can lead to the transmit ring
being restarted by an intervening packet queued for transmission, or
by the tx quirk timer expiring.  Fix this by moving the call to
fec_enet_netif_quiesce() before fec_stop().

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 927c283e43b1..789678c6f6d4 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -2009,9 +2009,9 @@ static int fec_set_features(struct net_device *netdev,
 			fep->csum_flags &= ~FLAG_RX_CSUM_ENABLED;
 
 		if (netif_running(netdev)) {
-			fec_stop(netdev);
 			napi_disable(&fep->napi);
 			netif_tx_lock_bh(netdev);
+			fec_stop(netdev);
 			fec_restart(netdev, fep->phy_dev->duplex);
 			netif_wake_queue(netdev);
 			netif_tx_unlock_bh(netdev);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 092/222] net:fec: quiesce packet processing before changing features
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (90 preceding siblings ...)
  2014-04-25 11:38 ` [PATCH 091/222] net:fec: quiesce packet processing before stopping device in fec_set_features() Russell King
@ 2014-04-25 11:38 ` Russell King
  2014-04-25 11:38 ` [PATCH 093/222] net:fec: quiesce packet processing when taking link down in fec_enet_adjust_link() Russell King
                   ` (130 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:38 UTC (permalink / raw)
  To: linux-arm-kernel

Changing the features (receive checksumming) requires the hardware to be
reprogrammed, and also changes the checks in the receive packet
processing.

The current implementation has a race - fec_set_features() changes the
flags which alter the receive packet processing while we are active.
Only afterwards do we shutdown and reconfigure the hardware.

This can lead to packets being received and marked with a valid checksum
(via CHECKSUM_UNNECESSARY) when the hardware checksum validation has not
yet been enabled.

We must quiesce the device, then change the software configuration for
this feature, and then resume the device if it was previously running.

The resulting code structure also allows us to add other configuration
features in this path without having to quiesce and resume the network
interface and device.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 789678c6f6d4..c5a5a0aedf21 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1993,12 +1993,21 @@ static void fec_poll_controller(struct net_device *dev)
 }
 #endif
 
+#define FEATURES_NEED_QUIESCE NETIF_F_RXCSUM
+
 static int fec_set_features(struct net_device *netdev,
 	netdev_features_t features)
 {
 	struct fec_enet_private *fep = netdev_priv(netdev);
 	netdev_features_t changed = features ^ netdev->features;
 
+	/* Quiesce the device if necessary */
+	if (netif_running(netdev) && changed & FEATURES_NEED_QUIESCE) {
+		napi_disable(&fep->napi);
+		netif_tx_lock_bh(netdev);
+		fec_stop(netdev);
+	}
+
 	netdev->features = features;
 
 	/* Receive checksum has been changed */
@@ -2007,16 +2016,14 @@ static int fec_set_features(struct net_device *netdev,
 			fep->csum_flags |= FLAG_RX_CSUM_ENABLED;
 		else
 			fep->csum_flags &= ~FLAG_RX_CSUM_ENABLED;
+	}
 
-		if (netif_running(netdev)) {
-			napi_disable(&fep->napi);
-			netif_tx_lock_bh(netdev);
-			fec_stop(netdev);
-			fec_restart(netdev, fep->phy_dev->duplex);
-			netif_wake_queue(netdev);
-			netif_tx_unlock_bh(netdev);
-			napi_enable(&fep->napi);
-		}
+	/* Resume the device after updates */
+	if (netif_running(netdev) && changed & FEATURES_NEED_QUIESCE) {
+		fec_restart(netdev, fep->phy_dev->duplex);
+		netif_wake_queue(netdev);
+		netif_tx_unlock_bh(netdev);
+		napi_enable(&fep->napi);
 	}
 
 	return 0;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 093/222] net:fec: quiesce packet processing when taking link down in fec_enet_adjust_link()
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (91 preceding siblings ...)
  2014-04-25 11:38 ` [PATCH 092/222] net:fec: quiesce packet processing before changing features Russell King
@ 2014-04-25 11:38 ` Russell King
  2014-04-25 11:38 ` [PATCH 094/222] net:fec: fix ethtool set_pauseparam duplex bug Russell King
                   ` (129 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:38 UTC (permalink / raw)
  To: linux-arm-kernel

When the link goes down, the adjust_link method will be called, but
there is no synchronisation to ensure that we won't be processing some
last remaining packets while performing a reset of the device.

Add the necessary synchronisation to ensure that packet processing
is complete before we stop and reset the FEC.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index c5a5a0aedf21..6156d423a6a9 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1226,7 +1226,11 @@ static void fec_enet_adjust_link(struct net_device *ndev)
 		}
 	} else {
 		if (fep->link) {
+			napi_disable(&fep->napi);
+			netif_tx_lock_bh(ndev);
 			fec_stop(ndev);
+			netif_tx_unlock_bh(ndev);
+			napi_enable(&fep->napi);
 			fep->link = phy_dev->link;
 			status_change = 1;
 		}
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 094/222] net:fec: fix ethtool set_pauseparam duplex bug
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (92 preceding siblings ...)
  2014-04-25 11:38 ` [PATCH 093/222] net:fec: quiesce packet processing when taking link down in fec_enet_adjust_link() Russell King
@ 2014-04-25 11:38 ` Russell King
  2014-04-25 11:39 ` [PATCH 095/222] net:fec: clean up duplex mode handling Russell King
                   ` (128 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:38 UTC (permalink / raw)
  To: linux-arm-kernel

Setting the pause parameters causes a running network interface to be
restarted.  However, the restart forces the FEC into half-duplex mode,
whether or not the remote end is in half-duplex mode.  Misconfigured
duplex mode is a known source of problems on a link.

Fix this by always preserving the duplex mode on configuration changes.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 6156d423a6a9..c79d604372a4 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1572,7 +1572,7 @@ static int fec_enet_set_pauseparam(struct net_device *ndev,
 	if (netif_running(ndev)) {
 		napi_disable(&fep->napi);
 		netif_tx_lock_bh(ndev);
-		fec_restart(ndev, 0);
+		fec_restart(ndev, fep->full_duplex);
 		netif_wake_queue(ndev);
 		netif_tx_unlock_bh(ndev);
 		napi_enable(&fep->napi);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 095/222] net:fec: clean up duplex mode handling
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (93 preceding siblings ...)
  2014-04-25 11:38 ` [PATCH 094/222] net:fec: fix ethtool set_pauseparam duplex bug Russell King
@ 2014-04-25 11:39 ` Russell King
  2014-04-25 11:39 ` [PATCH 096/222] net:fec: add barrier to transmit path to ensure proper ordering Russell King
                   ` (127 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:39 UTC (permalink / raw)
  To: linux-arm-kernel

Many places call fec_restart() with the second parameter being some kind
of previously saved duplex value, but only two places call it with some
other setting.  This is at odds with how the other link settings are
handled, and used to be racy before the rtnl locks were added to
fec_restart()'s various call paths.

Clean this up so all link capabilities are handled in the same way -
saved into the fec_enet_private structure, and then fec_restart() acts
on those settings.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index c79d604372a4..d5ad0c70e6a0 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -521,7 +521,7 @@ static void fec_enet_bd_init(struct net_device *dev)
  * packet processing for this device must be stopped before this call.
  */
 static void
-fec_restart(struct net_device *ndev, int duplex)
+fec_restart(struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	const struct platform_device_id *id_entry =
@@ -572,7 +572,7 @@ fec_restart(struct net_device *ndev, int duplex)
 	}
 
 	/* Enable MII mode */
-	if (duplex) {
+	if (fep->full_duplex == DUPLEX_FULL) {
 		/* FD enable */
 		writel(0x04, fep->hwp + FEC_X_CNTRL);
 	} else {
@@ -581,8 +581,6 @@ fec_restart(struct net_device *ndev, int duplex)
 		writel(0x0, fep->hwp + FEC_X_CNTRL);
 	}
 
-	fep->full_duplex = duplex;
-
 	/* Set MII speed */
 	writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
 
@@ -759,7 +757,7 @@ static void fec_enet_work(struct work_struct *work)
 		if (netif_device_present(ndev) || netif_running(ndev)) {
 			napi_disable(&fep->napi);
 			netif_tx_lock_bh(ndev);
-			fec_restart(ndev, fep->full_duplex);
+			fec_restart(ndev);
 			netif_wake_queue(ndev);
 			netif_tx_unlock_bh(ndev);
 			napi_enable(&fep->napi);
@@ -1207,8 +1205,10 @@ static void fec_enet_adjust_link(struct net_device *ndev)
 			status_change = 1;
 		}
 
-		if (fep->full_duplex != phy_dev->duplex)
+		if (fep->full_duplex != phy_dev->duplex) {
+			fep->full_duplex = phy_dev->duplex;
 			status_change = 1;
+		}
 
 		if (phy_dev->speed != fep->speed) {
 			fep->speed = phy_dev->speed;
@@ -1219,7 +1219,7 @@ static void fec_enet_adjust_link(struct net_device *ndev)
 		if (status_change) {
 			napi_disable(&fep->napi);
 			netif_tx_lock_bh(ndev);
-			fec_restart(ndev, phy_dev->duplex);
+			fec_restart(ndev);
 			netif_wake_queue(ndev);
 			netif_tx_unlock_bh(ndev);
 			napi_enable(&fep->napi);
@@ -1572,7 +1572,7 @@ static int fec_enet_set_pauseparam(struct net_device *ndev,
 	if (netif_running(ndev)) {
 		napi_disable(&fep->napi);
 		netif_tx_lock_bh(ndev);
-		fec_restart(ndev, fep->full_duplex);
+		fec_restart(ndev);
 		netif_wake_queue(ndev);
 		netif_tx_unlock_bh(ndev);
 		napi_enable(&fep->napi);
@@ -1850,7 +1850,7 @@ fec_enet_open(struct net_device *ndev)
 		return ret;
 	}
 
-	fec_restart(ndev, fep->full_duplex);
+	fec_restart(ndev);
 	napi_enable(&fep->napi);
 	phy_start(fep->phy_dev);
 	netif_start_queue(ndev);
@@ -2024,7 +2024,7 @@ static int fec_set_features(struct net_device *netdev,
 
 	/* Resume the device after updates */
 	if (netif_running(netdev) && changed & FEATURES_NEED_QUIESCE) {
-		fec_restart(netdev, fep->phy_dev->duplex);
+		fec_restart(netdev);
 		netif_wake_queue(netdev);
 		netif_tx_unlock_bh(netdev);
 		napi_enable(&fep->napi);
@@ -2110,7 +2110,7 @@ static int fec_enet_init(struct net_device *ndev)
 		fep->csum_flags |= FLAG_RX_CSUM_ENABLED;
 	}
 
-	fec_restart(ndev, 0);
+	fec_restart(ndev);
 
 	return 0;
 }
@@ -2422,7 +2422,7 @@ fec_resume(struct device *dev)
 
 	rtnl_lock();
 	if (netif_running(ndev)) {
-		fec_restart(ndev, fep->full_duplex);
+		fec_restart(ndev);
 		netif_tx_lock_bh(ndev);
 		netif_device_attach(ndev);
 		netif_tx_unlock_bh(ndev);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 096/222] net:fec: add barrier to transmit path to ensure proper ordering
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (94 preceding siblings ...)
  2014-04-25 11:39 ` [PATCH 095/222] net:fec: clean up duplex mode handling Russell King
@ 2014-04-25 11:39 ` Russell King
  2014-04-25 11:39 ` [PATCH 097/222] net:fec: add barrier to receive " Russell King
                   ` (126 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:39 UTC (permalink / raw)
  To: linux-arm-kernel

Ensure that the writes to the descriptor data is visible to the hardware
before the descriptor is handed over to the hardware.

Having discussed this with Will Deacon, we need a wmb() between writing
the descriptor data and handing the descriptor over to the hardware.
The corresponding rmb() is in the ethernet hardware.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index d5ad0c70e6a0..2d9a6493b33b 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -436,6 +436,13 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 		}
 	}
 
+	/*
+	 * We need the preceding stores to the descriptor to complete
+	 * before updating the status field, which hands it over to the
+	 * hardware.  The corresponding rmb() is "in the hardware".
+	 */
+	wmb();
+
 	/* Send it on its way.  Tell FEC it's ready, interrupt when done,
 	 * it's the last BD of the frame, and to put the CRC on the end.
 	 */
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 097/222] net:fec: add barrier to receive path to ensure proper ordering
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (95 preceding siblings ...)
  2014-04-25 11:39 ` [PATCH 096/222] net:fec: add barrier to transmit path to ensure proper ordering Russell King
@ 2014-04-25 11:39 ` Russell King
  2014-04-25 11:39 ` [PATCH 098/222] net:fec: better implementation of iMX6 ERR006358 quirk Russell King
                   ` (125 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:39 UTC (permalink / raw)
  To: linux-arm-kernel

Just as we need a barrier in the transmit path, we also need a barrier
in the receive path to ensure that we don't modify a handed over
descriptor.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 2d9a6493b33b..9d2023b3e5ce 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1036,13 +1036,6 @@ fec_enet_rx(struct net_device *ndev, int budget)
 		dma_sync_single_for_device(&fep->pdev->dev, bdp->cbd_bufaddr,
 					FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
 rx_processing_done:
-		/* Clear the status flags for this buffer */
-		status &= ~BD_ENET_RX_STATS;
-
-		/* Mark the buffer empty */
-		status |= BD_ENET_RX_EMPTY;
-		bdp->cbd_sc = status;
-
 		if (fep->bufdesc_ex) {
 			struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
 
@@ -1051,6 +1044,19 @@ fec_enet_rx(struct net_device *ndev, int budget)
 			ebdp->cbd_bdu = 0;
 		}
 
+		/*
+		 * Ensure that the previous writes have completed before
+		 * the status update becomes visible.
+		 */
+		wmb();
+
+		/* Clear the status flags for this buffer */
+		status &= ~BD_ENET_RX_STATS;
+
+		/* Mark the buffer empty */
+		status |= BD_ENET_RX_EMPTY;
+		bdp->cbd_sc = status;
+
 		/* Update BD pointer to next entry */
 		bdp = fec_enet_get_nextdesc(bdp, fep);
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 098/222] net:fec: better implementation of iMX6 ERR006358 quirk
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (96 preceding siblings ...)
  2014-04-25 11:39 ` [PATCH 097/222] net:fec: add barrier to receive " Russell King
@ 2014-04-25 11:39 ` Russell King
  2014-04-25 11:39 ` [PATCH 099/222] net:fec: avoid hitting transmitter if it is still running Russell King
                   ` (124 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:39 UTC (permalink / raw)
  To: linux-arm-kernel

Using a (delayed) workqueue for ERR006358 is not correct - a work queue
is a single-trigger device.  Once the work queue has been scheduled, it
can't be re-scheduled until it has been run.  This can cause problems -
with an appropriate packet timing, we can end up with packets queued,
but not sent by the hardware, resulting in the transmit timeout firing.

Re-implement this as per the workaround detailed in the ERR006358
documentation - if there are packets waiting to be sent when we service
the transmit ring, and we see that the transmitter is not running,
kick the transmitter to run the pending entries in the ring.

Testing here with a 10Mbit half duplex link sees the resulting iperf
TCP bandwidth increase from between 1 to 2Mbps to between 8 to 9Mbps.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec.h      |  1 -
 drivers/net/ethernet/freescale/fec_main.c | 20 +++++++-------------
 2 files changed, 7 insertions(+), 14 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 88ef53b18ae7..d124a19e3fe8 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -259,7 +259,6 @@ struct bufdesc_ex {
 struct fec_enet_delayed_work {
 	struct delayed_work delay_work;
 	bool timeout;
-	bool trig_tx;
 };
 
 /* The FEC buffer descriptors track the ring buffers.  The rx_bd_base and
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 9d2023b3e5ce..7e48d1960bf0 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -344,7 +344,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	const struct platform_device_id *id_entry =
 				platform_get_device_id(fep->pdev);
-	struct bufdesc *bdp, *bdp_pre;
+	struct bufdesc *bdp;
 	void *bufaddr;
 	unsigned short	status;
 	unsigned int index;
@@ -450,13 +450,6 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 			| BD_ENET_TX_LAST | BD_ENET_TX_TC);
 	bdp->cbd_sc = status;
 
-	bdp_pre = fec_enet_get_prevdesc(bdp, fep);
-	if ((id_entry->driver_data & FEC_QUIRK_ERR006358) &&
-	    !(bdp_pre->cbd_sc & BD_ENET_TX_READY)) {
-		fep->delay_work.trig_tx = true;
-		schedule_delayed_work(&(fep->delay_work.delay_work),
-					msecs_to_jiffies(1));
-	}
 
 	/* If this was the last BD in the ring, start at the beginning again. */
 	bdp = fec_enet_get_nextdesc(bdp, fep);
@@ -771,11 +764,6 @@ static void fec_enet_work(struct work_struct *work)
 		}
 		rtnl_unlock();
 	}
-
-	if (fep->delay_work.trig_tx) {
-		fep->delay_work.trig_tx = false;
-		writel(0, fep->hwp + FEC_X_DES_ACTIVE);
-	}
 }
 
 static void
@@ -868,6 +856,12 @@ fec_enet_tx(struct net_device *ndev)
 				netif_wake_queue(ndev);
 		}
 	}
+
+	/* ERR006538: Keep the transmitter going */
+	if (fep->dirty_tx != fep->cur_tx &&
+	    readl(fep->hwp + FEC_X_DES_ACTIVE) == 0)
+		writel(0, fep->hwp + FEC_X_DES_ACTIVE);
+
 	return;
 }
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 099/222] net:fec: avoid hitting transmitter if it is still running
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (97 preceding siblings ...)
  2014-04-25 11:39 ` [PATCH 098/222] net:fec: better implementation of iMX6 ERR006358 quirk Russell King
@ 2014-04-25 11:39 ` Russell King
  2014-04-25 11:39 ` [PATCH 100/222] net:fec: remove delayed work Russell King
                   ` (123 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:39 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 7e48d1960bf0..bf186cc54891 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -462,7 +462,8 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 		netif_stop_queue(ndev);
 
 	/* Trigger transmission start */
-	writel(0, fep->hwp + FEC_X_DES_ACTIVE);
+	if (readl(fep->hwp + FEC_X_DES_ACTIVE) == 0)
+		writel(0, fep->hwp + FEC_X_DES_ACTIVE);
 
 	return NETDEV_TX_OK;
 }
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 100/222] net:fec: remove delayed work
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (98 preceding siblings ...)
  2014-04-25 11:39 ` [PATCH 099/222] net:fec: avoid hitting transmitter if it is still running Russell King
@ 2014-04-25 11:39 ` Russell King
  2014-04-25 11:39 ` [PATCH 101/222] net:fec: fix interrupt handling races Russell King
                   ` (122 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:39 UTC (permalink / raw)
  To: linux-arm-kernel

We no longer need a delayed work in this driver, since we no longer have
the requirement to delay any work - instead, use a work_struct directly.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec.h      |  8 ++------
 drivers/net/ethernet/freescale/fec_main.c | 34 +++++++++++++------------------
 2 files changed, 16 insertions(+), 26 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index d124a19e3fe8..aecc46c33a82 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -256,11 +256,6 @@ struct bufdesc_ex {
 #define FLAG_RX_CSUM_ENABLED	(BD_ENET_RX_ICE | BD_ENET_RX_PCR)
 #define FLAG_RX_CSUM_ERROR	(BD_ENET_RX_ICE | BD_ENET_RX_PCR)
 
-struct fec_enet_delayed_work {
-	struct delayed_work delay_work;
-	bool timeout;
-};
-
 /* The FEC buffer descriptors track the ring buffers.  The rx_bd_base and
  * tx_bd_base always point to the base of the buffer descriptors.  The
  * cur_rx and cur_tx point to the currently available buffer.
@@ -319,6 +314,8 @@ struct fec_enet_private {
 	struct	napi_struct napi;
 	int	csum_flags;
 
+	struct work_struct tx_timeout_work;
+
 	struct ptp_clock *ptp_clock;
 	struct ptp_clock_info ptp_caps;
 	unsigned long last_overflow_check;
@@ -331,7 +328,6 @@ struct fec_enet_private {
 	int hwts_rx_en;
 	int hwts_tx_en;
 	struct timer_list time_keep;
-	struct fec_enet_delayed_work delay_work;
 	struct regulator *reg_phy;
 };
 
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index bf186cc54891..3de6634867a6 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -740,31 +740,25 @@ fec_timeout(struct net_device *ndev)
 
 	ndev->stats.tx_errors++;
 
-	fep->delay_work.timeout = true;
-	schedule_delayed_work(&(fep->delay_work.delay_work), 0);
+	schedule_work(&fep->tx_timeout_work);
 }
 
-static void fec_enet_work(struct work_struct *work)
+static void fec_enet_timeout_work(struct work_struct *work)
 {
 	struct fec_enet_private *fep =
-		container_of(work,
-			     struct fec_enet_private,
-			     delay_work.delay_work.work);
+		container_of(work, struct fec_enet_private, tx_timeout_work);
 	struct net_device *ndev = fep->netdev;
 
-	if (fep->delay_work.timeout) {
-		fep->delay_work.timeout = false;
-		rtnl_lock();
-		if (netif_device_present(ndev) || netif_running(ndev)) {
-			napi_disable(&fep->napi);
-			netif_tx_lock_bh(ndev);
-			fec_restart(ndev);
-			netif_wake_queue(ndev);
-			netif_tx_unlock_bh(ndev);
-			napi_enable(&fep->napi);
-		}
-		rtnl_unlock();
+	rtnl_lock();
+	if (netif_device_present(ndev) || netif_running(ndev)) {
+		napi_disable(&fep->napi);
+		netif_tx_lock_bh(ndev);
+		fec_restart(ndev);
+		netif_wake_queue(ndev);
+		netif_tx_unlock_bh(ndev);
+		napi_enable(&fep->napi);
 	}
+	rtnl_unlock();
 }
 
 static void
@@ -2312,7 +2306,7 @@ fec_probe(struct platform_device *pdev)
 	if (fep->bufdesc_ex && fep->ptp_clock)
 		netdev_info(ndev, "registered PHC device %d\n", fep->dev_id);
 
-	INIT_DELAYED_WORK(&(fep->delay_work.delay_work), fec_enet_work);
+	INIT_WORK(&fep->tx_timeout_work, fec_enet_timeout_work);
 	return 0;
 
 failed_register:
@@ -2345,7 +2339,7 @@ fec_drv_remove(struct platform_device *pdev)
 	struct net_device *ndev = platform_get_drvdata(pdev);
 	struct fec_enet_private *fep = netdev_priv(ndev);
 
-	cancel_delayed_work_sync(&(fep->delay_work.delay_work));
+	cancel_work_sync(&fep->tx_timeout_work);
 	unregister_netdev(ndev);
 	fec_enet_mii_remove(fep);
 	del_timer_sync(&fep->time_keep);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 101/222] net:fec: fix interrupt handling races
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (99 preceding siblings ...)
  2014-04-25 11:39 ` [PATCH 100/222] net:fec: remove delayed work Russell King
@ 2014-04-25 11:39 ` Russell King
  2014-04-25 11:39 ` [PATCH 102/222] net:fec: clear receive interrupts before processing a packet Russell King
                   ` (121 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:39 UTC (permalink / raw)
  To: linux-arm-kernel

While running: while :; do iperf -c <HOST> -P 4; done, transmit timeouts
are regularly reported.  With the tx ring dumping in place, we can see
that all entries are in use, and the hardware has finished transmitting
these packets.  However, the driver has not reclaimed these ring
entries.

This can occur if the interrupt handler is invoked at the wrong moment -
eg:

	CPU0				CPU1
	fec_enet_tx()
					interrupt, IEVENT = FEC_ENET_TXF
					FEC_ENET_TXF cleared
					napi_schedule_prep()
	napi_complete()

The result is that we clear the transmit interrupt, but we don't trigger
any cleaning of the transmit ring.  Instead, use a different strategy:

- When receiving a transmit or receive interrupt, disable both tx and rx
  interrupts, but do not acknowledge them.  Schedule a napi poll.  Don't
  loop.

- When we are polled, read IEVENT, acknowledging the pending transmit
  and receive interrupts, before then going on to process the
  appropriate rings.

This allows us to avoid the race, and has a number of other advantages:
- we cut down on the number of transmit interrupts we have to process.
- we only look at the rings which have pending events.
- we gain additional throughput: the iperf total bandwidth increases
  from about 180Mbps to 240Mbps:

[  3]  0.0-10.0 sec  68.1 MBytes  57.0 Mbits/sec
[  5]  0.0-10.0 sec  72.4 MBytes  60.5 Mbits/sec
[  4]  0.0-10.1 sec  76.1 MBytes  63.5 Mbits/sec
[  6]  0.0-10.1 sec  71.9 MBytes  59.9 Mbits/sec
[SUM]  0.0-10.1 sec   288 MBytes   241 Mbits/sec

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 40 +++++++++++++++++--------------
 1 file changed, 22 insertions(+), 18 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 3de6634867a6..0d1580ebaede 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1065,29 +1065,25 @@ fec_enet_interrupt(int irq, void *dev_id)
 {
 	struct net_device *ndev = dev_id;
 	struct fec_enet_private *fep = netdev_priv(ndev);
+	const unsigned napi_mask = FEC_ENET_RXF | FEC_ENET_TXF;
 	uint int_events;
 	irqreturn_t ret = IRQ_NONE;
 
-	do {
-		int_events = readl(fep->hwp + FEC_IEVENT);
-		writel(int_events, fep->hwp + FEC_IEVENT);
+	int_events = readl(fep->hwp + FEC_IEVENT);
+	writel(int_events & ~napi_mask, fep->hwp + FEC_IEVENT);
 
-		if (int_events & (FEC_ENET_RXF | FEC_ENET_TXF)) {
-			ret = IRQ_HANDLED;
+	if (int_events & napi_mask) {
+		ret = IRQ_HANDLED;
 
-			/* Disable the RX interrupt */
-			if (napi_schedule_prep(&fep->napi)) {
-				writel(FEC_RX_DISABLED_IMASK,
-					fep->hwp + FEC_IMASK);
-				__napi_schedule(&fep->napi);
-			}
-		}
+		/* Disable the NAPI interrupts */
+		writel(FEC_ENET_MII, fep->hwp + FEC_IMASK);
+		napi_schedule(&fep->napi);
+	}
 
-		if (int_events & FEC_ENET_MII) {
-			ret = IRQ_HANDLED;
-			complete(&fep->mdio_done);
-		}
-	} while (int_events);
+	if (int_events & FEC_ENET_MII) {
+		ret = IRQ_HANDLED;
+		complete(&fep->mdio_done);
+	}
 
 	return ret;
 }
@@ -1095,8 +1091,16 @@ fec_enet_interrupt(int irq, void *dev_id)
 static int fec_enet_rx_napi(struct napi_struct *napi, int budget)
 {
 	struct net_device *ndev = napi->dev;
-	int pkts = fec_enet_rx(ndev, budget);
 	struct fec_enet_private *fep = netdev_priv(ndev);
+	int pkts;
+
+	/*
+	 * Clear any pending transmit or receive interrupts before
+	 * processing the rings to avoid racing with the hardware.
+	 */
+	writel(FEC_ENET_RXF | FEC_ENET_TXF, fep->hwp + FEC_IEVENT);
+
+	pkts = fec_enet_rx(ndev, budget);
 
 	fec_enet_tx(ndev);
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 102/222] net:fec: clear receive interrupts before processing a packet
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (100 preceding siblings ...)
  2014-04-25 11:39 ` [PATCH 101/222] net:fec: fix interrupt handling races Russell King
@ 2014-04-25 11:39 ` Russell King
  2014-04-25 11:39 ` [PATCH 103/222] net:fec: remove useless status check in tx reap path Russell King
                   ` (120 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:39 UTC (permalink / raw)
  To: linux-arm-kernel

Clear any pending receive interrupt before we process a pending packet.
This helps to avoid any spurious interrupts being raised after we have
fully cleaned the receive ring, while still allowing an interrupt to be
raised if we receive another packet.

The timing of this is critical: we must do this prior to reading the
next packet status to avoid delaying a pending packet.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 0d1580ebaede..51b00c77bf00 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -904,6 +904,8 @@ fec_enet_rx(struct net_device *ndev, int budget)
 		if ((status & BD_ENET_RX_LAST) == 0)
 			netdev_err(ndev, "rcv is not +last\n");
 
+		writel(FEC_ENET_RXF, fep->hwp + FEC_IEVENT);
+
 		/* Check for errors. */
 		if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
 			   BD_ENET_RX_CR | BD_ENET_RX_OV)) {
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 103/222] net:fec: remove useless status check in tx reap path
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (101 preceding siblings ...)
  2014-04-25 11:39 ` [PATCH 102/222] net:fec: clear receive interrupts before processing a packet Russell King
@ 2014-04-25 11:39 ` Russell King
  2014-04-25 11:39 ` [PATCH 104/222] net:fec: use a union for the buffer descriptors Russell King
                   ` (119 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:39 UTC (permalink / raw)
  To: linux-arm-kernel

Remove a useless status check in the transmit reap path - we have
already checked that the DB_ENET_TX_READY bit is clear, so there is
no way this test can ever be true.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 51b00c77bf00..c7fe6eb8be12 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -827,9 +827,6 @@ fec_enet_tx(struct net_device *ndev)
 			skb_tstamp_tx(skb, &shhwtstamps);
 		}
 
-		if (status & BD_ENET_TX_READY)
-			netdev_err(ndev, "HEY! Enet xmit interrupt and TX_READY\n");
-
 		/* Deferred means some collisions occurred during transmit,
 		 * but we eventually sent the packet OK.
 		 */
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 104/222] net:fec: use a union for the buffer descriptors
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (102 preceding siblings ...)
  2014-04-25 11:39 ` [PATCH 103/222] net:fec: remove useless status check in tx reap path Russell King
@ 2014-04-25 11:39 ` Russell King
  2014-04-25 11:39 ` [PATCH 105/222] net:fec: consolidate hwtstamp implementation Russell King
                   ` (118 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:39 UTC (permalink / raw)
  To: linux-arm-kernel

Using a union gives clearer C code than the existing solution, and
allows the removal of some odd code from the receive path whose
purpose was to merely store the enhanced buffer descriptor.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec.h      |  13 +-
 drivers/net/ethernet/freescale/fec_main.c | 194 ++++++++++++++----------------
 2 files changed, 96 insertions(+), 111 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index aecc46c33a82..30c683c0b480 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -170,6 +170,11 @@ struct bufdesc_ex {
 	unsigned short res0[4];
 };
 
+union bufdesc_u {
+	struct bufdesc bd;
+	struct bufdesc_ex ebd;
+};
+
 /*
  *	The following definitions courtesy of commproc.h, which where
  *	Copyright (c) 1997 Dan Malek (dmalek at jlc.net).
@@ -283,12 +288,12 @@ struct fec_enet_private {
 	/* CPM dual port RAM relative addresses */
 	dma_addr_t	bd_dma;
 	/* Address of Rx and Tx buffers */
-	struct bufdesc	*rx_bd_base;
-	struct bufdesc	*tx_bd_base;
+	union bufdesc_u	*rx_bd_base;
+	union bufdesc_u	*tx_bd_base;
 	/* The next free ring entry */
-	struct bufdesc	*cur_rx, *cur_tx;
+	union bufdesc_u	*cur_rx, *cur_tx;
 	/* The ring entries to be free()ed */
-	struct bufdesc	*dirty_tx;
+	union bufdesc_u	*dirty_tx;
 
 	unsigned short tx_ring_size;
 	unsigned short rx_ring_size;
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index c7fe6eb8be12..b9d0f0c8cae1 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -228,56 +228,53 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
 static int mii_cnt;
 
 static inline
-struct bufdesc *fec_enet_get_nextdesc(struct bufdesc *bdp, struct fec_enet_private *fep)
+union bufdesc_u *fec_enet_get_nextdesc(union bufdesc_u *bdp, struct fec_enet_private *fep)
 {
-	struct bufdesc *new_bd = bdp + 1;
-	struct bufdesc_ex *ex_new_bd = (struct bufdesc_ex *)bdp + 1;
-	struct bufdesc_ex *ex_base;
-	struct bufdesc *base;
+	union bufdesc_u *base;
 	int ring_size;
 
 	if (bdp >= fep->tx_bd_base) {
 		base = fep->tx_bd_base;
 		ring_size = fep->tx_ring_size;
-		ex_base = (struct bufdesc_ex *)fep->tx_bd_base;
 	} else {
 		base = fep->rx_bd_base;
 		ring_size = fep->rx_ring_size;
-		ex_base = (struct bufdesc_ex *)fep->rx_bd_base;
 	}
 
-	if (fep->bufdesc_ex)
-		return (struct bufdesc *)((ex_new_bd >= (ex_base + ring_size)) ?
-			ex_base : ex_new_bd);
-	else
-		return (new_bd >= (base + ring_size)) ?
-			base : new_bd;
+	if (fep->bufdesc_ex) {
+		struct bufdesc_ex *ebd = &bdp->ebd + 1;
+		return ebd >= (&base->ebd + ring_size) ?
+			base : (union bufdesc_u *)ebd;
+	} else {
+		struct bufdesc *bd = &bdp->bd + 1;
+		return bd >= (&base->bd + ring_size) ?
+			base : (union bufdesc_u *)bd;
+	}
 }
 
 static inline
-struct bufdesc *fec_enet_get_prevdesc(struct bufdesc *bdp, struct fec_enet_private *fep)
+union bufdesc_u *fec_enet_get_prevdesc(union bufdesc_u *bdp, struct fec_enet_private *fep)
 {
-	struct bufdesc *new_bd = bdp - 1;
-	struct bufdesc_ex *ex_new_bd = (struct bufdesc_ex *)bdp - 1;
-	struct bufdesc_ex *ex_base;
-	struct bufdesc *base;
+	union bufdesc_u *base;
 	int ring_size;
 
 	if (bdp >= fep->tx_bd_base) {
 		base = fep->tx_bd_base;
 		ring_size = fep->tx_ring_size;
-		ex_base = (struct bufdesc_ex *)fep->tx_bd_base;
 	} else {
 		base = fep->rx_bd_base;
 		ring_size = fep->rx_ring_size;
-		ex_base = (struct bufdesc_ex *)fep->rx_bd_base;
 	}
 
-	if (fep->bufdesc_ex)
-		return (struct bufdesc *)((ex_new_bd < ex_base) ?
-			(ex_new_bd + ring_size) : ex_new_bd);
-	else
-		return (new_bd < base) ? (new_bd + ring_size) : new_bd;
+	if (fep->bufdesc_ex) {
+		struct bufdesc_ex *ebd = &bdp->ebd - 1;
+		return (union bufdesc_u *)(ebd < &base->ebd ?
+			ebd + ring_size : ebd);
+	} else {
+		struct bufdesc *bd = &bdp->bd - 1;
+		return (union bufdesc_u *)(bd < &base->bd ?
+			bd + ring_size : bd);
+	}
 }
 
 static void *swap_buffer(void *bufaddr, int len)
@@ -294,7 +291,7 @@ static void *swap_buffer(void *bufaddr, int len)
 static void fec_dump(struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
-	struct bufdesc *bdp = fep->tx_bd_base;
+	union bufdesc_u *bdp = fep->tx_bd_base;
 	unsigned index = 0;
 
 	netdev_info(ndev, "TX ring dump\n");
@@ -305,7 +302,8 @@ static void fec_dump(struct net_device *ndev)
 			index,
 			bdp == fep->cur_tx ? 'S' : ' ',
 			bdp == fep->dirty_tx ? 'H' : ' ',
-			bdp->cbd_sc, bdp->cbd_bufaddr, bdp->cbd_datlen,
+			bdp->bd.cbd_sc, bdp->bd.cbd_bufaddr,
+			bdp->bd.cbd_datlen,
 			fep->tx_skbuff[index]);
 		bdp = fec_enet_get_nextdesc(bdp, fep);
 		index++;
@@ -328,12 +326,12 @@ fec_enet_clear_csum(struct sk_buff *skb, struct net_device *ndev)
 }
 
 static void
-fec_enet_tx_unmap(struct bufdesc *bdp, struct fec_enet_private *fep)
+fec_enet_tx_unmap(union bufdesc_u *bdp, struct fec_enet_private *fep)
 {
-	dma_addr_t addr = bdp->cbd_bufaddr;
-	unsigned length = bdp->cbd_datlen;
+	dma_addr_t addr = bdp->bd.cbd_bufaddr;
+	unsigned length = bdp->bd.cbd_datlen;
 
-	bdp->cbd_bufaddr = 0;
+	bdp->bd.cbd_bufaddr = 0;
 
 	dma_unmap_single(&fep->pdev->dev, addr, length, DMA_TO_DEVICE);
 }
@@ -344,7 +342,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	const struct platform_device_id *id_entry =
 				platform_get_device_id(fep->pdev);
-	struct bufdesc *bdp;
+	union bufdesc_u *bdp;
 	void *bufaddr;
 	unsigned short	status;
 	unsigned int index;
@@ -354,7 +352,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	/* Fill in a Tx ring entry */
 	bdp = fep->cur_tx;
 
-	status = bdp->cbd_sc;
+	status = bdp->bd.cbd_sc;
 
 	if (status & BD_ENET_TX_READY) {
 		/* Ooops.  All transmit buffers are full.  Bail out.
@@ -383,10 +381,9 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	 * and get it aligned. Ugh.
 	 */
 	if (fep->bufdesc_ex)
-		index = (struct bufdesc_ex *)bdp -
-			(struct bufdesc_ex *)fep->tx_bd_base;
+		index = &bdp->ebd - &fep->tx_bd_base->ebd;
 	else
-		index = bdp - fep->tx_bd_base;
+		index = &bdp->bd - &fep->tx_bd_base->bd;
 
 	if (((unsigned long) bufaddr) & FEC_ALIGNMENT) {
 		memcpy(fep->tx_bounce[index], skb->data, length);
@@ -413,26 +410,24 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	/* Save skb pointer */
 	fep->tx_skbuff[index] = skb;
 
-	bdp->cbd_datlen = length;
-	bdp->cbd_bufaddr = addr;
+	bdp->bd.cbd_datlen = length;
+	bdp->bd.cbd_bufaddr = addr;
 
 	if (fep->bufdesc_ex) {
-
-		struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
-		ebdp->cbd_bdu = 0;
+		bdp->ebd.cbd_bdu = 0;
 		if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
 			fep->hwts_tx_en)) {
-			ebdp->cbd_esc = (BD_ENET_TX_TS | BD_ENET_TX_INT);
+			bdp->ebd.cbd_esc = (BD_ENET_TX_TS | BD_ENET_TX_INT);
 			skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
 		} else {
-			ebdp->cbd_esc = BD_ENET_TX_INT;
+			bdp->ebd.cbd_esc = BD_ENET_TX_INT;
 
 			/* Enable protocol checksum flags
 			 * We do not bother with the IP Checksum bits as they
 			 * are done by the kernel
 			 */
 			if (skb->ip_summed == CHECKSUM_PARTIAL)
-				ebdp->cbd_esc |= BD_ENET_TX_PINS;
+				bdp->ebd.cbd_esc |= BD_ENET_TX_PINS;
 		}
 	}
 
@@ -448,8 +443,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	 */
 	status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR
 			| BD_ENET_TX_LAST | BD_ENET_TX_TC);
-	bdp->cbd_sc = status;
-
+	bdp->bd.cbd_sc = status;
 
 	/* If this was the last BD in the ring, start at the beginning again. */
 	bdp = fec_enet_get_nextdesc(bdp, fep);
@@ -473,7 +467,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 static void fec_enet_bd_init(struct net_device *dev)
 {
 	struct fec_enet_private *fep = netdev_priv(dev);
-	struct bufdesc *bdp;
+	union bufdesc_u *bdp;
 	unsigned int i;
 
 	/* Initialize the receive buffer descriptors. */
@@ -481,16 +475,16 @@ static void fec_enet_bd_init(struct net_device *dev)
 	for (i = 0; i < fep->rx_ring_size; i++) {
 
 		/* Initialize the BD for every fragment in the page. */
-		if (bdp->cbd_bufaddr)
-			bdp->cbd_sc = BD_ENET_RX_EMPTY;
+		if (bdp->bd.cbd_bufaddr)
+			bdp->bd.cbd_sc = BD_ENET_RX_EMPTY;
 		else
-			bdp->cbd_sc = 0;
+			bdp->bd.cbd_sc = 0;
 		bdp = fec_enet_get_nextdesc(bdp, fep);
 	}
 
 	/* Set the last buffer to wrap */
 	bdp = fec_enet_get_prevdesc(bdp, fep);
-	bdp->cbd_sc |= BD_SC_WRAP;
+	bdp->bd.cbd_sc |= BD_SC_WRAP;
 
 	fep->cur_rx = fep->rx_bd_base;
 
@@ -500,8 +494,8 @@ static void fec_enet_bd_init(struct net_device *dev)
 	for (i = 0; i < fep->tx_ring_size; i++) {
 
 		/* Initialize the BD for every fragment in the page. */
-		bdp->cbd_sc = 0;
-		if (bdp->cbd_bufaddr)
+		bdp->bd.cbd_sc = 0;
+		if (bdp->bd.cbd_bufaddr)
 			fec_enet_tx_unmap(bdp, fep);
 		if (fep->tx_skbuff[i]) {
 			dev_kfree_skb_any(fep->tx_skbuff[i]);
@@ -512,7 +506,7 @@ static void fec_enet_bd_init(struct net_device *dev)
 
 	/* Set the last buffer to wrap */
 	bdp = fec_enet_get_prevdesc(bdp, fep);
-	bdp->cbd_sc |= BD_SC_WRAP;
+	bdp->bd.cbd_sc |= BD_SC_WRAP;
 	fep->dirty_tx = bdp;
 }
 
@@ -765,7 +759,7 @@ static void
 fec_enet_tx(struct net_device *ndev)
 {
 	struct	fec_enet_private *fep;
-	struct bufdesc *bdp;
+	union bufdesc_u *bdp;
 	unsigned short status;
 	struct	sk_buff	*skb;
 	int	index = 0;
@@ -776,17 +770,16 @@ fec_enet_tx(struct net_device *ndev)
 	/* get next bdp of dirty_tx */
 	bdp = fec_enet_get_nextdesc(bdp, fep);
 
-	while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) {
+	while (((status = bdp->bd.cbd_sc) & BD_ENET_TX_READY) == 0) {
 
 		/* current queue is empty */
 		if (bdp == fep->cur_tx)
 			break;
 
 		if (fep->bufdesc_ex)
-			index = (struct bufdesc_ex *)bdp -
-				(struct bufdesc_ex *)fep->tx_bd_base;
+			index = &bdp->ebd - &fep->tx_bd_base->ebd;
 		else
-			index = bdp - fep->tx_bd_base;
+			index = &bdp->bd - &fep->tx_bd_base->bd;
 
 		fec_enet_tx_unmap(bdp, fep);
 
@@ -810,19 +803,18 @@ fec_enet_tx(struct net_device *ndev)
 				ndev->stats.tx_carrier_errors++;
 		} else {
 			ndev->stats.tx_packets++;
-			ndev->stats.tx_bytes += bdp->cbd_datlen;
+			ndev->stats.tx_bytes += bdp->bd.cbd_datlen;
 		}
 
 		if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS) &&
 			fep->bufdesc_ex) {
 			struct skb_shared_hwtstamps shhwtstamps;
 			unsigned long flags;
-			struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
 
 			memset(&shhwtstamps, 0, sizeof(shhwtstamps));
 			spin_lock_irqsave(&fep->tmreg_lock, flags);
 			shhwtstamps.hwtstamp = ns_to_ktime(
-				timecounter_cyc2time(&fep->tc, ebdp->ts));
+				timecounter_cyc2time(&fep->tc, bdp->ebd.ts));
 			spin_unlock_irqrestore(&fep->tmreg_lock, flags);
 			skb_tstamp_tx(skb, &shhwtstamps);
 		}
@@ -869,13 +861,12 @@ fec_enet_rx(struct net_device *ndev, int budget)
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	const struct platform_device_id *id_entry =
 				platform_get_device_id(fep->pdev);
-	struct bufdesc *bdp;
+	union bufdesc_u *bdp;
 	unsigned short status;
 	struct	sk_buff	*skb;
 	ushort	pkt_len;
 	__u8 *data;
 	int	pkt_received = 0;
-	struct	bufdesc_ex *ebdp = NULL;
 	bool	vlan_packet_rcvd = false;
 	u16	vlan_tag;
 	int	index = 0;
@@ -889,7 +880,7 @@ fec_enet_rx(struct net_device *ndev, int budget)
 	 */
 	bdp = fep->cur_rx;
 
-	while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
+	while (!((status = bdp->bd.cbd_sc) & BD_ENET_RX_EMPTY)) {
 
 		if (pkt_received >= budget)
 			break;
@@ -931,30 +922,24 @@ fec_enet_rx(struct net_device *ndev, int budget)
 
 		/* Process the incoming frame. */
 		ndev->stats.rx_packets++;
-		pkt_len = bdp->cbd_datlen;
+		pkt_len = bdp->bd.cbd_datlen;
 		ndev->stats.rx_bytes += pkt_len;
 
 		if (fep->bufdesc_ex)
-			index = (struct bufdesc_ex *)bdp -
-				(struct bufdesc_ex *)fep->rx_bd_base;
+			index = &bdp->ebd - &fep->rx_bd_base->ebd;
 		else
-			index = bdp - fep->rx_bd_base;
+			index = &bdp->bd - &fep->rx_bd_base->bd;
 		data = fep->rx_skbuff[index]->data;
-		dma_sync_single_for_cpu(&fep->pdev->dev, bdp->cbd_bufaddr,
+		dma_sync_single_for_cpu(&fep->pdev->dev, bdp->bd.cbd_bufaddr,
 					FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
 
 		if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
 			swap_buffer(data, pkt_len);
 
-		/* Extract the enhanced buffer descriptor */
-		ebdp = NULL;
-		if (fep->bufdesc_ex)
-			ebdp = (struct bufdesc_ex *)bdp;
-
 		/* If this is a VLAN packet remove the VLAN Tag */
 		vlan_packet_rcvd = false;
 		if ((ndev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
-		    fep->bufdesc_ex && (ebdp->cbd_esc & BD_ENET_RX_VLAN)) {
+		    fep->bufdesc_ex && (bdp->ebd.cbd_esc & BD_ENET_RX_VLAN)) {
 			/* Push and remove the vlan tag */
 			struct vlan_hdr *vlan_header =
 					(struct vlan_hdr *) (data + ETH_HLEN);
@@ -998,13 +983,13 @@ fec_enet_rx(struct net_device *ndev, int budget)
 
 				spin_lock_irqsave(&fep->tmreg_lock, flags);
 				shhwtstamps->hwtstamp = ns_to_ktime(
-				    timecounter_cyc2time(&fep->tc, ebdp->ts));
+				    timecounter_cyc2time(&fep->tc, bdp->ebd.ts));
 				spin_unlock_irqrestore(&fep->tmreg_lock, flags);
 			}
 
 			if (fep->bufdesc_ex &&
 			    (fep->csum_flags & FLAG_RX_CSUM_ENABLED)) {
-				if (!(ebdp->cbd_esc & FLAG_RX_CSUM_ERROR)) {
+				if (!(bdp->ebd.cbd_esc & FLAG_RX_CSUM_ERROR)) {
 					/* don't check it */
 					skb->ip_summed = CHECKSUM_UNNECESSARY;
 				} else {
@@ -1021,15 +1006,13 @@ fec_enet_rx(struct net_device *ndev, int budget)
 			napi_gro_receive(&fep->napi, skb);
 		}
 
-		dma_sync_single_for_device(&fep->pdev->dev, bdp->cbd_bufaddr,
+		dma_sync_single_for_device(&fep->pdev->dev, bdp->bd.cbd_bufaddr,
 					FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
 rx_processing_done:
 		if (fep->bufdesc_ex) {
-			struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
-
-			ebdp->cbd_esc = BD_ENET_RX_INT;
-			ebdp->cbd_prot = 0;
-			ebdp->cbd_bdu = 0;
+			bdp->ebd.cbd_esc = BD_ENET_RX_INT;
+			bdp->ebd.cbd_prot = 0;
+			bdp->ebd.cbd_bdu = 0;
 		}
 
 		/*
@@ -1043,7 +1026,7 @@ fec_enet_rx(struct net_device *ndev, int budget)
 
 		/* Mark the buffer empty */
 		status |= BD_ENET_RX_EMPTY;
-		bdp->cbd_sc = status;
+		bdp->bd.cbd_sc = status;
 
 		/* Update BD pointer to next entry */
 		bdp = fec_enet_get_nextdesc(bdp, fep);
@@ -1739,14 +1722,14 @@ static void fec_enet_free_buffers(struct net_device *ndev)
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	unsigned int i;
 	struct sk_buff *skb;
-	struct bufdesc	*bdp;
+	union bufdesc_u *bdp;
 
 	bdp = fep->rx_bd_base;
 	for (i = 0; i < fep->rx_ring_size; i++) {
 		skb = fep->rx_skbuff[i];
 		fep->rx_skbuff[i] = NULL;
 		if (skb) {
-			dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
+			dma_unmap_single(&fep->pdev->dev, bdp->bd.cbd_bufaddr,
 					FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
 			dev_kfree_skb(skb);
 		}
@@ -1755,7 +1738,7 @@ static void fec_enet_free_buffers(struct net_device *ndev)
 
 	bdp = fep->tx_bd_base;
 	for (i = 0; i < fep->tx_ring_size; i++) {
-		if (bdp->cbd_bufaddr)
+		if (bdp->bd.cbd_bufaddr)
 			fec_enet_tx_unmap(bdp, fep);
 		kfree(fep->tx_bounce[i]);
 		fep->tx_bounce[i] = NULL;
@@ -1771,7 +1754,7 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	unsigned int i;
 	struct sk_buff *skb;
-	struct bufdesc	*bdp;
+	union bufdesc_u *bdp;
 
 	bdp = fep->rx_bd_base;
 	for (i = 0; i < fep->rx_ring_size; i++) {
@@ -1791,20 +1774,18 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
 		}
 
 		fep->rx_skbuff[i] = skb;
-		bdp->cbd_bufaddr = addr;
-		bdp->cbd_sc = BD_ENET_RX_EMPTY;
+		bdp->bd.cbd_bufaddr = addr;
+		bdp->bd.cbd_sc = BD_ENET_RX_EMPTY;
 
-		if (fep->bufdesc_ex) {
-			struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
-			ebdp->cbd_esc = BD_ENET_RX_INT;
-		}
+		if (fep->bufdesc_ex)
+			bdp->ebd.cbd_esc = BD_ENET_RX_INT;
 
 		bdp = fec_enet_get_nextdesc(bdp, fep);
 	}
 
 	/* Set the last buffer to wrap. */
 	bdp = fec_enet_get_prevdesc(bdp, fep);
-	bdp->cbd_sc |= BD_SC_WRAP;
+	bdp->bd.cbd_sc |= BD_SC_WRAP;
 
 	bdp = fep->tx_bd_base;
 	for (i = 0; i < fep->tx_ring_size; i++) {
@@ -1812,20 +1793,18 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
 		if (!fep->tx_bounce[i])
 			goto err_alloc;
 
-		bdp->cbd_sc = 0;
-		bdp->cbd_bufaddr = 0;
+		bdp->bd.cbd_sc = 0;
+		bdp->bd.cbd_bufaddr = 0;
 
-		if (fep->bufdesc_ex) {
-			struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
-			ebdp->cbd_esc = BD_ENET_TX_INT;
-		}
+		if (fep->bufdesc_ex)
+			bdp->ebd.cbd_esc = BD_ENET_TX_INT;
 
 		bdp = fec_enet_get_nextdesc(bdp, fep);
 	}
 
 	/* Set the last buffer to wrap. */
 	bdp = fec_enet_get_prevdesc(bdp, fep);
-	bdp->cbd_sc |= BD_SC_WRAP;
+	bdp->bd.cbd_sc |= BD_SC_WRAP;
 
 	return 0;
 
@@ -2063,7 +2042,7 @@ static int fec_enet_init(struct net_device *ndev)
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	const struct platform_device_id *id_entry =
 				platform_get_device_id(fep->pdev);
-	struct bufdesc *cbd_base;
+	union bufdesc_u *cbd_base;
 
 	/* Allocate memory for buffer descriptors. */
 	cbd_base = dma_alloc_coherent(NULL, PAGE_SIZE, &fep->bd_dma,
@@ -2087,10 +2066,11 @@ static int fec_enet_init(struct net_device *ndev)
 	/* Set receive and transmit descriptor base. */
 	fep->rx_bd_base = cbd_base;
 	if (fep->bufdesc_ex)
-		fep->tx_bd_base = (struct bufdesc *)
-			(((struct bufdesc_ex *)cbd_base) + fep->rx_ring_size);
+		fep->tx_bd_base = (union bufdesc_u *)
+			(&cbd_base->ebd + fep->rx_ring_size);
 	else
-		fep->tx_bd_base = cbd_base + fep->rx_ring_size;
+		fep->tx_bd_base = (union bufdesc_u *)
+			(&cbd_base->bd + fep->rx_ring_size);
 
 	/* The FEC Ethernet specific entries in the device structure */
 	ndev->watchdog_timeo = TX_TIMEOUT;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 105/222] net:fec: consolidate hwtstamp implementation
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (103 preceding siblings ...)
  2014-04-25 11:39 ` [PATCH 104/222] net:fec: use a union for the buffer descriptors Russell King
@ 2014-04-25 11:39 ` Russell King
  2014-04-25 11:39 ` [PATCH 106/222] net:fec: better indexing for transmit descriptor ring Russell King
                   ` (117 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:39 UTC (permalink / raw)
  To: linux-arm-kernel

Both transmit and receive use the same infrastructure for calculating
the packet timestamp.  Rather than duplicating the code, provide a
function to do this common work.  Model this function in the Intel
e1000e version which avoids calling ns_to_ktime() within the spinlock;
the spinlock is critical for timecounter_cyc2time() but not
ns_to_ktime().

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 37 ++++++++++++++++---------------
 1 file changed, 19 insertions(+), 18 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index b9d0f0c8cae1..01e43a75089d 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -756,6 +756,21 @@ static void fec_enet_timeout_work(struct work_struct *work)
 }
 
 static void
+fec_enet_hwtstamp(struct fec_enet_private *fep, unsigned ts,
+	struct skb_shared_hwtstamps *hwtstamps)
+{
+	unsigned long flags;
+	u64 ns;
+
+	spin_lock_irqsave(&fep->tmreg_lock, flags);
+	ns = timecounter_cyc2time(&fep->tc, ts);
+	spin_unlock_irqrestore(&fep->tmreg_lock, flags);
+
+	memset(hwtstamps, 0, sizeof(*hwtstamps));
+	hwtstamps->hwtstamp = ns_to_ktime(ns);
+}
+
+static void
 fec_enet_tx(struct net_device *ndev)
 {
 	struct	fec_enet_private *fep;
@@ -809,13 +824,8 @@ fec_enet_tx(struct net_device *ndev)
 		if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS) &&
 			fep->bufdesc_ex) {
 			struct skb_shared_hwtstamps shhwtstamps;
-			unsigned long flags;
 
-			memset(&shhwtstamps, 0, sizeof(shhwtstamps));
-			spin_lock_irqsave(&fep->tmreg_lock, flags);
-			shhwtstamps.hwtstamp = ns_to_ktime(
-				timecounter_cyc2time(&fep->tc, bdp->ebd.ts));
-			spin_unlock_irqrestore(&fep->tmreg_lock, flags);
+			fec_enet_hwtstamp(fep, bdp->ebd.ts, &shhwtstamps);
 			skb_tstamp_tx(skb, &shhwtstamps);
 		}
 
@@ -974,18 +984,9 @@ fec_enet_rx(struct net_device *ndev, int budget)
 			skb->protocol = eth_type_trans(skb, ndev);
 
 			/* Get receive timestamp from the skb */
-			if (fep->hwts_rx_en && fep->bufdesc_ex) {
-				struct skb_shared_hwtstamps *shhwtstamps =
-							    skb_hwtstamps(skb);
-				unsigned long flags;
-
-				memset(shhwtstamps, 0, sizeof(*shhwtstamps));
-
-				spin_lock_irqsave(&fep->tmreg_lock, flags);
-				shhwtstamps->hwtstamp = ns_to_ktime(
-				    timecounter_cyc2time(&fep->tc, bdp->ebd.ts));
-				spin_unlock_irqrestore(&fep->tmreg_lock, flags);
-			}
+			if (fep->hwts_rx_en && fep->bufdesc_ex)
+				fec_enet_hwtstamp(fep, bdp->ebd.ts,
+						  skb_hwtstamps(skb));
 
 			if (fep->bufdesc_ex &&
 			    (fep->csum_flags & FLAG_RX_CSUM_ENABLED)) {
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 106/222] net:fec: better indexing for transmit descriptor ring
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (104 preceding siblings ...)
  2014-04-25 11:39 ` [PATCH 105/222] net:fec: consolidate hwtstamp implementation Russell King
@ 2014-04-25 11:39 ` Russell King
  2014-04-25 11:40 ` [PATCH 107/222] net:fec: better indexing for receive " Russell King
                   ` (116 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:39 UTC (permalink / raw)
  To: linux-arm-kernel

Maintaining the transmit ring position via pointers is inefficient,
especially when it involves complex pointer manipulation, and overlap
with the receive descriptor logic.

Re-implement this using indexes, and a single function which returns
the descriptor (appropriate to the descriptor type).  As an additional
benefit, using a union allows cleaner access to the descriptor.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec.h      |   6 +-
 drivers/net/ethernet/freescale/fec_main.c | 142 ++++++++++++++----------------
 2 files changed, 67 insertions(+), 81 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 30c683c0b480..c5a72c4bd07d 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -291,9 +291,9 @@ struct fec_enet_private {
 	union bufdesc_u	*rx_bd_base;
 	union bufdesc_u	*tx_bd_base;
 	/* The next free ring entry */
-	union bufdesc_u	*cur_rx, *cur_tx;
-	/* The ring entries to be free()ed */
-	union bufdesc_u	*dirty_tx;
+	unsigned short tx_next;
+	unsigned short tx_dirty;
+	union bufdesc_u *cur_rx;
 
 	unsigned short tx_ring_size;
 	unsigned short rx_ring_size;
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 01e43a75089d..aec802b778f7 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -227,19 +227,28 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
 
 static int mii_cnt;
 
+static union bufdesc_u *
+fec_enet_tx_get(unsigned index, struct fec_enet_private *fep)
+{
+	union bufdesc_u *base = fep->tx_bd_base;
+	union bufdesc_u *bdp;
+
+	if (fep->bufdesc_ex)
+		bdp = (union bufdesc_u *)(&base->ebd + index);
+	else
+		bdp = (union bufdesc_u *)(&base->bd + index);
+
+	return bdp;
+}
+
 static inline
 union bufdesc_u *fec_enet_get_nextdesc(union bufdesc_u *bdp, struct fec_enet_private *fep)
 {
 	union bufdesc_u *base;
 	int ring_size;
 
-	if (bdp >= fep->tx_bd_base) {
-		base = fep->tx_bd_base;
-		ring_size = fep->tx_ring_size;
-	} else {
-		base = fep->rx_bd_base;
-		ring_size = fep->rx_ring_size;
-	}
+	base = fep->rx_bd_base;
+	ring_size = fep->rx_ring_size;
 
 	if (fep->bufdesc_ex) {
 		struct bufdesc_ex *ebd = &bdp->ebd + 1;
@@ -258,13 +267,8 @@ union bufdesc_u *fec_enet_get_prevdesc(union bufdesc_u *bdp, struct fec_enet_pri
 	union bufdesc_u *base;
 	int ring_size;
 
-	if (bdp >= fep->tx_bd_base) {
-		base = fep->tx_bd_base;
-		ring_size = fep->tx_ring_size;
-	} else {
-		base = fep->rx_bd_base;
-		ring_size = fep->rx_ring_size;
-	}
+	base = fep->rx_bd_base;
+	ring_size = fep->rx_ring_size;
 
 	if (fep->bufdesc_ex) {
 		struct bufdesc_ex *ebd = &bdp->ebd - 1;
@@ -291,23 +295,23 @@ static void *swap_buffer(void *bufaddr, int len)
 static void fec_dump(struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
-	union bufdesc_u *bdp = fep->tx_bd_base;
+	union bufdesc_u *bdp;
 	unsigned index = 0;
 
 	netdev_info(ndev, "TX ring dump\n");
 	pr_info("Nr     SC     addr       len  SKB\n");
 
-	do {
+	for (index = 0; index < fep->tx_ring_size; index++) {
+		bdp = fec_enet_tx_get(index, fep);
+
 		pr_info("%3u %c%c 0x%04x 0x%08lx %4u %p\n",
 			index,
-			bdp == fep->cur_tx ? 'S' : ' ',
-			bdp == fep->dirty_tx ? 'H' : ' ',
+			index == fep->tx_next ? 'S' : ' ',
+			index == fep->tx_dirty ? 'H' : ' ',
 			bdp->bd.cbd_sc, bdp->bd.cbd_bufaddr,
 			bdp->bd.cbd_datlen,
 			fep->tx_skbuff[index]);
-		bdp = fec_enet_get_nextdesc(bdp, fep);
-		index++;
-	} while (bdp != fep->tx_bd_base);
+	}
 }
 
 static int
@@ -345,12 +349,13 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	union bufdesc_u *bdp;
 	void *bufaddr;
 	unsigned short	status;
-	unsigned int index;
+	unsigned index;
 	unsigned length;
 	dma_addr_t addr;
 
 	/* Fill in a Tx ring entry */
-	bdp = fep->cur_tx;
+	index = fep->tx_next;
+	bdp = fec_enet_tx_get(index, fep);
 
 	status = bdp->bd.cbd_sc;
 
@@ -380,11 +385,6 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	 * 4-byte boundaries. Use bounce buffers to copy data
 	 * and get it aligned. Ugh.
 	 */
-	if (fep->bufdesc_ex)
-		index = &bdp->ebd - &fep->tx_bd_base->ebd;
-	else
-		index = &bdp->bd - &fep->tx_bd_base->bd;
-
 	if (((unsigned long) bufaddr) & FEC_ALIGNMENT) {
 		memcpy(fep->tx_bounce[index], skb->data, length);
 		bufaddr = fep->tx_bounce[index];
@@ -445,14 +445,14 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 			| BD_ENET_TX_LAST | BD_ENET_TX_TC);
 	bdp->bd.cbd_sc = status;
 
-	/* If this was the last BD in the ring, start at the beginning again. */
-	bdp = fec_enet_get_nextdesc(bdp, fep);
-
 	skb_tx_timestamp(skb);
 
-	fep->cur_tx = bdp;
+	if (++index >= fep->tx_ring_size)
+		index = 0;
 
-	if (fep->cur_tx == fep->dirty_tx)
+	fep->tx_next = index;
+
+	if (fep->tx_next == fep->tx_dirty)
 		netif_stop_queue(ndev);
 
 	/* Trigger transmission start */
@@ -489,25 +489,24 @@ static void fec_enet_bd_init(struct net_device *dev)
 	fep->cur_rx = fep->rx_bd_base;
 
 	/* ...and the same for transmit */
-	bdp = fep->tx_bd_base;
-	fep->cur_tx = bdp;
 	for (i = 0; i < fep->tx_ring_size; i++) {
+		bdp = fec_enet_tx_get(i, fep);
 
 		/* Initialize the BD for every fragment in the page. */
-		bdp->bd.cbd_sc = 0;
+		if (i == fep->tx_ring_size - 1)
+			bdp->bd.cbd_sc = BD_SC_WRAP;
+		else
+			bdp->bd.cbd_sc = 0;
 		if (bdp->bd.cbd_bufaddr)
 			fec_enet_tx_unmap(bdp, fep);
 		if (fep->tx_skbuff[i]) {
 			dev_kfree_skb_any(fep->tx_skbuff[i]);
 			fep->tx_skbuff[i] = NULL;
 		}
-		bdp = fec_enet_get_nextdesc(bdp, fep);
 	}
 
-	/* Set the last buffer to wrap */
-	bdp = fec_enet_get_prevdesc(bdp, fep);
-	bdp->bd.cbd_sc |= BD_SC_WRAP;
-	fep->dirty_tx = bdp;
+	fep->tx_next = 0;
+	fep->tx_dirty = fep->tx_ring_size - 1;
 }
 
 /*
@@ -773,28 +772,25 @@ fec_enet_hwtstamp(struct fec_enet_private *fep, unsigned ts,
 static void
 fec_enet_tx(struct net_device *ndev)
 {
-	struct	fec_enet_private *fep;
+	struct fec_enet_private *fep = netdev_priv(ndev);
 	union bufdesc_u *bdp;
 	unsigned short status;
 	struct	sk_buff	*skb;
-	int	index = 0;
+	unsigned index = fep->tx_dirty;
 
-	fep = netdev_priv(ndev);
-	bdp = fep->dirty_tx;
-
-	/* get next bdp of dirty_tx */
-	bdp = fec_enet_get_nextdesc(bdp, fep);
-
-	while (((status = bdp->bd.cbd_sc) & BD_ENET_TX_READY) == 0) {
+	do {
+		if (++index >= fep->tx_ring_size)
+			index = 0;
 
 		/* current queue is empty */
-		if (bdp == fep->cur_tx)
+		if (index == fep->tx_next)
 			break;
 
-		if (fep->bufdesc_ex)
-			index = &bdp->ebd - &fep->tx_bd_base->ebd;
-		else
-			index = &bdp->bd - &fep->tx_bd_base->bd;
+		bdp = fec_enet_tx_get(index, fep);
+
+		status = bdp->bd.cbd_sc;
+		if (status & BD_ENET_TX_READY)
+			break;
 
 		fec_enet_tx_unmap(bdp, fep);
 
@@ -838,25 +834,17 @@ fec_enet_tx(struct net_device *ndev)
 		/* Free the sk buffer associated with this last transmit */
 		dev_kfree_skb_any(skb);
 
-		fep->dirty_tx = bdp;
-
-		/* Update pointer to next buffer descriptor to be transmitted */
-		bdp = fec_enet_get_nextdesc(bdp, fep);
-
 		/* Since we have freed up a buffer, the ring is no longer full
 		 */
-		if (fep->dirty_tx != fep->cur_tx) {
-			if (netif_queue_stopped(ndev))
-				netif_wake_queue(ndev);
-		}
-	}
+		if (netif_queue_stopped(ndev))
+			netif_wake_queue(ndev);
+
+		fep->tx_dirty = index;
+	} while (1);
 
 	/* ERR006538: Keep the transmitter going */
-	if (fep->dirty_tx != fep->cur_tx &&
-	    readl(fep->hwp + FEC_X_DES_ACTIVE) == 0)
+	if (index != fep->tx_next && readl(fep->hwp + FEC_X_DES_ACTIVE) == 0)
 		writel(0, fep->hwp + FEC_X_DES_ACTIVE);
-
-	return;
 }
 
 
@@ -1737,8 +1725,8 @@ static void fec_enet_free_buffers(struct net_device *ndev)
 		bdp = fec_enet_get_nextdesc(bdp, fep);
 	}
 
-	bdp = fep->tx_bd_base;
 	for (i = 0; i < fep->tx_ring_size; i++) {
+		bdp = fec_enet_tx_get(i, fep);
 		if (bdp->bd.cbd_bufaddr)
 			fec_enet_tx_unmap(bdp, fep);
 		kfree(fep->tx_bounce[i]);
@@ -1788,25 +1776,23 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
 	bdp = fec_enet_get_prevdesc(bdp, fep);
 	bdp->bd.cbd_sc |= BD_SC_WRAP;
 
-	bdp = fep->tx_bd_base;
 	for (i = 0; i < fep->tx_ring_size; i++) {
+		bdp = fec_enet_tx_get(i, fep);
 		fep->tx_bounce[i] = kmalloc(FEC_ENET_TX_FRSIZE, GFP_KERNEL);
 		if (!fep->tx_bounce[i])
 			goto err_alloc;
 
-		bdp->bd.cbd_sc = 0;
+		/* Set the last buffer to wrap. */
+		if (i == fep->tx_ring_size - 1)
+			bdp->bd.cbd_sc = BD_SC_WRAP;
+		else
+			bdp->bd.cbd_sc = 0;
 		bdp->bd.cbd_bufaddr = 0;
 
 		if (fep->bufdesc_ex)
 			bdp->ebd.cbd_esc = BD_ENET_TX_INT;
-
-		bdp = fec_enet_get_nextdesc(bdp, fep);
 	}
 
-	/* Set the last buffer to wrap. */
-	bdp = fec_enet_get_prevdesc(bdp, fep);
-	bdp->bd.cbd_sc |= BD_SC_WRAP;
-
 	return 0;
 
  err_alloc:
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 107/222] net:fec: better indexing for receive descriptor ring
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (105 preceding siblings ...)
  2014-04-25 11:39 ` [PATCH 106/222] net:fec: better indexing for transmit descriptor ring Russell King
@ 2014-04-25 11:40 ` Russell King
  2014-04-25 11:40 ` [PATCH 108/222] net:fec: calculate ring space rather than relying on comparing indices Russell King
                   ` (115 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:40 UTC (permalink / raw)
  To: linux-arm-kernel

Extend the previous commit to the receive descriptor ring as well.  This
gets rid of the two nextdesc/prevdesc functions, since we now just need
to get the descriptor for an index instead.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec.h      |  2 +-
 drivers/net/ethernet/freescale/fec_main.c | 98 +++++++++++--------------------
 2 files changed, 35 insertions(+), 65 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index c5a72c4bd07d..4b92758b51b8 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -293,7 +293,7 @@ struct fec_enet_private {
 	/* The next free ring entry */
 	unsigned short tx_next;
 	unsigned short tx_dirty;
-	union bufdesc_u *cur_rx;
+	unsigned short rx_next;
 
 	unsigned short tx_ring_size;
 	unsigned short rx_ring_size;
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index aec802b778f7..dba2e315f937 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -241,44 +241,20 @@ fec_enet_tx_get(unsigned index, struct fec_enet_private *fep)
 	return bdp;
 }
 
-static inline
-union bufdesc_u *fec_enet_get_nextdesc(union bufdesc_u *bdp, struct fec_enet_private *fep)
+static union bufdesc_u *
+fec_enet_rx_get(unsigned index, struct fec_enet_private *fep)
 {
-	union bufdesc_u *base;
-	int ring_size;
-
-	base = fep->rx_bd_base;
-	ring_size = fep->rx_ring_size;
-
-	if (fep->bufdesc_ex) {
-		struct bufdesc_ex *ebd = &bdp->ebd + 1;
-		return ebd >= (&base->ebd + ring_size) ?
-			base : (union bufdesc_u *)ebd;
-	} else {
-		struct bufdesc *bd = &bdp->bd + 1;
-		return bd >= (&base->bd + ring_size) ?
-			base : (union bufdesc_u *)bd;
-	}
-}
+	union bufdesc_u *base = fep->rx_bd_base;
+	union bufdesc_u *bdp;
 
-static inline
-union bufdesc_u *fec_enet_get_prevdesc(union bufdesc_u *bdp, struct fec_enet_private *fep)
-{
-	union bufdesc_u *base;
-	int ring_size;
+	index &= fep->rx_ring_size - 1;
 
-	base = fep->rx_bd_base;
-	ring_size = fep->rx_ring_size;
+	if (fep->bufdesc_ex)
+		bdp = (union bufdesc_u *)(&base->ebd + index);
+	else
+		bdp = (union bufdesc_u *)(&base->bd + index);
 
-	if (fep->bufdesc_ex) {
-		struct bufdesc_ex *ebd = &bdp->ebd - 1;
-		return (union bufdesc_u *)(ebd < &base->ebd ?
-			ebd + ring_size : ebd);
-	} else {
-		struct bufdesc *bd = &bdp->bd - 1;
-		return (union bufdesc_u *)(bd < &base->bd ?
-			bd + ring_size : bd);
-	}
+	return bdp;
 }
 
 static void *swap_buffer(void *bufaddr, int len)
@@ -471,22 +447,20 @@ static void fec_enet_bd_init(struct net_device *dev)
 	unsigned int i;
 
 	/* Initialize the receive buffer descriptors. */
-	bdp = fep->rx_bd_base;
 	for (i = 0; i < fep->rx_ring_size; i++) {
+		bdp = fec_enet_rx_get(i, fep);
 
 		/* Initialize the BD for every fragment in the page. */
 		if (bdp->bd.cbd_bufaddr)
 			bdp->bd.cbd_sc = BD_ENET_RX_EMPTY;
 		else
 			bdp->bd.cbd_sc = 0;
-		bdp = fec_enet_get_nextdesc(bdp, fep);
-	}
 
-	/* Set the last buffer to wrap */
-	bdp = fec_enet_get_prevdesc(bdp, fep);
-	bdp->bd.cbd_sc |= BD_SC_WRAP;
+		if (i == fep->rx_ring_size - 1)
+			bdp->bd.cbd_sc |= BD_SC_WRAP;
+	}
 
-	fep->cur_rx = fep->rx_bd_base;
+	fep->rx_next = 0;
 
 	/* ...and the same for transmit */
 	for (i = 0; i < fep->tx_ring_size; i++) {
@@ -848,7 +822,7 @@ fec_enet_tx(struct net_device *ndev)
 }
 
 
-/* During a receive, the cur_rx points to the current incoming buffer.
+/* During a receive, the rx_next points to the current incoming buffer.
  * When we update through the ring, if the next incoming buffer has
  * not been given to the system, we just set the empty indicator,
  * effectively tossing the packet.
@@ -859,7 +833,6 @@ fec_enet_rx(struct net_device *ndev, int budget)
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	const struct platform_device_id *id_entry =
 				platform_get_device_id(fep->pdev);
-	union bufdesc_u *bdp;
 	unsigned short status;
 	struct	sk_buff	*skb;
 	ushort	pkt_len;
@@ -867,7 +840,7 @@ fec_enet_rx(struct net_device *ndev, int budget)
 	int	pkt_received = 0;
 	bool	vlan_packet_rcvd = false;
 	u16	vlan_tag;
-	int	index = 0;
+	unsigned index = fep->rx_next;
 
 #ifdef CONFIG_M532x
 	flush_cache_all();
@@ -876,12 +849,16 @@ fec_enet_rx(struct net_device *ndev, int budget)
 	/* First, grab all of the stats for the incoming packet.
 	 * These get messed up if we get called due to a busy condition.
 	 */
-	bdp = fep->cur_rx;
+	do {
+		union bufdesc_u *bdp = fec_enet_rx_get(index, fep);
 
-	while (!((status = bdp->bd.cbd_sc) & BD_ENET_RX_EMPTY)) {
+		status = bdp->bd.cbd_sc;
+		if (status & BD_ENET_RX_EMPTY)
+			break;
 
 		if (pkt_received >= budget)
 			break;
+
 		pkt_received++;
 
 		/* Since we have allocated space to hold a complete frame,
@@ -923,10 +900,6 @@ fec_enet_rx(struct net_device *ndev, int budget)
 		pkt_len = bdp->bd.cbd_datlen;
 		ndev->stats.rx_bytes += pkt_len;
 
-		if (fep->bufdesc_ex)
-			index = &bdp->ebd - &fep->rx_bd_base->ebd;
-		else
-			index = &bdp->bd - &fep->rx_bd_base->bd;
 		data = fep->rx_skbuff[index]->data;
 		dma_sync_single_for_cpu(&fep->pdev->dev, bdp->bd.cbd_bufaddr,
 					FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
@@ -1017,16 +990,16 @@ fec_enet_rx(struct net_device *ndev, int budget)
 		status |= BD_ENET_RX_EMPTY;
 		bdp->bd.cbd_sc = status;
 
-		/* Update BD pointer to next entry */
-		bdp = fec_enet_get_nextdesc(bdp, fep);
-
 		/* Doing this here will keep the FEC running while we process
 		 * incoming frames.  On a heavily loaded network, we should be
 		 * able to keep up at the expense of system resources.
 		 */
 		writel(0, fep->hwp + FEC_R_DES_ACTIVE);
-	}
-	fep->cur_rx = bdp;
+
+		if (++index >= fep->rx_ring_size)
+			index = 0;
+	} while (1);
+	fep->rx_next = index;
 
 	return pkt_received;
 }
@@ -1713,8 +1686,9 @@ static void fec_enet_free_buffers(struct net_device *ndev)
 	struct sk_buff *skb;
 	union bufdesc_u *bdp;
 
-	bdp = fep->rx_bd_base;
 	for (i = 0; i < fep->rx_ring_size; i++) {
+		bdp = fec_enet_rx_get(i, fep);
+
 		skb = fep->rx_skbuff[i];
 		fep->rx_skbuff[i] = NULL;
 		if (skb) {
@@ -1722,7 +1696,6 @@ static void fec_enet_free_buffers(struct net_device *ndev)
 					FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
 			dev_kfree_skb(skb);
 		}
-		bdp = fec_enet_get_nextdesc(bdp, fep);
 	}
 
 	for (i = 0; i < fep->tx_ring_size; i++) {
@@ -1745,7 +1718,6 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
 	struct sk_buff *skb;
 	union bufdesc_u *bdp;
 
-	bdp = fep->rx_bd_base;
 	for (i = 0; i < fep->rx_ring_size; i++) {
 		dma_addr_t addr;
 
@@ -1763,19 +1735,17 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
 		}
 
 		fep->rx_skbuff[i] = skb;
+		bdp = fec_enet_rx_get(i, fep);
 		bdp->bd.cbd_bufaddr = addr;
 		bdp->bd.cbd_sc = BD_ENET_RX_EMPTY;
+		/* Set the last buffer to wrap. */
+		if (i == fep->rx_ring_size - 1)
+			bdp->bd.cbd_sc |= BD_SC_WRAP;
 
 		if (fep->bufdesc_ex)
 			bdp->ebd.cbd_esc = BD_ENET_RX_INT;
-
-		bdp = fec_enet_get_nextdesc(bdp, fep);
 	}
 
-	/* Set the last buffer to wrap. */
-	bdp = fec_enet_get_prevdesc(bdp, fep);
-	bdp->bd.cbd_sc |= BD_SC_WRAP;
-
 	for (i = 0; i < fep->tx_ring_size; i++) {
 		bdp = fec_enet_tx_get(i, fep);
 		fep->tx_bounce[i] = kmalloc(FEC_ENET_TX_FRSIZE, GFP_KERNEL);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 108/222] net:fec: calculate ring space rather than relying on comparing indices
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (106 preceding siblings ...)
  2014-04-25 11:40 ` [PATCH 107/222] net:fec: better indexing for receive " Russell King
@ 2014-04-25 11:40 ` Russell King
  2014-04-25 11:40 ` [PATCH 109/222] net:fec: increase transmit ring size Russell King
                   ` (114 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:40 UTC (permalink / raw)
  To: linux-arm-kernel

Calculate the space in the transmit ring rather than comparing indices.
This allows us to positively calculate the number of entries remaining,
which will be required when we handle fragmented skbs.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 32 +++++++++++++++----------------
 1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index dba2e315f937..47d4aa2842a4 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -316,6 +316,12 @@ fec_enet_tx_unmap(union bufdesc_u *bdp, struct fec_enet_private *fep)
 	dma_unmap_single(&fep->pdev->dev, addr, length, DMA_TO_DEVICE);
 }
 
+static unsigned ring_free(unsigned ins, unsigned rem, unsigned size)
+{
+	int num = rem - ins;
+	return num < 0 ? num + size : num;
+}
+
 static netdev_tx_t
 fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
@@ -331,11 +337,8 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 
 	/* Fill in a Tx ring entry */
 	index = fep->tx_next;
-	bdp = fec_enet_tx_get(index, fep);
-
-	status = bdp->bd.cbd_sc;
 
-	if (status & BD_ENET_TX_READY) {
+	if (ring_free(index, fep->tx_dirty, fep->tx_ring_size) < 1) {
 		/* Ooops.  All transmit buffers are full.  Bail out.
 		 * This should not happen, since ndev->tbusy should be set.
 		 */
@@ -349,9 +352,6 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 		return NETDEV_TX_OK;
 	}
 
-	/* Clear all of the status flags */
-	status &= ~BD_ENET_TX_STATS;
-
 	/* Set buffer length and buffer pointer */
 	bufaddr = skb->data;
 	length = skb->len;
@@ -386,6 +386,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	/* Save skb pointer */
 	fep->tx_skbuff[index] = skb;
 
+	bdp = fec_enet_tx_get(index, fep);
 	bdp->bd.cbd_datlen = length;
 	bdp->bd.cbd_bufaddr = addr;
 
@@ -417,9 +418,9 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	/* Send it on its way.  Tell FEC it's ready, interrupt when done,
 	 * it's the last BD of the frame, and to put the CRC on the end.
 	 */
-	status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR
-			| BD_ENET_TX_LAST | BD_ENET_TX_TC);
-	bdp->bd.cbd_sc = status;
+	status = bdp->bd.cbd_sc & ~BD_ENET_TX_STATS;
+	bdp->bd.cbd_sc = status | BD_ENET_TX_READY | BD_ENET_TX_INTR |
+			 BD_ENET_TX_LAST | BD_ENET_TX_TC;
 
 	skb_tx_timestamp(skb);
 
@@ -428,7 +429,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 
 	fep->tx_next = index;
 
-	if (fep->tx_next == fep->tx_dirty)
+	if (ring_free(index, fep->tx_dirty, fep->tx_ring_size) < 1)
 		netif_stop_queue(ndev);
 
 	/* Trigger transmission start */
@@ -808,17 +809,16 @@ fec_enet_tx(struct net_device *ndev)
 		/* Free the sk buffer associated with this last transmit */
 		dev_kfree_skb_any(skb);
 
-		/* Since we have freed up a buffer, the ring is no longer full
-		 */
-		if (netif_queue_stopped(ndev))
-			netif_wake_queue(ndev);
-
 		fep->tx_dirty = index;
 	} while (1);
 
 	/* ERR006538: Keep the transmitter going */
 	if (index != fep->tx_next && readl(fep->hwp + FEC_X_DES_ACTIVE) == 0)
 		writel(0, fep->hwp + FEC_X_DES_ACTIVE);
+
+	if (netif_queue_stopped(ndev) &&
+	    ring_free(fep->tx_next, fep->tx_dirty, fep->tx_ring_size))
+		netif_wake_queue(ndev);
 }
 
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 109/222] net:fec: increase transmit ring size
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (107 preceding siblings ...)
  2014-04-25 11:40 ` [PATCH 108/222] net:fec: calculate ring space rather than relying on comparing indices Russell King
@ 2014-04-25 11:40 ` Russell King
  2014-04-25 11:40 ` [PATCH 110/222] net:fec: increase receive " Russell King
                   ` (113 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:40 UTC (permalink / raw)
  To: linux-arm-kernel

Increasing the transmit ring size allows us to queue more packets before
needing to stop the transmit queue.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 4b92758b51b8..62fe1217b781 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -251,8 +251,8 @@ union bufdesc_u {
 #define RX_RING_SIZE		(FEC_ENET_RX_FRPPG * FEC_ENET_RX_PAGES)
 #define FEC_ENET_TX_FRSIZE	2048
 #define FEC_ENET_TX_FRPPG	(PAGE_SIZE / FEC_ENET_TX_FRSIZE)
-#define TX_RING_SIZE		16	/* Must be power of two */
-#define TX_RING_MOD_MASK	15	/*   for this to work */
+#define TX_RING_SIZE		64	/* Must be power of two */
+#define TX_RING_MOD_MASK	63	/*   for this to work */
 
 #define BD_ENET_RX_INT          0x00800000
 #define BD_ENET_RX_PTP          ((ushort)0x0400)
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 110/222] net:fec: increase receive ring size
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (108 preceding siblings ...)
  2014-04-25 11:40 ` [PATCH 109/222] net:fec: increase transmit ring size Russell King
@ 2014-04-25 11:40 ` Russell King
  2014-04-25 11:40 ` [PATCH 111/222] net:fec: add scatter-gather support Russell King
                   ` (112 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:40 UTC (permalink / raw)
  To: linux-arm-kernel

Increasing the receive ring size allows more packets to be received
before we run out of ring entries to store the packets.  With 16
ring entries, this corresponds with a maximum of 16 * 1514 bytes,
or just 23K.  At gigabit speeds, this would take around 200us to
fill.  Increasing this to 64 entries gives us more scope when we
have busy workloads, since it increases us to 95K, and around 700us.

Going above this requires the ring buffer allocation to be changed.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 62fe1217b781..1650c8440f5f 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -245,7 +245,7 @@ union bufdesc_u {
  * the skbuffer directly.
  */
 
-#define FEC_ENET_RX_PAGES	8
+#define FEC_ENET_RX_PAGES	32
 #define FEC_ENET_RX_FRSIZE	2048
 #define FEC_ENET_RX_FRPPG	(PAGE_SIZE / FEC_ENET_RX_FRSIZE)
 #define RX_RING_SIZE		(FEC_ENET_RX_FRPPG * FEC_ENET_RX_PAGES)
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 111/222] net:fec: add scatter-gather support
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (109 preceding siblings ...)
  2014-04-25 11:40 ` [PATCH 110/222] net:fec: increase receive " Russell King
@ 2014-04-25 11:40 ` Russell King
  2014-04-25 11:40 ` [PATCH 112/222] net:fec: add byte queue limits support Russell King
                   ` (111 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:40 UTC (permalink / raw)
  To: linux-arm-kernel

Add scatter-gather support for SKB transmission.  This allows the
driver to make use of GSO, which when enabled allows the iMX6Q to
increase TCP transmission throughput from about 320 to 420Mbps,
measured with iperf 2.0.5

We adjust the minimum transmit ring space according to whether SG
support is enabled or not.  This allows non-SG configurations to avoid
the tx ring reservation necessary for SG, thereby making full use of
their available ring (since non-SG requires just one tx ring entry per
packet.)

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec.h      |   2 +
 drivers/net/ethernet/freescale/fec_main.c | 204 ++++++++++++++++++++++++------
 2 files changed, 164 insertions(+), 42 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 1650c8440f5f..aca92660d2be 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -280,6 +280,7 @@ struct fec_enet_private {
 	struct clk *clk_enet_out;
 	struct clk *clk_ptp;
 
+	unsigned char tx_page_map[TX_RING_SIZE];
 	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
 	unsigned char *tx_bounce[TX_RING_SIZE];
 	struct	sk_buff *tx_skbuff[TX_RING_SIZE];
@@ -293,6 +294,7 @@ struct fec_enet_private {
 	/* The next free ring entry */
 	unsigned short tx_next;
 	unsigned short tx_dirty;
+	unsigned short tx_min;
 	unsigned short rx_next;
 
 	unsigned short tx_ring_size;
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 47d4aa2842a4..45733f9c3c85 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -170,6 +170,9 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
 #error "FEC: descriptor ring size constants too large"
 #endif
 
+/* Minimum TX ring size when using NETIF_F_SG */
+#define TX_RING_SIZE_MIN_SG (2 * (MAX_SKB_FRAGS + 1))
+
 /* Interrupt events/masks. */
 #define FEC_ENET_HBERR	((uint)0x80000000)	/* Heartbeat error */
 #define FEC_ENET_BABR	((uint)0x40000000)	/* Babbling receiver */
@@ -293,10 +296,19 @@ static void fec_dump(struct net_device *ndev)
 static int
 fec_enet_clear_csum(struct sk_buff *skb, struct net_device *ndev)
 {
+	int csum_start;
+
 	/* Only run for packets requiring a checksum. */
 	if (skb->ip_summed != CHECKSUM_PARTIAL)
 		return 0;
 
+	csum_start = skb_checksum_start_offset(skb);
+	if (csum_start + skb->csum_offset > skb_headlen(skb)) {
+		netdev_err(ndev, "checksum outside skb head: headlen %u start %u offset %u\n",
+			   skb_headlen(skb), csum_start, skb->csum_offset);
+		return -1;
+	}
+
 	if (unlikely(skb_cow_head(skb, 0)))
 		return -1;
 
@@ -306,14 +318,32 @@ fec_enet_clear_csum(struct sk_buff *skb, struct net_device *ndev)
 }
 
 static void
-fec_enet_tx_unmap(union bufdesc_u *bdp, struct fec_enet_private *fep)
+fec_enet_tx_unmap(unsigned index, union bufdesc_u *bdp, struct fec_enet_private *fep)
 {
 	dma_addr_t addr = bdp->bd.cbd_bufaddr;
 	unsigned length = bdp->bd.cbd_datlen;
 
 	bdp->bd.cbd_bufaddr = 0;
 
-	dma_unmap_single(&fep->pdev->dev, addr, length, DMA_TO_DEVICE);
+	if (fep->tx_page_map[index])
+		dma_unmap_page(&fep->pdev->dev, addr, length, DMA_TO_DEVICE);
+	else
+		dma_unmap_single(&fep->pdev->dev, addr, length, DMA_TO_DEVICE);
+}
+
+static void
+fec_enet_tx_unmap_range(unsigned index, unsigned last, struct fec_enet_private *fep)
+{
+	union bufdesc_u *bdp;
+
+	do {
+		if (last == 0)
+			last = fep->tx_ring_size;
+		last--;
+
+		bdp = fec_enet_tx_get(last, fep);
+		fec_enet_tx_unmap(last, bdp, fep);
+	} while (index != last);
 }
 
 static unsigned ring_free(unsigned ins, unsigned rem, unsigned size)
@@ -331,14 +361,14 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	union bufdesc_u *bdp;
 	void *bufaddr;
 	unsigned short	status;
-	unsigned index;
-	unsigned length;
+	unsigned index, last, length, cbd_esc;
+	int f, nr_frags = skb_shinfo(skb)->nr_frags;
 	dma_addr_t addr;
 
 	/* Fill in a Tx ring entry */
 	index = fep->tx_next;
 
-	if (ring_free(index, fep->tx_dirty, fep->tx_ring_size) < 1) {
+	if (ring_free(index, fep->tx_dirty, fep->tx_ring_size) < 1 + nr_frags) {
 		/* Ooops.  All transmit buffers are full.  Bail out.
 		 * This should not happen, since ndev->tbusy should be set.
 		 */
@@ -354,7 +384,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 
 	/* Set buffer length and buffer pointer */
 	bufaddr = skb->data;
-	length = skb->len;
+	length = skb_headlen(skb);
 
 	/*
 	 * On some FEC implementations data must be aligned on
@@ -376,38 +406,72 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 
 	/* Push the data cache so the CPM does not get stale memory data. */
 	addr = dma_map_single(&fep->pdev->dev, bufaddr, length, DMA_TO_DEVICE);
-	if (dma_mapping_error(&fep->pdev->dev, addr)) {
-		dev_kfree_skb_any(skb);
-		if (net_ratelimit())
-			netdev_err(ndev, "Tx DMA memory map failed\n");
-		return NETDEV_TX_OK;
-	}
-
-	/* Save skb pointer */
-	fep->tx_skbuff[index] = skb;
+	if (dma_mapping_error(&fep->pdev->dev, addr))
+		goto release;
 
 	bdp = fec_enet_tx_get(index, fep);
 	bdp->bd.cbd_datlen = length;
 	bdp->bd.cbd_bufaddr = addr;
 
+	fep->tx_page_map[index] = 0;
+
+	cbd_esc = BD_ENET_TX_INT;
 	if (fep->bufdesc_ex) {
-		bdp->ebd.cbd_bdu = 0;
 		if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
 			fep->hwts_tx_en)) {
-			bdp->ebd.cbd_esc = (BD_ENET_TX_TS | BD_ENET_TX_INT);
+			cbd_esc |= BD_ENET_TX_TS;
 			skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
 		} else {
-			bdp->ebd.cbd_esc = BD_ENET_TX_INT;
-
 			/* Enable protocol checksum flags
 			 * We do not bother with the IP Checksum bits as they
 			 * are done by the kernel
 			 */
 			if (skb->ip_summed == CHECKSUM_PARTIAL)
-				bdp->ebd.cbd_esc |= BD_ENET_TX_PINS;
+				cbd_esc |= BD_ENET_TX_PINS;
+		}
+		bdp->ebd.cbd_bdu = 0;
+		bdp->ebd.cbd_esc = cbd_esc;
+	}
+
+	for (last = index, f = 0; f < nr_frags; f++) {
+		const struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[f];
+
+		if (++last >= fep->tx_ring_size)
+			last = 0;
+
+		length = skb_frag_size(frag);
+
+		/* If the alignment is unsuitable, we need to bounce. */
+		if (frag->page_offset & FEC_ALIGNMENT) {
+			unsigned char *bounce = fep->tx_bounce[last];
+
+			/* FIXME: highdma? */
+			memcpy(bounce, skb_frag_address(frag), length);
+
+			addr = dma_map_single(&fep->pdev->dev, bounce,
+					      length, DMA_TO_DEVICE);
+			fep->tx_page_map[last] = 0;
+		} else {
+			addr = skb_frag_dma_map(&fep->pdev->dev, frag, 0,
+						length, DMA_TO_DEVICE);
+			fep->tx_page_map[last] = 1;
+		}
+
+		if (dma_mapping_error(&fep->pdev->dev, addr))
+			goto release_frags;
+
+		bdp = fec_enet_tx_get(last, fep);
+		bdp->bd.cbd_datlen = length;
+		bdp->bd.cbd_bufaddr = addr;
+		if (fep->bufdesc_ex) {
+			bdp->ebd.cbd_esc = cbd_esc;
+			bdp->ebd.cbd_bdu = 0;
 		}
 	}
 
+	/* Save skb pointer */
+	fep->tx_skbuff[last] = skb;
+
 	/*
 	 * We need the preceding stores to the descriptor to complete
 	 * before updating the status field, which hands it over to the
@@ -418,18 +482,30 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	/* Send it on its way.  Tell FEC it's ready, interrupt when done,
 	 * it's the last BD of the frame, and to put the CRC on the end.
 	 */
-	status = bdp->bd.cbd_sc & ~BD_ENET_TX_STATS;
+	status = bdp->bd.cbd_sc & BD_ENET_TX_WRAP;
 	bdp->bd.cbd_sc = status | BD_ENET_TX_READY | BD_ENET_TX_INTR |
 			 BD_ENET_TX_LAST | BD_ENET_TX_TC;
 
+	/* Now walk backwards setting the TX_READY on each fragment */
+	for (f = nr_frags - 1; f >= 0; f--) {
+		unsigned i = index + f;
+
+		if (i >= fep->tx_ring_size)
+			i -= fep->tx_ring_size;
+
+		bdp = fec_enet_tx_get(i, fep);
+		status = bdp->bd.cbd_sc & BD_ENET_TX_WRAP;
+		bdp->bd.cbd_sc = status | BD_ENET_TX_READY | BD_ENET_TX_INTR;
+	}
+
 	skb_tx_timestamp(skb);
 
-	if (++index >= fep->tx_ring_size)
-		index = 0;
+	if (++last >= fep->tx_ring_size)
+		last = 0;
 
-	fep->tx_next = index;
+	fep->tx_next = last;
 
-	if (ring_free(index, fep->tx_dirty, fep->tx_ring_size) < 1)
+	if (ring_free(last, fep->tx_dirty, fep->tx_ring_size) < fep->tx_min)
 		netif_stop_queue(ndev);
 
 	/* Trigger transmission start */
@@ -437,6 +513,14 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 		writel(0, fep->hwp + FEC_X_DES_ACTIVE);
 
 	return NETDEV_TX_OK;
+
+ release_frags:
+	fec_enet_tx_unmap_range(index, last, fep);
+ release:
+	dev_kfree_skb_any(skb);
+	if (net_ratelimit())
+		netdev_err(ndev, "Tx DMA memory map failed\n");
+	return NETDEV_TX_OK;
 }
 
 /* Init RX & TX buffer descriptors
@@ -473,7 +557,7 @@ static void fec_enet_bd_init(struct net_device *dev)
 		else
 			bdp->bd.cbd_sc = 0;
 		if (bdp->bd.cbd_bufaddr)
-			fec_enet_tx_unmap(bdp, fep);
+			fec_enet_tx_unmap(i, bdp, fep);
 		if (fep->tx_skbuff[i]) {
 			dev_kfree_skb_any(fep->tx_skbuff[i]);
 			fep->tx_skbuff[i] = NULL;
@@ -767,7 +851,7 @@ fec_enet_tx(struct net_device *ndev)
 		if (status & BD_ENET_TX_READY)
 			break;
 
-		fec_enet_tx_unmap(bdp, fep);
+		fec_enet_tx_unmap(index, bdp, fep);
 
 		skb = fep->tx_skbuff[index];
 		fep->tx_skbuff[index] = NULL;
@@ -787,17 +871,9 @@ fec_enet_tx(struct net_device *ndev)
 				ndev->stats.tx_fifo_errors++;
 			if (status & BD_ENET_TX_CSL) /* Carrier lost */
 				ndev->stats.tx_carrier_errors++;
-		} else {
+		} else if (skb) {
 			ndev->stats.tx_packets++;
-			ndev->stats.tx_bytes += bdp->bd.cbd_datlen;
-		}
-
-		if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS) &&
-			fep->bufdesc_ex) {
-			struct skb_shared_hwtstamps shhwtstamps;
-
-			fec_enet_hwtstamp(fep, bdp->ebd.ts, &shhwtstamps);
-			skb_tstamp_tx(skb, &shhwtstamps);
+			ndev->stats.tx_bytes += skb->len;
 		}
 
 		/* Deferred means some collisions occurred during transmit,
@@ -806,8 +882,18 @@ fec_enet_tx(struct net_device *ndev)
 		if (status & BD_ENET_TX_DEF)
 			ndev->stats.collisions++;
 
-		/* Free the sk buffer associated with this last transmit */
-		dev_kfree_skb_any(skb);
+		if (skb) {
+			if (fep->bufdesc_ex &&
+			    unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) {
+				struct skb_shared_hwtstamps shhwtstamps;
+
+				fec_enet_hwtstamp(fep, bdp->ebd.ts, &shhwtstamps);
+				skb_tstamp_tx(skb, &shhwtstamps);
+			}
+
+			/* Free the sk buffer associated with this last transmit */
+			dev_kfree_skb_any(skb);
+		}
 
 		fep->tx_dirty = index;
 	} while (1);
@@ -817,7 +903,8 @@ fec_enet_tx(struct net_device *ndev)
 		writel(0, fep->hwp + FEC_X_DES_ACTIVE);
 
 	if (netif_queue_stopped(ndev) &&
-	    ring_free(fep->tx_next, fep->tx_dirty, fep->tx_ring_size))
+	    ring_free(fep->tx_next, fep->tx_dirty, fep->tx_ring_size) >=
+	      fep->tx_min)
 		netif_wake_queue(ndev);
 }
 
@@ -1701,7 +1788,7 @@ static void fec_enet_free_buffers(struct net_device *ndev)
 	for (i = 0; i < fep->tx_ring_size; i++) {
 		bdp = fec_enet_tx_get(i, fep);
 		if (bdp->bd.cbd_bufaddr)
-			fec_enet_tx_unmap(bdp, fep);
+			fec_enet_tx_unmap(i, bdp, fep);
 		kfree(fep->tx_bounce[i]);
 		fep->tx_bounce[i] = NULL;
 		skb = fep->tx_skbuff[i];
@@ -1938,7 +2025,22 @@ static void fec_poll_controller(struct net_device *dev)
 }
 #endif
 
-#define FEATURES_NEED_QUIESCE NETIF_F_RXCSUM
+static netdev_features_t fec_fix_features(struct net_device *ndev,
+	netdev_features_t features)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+
+	/*
+	 * NETIF_F_SG requires a minimum transmit ring size.  If we
+	 * have less than this size, we can't support this feature.
+	 */
+	if (fep->tx_ring_size < TX_RING_SIZE_MIN_SG)
+		features &= ~NETIF_F_SG;
+
+	return features;
+}
+
+#define FEATURES_NEED_QUIESCE (NETIF_F_RXCSUM | NETIF_F_SG)
 
 static int fec_set_features(struct net_device *netdev,
 	netdev_features_t features)
@@ -1963,6 +2065,12 @@ static int fec_set_features(struct net_device *netdev,
 			fep->csum_flags &= ~FLAG_RX_CSUM_ENABLED;
 	}
 
+	/* Set the appropriate minimum transmit ring free threshold */
+	if (features & NETIF_F_SG)
+		fep->tx_min = MAX_SKB_FRAGS + 1;
+	else
+		fep->tx_min = 1;
+
 	/* Resume the device after updates */
 	if (netif_running(netdev) && changed & FEATURES_NEED_QUIESCE) {
 		fec_restart(netdev);
@@ -1987,6 +2095,7 @@ static const struct net_device_ops fec_netdev_ops = {
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	.ndo_poll_controller	= fec_poll_controller,
 #endif
+	.ndo_fix_features	= fec_fix_features,
 	.ndo_set_features	= fec_set_features,
 };
 
@@ -2052,6 +2161,17 @@ static int fec_enet_init(struct net_device *ndev)
 		fep->csum_flags |= FLAG_RX_CSUM_ENABLED;
 	}
 
+	if (!(id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)) {
+		/* don't enable SG if we need to swap frames */
+		ndev->features |= NETIF_F_SG;
+		ndev->hw_features |= NETIF_F_SG;
+	}
+
+	if (ndev->features & NETIF_F_SG)
+		fep->tx_min = MAX_SKB_FRAGS + 1;
+	else
+		fep->tx_min = 1;
+
 	fec_restart(ndev);
 
 	return 0;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 112/222] net:fec: add byte queue limits support
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (110 preceding siblings ...)
  2014-04-25 11:40 ` [PATCH 111/222] net:fec: add scatter-gather support Russell King
@ 2014-04-25 11:40 ` Russell King
  2014-04-25 11:41 ` [PATCH 113/222] net:fec: add better flow control support Russell King
                   ` (110 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:40 UTC (permalink / raw)
  To: linux-arm-kernel

Add support for byte queue limits.  Information on this feature can
be found here: https://lwn.net/Articles/469652/

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 45733f9c3c85..c697b6ae9039 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -499,6 +499,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	}
 
 	skb_tx_timestamp(skb);
+	netdev_sent_queue(ndev, skb->len);
 
 	if (++last >= fep->tx_ring_size)
 		last = 0;
@@ -606,6 +607,7 @@ fec_restart(struct net_device *ndev)
 	writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE);
 
 	fec_enet_bd_init(ndev);
+	netdev_reset_queue(ndev);
 
 	/* Set receive and transmit descriptor base. */
 	writel(fep->bd_dma, fep->hwp + FEC_R_DES_START);
@@ -836,7 +838,9 @@ fec_enet_tx(struct net_device *ndev)
 	unsigned short status;
 	struct	sk_buff	*skb;
 	unsigned index = fep->tx_dirty;
+	unsigned pkts_compl, bytes_compl;
 
+	pkts_compl = bytes_compl = 0;
 	do {
 		if (++index >= fep->tx_ring_size)
 			index = 0;
@@ -891,6 +895,9 @@ fec_enet_tx(struct net_device *ndev)
 				skb_tstamp_tx(skb, &shhwtstamps);
 			}
 
+			pkts_compl++;
+			bytes_compl += skb->len;
+
 			/* Free the sk buffer associated with this last transmit */
 			dev_kfree_skb_any(skb);
 		}
@@ -898,6 +905,8 @@ fec_enet_tx(struct net_device *ndev)
 		fep->tx_dirty = index;
 	} while (1);
 
+	netdev_completed_queue(ndev, pkts_compl, bytes_compl);
+
 	/* ERR006538: Keep the transmitter going */
 	if (index != fep->tx_next && readl(fep->hwp + FEC_X_DES_ACTIVE) == 0)
 		writel(0, fep->hwp + FEC_X_DES_ACTIVE);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 113/222] net:fec: add better flow control support
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (111 preceding siblings ...)
  2014-04-25 11:40 ` [PATCH 112/222] net:fec: add byte queue limits support Russell King
@ 2014-04-25 11:41 ` Russell King
  2014-04-25 11:41 ` [PATCH 114/222] net:fec: move transmit dma ring address calculation to fec_enet_init() Russell King
                   ` (109 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:41 UTC (permalink / raw)
  To: linux-arm-kernel

The FEC hardware in iMX6 is capable of separate control of each flow
control path: the receiver can be programmed via the receive control
register to detect flow control frames, and the transmitter can be
programmed via the receive FIFO thresholds to enable generation of
pause frames.

This means we can implement the full range of flow control: both
symmetric and asymmetric flow control.  We support ethtool configuring
all options: forced manual mode, where each path can be controlled
individually, and autonegotiation mode.

In autonegotiation mode, the tx/rx enable bits can be used to influence
the outcome, though they don't precisely define which paths will be
enabled.  One combination we don't support is "symmetric only" since we
can always configure each path independently, a case which Linux seems
to often get wrong.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec.h      |   3 +-
 drivers/net/ethernet/freescale/fec_main.c | 196 ++++++++++++++++++++++--------
 2 files changed, 146 insertions(+), 53 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index aca92660d2be..af81d0f62dae 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -316,7 +316,8 @@ struct fec_enet_private {
 	struct	completion mdio_done;
 	int	irq[FEC_IRQ_NUM];
 	int	bufdesc_ex;
-	int	pause_flag;
+	unsigned short pause_flag;
+	unsigned short pause_mode;
 
 	struct	napi_struct napi;
 	int	csum_flags;
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index c697b6ae9039..fb01d7891b67 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -225,8 +225,9 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
 /* Transmitter timeout */
 #define TX_TIMEOUT (2 * HZ)
 
-#define FEC_PAUSE_FLAG_AUTONEG	0x1
-#define FEC_PAUSE_FLAG_ENABLE	0x2
+#define FEC_PAUSE_FLAG_AUTONEG	BIT(0)
+#define FEC_PAUSE_FLAG_RX	BIT(1)
+#define FEC_PAUSE_FLAG_TX	BIT(2)
 
 static int mii_cnt;
 
@@ -655,7 +656,7 @@ fec_restart(struct net_device *ndev)
 	 */
 	if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
 		/* Enable flow control and length check */
-		rcntl |= 0x40000000 | 0x00000020;
+		rcntl |= 0x40000000;
 
 		/* RGMII, RMII or MII */
 		if (fep->phy_interface == PHY_INTERFACE_MODE_RGMII)
@@ -701,22 +702,24 @@ fec_restart(struct net_device *ndev)
 	}
 
 #if !defined(CONFIG_M5272)
-	/* enable pause frame*/
-	if ((fep->pause_flag & FEC_PAUSE_FLAG_ENABLE) ||
-	    ((fep->pause_flag & FEC_PAUSE_FLAG_AUTONEG) &&
-	     fep->phy_dev && fep->phy_dev->pause)) {
-		rcntl |= FEC_ENET_FCE;
-
-		/* set FIFO threshold parameter to reduce overrun */
-		writel(FEC_ENET_RSEM_V, fep->hwp + FEC_R_FIFO_RSEM);
-		writel(FEC_ENET_RSFL_V, fep->hwp + FEC_R_FIFO_RSFL);
-		writel(FEC_ENET_RAEM_V, fep->hwp + FEC_R_FIFO_RAEM);
-		writel(FEC_ENET_RAFL_V, fep->hwp + FEC_R_FIFO_RAFL);
-
-		/* OPD */
-		writel(FEC_ENET_OPD_V, fep->hwp + FEC_OPD);
-	} else {
-		rcntl &= ~FEC_ENET_FCE;
+	if (fep->full_duplex == DUPLEX_FULL) {
+		/*
+		 * Configure pause modes according to the current status.
+		 * Must only be enabled for full duplex links.
+		 */
+		if (fep->pause_mode & FEC_PAUSE_FLAG_RX)
+			rcntl |= FEC_ENET_FCE;
+
+		if (fep->pause_mode & FEC_PAUSE_FLAG_TX) {
+			/* set FIFO threshold parameter to reduce overrun */
+			writel(FEC_ENET_RSEM_V, fep->hwp + FEC_R_FIFO_RSEM);
+			writel(FEC_ENET_RSFL_V, fep->hwp + FEC_R_FIFO_RSFL);
+			writel(FEC_ENET_RAEM_V, fep->hwp + FEC_R_FIFO_RAEM);
+			writel(FEC_ENET_RAFL_V, fep->hwp + FEC_R_FIFO_RAFL);
+
+			/* OPD */
+			writel(FEC_ENET_OPD_V, fep->hwp + FEC_OPD);
+		}
 	}
 #endif /* !defined(CONFIG_M5272) */
 
@@ -1261,6 +1264,35 @@ static void fec_enet_adjust_link(struct net_device *ndev)
 			status_change = 1;
 		}
 
+		if (fep->pause_flag & FEC_PAUSE_FLAG_AUTONEG) {
+			u32 lcl_adv = phy_dev->advertising;
+			u32 rmt_adv = phy_dev->lp_advertising;
+			unsigned mode = 0;
+
+			if (lcl_adv & rmt_adv & ADVERTISED_Pause) {
+				/*
+				 * Local Device  Link Partner
+				 * Pause AsymDir Pause AsymDir Result
+				 *   1     X       1     X     TX+RX
+				 */
+				mode = FEC_PAUSE_FLAG_TX | FEC_PAUSE_FLAG_RX;
+			} else if (lcl_adv & rmt_adv & ADVERTISED_Asym_Pause) {
+				/*
+				 *   0     1       1     1     RX
+				 *   1     1       0     1     TX
+				 */
+				if (rmt_adv & ADVERTISED_Pause)
+					mode = FEC_PAUSE_FLAG_RX;
+				else
+					mode = FEC_PAUSE_FLAG_TX;
+			}
+
+			if (mode != fep->pause_mode) {
+				fep->pause_mode = mode;
+				status_change = 1;
+			}
+		}
+
 		/* if any of the above changed restart the FEC */
 		if (status_change) {
 			napi_disable(&fep->napi);
@@ -1339,6 +1371,34 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
 	return 0;
 }
 
+static void fec_enet_phy_config(struct net_device *ndev)
+{
+#ifndef CONFIG_M5272
+	struct fec_enet_private *fep = netdev_priv(ndev);
+	struct phy_device *phy = fep->phy_dev;
+	unsigned pause = 0;
+
+	/*
+	 * Pause advertisment logic is weird.  We don't advertise the raw
+	 * "can tx" and "can rx" modes, but instead it is whether we support
+	 * symmetric flow or asymmetric flow.
+	 *
+	 * Symmetric flow means we can only support both transmit and receive
+	 * flow control frames together.  Asymmetric flow means we can
+	 * independently control each.  Note that there is no bit encoding
+	 * for "I can only receive flow control frames."
+	 */
+	if (fep->pause_flag & FEC_PAUSE_FLAG_RX)
+		pause |= ADVERTISED_Asym_Pause | ADVERTISED_Pause;
+	if (fep->pause_flag & FEC_PAUSE_FLAG_TX)
+		pause |= ADVERTISED_Asym_Pause;
+
+	pause &= phy->supported;
+	pause |= phy->advertising & ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause);
+	phy->advertising = pause;
+#endif
+}
+
 static int fec_enet_mii_probe(struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
@@ -1385,7 +1445,7 @@ static int fec_enet_mii_probe(struct net_device *ndev)
 		phy_dev->supported &= PHY_GBIT_FEATURES;
 		phy_dev->supported &= ~SUPPORTED_1000baseT_Half;
 #if !defined(CONFIG_M5272)
-		phy_dev->supported |= SUPPORTED_Pause;
+		phy_dev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
 #endif
 	}
 	else
@@ -1397,6 +1457,8 @@ static int fec_enet_mii_probe(struct net_device *ndev)
 	fep->link = 0;
 	fep->full_duplex = 0;
 
+	fec_enet_phy_config(ndev);
+
 	netdev_info(ndev, "Freescale FEC PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
 		    fep->phy_dev->drv->name, dev_name(&fep->phy_dev->dev),
 		    fep->phy_dev->irq);
@@ -1578,50 +1640,78 @@ static void fec_enet_get_pauseparam(struct net_device *ndev,
 	struct fec_enet_private *fep = netdev_priv(ndev);
 
 	pause->autoneg = (fep->pause_flag & FEC_PAUSE_FLAG_AUTONEG) != 0;
-	pause->tx_pause = (fep->pause_flag & FEC_PAUSE_FLAG_ENABLE) != 0;
-	pause->rx_pause = pause->tx_pause;
+	pause->rx_pause = (fep->pause_flag & FEC_PAUSE_FLAG_RX) != 0;
+	pause->tx_pause = (fep->pause_flag & FEC_PAUSE_FLAG_TX) != 0;
 }
 
 static int fec_enet_set_pauseparam(struct net_device *ndev,
 				   struct ethtool_pauseparam *pause)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
+	unsigned pause_flag, changed;
+	struct phy_device *phy = fep->phy_dev;
 
-	if (!fep->phy_dev)
+	if (!phy)
 		return -ENODEV;
-
-	if (pause->tx_pause != pause->rx_pause) {
-		netdev_info(ndev,
-			"hardware only support enable/disable both tx and rx");
+	if (!(phy->supported & SUPPORTED_Pause))
+		return -EINVAL;
+	if (!(phy->supported & SUPPORTED_Asym_Pause) &&
+	    pause->rx_pause != pause->tx_pause)
 		return -EINVAL;
-	}
 
-	fep->pause_flag = 0;
+	pause_flag = 0;
+	if (pause->autoneg)
+		pause_flag |= FEC_PAUSE_FLAG_AUTONEG;
+	if (pause->rx_pause)
+		pause_flag |= FEC_PAUSE_FLAG_RX;
+	if (pause->tx_pause)
+		pause_flag |= FEC_PAUSE_FLAG_TX;
 
-	/* tx pause must be same as rx pause */
-	fep->pause_flag |= pause->rx_pause ? FEC_PAUSE_FLAG_ENABLE : 0;
-	fep->pause_flag |= pause->autoneg ? FEC_PAUSE_FLAG_AUTONEG : 0;
+	changed = fep->pause_flag ^ pause_flag;
+	fep->pause_flag = pause_flag;
 
-	if (pause->rx_pause || pause->autoneg) {
-		fep->phy_dev->supported |= ADVERTISED_Pause;
-		fep->phy_dev->advertising |= ADVERTISED_Pause;
-	} else {
-		fep->phy_dev->supported &= ~ADVERTISED_Pause;
-		fep->phy_dev->advertising &= ~ADVERTISED_Pause;
-	}
+	/* configure the phy advertisment according to our new options */
+	fec_enet_phy_config(ndev);
 
-	if (pause->autoneg) {
-		if (netif_running(ndev))
-			fec_stop(ndev);
-		phy_start_aneg(fep->phy_dev);
-	}
-	if (netif_running(ndev)) {
-		napi_disable(&fep->napi);
-		netif_tx_lock_bh(ndev);
-		fec_restart(ndev);
-		netif_wake_queue(ndev);
-		netif_tx_unlock_bh(ndev);
-		napi_enable(&fep->napi);
+	if (changed) {
+		if (pause_flag & FEC_PAUSE_FLAG_AUTONEG) {
+			if (netif_running(ndev))
+				phy_start_aneg(fep->phy_dev);
+		} else {
+			int adv, old_adv;
+
+			/*
+			 * Even if we are not in autonegotiate mode, we
+			 * still update the phy with our capabilities so
+			 * our link parter can make the appropriate
+			 * decision.  PHYLIB provides no way to do this.
+			 */
+			adv = phy_read(phy, MII_ADVERTISE);
+			if (adv >= 0) {
+				old_adv = adv;
+				adv &= ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
+				if (phy->advertising & ADVERTISED_Pause)
+					adv |= ADVERTISE_PAUSE_CAP;
+				if (phy->advertising & ADVERTISED_Asym_Pause)
+					adv |= ADVERTISE_PAUSE_ASYM;
+
+				if (old_adv != adv)
+					phy_write(phy, MII_ADVERTISE, adv);
+			}
+
+			/* Forced pause mode */
+			fep->pause_mode = fep->pause_flag;
+
+			if (netif_running(ndev)) {
+				napi_disable(&fep->napi);
+				netif_tx_lock_bh(ndev);
+				fec_stop(ndev);
+				fec_restart(ndev);
+				netif_wake_queue(ndev);
+				netif_tx_unlock_bh(ndev);
+				napi_enable(&fep->napi);
+			}
+		}
 	}
 
 	return 0;
@@ -2253,7 +2343,9 @@ fec_probe(struct platform_device *pdev)
 	/* default enable pause frame auto negotiation */
 	if (pdev->id_entry &&
 	    (pdev->id_entry->driver_data & FEC_QUIRK_HAS_GBIT))
-		fep->pause_flag |= FEC_PAUSE_FLAG_AUTONEG;
+		fep->pause_flag |= FEC_PAUSE_FLAG_AUTONEG |
+				   FEC_PAUSE_FLAG_TX |
+				   FEC_PAUSE_FLAG_RX;
 #endif
 
 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 114/222] net:fec: move transmit dma ring address calculation to fec_enet_init()
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (112 preceding siblings ...)
  2014-04-25 11:41 ` [PATCH 113/222] net:fec: add better flow control support Russell King
@ 2014-04-25 11:41 ` Russell King
  2014-04-25 11:41 ` [PATCH 115/222] net:fec: allocate descriptor rings at device open, and free on device close Russell King
                   ` (108 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:41 UTC (permalink / raw)
  To: linux-arm-kernel

Move the calculation of the transmit DMA ring address to fec_enet_init()
so the CPU and DMA ring address calculations are localised.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec.h      |  3 ++-
 drivers/net/ethernet/freescale/fec_main.c | 24 ++++++++++++------------
 2 files changed, 14 insertions(+), 13 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index af81d0f62dae..29f607a2d9b0 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -287,7 +287,8 @@ struct fec_enet_private {
 	struct	sk_buff *rx_skbuff[RX_RING_SIZE];
 
 	/* CPM dual port RAM relative addresses */
-	dma_addr_t	bd_dma;
+	dma_addr_t	rx_bd_dma;
+	dma_addr_t	tx_bd_dma;
 	/* Address of Rx and Tx buffers */
 	union bufdesc_u	*rx_bd_base;
 	union bufdesc_u	*tx_bd_base;
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index fb01d7891b67..96e74ef0c4d6 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -611,14 +611,8 @@ fec_restart(struct net_device *ndev)
 	netdev_reset_queue(ndev);
 
 	/* Set receive and transmit descriptor base. */
-	writel(fep->bd_dma, fep->hwp + FEC_R_DES_START);
-	if (fep->bufdesc_ex)
-		writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc_ex)
-			* fep->rx_ring_size, fep->hwp + FEC_X_DES_START);
-	else
-		writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc)
-			* fep->rx_ring_size,	fep->hwp + FEC_X_DES_START);
-
+	writel(fep->rx_bd_dma, fep->hwp + FEC_R_DES_START);
+	writel(fep->tx_bd_dma, fep->hwp + FEC_X_DES_START);
 
 	for (i = 0; i <= TX_RING_MOD_MASK; i++) {
 		if (fep->tx_skbuff[i]) {
@@ -2208,10 +2202,10 @@ static int fec_enet_init(struct net_device *ndev)
 	const struct platform_device_id *id_entry =
 				platform_get_device_id(fep->pdev);
 	union bufdesc_u *cbd_base;
+	dma_addr_t cbd_dma;
 
 	/* Allocate memory for buffer descriptors. */
-	cbd_base = dma_alloc_coherent(NULL, PAGE_SIZE, &fep->bd_dma,
-				      GFP_KERNEL);
+	cbd_base = dma_alloc_coherent(NULL, PAGE_SIZE, &cbd_dma, GFP_KERNEL);
 	if (!cbd_base)
 		return -ENOMEM;
 
@@ -2230,12 +2224,18 @@ static int fec_enet_init(struct net_device *ndev)
 
 	/* Set receive and transmit descriptor base. */
 	fep->rx_bd_base = cbd_base;
-	if (fep->bufdesc_ex)
+	fep->rx_bd_dma = cbd_dma;
+	if (fep->bufdesc_ex) {
 		fep->tx_bd_base = (union bufdesc_u *)
 			(&cbd_base->ebd + fep->rx_ring_size);
-	else
+		fep->tx_bd_dma = cbd_dma + sizeof(struct bufdesc_ex) *
+			fep->rx_ring_size;
+	} else {
 		fep->tx_bd_base = (union bufdesc_u *)
 			(&cbd_base->bd + fep->rx_ring_size);
+		fep->tx_bd_dma = cbd_dma + sizeof(struct bufdesc) *
+			fep->rx_ring_size;
+	}
 
 	/* The FEC Ethernet specific entries in the device structure */
 	ndev->watchdog_timeo = TX_TIMEOUT;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 115/222] net:fec: allocate descriptor rings at device open, and free on device close
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (113 preceding siblings ...)
  2014-04-25 11:41 ` [PATCH 114/222] net:fec: move transmit dma ring address calculation to fec_enet_init() Russell King
@ 2014-04-25 11:41 ` Russell King
  2014-04-25 11:41 ` [PATCH 116/222] net:fec: remove unnecessary code Russell King
                   ` (107 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:41 UTC (permalink / raw)
  To: linux-arm-kernel

The driver has had a memory leak for quite some time: when the device is
probed, we allocate a page for the descriptor rings, but we never free
this.

Rather than trying to free it on the various probe failure paths, move
its allocation to device open time - we have to restart the FEC for this
to take effect.  This also means we can free the descriptor rings when
we clean up in the device close function, which gives this a nice
symmetry.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 67 +++++++++++++++----------------
 1 file changed, 32 insertions(+), 35 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 96e74ef0c4d6..9471abb189bc 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -607,7 +607,8 @@ fec_restart(struct net_device *ndev)
 	/* Set maximum receive buffer size. */
 	writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE);
 
-	fec_enet_bd_init(ndev);
+	if (fep->rx_bd_base)
+		fec_enet_bd_init(ndev);
 	netdev_reset_queue(ndev);
 
 	/* Set receive and transmit descriptor base. */
@@ -1889,6 +1890,8 @@ static void fec_enet_free_buffers(struct net_device *ndev)
 		if (skb)
 			dev_kfree_skb(skb);
 	}
+
+	dma_free_coherent(NULL, PAGE_SIZE, fep->rx_bd_base, fep->rx_bd_dma);
 }
 
 static int fec_enet_alloc_buffers(struct net_device *ndev)
@@ -1897,6 +1900,30 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
 	unsigned int i;
 	struct sk_buff *skb;
 	union bufdesc_u *bdp;
+	union bufdesc_u *cbd_base;
+	dma_addr_t cbd_dma;
+
+	/* Allocate memory for buffer descriptors. */
+	cbd_base = dma_alloc_coherent(NULL, PAGE_SIZE, &cbd_dma, GFP_KERNEL);
+	if (!cbd_base)
+		return -ENOMEM;
+
+	memset(cbd_base, 0, PAGE_SIZE);
+
+	/* Set receive and transmit descriptor base. */
+	fep->rx_bd_base = cbd_base;
+	fep->rx_bd_dma = cbd_dma;
+	if (fep->bufdesc_ex) {
+		fep->tx_bd_base = (union bufdesc_u *)
+			(&cbd_base->ebd + fep->rx_ring_size);
+		fep->tx_bd_dma = cbd_dma + sizeof(struct bufdesc_ex) *
+			fep->rx_ring_size;
+	} else {
+		fep->tx_bd_base = (union bufdesc_u *)
+			(&cbd_base->bd + fep->rx_ring_size);
+		fep->tx_bd_dma = cbd_dma + sizeof(struct bufdesc) *
+			fep->rx_ring_size;
+	}
 
 	for (i = 0; i < fep->rx_ring_size; i++) {
 		dma_addr_t addr;
@@ -2192,24 +2219,11 @@ static const struct net_device_ops fec_netdev_ops = {
 	.ndo_set_features	= fec_set_features,
 };
 
- /*
-  * XXX:  We need to clean up on failure exits here.
-  *
-  */
-static int fec_enet_init(struct net_device *ndev)
+static void fec_enet_init(struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	const struct platform_device_id *id_entry =
 				platform_get_device_id(fep->pdev);
-	union bufdesc_u *cbd_base;
-	dma_addr_t cbd_dma;
-
-	/* Allocate memory for buffer descriptors. */
-	cbd_base = dma_alloc_coherent(NULL, PAGE_SIZE, &cbd_dma, GFP_KERNEL);
-	if (!cbd_base)
-		return -ENOMEM;
-
-	memset(cbd_base, 0, PAGE_SIZE);
 
 	fep->netdev = ndev;
 
@@ -2222,20 +2236,8 @@ static int fec_enet_init(struct net_device *ndev)
 	fep->tx_ring_size = TX_RING_SIZE;
 	fep->rx_ring_size = RX_RING_SIZE;
 
-	/* Set receive and transmit descriptor base. */
-	fep->rx_bd_base = cbd_base;
-	fep->rx_bd_dma = cbd_dma;
-	if (fep->bufdesc_ex) {
-		fep->tx_bd_base = (union bufdesc_u *)
-			(&cbd_base->ebd + fep->rx_ring_size);
-		fep->tx_bd_dma = cbd_dma + sizeof(struct bufdesc_ex) *
-			fep->rx_ring_size;
-	} else {
-		fep->tx_bd_base = (union bufdesc_u *)
-			(&cbd_base->bd + fep->rx_ring_size);
-		fep->tx_bd_dma = cbd_dma + sizeof(struct bufdesc) *
-			fep->rx_ring_size;
-	}
+	fep->rx_bd_base = fep->tx_bd_base = NULL;
+	fep->rx_bd_dma = fep->tx_bd_dma = 0;
 
 	/* The FEC Ethernet specific entries in the device structure */
 	ndev->watchdog_timeo = TX_TIMEOUT;
@@ -2272,8 +2274,6 @@ static int fec_enet_init(struct net_device *ndev)
 		fep->tx_min = 1;
 
 	fec_restart(ndev);
-
-	return 0;
 }
 
 #ifdef CONFIG_OF
@@ -2435,9 +2435,7 @@ fec_probe(struct platform_device *pdev)
 	if (fep->bufdesc_ex)
 		fec_ptp_init(pdev);
 
-	ret = fec_enet_init(ndev);
-	if (ret)
-		goto failed_init;
+	fec_enet_init(ndev);
 
 	for (i = 0; i < FEC_IRQ_NUM; i++) {
 		irq = platform_get_irq(pdev, i);
@@ -2474,7 +2472,6 @@ fec_probe(struct platform_device *pdev)
 	fec_enet_mii_remove(fep);
 failed_mii_init:
 failed_irq:
-failed_init:
 	if (fep->reg_phy)
 		regulator_disable(fep->reg_phy);
 failed_regulator:
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 116/222] net:fec: remove unnecessary code
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (114 preceding siblings ...)
  2014-04-25 11:41 ` [PATCH 115/222] net:fec: allocate descriptor rings at device open, and free on device close Russell King
@ 2014-04-25 11:41 ` Russell King
  2014-04-25 11:41 ` [PATCH 117/222] net:fec: consolidate common parts of mdio read/write Russell King
                   ` (106 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:41 UTC (permalink / raw)
  To: linux-arm-kernel

fec_enet_bd_init() already frees the transmit skbuffs, so there's no
need for fec_restart() to do this again.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec.h      | 1 -
 drivers/net/ethernet/freescale/fec_main.c | 8 --------
 2 files changed, 9 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 29f607a2d9b0..70ef32c965e5 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -252,7 +252,6 @@ union bufdesc_u {
 #define FEC_ENET_TX_FRSIZE	2048
 #define FEC_ENET_TX_FRPPG	(PAGE_SIZE / FEC_ENET_TX_FRSIZE)
 #define TX_RING_SIZE		64	/* Must be power of two */
-#define TX_RING_MOD_MASK	63	/*   for this to work */
 
 #define BD_ENET_RX_INT          0x00800000
 #define BD_ENET_RX_PTP          ((ushort)0x0400)
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 9471abb189bc..40ab7b7ccacf 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -581,7 +581,6 @@ fec_restart(struct net_device *ndev)
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	const struct platform_device_id *id_entry =
 				platform_get_device_id(fep->pdev);
-	int i;
 	u32 val;
 	u32 temp_mac[2];
 	u32 rcntl = OPT_FRAME_SIZE | 0x04;
@@ -615,13 +614,6 @@ fec_restart(struct net_device *ndev)
 	writel(fep->rx_bd_dma, fep->hwp + FEC_R_DES_START);
 	writel(fep->tx_bd_dma, fep->hwp + FEC_X_DES_START);
 
-	for (i = 0; i <= TX_RING_MOD_MASK; i++) {
-		if (fep->tx_skbuff[i]) {
-			dev_kfree_skb_any(fep->tx_skbuff[i]);
-			fep->tx_skbuff[i] = NULL;
-		}
-	}
-
 	/* Enable MII mode */
 	if (fep->full_duplex == DUPLEX_FULL) {
 		/* FD enable */
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 117/222] net:fec: consolidate common parts of mdio read/write
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (115 preceding siblings ...)
  2014-04-25 11:41 ` [PATCH 116/222] net:fec: remove unnecessary code Russell King
@ 2014-04-25 11:41 ` Russell King
  2014-04-25 11:41 ` [PATCH 118/222] net:fec: add locking for MDIO bus access Russell King
                   ` (105 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:41 UTC (permalink / raw)
  To: linux-arm-kernel

There is a commonality to fec_enet_mdio_read() and fec_enet_mdio_write()
which can be factored out.  Factor that commonality out, since we need
to add some locking to prevent resets interfering with MDIO accesses.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 41 +++++++++++++------------------
 1 file changed, 17 insertions(+), 24 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 40ab7b7ccacf..f6763686d5a9 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1305,23 +1305,27 @@ static void fec_enet_adjust_link(struct net_device *ndev)
 		phy_print_status(phy_dev);
 }
 
-static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+static unsigned long fec_enet_mdio_op(struct fec_enet_private *fep,
+	unsigned data)
 {
-	struct fec_enet_private *fep = bus->priv;
-	unsigned long time_left;
-
 	fep->mii_timeout = 0;
 	init_completion(&fep->mdio_done);
 
-	/* start a read op */
-	writel(FEC_MMFR_ST | FEC_MMFR_OP_READ |
-		FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(regnum) |
-		FEC_MMFR_TA, fep->hwp + FEC_MII_DATA);
+	/* start operation */
+	writel(data, fep->hwp + FEC_MII_DATA);
 
 	/* wait for end of transfer */
-	time_left = wait_for_completion_timeout(&fep->mdio_done,
+	return wait_for_completion_timeout(&fep->mdio_done,
 			usecs_to_jiffies(FEC_MII_TIMEOUT));
-	if (time_left == 0) {
+}
+
+static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+	struct fec_enet_private *fep = bus->priv;
+
+	if (fec_enet_mdio_op(fep, FEC_MMFR_ST | FEC_MMFR_OP_READ |
+				  FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(regnum) |
+				  FEC_MMFR_TA) == 0) {
 		fep->mii_timeout = 1;
 		netdev_err(fep->netdev, "MDIO read timeout\n");
 		return -ETIMEDOUT;
@@ -1335,21 +1339,10 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
 			   u16 value)
 {
 	struct fec_enet_private *fep = bus->priv;
-	unsigned long time_left;
-
-	fep->mii_timeout = 0;
-	init_completion(&fep->mdio_done);
 
-	/* start a write op */
-	writel(FEC_MMFR_ST | FEC_MMFR_OP_WRITE |
-		FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(regnum) |
-		FEC_MMFR_TA | FEC_MMFR_DATA(value),
-		fep->hwp + FEC_MII_DATA);
-
-	/* wait for end of transfer */
-	time_left = wait_for_completion_timeout(&fep->mdio_done,
-			usecs_to_jiffies(FEC_MII_TIMEOUT));
-	if (time_left == 0) {
+	if (fec_enet_mdio_op(fep, FEC_MMFR_ST | FEC_MMFR_OP_WRITE |
+				  FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(regnum) |
+				  FEC_MMFR_TA | FEC_MMFR_DATA(value)) == 0) {
 		fep->mii_timeout = 1;
 		netdev_err(fep->netdev, "MDIO write timeout\n");
 		return -ETIMEDOUT;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 118/222] net:fec: add locking for MDIO bus access
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (116 preceding siblings ...)
  2014-04-25 11:41 ` [PATCH 117/222] net:fec: consolidate common parts of mdio read/write Russell King
@ 2014-04-25 11:41 ` Russell King
  2014-04-25 11:41 ` [PATCH 119/222] net:fec: move bufdesc_ex flag into flags Russell King
                   ` (104 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:41 UTC (permalink / raw)
  To: linux-arm-kernel

Both fec_restart() and fec_stop() both perform a reset of the FEC.  This
reset can result in an in-process MDIO transfer being terminated, which
can lead to the MDIO read/write functions timing out.  Add some locking
to prevent this occuring.

We can't use a spinlock for this as the MDIO accessor functions use
wait_for_completion_timeout(), which sleeps.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec.h      |  3 +++
 drivers/net/ethernet/freescale/fec_main.c | 30 +++++++++++++++++++++++++++++-
 2 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 70ef32c965e5..11717d2fd520 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -14,6 +14,7 @@
 /****************************************************************************/
 
 #include <linux/clocksource.h>
+#include <linux/mutex.h>
 #include <linux/net_tstamp.h>
 #include <linux/ptp_clock_kernel.h>
 
@@ -300,6 +301,8 @@ struct fec_enet_private {
 	unsigned short tx_ring_size;
 	unsigned short rx_ring_size;
 
+	struct mutex mutex;
+
 	struct	platform_device *pdev;
 
 	int	dev_id;
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index f6763686d5a9..afbcd7f14951 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -795,12 +795,14 @@ static void fec_enet_timeout_work(struct work_struct *work)
 
 	rtnl_lock();
 	if (netif_device_present(ndev) || netif_running(ndev)) {
+		mutex_lock(&fep->mutex);
 		napi_disable(&fep->napi);
 		netif_tx_lock_bh(ndev);
 		fec_restart(ndev);
 		netif_wake_queue(ndev);
 		netif_tx_unlock_bh(ndev);
 		napi_enable(&fep->napi);
+		mutex_unlock(&fep->mutex);
 	}
 	rtnl_unlock();
 }
@@ -1282,20 +1284,24 @@ static void fec_enet_adjust_link(struct net_device *ndev)
 
 		/* if any of the above changed restart the FEC */
 		if (status_change) {
+			mutex_lock(&fep->mutex);
 			napi_disable(&fep->napi);
 			netif_tx_lock_bh(ndev);
 			fec_restart(ndev);
 			netif_wake_queue(ndev);
 			netif_tx_unlock_bh(ndev);
 			napi_enable(&fep->napi);
+			mutex_unlock(&fep->mutex);
 		}
 	} else {
 		if (fep->link) {
+			mutex_lock(&fep->mutex);
 			napi_disable(&fep->napi);
 			netif_tx_lock_bh(ndev);
 			fec_stop(ndev);
 			netif_tx_unlock_bh(ndev);
 			napi_enable(&fep->napi);
+			mutex_unlock(&fep->mutex);
 			fep->link = phy_dev->link;
 			status_change = 1;
 		}
@@ -1308,15 +1314,23 @@ static void fec_enet_adjust_link(struct net_device *ndev)
 static unsigned long fec_enet_mdio_op(struct fec_enet_private *fep,
 	unsigned data)
 {
+	unsigned long time_left;
+
 	fep->mii_timeout = 0;
 	init_completion(&fep->mdio_done);
 
+	mutex_lock(&fep->mutex);
+
 	/* start operation */
 	writel(data, fep->hwp + FEC_MII_DATA);
 
 	/* wait for end of transfer */
-	return wait_for_completion_timeout(&fep->mdio_done,
+	time_left = wait_for_completion_timeout(&fep->mdio_done,
 			usecs_to_jiffies(FEC_MII_TIMEOUT));
+
+	mutex_unlock(&fep->mutex);
+
+	return time_left;
 }
 
 static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
@@ -1683,6 +1697,7 @@ static int fec_enet_set_pauseparam(struct net_device *ndev,
 			fep->pause_mode = fep->pause_flag;
 
 			if (netif_running(ndev)) {
+				mutex_lock(&fep->mutex);
 				napi_disable(&fep->napi);
 				netif_tx_lock_bh(ndev);
 				fec_stop(ndev);
@@ -1690,6 +1705,7 @@ static int fec_enet_set_pauseparam(struct net_device *ndev,
 				netif_wake_queue(ndev);
 				netif_tx_unlock_bh(ndev);
 				napi_enable(&fep->napi);
+				mutex_unlock(&fep->mutex);
 			}
 		}
 	}
@@ -1983,7 +1999,9 @@ fec_enet_open(struct net_device *ndev)
 		return ret;
 	}
 
+	mutex_lock(&fep->mutex);
 	fec_restart(ndev);
+	mutex_unlock(&fep->mutex);
 	napi_enable(&fep->napi);
 	phy_start(fep->phy_dev);
 	netif_start_queue(ndev);
@@ -2000,7 +2018,9 @@ fec_enet_close(struct net_device *ndev)
 	if (netif_device_present(ndev)) {
 		napi_disable(&fep->napi);
 		netif_tx_disable(ndev);
+		mutex_lock(&fep->mutex);
 		fec_stop(ndev);
+		mutex_unlock(&fep->mutex);
 	}
 
 	phy_disconnect(fep->phy_dev);
@@ -2155,6 +2175,7 @@ static int fec_set_features(struct net_device *netdev,
 
 	/* Quiesce the device if necessary */
 	if (netif_running(netdev) && changed & FEATURES_NEED_QUIESCE) {
+		mutex_lock(&fep->mutex);
 		napi_disable(&fep->napi);
 		netif_tx_lock_bh(netdev);
 		fec_stop(netdev);
@@ -2182,6 +2203,7 @@ static int fec_set_features(struct net_device *netdev,
 		netif_wake_queue(netdev);
 		netif_tx_unlock_bh(netdev);
 		napi_enable(&fep->napi);
+		mutex_unlock(&fep->mutex);
 	}
 
 	return 0;
@@ -2324,6 +2346,8 @@ fec_probe(struct platform_device *pdev)
 	/* setup board info structure */
 	fep = netdev_priv(ndev);
 
+	mutex_init(&fep->mutex);
+
 #if !defined(CONFIG_M5272)
 	/* default enable pause frame auto negotiation */
 	if (pdev->id_entry &&
@@ -2515,7 +2539,9 @@ fec_suspend(struct device *dev)
 		netif_tx_lock_bh(ndev);
 		netif_device_detach(ndev);
 		netif_tx_unlock_bh(ndev);
+		mutex_lock(&fep->mutex);
 		fec_stop(ndev);
+		mutex_unlock(&fep->mutex);
 	}
 	rtnl_unlock();
 
@@ -2567,7 +2593,9 @@ fec_resume(struct device *dev)
 
 	rtnl_lock();
 	if (netif_running(ndev)) {
+		mutex_lock(&fep->mutex);
 		fec_restart(ndev);
+		mutex_unlock(&fep->mutex);
 		netif_tx_lock_bh(ndev);
 		netif_device_attach(ndev);
 		netif_tx_unlock_bh(ndev);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 119/222] net:fec: move bufdesc_ex flag into flags
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (117 preceding siblings ...)
  2014-04-25 11:41 ` [PATCH 118/222] net:fec: add locking for MDIO bus access Russell King
@ 2014-04-25 11:41 ` Russell King
  2014-04-25 11:41 ` [PATCH 120/222] net:fec: move receive checksum flags into new flags member Russell King
                   ` (103 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:41 UTC (permalink / raw)
  To: linux-arm-kernel

Add a new flags field to contain the mostly static driver configuration,
the first of which is the bufdesc_ex flag.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec.h      |  3 +-
 drivers/net/ethernet/freescale/fec_main.c | 48 +++++++++++++++++--------------
 2 files changed, 28 insertions(+), 23 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 11717d2fd520..a5d38e4c770c 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -301,6 +301,8 @@ struct fec_enet_private {
 	unsigned short tx_ring_size;
 	unsigned short rx_ring_size;
 
+	unsigned char flags;
+
 	struct mutex mutex;
 
 	struct	platform_device *pdev;
@@ -318,7 +320,6 @@ struct fec_enet_private {
 	int	speed;
 	struct	completion mdio_done;
 	int	irq[FEC_IRQ_NUM];
-	int	bufdesc_ex;
 	unsigned short pause_flag;
 	unsigned short pause_mode;
 
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index afbcd7f14951..c35a1e00129c 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -225,10 +225,14 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
 /* Transmitter timeout */
 #define TX_TIMEOUT (2 * HZ)
 
+/* pause mode/flag */
 #define FEC_PAUSE_FLAG_AUTONEG	BIT(0)
 #define FEC_PAUSE_FLAG_RX	BIT(1)
 #define FEC_PAUSE_FLAG_TX	BIT(2)
 
+/* flags */
+#define FEC_FLAG_BUFDESC_EX	BIT(0)
+
 static int mii_cnt;
 
 static union bufdesc_u *
@@ -237,7 +241,7 @@ fec_enet_tx_get(unsigned index, struct fec_enet_private *fep)
 	union bufdesc_u *base = fep->tx_bd_base;
 	union bufdesc_u *bdp;
 
-	if (fep->bufdesc_ex)
+	if (fep->flags & FEC_FLAG_BUFDESC_EX)
 		bdp = (union bufdesc_u *)(&base->ebd + index);
 	else
 		bdp = (union bufdesc_u *)(&base->bd + index);
@@ -253,7 +257,7 @@ fec_enet_rx_get(unsigned index, struct fec_enet_private *fep)
 
 	index &= fep->rx_ring_size - 1;
 
-	if (fep->bufdesc_ex)
+	if (fep->flags & FEC_FLAG_BUFDESC_EX)
 		bdp = (union bufdesc_u *)(&base->ebd + index);
 	else
 		bdp = (union bufdesc_u *)(&base->bd + index);
@@ -417,7 +421,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	fep->tx_page_map[index] = 0;
 
 	cbd_esc = BD_ENET_TX_INT;
-	if (fep->bufdesc_ex) {
+	if (fep->flags & FEC_FLAG_BUFDESC_EX) {
 		if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
 			fep->hwts_tx_en)) {
 			cbd_esc |= BD_ENET_TX_TS;
@@ -464,7 +468,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 		bdp = fec_enet_tx_get(last, fep);
 		bdp->bd.cbd_datlen = length;
 		bdp->bd.cbd_bufaddr = addr;
-		if (fep->bufdesc_ex) {
+		if (fep->flags & FEC_FLAG_BUFDESC_EX) {
 			bdp->ebd.cbd_esc = cbd_esc;
 			bdp->ebd.cbd_bdu = 0;
 		}
@@ -726,7 +730,7 @@ fec_restart(struct net_device *ndev)
 		writel(1 << 8, fep->hwp + FEC_X_WMRK);
 	}
 
-	if (fep->bufdesc_ex)
+	if (fep->flags & FEC_FLAG_BUFDESC_EX)
 		ecntl |= (1 << 4);
 
 #ifndef CONFIG_M5272
@@ -738,7 +742,7 @@ fec_restart(struct net_device *ndev)
 	writel(ecntl, fep->hwp + FEC_ECNTRL);
 	writel(0, fep->hwp + FEC_R_DES_ACTIVE);
 
-	if (fep->bufdesc_ex)
+	if (fep->flags & FEC_FLAG_BUFDESC_EX)
 		fec_ptp_start_cyclecounter(ndev);
 
 	/* Enable interrupts we wish to service */
@@ -879,7 +883,7 @@ fec_enet_tx(struct net_device *ndev)
 			ndev->stats.collisions++;
 
 		if (skb) {
-			if (fep->bufdesc_ex &&
+			if (fep->flags & FEC_FLAG_BUFDESC_EX &&
 			    unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) {
 				struct skb_shared_hwtstamps shhwtstamps;
 
@@ -998,7 +1002,7 @@ fec_enet_rx(struct net_device *ndev, int budget)
 		/* If this is a VLAN packet remove the VLAN Tag */
 		vlan_packet_rcvd = false;
 		if ((ndev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
-		    fep->bufdesc_ex && (bdp->ebd.cbd_esc & BD_ENET_RX_VLAN)) {
+		    fep->flags & FEC_FLAG_BUFDESC_EX && (bdp->ebd.cbd_esc & BD_ENET_RX_VLAN)) {
 			/* Push and remove the vlan tag */
 			struct vlan_hdr *vlan_header =
 					(struct vlan_hdr *) (data + ETH_HLEN);
@@ -1033,11 +1037,11 @@ fec_enet_rx(struct net_device *ndev, int budget)
 			skb->protocol = eth_type_trans(skb, ndev);
 
 			/* Get receive timestamp from the skb */
-			if (fep->hwts_rx_en && fep->bufdesc_ex)
+			if (fep->hwts_rx_en && fep->flags & FEC_FLAG_BUFDESC_EX)
 				fec_enet_hwtstamp(fep, bdp->ebd.ts,
 						  skb_hwtstamps(skb));
 
-			if (fep->bufdesc_ex &&
+			if (fep->flags & FEC_FLAG_BUFDESC_EX &&
 			    (fep->csum_flags & FLAG_RX_CSUM_ENABLED)) {
 				if (!(bdp->ebd.cbd_esc & FLAG_RX_CSUM_ERROR)) {
 					/* don't check it */
@@ -1059,7 +1063,7 @@ fec_enet_rx(struct net_device *ndev, int budget)
 		dma_sync_single_for_device(&fep->pdev->dev, bdp->bd.cbd_bufaddr,
 					FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
 rx_processing_done:
-		if (fep->bufdesc_ex) {
+		if (fep->flags & FEC_FLAG_BUFDESC_EX) {
 			bdp->ebd.cbd_esc = BD_ENET_RX_INT;
 			bdp->ebd.cbd_prot = 0;
 			bdp->ebd.cbd_bdu = 0;
@@ -1602,7 +1606,7 @@ static int fec_enet_get_ts_info(struct net_device *ndev,
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 
-	if (fep->bufdesc_ex) {
+	if (fep->flags & FEC_FLAG_BUFDESC_EX) {
 
 		info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
 					SOF_TIMESTAMPING_RX_SOFTWARE |
@@ -1851,7 +1855,7 @@ static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
 	if (!phydev)
 		return -ENODEV;
 
-	if (fep->bufdesc_ex) {
+	if (fep->flags & FEC_FLAG_BUFDESC_EX) {
 		if (cmd == SIOCSHWTSTAMP)
 			return fec_ptp_set(ndev, rq);
 		if (cmd == SIOCGHWTSTAMP)
@@ -1914,7 +1918,7 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
 	/* Set receive and transmit descriptor base. */
 	fep->rx_bd_base = cbd_base;
 	fep->rx_bd_dma = cbd_dma;
-	if (fep->bufdesc_ex) {
+	if (fep->flags & FEC_FLAG_BUFDESC_EX) {
 		fep->tx_bd_base = (union bufdesc_u *)
 			(&cbd_base->ebd + fep->rx_ring_size);
 		fep->tx_bd_dma = cbd_dma + sizeof(struct bufdesc_ex) *
@@ -1950,7 +1954,7 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
 		if (i == fep->rx_ring_size - 1)
 			bdp->bd.cbd_sc |= BD_SC_WRAP;
 
-		if (fep->bufdesc_ex)
+		if (fep->flags & FEC_FLAG_BUFDESC_EX)
 			bdp->ebd.cbd_esc = BD_ENET_RX_INT;
 	}
 
@@ -1967,7 +1971,7 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
 			bdp->bd.cbd_sc = 0;
 		bdp->bd.cbd_bufaddr = 0;
 
-		if (fep->bufdesc_ex)
+		if (fep->flags & FEC_FLAG_BUFDESC_EX)
 			bdp->ebd.cbd_esc = BD_ENET_TX_INT;
 	}
 
@@ -2367,7 +2371,9 @@ fec_probe(struct platform_device *pdev)
 	fep->pdev = pdev;
 	fep->dev_id = dev_id++;
 
-	fep->bufdesc_ex = 0;
+	fep->flags = 0;
+	if (pdev->id_entry->driver_data & FEC_QUIRK_HAS_BUFDESC_EX)
+		fep->flags |= FEC_FLAG_BUFDESC_EX;
 
 	platform_set_drvdata(pdev, ndev);
 
@@ -2400,11 +2406,9 @@ fec_probe(struct platform_device *pdev)
 		fep->clk_enet_out = NULL;
 
 	fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp");
-	fep->bufdesc_ex =
-		pdev->id_entry->driver_data & FEC_QUIRK_HAS_BUFDESC_EX;
 	if (IS_ERR(fep->clk_ptp)) {
 		fep->clk_ptp = NULL;
-		fep->bufdesc_ex = 0;
+		fep->flags &= ~FEC_FLAG_BUFDESC_EX;
 	}
 
 	ret = clk_prepare_enable(fep->clk_ahb);
@@ -2441,7 +2445,7 @@ fec_probe(struct platform_device *pdev)
 
 	fec_reset_phy(pdev);
 
-	if (fep->bufdesc_ex)
+	if (fep->flags & FEC_FLAG_BUFDESC_EX)
 		fec_ptp_init(pdev);
 
 	fec_enet_init(ndev);
@@ -2471,7 +2475,7 @@ fec_probe(struct platform_device *pdev)
 	if (ret)
 		goto failed_register;
 
-	if (fep->bufdesc_ex && fep->ptp_clock)
+	if (fep->flags & FEC_FLAG_BUFDESC_EX && fep->ptp_clock)
 		netdev_info(ndev, "registered PHC device %d\n", fep->dev_id);
 
 	INIT_WORK(&fep->tx_timeout_work, fec_enet_timeout_work);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 120/222] net:fec: move receive checksum flags into new flags member
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (118 preceding siblings ...)
  2014-04-25 11:41 ` [PATCH 119/222] net:fec: move bufdesc_ex flag into flags Russell King
@ 2014-04-25 11:41 ` Russell King
  2014-04-25 11:41 ` [PATCH 121/222] net:fec: only enable CTAG_RX and IP checksumming if we have enhanced buffer descriptors Russell King
                   ` (102 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:41 UTC (permalink / raw)
  To: linux-arm-kernel

The receive checksum flag is mostly static, so move it into the flags
member.  In any case, this is checked alongside the BUFDESC_EX flag.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec.h      |  2 --
 drivers/net/ethernet/freescale/fec_main.c | 11 ++++++-----
 2 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index a5d38e4c770c..aaf5aaaf9e56 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -258,7 +258,6 @@ union bufdesc_u {
 #define BD_ENET_RX_PTP          ((ushort)0x0400)
 #define BD_ENET_RX_ICE		0x00000020
 #define BD_ENET_RX_PCR		0x00000010
-#define FLAG_RX_CSUM_ENABLED	(BD_ENET_RX_ICE | BD_ENET_RX_PCR)
 #define FLAG_RX_CSUM_ERROR	(BD_ENET_RX_ICE | BD_ENET_RX_PCR)
 
 /* The FEC buffer descriptors track the ring buffers.  The rx_bd_base and
@@ -324,7 +323,6 @@ struct fec_enet_private {
 	unsigned short pause_mode;
 
 	struct	napi_struct napi;
-	int	csum_flags;
 
 	struct work_struct tx_timeout_work;
 
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index c35a1e00129c..81ade95c06e0 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -232,6 +232,7 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
 
 /* flags */
 #define FEC_FLAG_BUFDESC_EX	BIT(0)
+#define FEC_FLAG_RX_CSUM	BIT(1)
 
 static int mii_cnt;
 
@@ -634,7 +635,7 @@ fec_restart(struct net_device *ndev)
 #if !defined(CONFIG_M5272)
 	/* set RX checksum */
 	val = readl(fep->hwp + FEC_RACC);
-	if (fep->csum_flags & FLAG_RX_CSUM_ENABLED)
+	if (fep->flags & FEC_FLAG_RX_CSUM)
 		val |= FEC_RACC_OPTIONS;
 	else
 		val &= ~FEC_RACC_OPTIONS;
@@ -1042,7 +1043,7 @@ fec_enet_rx(struct net_device *ndev, int budget)
 						  skb_hwtstamps(skb));
 
 			if (fep->flags & FEC_FLAG_BUFDESC_EX &&
-			    (fep->csum_flags & FLAG_RX_CSUM_ENABLED)) {
+			    fep->flags & FEC_FLAG_RX_CSUM) {
 				if (!(bdp->ebd.cbd_esc & FLAG_RX_CSUM_ERROR)) {
 					/* don't check it */
 					skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -2190,9 +2191,9 @@ static int fec_set_features(struct net_device *netdev,
 	/* Receive checksum has been changed */
 	if (changed & NETIF_F_RXCSUM) {
 		if (features & NETIF_F_RXCSUM)
-			fep->csum_flags |= FLAG_RX_CSUM_ENABLED;
+			fep->flags |= FEC_FLAG_RX_CSUM;
 		else
-			fep->csum_flags &= ~FLAG_RX_CSUM_ENABLED;
+			fep->flags &= ~FEC_FLAG_RX_CSUM;
 	}
 
 	/* Set the appropriate minimum transmit ring free threshold */
@@ -2270,7 +2271,7 @@ static void fec_enet_init(struct net_device *ndev)
 				| NETIF_F_RXCSUM);
 		ndev->hw_features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM
 				| NETIF_F_RXCSUM);
-		fep->csum_flags |= FLAG_RX_CSUM_ENABLED;
+		fep->flags |= FEC_FLAG_RX_CSUM;
 	}
 
 	if (!(id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)) {
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 121/222] net:fec: only enable CTAG_RX and IP checksumming if we have enhanced buffer descriptors
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (119 preceding siblings ...)
  2014-04-25 11:41 ` [PATCH 120/222] net:fec: move receive checksum flags into new flags member Russell King
@ 2014-04-25 11:41 ` Russell King
  2014-04-25 11:41 ` [PATCH 122/222] net:fec: avoid checking more flags than necessary in rx path Russell King
                   ` (101 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:41 UTC (permalink / raw)
  To: linux-arm-kernel

Only set the vlan tag and ip checksumming options if we have enhanced
buffer descriptors - enhanced descriptors are required for these
features.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 28 +++++++++++++++-------------
 1 file changed, 15 insertions(+), 13 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 81ade95c06e0..7cb852991bf1 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -2259,19 +2259,21 @@ static void fec_enet_init(struct net_device *ndev)
 	writel(FEC_RX_DISABLED_IMASK, fep->hwp + FEC_IMASK);
 	netif_napi_add(ndev, &fep->napi, fec_enet_rx_napi, NAPI_POLL_WEIGHT);
 
-	if (id_entry->driver_data & FEC_QUIRK_HAS_VLAN) {
-		/* enable hw VLAN support */
-		ndev->features |= NETIF_F_HW_VLAN_CTAG_RX;
-		ndev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX;
-	}
-
-	if (id_entry->driver_data & FEC_QUIRK_HAS_CSUM) {
-		/* enable hw accelerator */
-		ndev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM
-				| NETIF_F_RXCSUM);
-		ndev->hw_features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM
-				| NETIF_F_RXCSUM);
-		fep->flags |= FEC_FLAG_RX_CSUM;
+	if (fep->flags & FEC_FLAG_BUFDESC_EX) {
+		if (id_entry->driver_data & FEC_QUIRK_HAS_VLAN) {
+			/* enable hw VLAN support */
+			ndev->features |= NETIF_F_HW_VLAN_CTAG_RX;
+			ndev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX;
+		}
+
+		if (id_entry->driver_data & FEC_QUIRK_HAS_CSUM) {
+			/* enable hw accelerator */
+			ndev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM
+					| NETIF_F_RXCSUM);
+			ndev->hw_features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM
+					| NETIF_F_RXCSUM);
+			fep->flags |= FEC_FLAG_RX_CSUM;
+		}
 	}
 
 	if (!(id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)) {
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 122/222] net:fec: avoid checking more flags than necessary in rx path
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (120 preceding siblings ...)
  2014-04-25 11:41 ` [PATCH 121/222] net:fec: only enable CTAG_RX and IP checksumming if we have enhanced buffer descriptors Russell King
@ 2014-04-25 11:41 ` Russell King
  2014-04-25 11:41 ` [PATCH 123/222] net:fec: move vlan receive flag into our private flags Russell King
                   ` (100 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:41 UTC (permalink / raw)
  To: linux-arm-kernel

Avoid checking for both the receive checksumming flag and the enhanced
buffer descriptor flags - we now only set receive checksumming if we
know we have enhanced buffer descriptors.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 7cb852991bf1..7f05866acee3 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1042,8 +1042,7 @@ fec_enet_rx(struct net_device *ndev, int budget)
 				fec_enet_hwtstamp(fep, bdp->ebd.ts,
 						  skb_hwtstamps(skb));
 
-			if (fep->flags & FEC_FLAG_BUFDESC_EX &&
-			    fep->flags & FEC_FLAG_RX_CSUM) {
+			if (fep->flags & FEC_FLAG_RX_CSUM) {
 				if (!(bdp->ebd.cbd_esc & FLAG_RX_CSUM_ERROR)) {
 					/* don't check it */
 					skb->ip_summed = CHECKSUM_UNNECESSARY;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 123/222] net:fec: move vlan receive flag into our private flags
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (121 preceding siblings ...)
  2014-04-25 11:41 ` [PATCH 122/222] net:fec: avoid checking more flags than necessary in rx path Russell King
@ 2014-04-25 11:41 ` Russell King
  2014-04-25 11:42 ` [PATCH 124/222] net:fec: add ethtool support for tx/rx ring sizes Russell King
                   ` (99 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:41 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 7f05866acee3..11176d483db4 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -233,6 +233,7 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
 /* flags */
 #define FEC_FLAG_BUFDESC_EX	BIT(0)
 #define FEC_FLAG_RX_CSUM	BIT(1)
+#define FEC_FLAG_RX_VLAN	BIT(2)
 
 static int mii_cnt;
 
@@ -1002,8 +1003,8 @@ fec_enet_rx(struct net_device *ndev, int budget)
 
 		/* If this is a VLAN packet remove the VLAN Tag */
 		vlan_packet_rcvd = false;
-		if ((ndev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
-		    fep->flags & FEC_FLAG_BUFDESC_EX && (bdp->ebd.cbd_esc & BD_ENET_RX_VLAN)) {
+		if (fep->flags & FEC_FLAG_RX_VLAN &&
+		    bdp->ebd.cbd_esc & BD_ENET_RX_VLAN) {
 			/* Push and remove the vlan tag */
 			struct vlan_hdr *vlan_header =
 					(struct vlan_hdr *) (data + ETH_HLEN);
@@ -2195,6 +2196,13 @@ static int fec_set_features(struct net_device *netdev,
 			fep->flags &= ~FEC_FLAG_RX_CSUM;
 	}
 
+	if (changed & NETIF_F_HW_VLAN_CTAG_RX) {
+		if (features & NETIF_F_HW_VLAN_CTAG_RX)
+			fep->flags |= FEC_FLAG_RX_VLAN;
+		else
+			fep->flags &= ~FEC_FLAG_RX_VLAN;
+	}
+
 	/* Set the appropriate minimum transmit ring free threshold */
 	if (features & NETIF_F_SG)
 		fep->tx_min = MAX_SKB_FRAGS + 1;
@@ -2263,6 +2271,7 @@ static void fec_enet_init(struct net_device *ndev)
 			/* enable hw VLAN support */
 			ndev->features |= NETIF_F_HW_VLAN_CTAG_RX;
 			ndev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX;
+			fep->flags |= FEC_FLAG_RX_VLAN;
 		}
 
 		if (id_entry->driver_data & FEC_QUIRK_HAS_CSUM) {
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 124/222] net:fec: add ethtool support for tx/rx ring sizes
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (122 preceding siblings ...)
  2014-04-25 11:41 ` [PATCH 123/222] net:fec: move vlan receive flag into our private flags Russell King
@ 2014-04-25 11:42 ` Russell King
  2014-04-25 11:42 ` [PATCH 125/222] net:fec: even larger rings Russell King
                   ` (98 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:42 UTC (permalink / raw)
  To: linux-arm-kernel

Add ethtool support to retrieve and set the transmit and receive ring
sizes.  This allows runtime tuning of these parameters, which can
result in better throughput with gigabit parts.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec_main.c | 47 +++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 11176d483db4..12d48b997744 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1631,6 +1631,51 @@ static int fec_enet_get_ts_info(struct net_device *ndev,
 	}
 }
 
+static void fec_enet_get_ringparam(struct net_device *ndev,
+				   struct ethtool_ringparam *ring)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+
+	ring->rx_max_pending = RX_RING_SIZE;
+	ring->tx_max_pending = TX_RING_SIZE;
+	ring->rx_pending = fep->rx_ring_size;
+	ring->tx_pending = fep->tx_ring_size;
+}
+
+static int fec_enet_set_ringparam(struct net_device *ndev,
+				   struct ethtool_ringparam *ring)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+	unsigned rx, tx, tx_min;
+
+	tx_min = ndev->features & NETIF_F_SG ? TX_RING_SIZE_MIN_SG : 16;
+
+	rx = clamp_t(u32, ring->rx_pending, 16, RX_RING_SIZE);
+	tx = clamp_t(u32, ring->tx_pending, tx_min, TX_RING_SIZE);
+
+	if (tx == fep->tx_ring_size && rx == fep->rx_ring_size)
+		return 0;
+
+	/* Setting the ring size while the interface is down is easy */
+	if (!netif_running(ndev)) {
+		fep->tx_ring_size = tx;
+		fep->rx_ring_size = rx;
+	} else {
+		return -EINVAL;
+
+		napi_disable(&fep->napi);
+		netif_tx_lock_bh(ndev);
+		fec_stop(ndev);
+		/* reallocate ring */
+		fec_restart(ndev);
+		netif_wake_queue(ndev);
+		netif_tx_unlock_bh(ndev);
+		napi_enable(&fep->napi);
+	}
+
+	return 0;
+}
+
 #if !defined(CONFIG_M5272)
 
 static void fec_enet_get_pauseparam(struct net_device *ndev,
@@ -1835,6 +1880,8 @@ static const struct ethtool_ops fec_enet_ethtool_ops = {
 	.get_drvinfo		= fec_enet_get_drvinfo,
 	.nway_reset		= fec_enet_nway_reset,
 	.get_link		= ethtool_op_get_link,
+	.get_ringparam		= fec_enet_get_ringparam,
+	.set_ringparam		= fec_enet_set_ringparam,
 #ifndef CONFIG_M5272
 	.get_pauseparam		= fec_enet_get_pauseparam,
 	.set_pauseparam		= fec_enet_set_pauseparam,
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 125/222] net:fec: even larger rings
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (123 preceding siblings ...)
  2014-04-25 11:42 ` [PATCH 124/222] net:fec: add ethtool support for tx/rx ring sizes Russell King
@ 2014-04-25 11:42 ` Russell King
  2014-04-25 11:42 ` [PATCH 126/222] net:fec: unsorted hacks Russell King
                   ` (97 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:42 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec.h      |  4 +--
 drivers/net/ethernet/freescale/fec_main.c | 45 ++++++++++++++++---------------
 2 files changed, 26 insertions(+), 23 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index aaf5aaaf9e56..bfcab01131cc 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -246,13 +246,13 @@ union bufdesc_u {
  * the skbuffer directly.
  */
 
-#define FEC_ENET_RX_PAGES	32
+#define FEC_ENET_RX_PAGES	64
 #define FEC_ENET_RX_FRSIZE	2048
 #define FEC_ENET_RX_FRPPG	(PAGE_SIZE / FEC_ENET_RX_FRSIZE)
 #define RX_RING_SIZE		(FEC_ENET_RX_FRPPG * FEC_ENET_RX_PAGES)
 #define FEC_ENET_TX_FRSIZE	2048
 #define FEC_ENET_TX_FRPPG	(PAGE_SIZE / FEC_ENET_TX_FRSIZE)
-#define TX_RING_SIZE		64	/* Must be power of two */
+#define TX_RING_SIZE		128	/* Must be power of two */
 
 #define BD_ENET_RX_INT          0x00800000
 #define BD_ENET_RX_PTP          ((ushort)0x0400)
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 12d48b997744..441e472f7779 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -166,8 +166,11 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
 #endif
 #endif /* CONFIG_M5272 */
 
-#if (((RX_RING_SIZE + TX_RING_SIZE) * 32) > PAGE_SIZE)
-#error "FEC: descriptor ring size constants too large"
+#if RX_RING_SIZE * 32 > PAGE_SIZE
+#error "FEC: receive descriptor ring size too large"
+#endif
+#if TX_RING_SIZE * 32 > PAGE_SIZE
+#error "FEC: transmit descriptor ring size too large"
 #endif
 
 /* Minimum TX ring size when using NETIF_F_SG */
@@ -828,7 +831,7 @@ fec_enet_hwtstamp(struct fec_enet_private *fep, unsigned ts,
 	hwtstamps->hwtstamp = ns_to_ktime(ns);
 }
 
-static void
+static void noinline
 fec_enet_tx(struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
@@ -1953,30 +1956,30 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
 	unsigned int i;
 	struct sk_buff *skb;
 	union bufdesc_u *bdp;
-	union bufdesc_u *cbd_base;
-	dma_addr_t cbd_dma;
+	union bufdesc_u *rx_cbd_cpu, *tx_cbd_cpu;
+	dma_addr_t rx_cbd_dma, tx_cbd_dma;
 
 	/* Allocate memory for buffer descriptors. */
-	cbd_base = dma_alloc_coherent(NULL, PAGE_SIZE, &cbd_dma, GFP_KERNEL);
-	if (!cbd_base)
+	rx_cbd_cpu = dma_alloc_coherent(NULL, PAGE_SIZE, &rx_cbd_dma,
+					GFP_KERNEL);
+	tx_cbd_cpu = dma_alloc_coherent(NULL, PAGE_SIZE, &tx_cbd_dma,
+					GFP_KERNEL);
+	if (!rx_cbd_cpu || !tx_cbd_cpu) {
+		if (rx_cbd_cpu)
+			dma_free_coherent(NULL, PAGE_SIZE, rx_cbd_cpu, rx_cbd_dma);
+		if (tx_cbd_cpu)
+			dma_free_coherent(NULL, PAGE_SIZE, tx_cbd_cpu, tx_cbd_dma);
 		return -ENOMEM;
+	}
 
-	memset(cbd_base, 0, PAGE_SIZE);
+	memset(rx_cbd_cpu, 0, PAGE_SIZE);
+	memset(tx_cbd_cpu, 0, PAGE_SIZE);
 
 	/* Set receive and transmit descriptor base. */
-	fep->rx_bd_base = cbd_base;
-	fep->rx_bd_dma = cbd_dma;
-	if (fep->flags & FEC_FLAG_BUFDESC_EX) {
-		fep->tx_bd_base = (union bufdesc_u *)
-			(&cbd_base->ebd + fep->rx_ring_size);
-		fep->tx_bd_dma = cbd_dma + sizeof(struct bufdesc_ex) *
-			fep->rx_ring_size;
-	} else {
-		fep->tx_bd_base = (union bufdesc_u *)
-			(&cbd_base->bd + fep->rx_ring_size);
-		fep->tx_bd_dma = cbd_dma + sizeof(struct bufdesc) *
-			fep->rx_ring_size;
-	}
+	fep->rx_bd_base = rx_cbd_cpu;
+	fep->rx_bd_dma = rx_cbd_dma;
+	fep->tx_bd_base = tx_cbd_cpu;
+	fep->tx_bd_dma = tx_cbd_dma;
 
 	for (i = 0; i < fep->rx_ring_size; i++) {
 		dma_addr_t addr;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 126/222] net:fec: unsorted hacks
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (124 preceding siblings ...)
  2014-04-25 11:42 ` [PATCH 125/222] net:fec: even larger rings Russell King
@ 2014-04-25 11:42 ` Russell King
  2014-04-25 11:42 ` [PATCH 127/222] leds: leds-pwm: provide a common function to setup a single led-pwm device Russell King
                   ` (96 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:42 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/freescale/fec.h      |  16 +++-
 drivers/net/ethernet/freescale/fec_main.c | 126 +++++++++++++++++-------------
 2 files changed, 85 insertions(+), 57 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index bfcab01131cc..09bdf6fea8ea 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -208,6 +208,7 @@ union bufdesc_u {
 #define BD_ENET_RX_OV           ((ushort)0x0002)
 #define BD_ENET_RX_CL           ((ushort)0x0001)
 #define BD_ENET_RX_STATS        ((ushort)0x013f)        /* All status bits */
+#define BD_ENET_RX_ERROR	((ushort)0x003f)
 
 /* Enhanced buffer descriptor control/status used by Ethernet receive */
 #define BD_ENET_RX_VLAN         0x00000004
@@ -230,10 +231,17 @@ union bufdesc_u {
 #define BD_ENET_TX_STATS        ((ushort)0x03ff)        /* All status bits */
 
 /*enhanced buffer descriptor control/status used by Ethernet transmit*/
-#define BD_ENET_TX_INT          0x40000000
-#define BD_ENET_TX_TS           0x20000000
-#define BD_ENET_TX_PINS         0x10000000
-#define BD_ENET_TX_IINS         0x08000000
+#define BD_ENET_TX_INT          BIT(30)
+#define BD_ENET_TX_TS           BIT(29)
+#define BD_ENET_TX_PINS         BIT(28)
+#define BD_ENET_TX_IINS         BIT(27)
+#define BD_ENET_TX_TXE		BIT(15)
+#define BD_ENET_TX_UE		BIT(13)
+#define BD_ENET_TX_EE		BIT(12)
+#define BD_ENET_TX_FE		BIT(11)
+#define BD_ENET_TX_LCE		BIT(10)
+#define BD_ENET_TX_OE		BIT(9)
+#define BD_ENET_TX_TSE		BIT(8)
 
 
 /* This device has up to three irqs on some platforms */
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 441e472f7779..7330bc5c64e0 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -85,16 +85,6 @@ static void set_multicast_list(struct net_device *ndev);
 #define FEC_QUIRK_HAS_CSUM		(1 << 5)
 /* Controller has hardware vlan support */
 #define FEC_QUIRK_HAS_VLAN		(1 << 6)
-/* ENET IP errata ERR006358
- *
- * If the ready bit in the transmit buffer descriptor (TxBD[R]) is previously
- * detected as not set during a prior frame transmission, then the
- * ENET_TDAR[TDAR] bit is cleared@a later time, even if additional TxBDs
- * were added to the ring and the ENET_TDAR[TDAR] bit is set. This results in
- * frames not being transmitted until there is a 0-to-1 transition on
- * ENET_TDAR[TDAR].
- */
-#define FEC_QUIRK_ERR006358            (1 << 7)
 
 static struct platform_device_id fec_devtype[] = {
 	{
@@ -114,7 +104,7 @@ static struct platform_device_id fec_devtype[] = {
 		.name = "imx6q-fec",
 		.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
 				FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
-				FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358,
+				FEC_QUIRK_HAS_VLAN,
 	}, {
 		.name = "mvf600-fec",
 		.driver_data = FEC_QUIRK_ENET_MAC,
@@ -293,13 +283,16 @@ static void fec_dump(struct net_device *ndev)
 	for (index = 0; index < fep->tx_ring_size; index++) {
 		bdp = fec_enet_tx_get(index, fep);
 
-		pr_info("%3u %c%c 0x%04x 0x%08lx %4u %p\n",
+		pr_info("%3u %c%c 0x%04x 0x%08lx %4u %p",
 			index,
 			index == fep->tx_next ? 'S' : ' ',
 			index == fep->tx_dirty ? 'H' : ' ',
 			bdp->bd.cbd_sc, bdp->bd.cbd_bufaddr,
 			bdp->bd.cbd_datlen,
 			fep->tx_skbuff[index]);
+		if (fep->flags & FEC_FLAG_BUFDESC_EX)
+			pr_cont(" %08lx", bdp->ebd.cbd_esc);
+		pr_cont("\n");
 	}
 }
 
@@ -836,13 +829,14 @@ fec_enet_tx(struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	union bufdesc_u *bdp;
-	unsigned short status;
 	struct	sk_buff	*skb;
 	unsigned index = fep->tx_dirty;
 	unsigned pkts_compl, bytes_compl;
 
 	pkts_compl = bytes_compl = 0;
 	do {
+		unsigned status, cbd_esc;
+
 		if (++index >= fep->tx_ring_size)
 			index = 0;
 
@@ -862,21 +856,40 @@ fec_enet_tx(struct net_device *ndev)
 		fep->tx_skbuff[index] = NULL;
 
 		/* Check for errors. */
-		if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC |
-				   BD_ENET_TX_RL | BD_ENET_TX_UN |
-				   BD_ENET_TX_CSL)) {
-			ndev->stats.tx_errors++;
-			if (status & BD_ENET_TX_HB)  /* No heartbeat */
-				ndev->stats.tx_heartbeat_errors++;
-			if (status & BD_ENET_TX_LC)  /* Late collision */
-				ndev->stats.tx_window_errors++;
-			if (status & BD_ENET_TX_RL)  /* Retrans limit */
-				ndev->stats.tx_aborted_errors++;
-			if (status & BD_ENET_TX_UN)  /* Underrun */
-				ndev->stats.tx_fifo_errors++;
-			if (status & BD_ENET_TX_CSL) /* Carrier lost */
-				ndev->stats.tx_carrier_errors++;
-		} else if (skb) {
+		if (fep->flags & FEC_FLAG_BUFDESC_EX) {
+			cbd_esc = bdp->ebd.cbd_esc;
+			if (cbd_esc & BD_ENET_TX_TXE) {
+				ndev->stats.tx_errors++;
+				if (cbd_esc & BD_ENET_TX_EE) { /* excess collision */
+					ndev->stats.collisions += 16;
+					ndev->stats.tx_aborted_errors++;
+				}
+				if (cbd_esc & BD_ENET_TX_LCE) /* late collision error */
+					ndev->stats.tx_window_errors++;
+				if (cbd_esc & (BD_ENET_TX_UE | BD_ENET_TX_FE | BD_ENET_TX_OE))
+					ndev->stats.tx_fifo_errors++;
+				goto next;
+			}
+		} else {
+			if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC |
+					   BD_ENET_TX_RL | BD_ENET_TX_UN |
+					   BD_ENET_TX_CSL)) {
+				ndev->stats.tx_errors++;
+				if (status & BD_ENET_TX_HB)  /* No heartbeat */
+					ndev->stats.tx_heartbeat_errors++;
+				if (status & BD_ENET_TX_LC)  /* Late collision */
+					ndev->stats.tx_window_errors++;
+				if (status & BD_ENET_TX_RL)  /* Retrans limit */
+					ndev->stats.tx_aborted_errors++;
+				if (status & BD_ENET_TX_UN)  /* Underrun */
+					ndev->stats.tx_fifo_errors++;
+				if (status & BD_ENET_TX_CSL) /* Carrier lost */
+					ndev->stats.tx_carrier_errors++;
+				goto next;
+			}
+		}
+
+		if (skb) {
 			ndev->stats.tx_packets++;
 			ndev->stats.tx_bytes += skb->len;
 		}
@@ -886,7 +899,7 @@ fec_enet_tx(struct net_device *ndev)
 		 */
 		if (status & BD_ENET_TX_DEF)
 			ndev->stats.collisions++;
-
+ next:
 		if (skb) {
 			if (fep->flags & FEC_FLAG_BUFDESC_EX &&
 			    unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) {
@@ -930,7 +943,6 @@ fec_enet_rx(struct net_device *ndev, int budget)
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	const struct platform_device_id *id_entry =
 				platform_get_device_id(fep->pdev);
-	unsigned short status;
 	struct	sk_buff	*skb;
 	ushort	pkt_len;
 	__u8 *data;
@@ -948,6 +960,7 @@ fec_enet_rx(struct net_device *ndev, int budget)
 	 */
 	do {
 		union bufdesc_u *bdp = fec_enet_rx_get(index, fep);
+		unsigned status, cbd_esc;
 
 		status = bdp->bd.cbd_sc;
 		if (status & BD_ENET_RX_EMPTY)
@@ -966,29 +979,37 @@ fec_enet_rx(struct net_device *ndev, int budget)
 
 		writel(FEC_ENET_RXF, fep->hwp + FEC_IEVENT);
 
-		/* Check for errors. */
-		if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
-			   BD_ENET_RX_CR | BD_ENET_RX_OV)) {
-			ndev->stats.rx_errors++;
-			if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) {
-				/* Frame too long or too short. */
-				ndev->stats.rx_length_errors++;
-			}
-			if (status & BD_ENET_RX_NO)	/* Frame alignment */
-				ndev->stats.rx_frame_errors++;
-			if (status & BD_ENET_RX_CR)	/* CRC Error */
-				ndev->stats.rx_crc_errors++;
-			if (status & BD_ENET_RX_OV)	/* FIFO overrun */
-				ndev->stats.rx_fifo_errors++;
+		if (fep->flags & FEC_FLAG_BUFDESC_EX) {
+			cbd_esc = bdp->ebd.cbd_esc;
+			if (!(fep->flags & FEC_FLAG_RX_VLAN))
+				cbd_esc &= ~BD_ENET_RX_VLAN;
+		} else {
+			cbd_esc = 0;
 		}
 
-		/* Report late collisions as a frame error.
-		 * On this error, the BD is closed, but we don't know what we
-		 * have in the buffer.  So, just drop this frame on the floor.
-		 */
-		if (status & BD_ENET_RX_CL) {
+		/* Check for errors. */
+		if (status & BD_ENET_RX_ERROR) {
 			ndev->stats.rx_errors++;
-			ndev->stats.rx_frame_errors++;
+
+			/*
+			 * Report late collisions as a frame error.  On this
+			 * error, the BD is closed, but we don't know what we
+			 * have in the buffer.  So, just drop this frame on
+			 * the floor.
+			 */
+			if (status & BD_ENET_RX_CL) {
+				ndev->stats.rx_frame_errors++;
+			} else {
+				if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH))
+					/* Frame too long or too short. */
+					ndev->stats.rx_length_errors++;
+				if (status & BD_ENET_RX_NO)	/* Frame alignment */
+					ndev->stats.rx_frame_errors++;
+				if (status & BD_ENET_RX_CR)	/* CRC Error */
+					ndev->stats.rx_crc_errors++;
+				if (status & BD_ENET_RX_OV)	/* FIFO overrun */
+					ndev->stats.rx_fifo_errors++;
+			}
 			goto rx_processing_done;
 		}
 
@@ -1006,8 +1027,7 @@ fec_enet_rx(struct net_device *ndev, int budget)
 
 		/* If this is a VLAN packet remove the VLAN Tag */
 		vlan_packet_rcvd = false;
-		if (fep->flags & FEC_FLAG_RX_VLAN &&
-		    bdp->ebd.cbd_esc & BD_ENET_RX_VLAN) {
+		if (cbd_esc & BD_ENET_RX_VLAN) {
 			/* Push and remove the vlan tag */
 			struct vlan_hdr *vlan_header =
 					(struct vlan_hdr *) (data + ETH_HLEN);
@@ -1047,7 +1067,7 @@ fec_enet_rx(struct net_device *ndev, int budget)
 						  skb_hwtstamps(skb));
 
 			if (fep->flags & FEC_FLAG_RX_CSUM) {
-				if (!(bdp->ebd.cbd_esc & FLAG_RX_CSUM_ERROR)) {
+				if (!(cbd_esc & FLAG_RX_CSUM_ERROR)) {
 					/* don't check it */
 					skb->ip_summed = CHECKSUM_UNNECESSARY;
 				} else {
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 127/222] leds: leds-pwm: provide a common function to setup a single led-pwm device
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (125 preceding siblings ...)
  2014-04-25 11:42 ` [PATCH 126/222] net:fec: unsorted hacks Russell King
@ 2014-04-25 11:42 ` Russell King
  2014-04-25 11:42 ` [PATCH 128/222] leds: leds-pwm: convert OF parsing code to use led_pwm_add() Russell King
                   ` (95 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:42 UTC (permalink / raw)
  To: linux-arm-kernel

Provide a common function to setup a single led-pwm device, replacing
the platform data initialisation path with this function.  This allows
us to have a common method of creating these devices in a consistent
manner, which then allows us to place the probe failure cleanup in one
place.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/leds/leds-pwm.c | 85 ++++++++++++++++++++++++++-----------------------
 1 file changed, 46 insertions(+), 39 deletions(-)

diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c
index 7d0aaed1e23a..203e332967b2 100644
--- a/drivers/leds/leds-pwm.c
+++ b/drivers/leds/leds-pwm.c
@@ -92,6 +92,44 @@ static void led_pwm_cleanup(struct led_pwm_priv *priv)
 	}
 }
 
+static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
+		       struct led_pwm *led)
+{
+	struct led_pwm_data *led_data = &priv->leds[priv->num_leds];
+	int ret;
+
+	led_data->active_low = led->active_low;
+	led_data->period = led->pwm_period_ns;
+	led_data->cdev.name = led->name;
+	led_data->cdev.default_trigger = led->default_trigger;
+	led_data->cdev.brightness_set = led_pwm_set;
+	led_data->cdev.brightness = LED_OFF;
+	led_data->cdev.max_brightness = led->max_brightness;
+	led_data->cdev.flags = LED_CORE_SUSPENDRESUME;
+
+	led_data->pwm = devm_pwm_get(dev, led->name);
+	if (IS_ERR(led_data->pwm)) {
+		ret = PTR_ERR(led_data->pwm);
+		dev_err(dev, "unable to request PWM for %s: %d\n",
+			led->name, ret);
+		return ret;
+	}
+
+	led_data->can_sleep = pwm_can_sleep(led_data->pwm);
+	if (led_data->can_sleep)
+		INIT_WORK(&led_data->work, led_pwm_work);
+
+	ret = led_classdev_register(dev, &led_data->cdev);
+	if (ret == 0) {
+		priv->num_leds++;
+	} else {
+		dev_err(dev, "failed to register PWM led for %s: %d\n",
+			led->name, ret);
+	}
+
+	return ret;
+}
+
 static int led_pwm_create_of(struct platform_device *pdev,
 			     struct led_pwm_priv *priv)
 {
@@ -139,8 +177,6 @@ static int led_pwm_create_of(struct platform_device *pdev,
 
 	return 0;
 err:
-	led_pwm_cleanup(priv);
-
 	return ret;
 }
 
@@ -166,51 +202,22 @@ static int led_pwm_probe(struct platform_device *pdev)
 
 	if (pdata) {
 		for (i = 0; i < count; i++) {
-			struct led_pwm *cur_led = &pdata->leds[i];
-			struct led_pwm_data *led_dat = &priv->leds[i];
-
-			led_dat->pwm = devm_pwm_get(&pdev->dev, cur_led->name);
-			if (IS_ERR(led_dat->pwm)) {
-				ret = PTR_ERR(led_dat->pwm);
-				dev_err(&pdev->dev,
-					"unable to request PWM for %s\n",
-					cur_led->name);
-				goto err;
-			}
-
-			led_dat->cdev.name = cur_led->name;
-			led_dat->cdev.default_trigger = cur_led->default_trigger;
-			led_dat->active_low = cur_led->active_low;
-			led_dat->period = cur_led->pwm_period_ns;
-			led_dat->cdev.brightness_set = led_pwm_set;
-			led_dat->cdev.brightness = LED_OFF;
-			led_dat->cdev.max_brightness = cur_led->max_brightness;
-			led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
-
-			led_dat->can_sleep = pwm_can_sleep(led_dat->pwm);
-			if (led_dat->can_sleep)
-				INIT_WORK(&led_dat->work, led_pwm_work);
-
-			ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
-			if (ret < 0)
-				goto err;
+			ret = led_pwm_add(&pdev->dev, priv, &pdata->leds[i]);
+			if (ret)
+				break;
 		}
-		priv->num_leds = count;
 	} else {
 		ret = led_pwm_create_of(pdev, priv);
-		if (ret)
-			return ret;
+	}
+
+	if (ret) {
+		led_pwm_cleanup(priv);
+		return ret;
 	}
 
 	platform_set_drvdata(pdev, priv);
 
 	return 0;
-
-err:
-	priv->num_leds = i;
-	led_pwm_cleanup(priv);
-
-	return ret;
 }
 
 static int led_pwm_remove(struct platform_device *pdev)
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 128/222] leds: leds-pwm: convert OF parsing code to use led_pwm_add()
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (126 preceding siblings ...)
  2014-04-25 11:42 ` [PATCH 127/222] leds: leds-pwm: provide a common function to setup a single led-pwm device Russell King
@ 2014-04-25 11:42 ` Russell King
  2014-04-25 11:42 ` [PATCH 129/222] leds: leds-pwm: implement PWM inversion Russell King
                   ` (94 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:42 UTC (permalink / raw)
  To: linux-arm-kernel

Convert the OF parsing code to use the common PWM LED registration code,
which means we have a consistent method, and single point where the
registration happens for both paths.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/leds/leds-pwm.c | 62 ++++++++++++++++++-------------------------------
 1 file changed, 23 insertions(+), 39 deletions(-)

diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c
index 203e332967b2..35c1c5f144dc 100644
--- a/drivers/leds/leds-pwm.c
+++ b/drivers/leds/leds-pwm.c
@@ -93,7 +93,7 @@ static void led_pwm_cleanup(struct led_pwm_priv *priv)
 }
 
 static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
-		       struct led_pwm *led)
+		       struct led_pwm *led, struct device_node *child)
 {
 	struct led_pwm_data *led_data = &priv->leds[priv->num_leds];
 	int ret;
@@ -107,7 +107,10 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
 	led_data->cdev.max_brightness = led->max_brightness;
 	led_data->cdev.flags = LED_CORE_SUSPENDRESUME;
 
-	led_data->pwm = devm_pwm_get(dev, led->name);
+	if (child)
+		led_data->pwm = devm_of_pwm_get(dev, child, NULL);
+	else
+		led_data->pwm = devm_pwm_get(dev, led->name);
 	if (IS_ERR(led_data->pwm)) {
 		ret = PTR_ERR(led_data->pwm);
 		dev_err(dev, "unable to request PWM for %s: %d\n",
@@ -115,6 +118,9 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
 		return ret;
 	}
 
+	if (child)
+		led_data->period = pwm_get_period(led_data->pwm);
+
 	led_data->can_sleep = pwm_can_sleep(led_data->pwm);
 	if (led_data->can_sleep)
 		INIT_WORK(&led_data->work, led_pwm_work);
@@ -130,53 +136,30 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
 	return ret;
 }
 
-static int led_pwm_create_of(struct platform_device *pdev,
-			     struct led_pwm_priv *priv)
+static int led_pwm_create_of(struct device *dev, struct led_pwm_priv *priv)
 {
 	struct device_node *child;
-	int ret;
-
-	for_each_child_of_node(pdev->dev.of_node, child) {
-		struct led_pwm_data *led_dat = &priv->leds[priv->num_leds];
+	struct led_pwm led;
+	int ret = 0;
 
-		led_dat->cdev.name = of_get_property(child, "label",
-						     NULL) ? : child->name;
+	memset(&led, 0, sizeof(led));
 
-		led_dat->pwm = devm_of_pwm_get(&pdev->dev, child, NULL);
-		if (IS_ERR(led_dat->pwm)) {
-			dev_err(&pdev->dev, "unable to request PWM for %s\n",
-				led_dat->cdev.name);
-			ret = PTR_ERR(led_dat->pwm);
-			goto err;
-		}
-		/* Get the period from PWM core when n*/
-		led_dat->period = pwm_get_period(led_dat->pwm);
+	for_each_child_of_node(dev->of_node, child) {
+		led.name = of_get_property(child, "label", NULL) ? :
+			   child->name;
 
-		led_dat->cdev.default_trigger = of_get_property(child,
+		led.default_trigger = of_get_property(child,
 						"linux,default-trigger", NULL);
 		of_property_read_u32(child, "max-brightness",
-				     &led_dat->cdev.max_brightness);
-
-		led_dat->cdev.brightness_set = led_pwm_set;
-		led_dat->cdev.brightness = LED_OFF;
-		led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
-
-		led_dat->can_sleep = pwm_can_sleep(led_dat->pwm);
-		if (led_dat->can_sleep)
-			INIT_WORK(&led_dat->work, led_pwm_work);
+				     &led.max_brightness);
 
-		ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
-		if (ret < 0) {
-			dev_err(&pdev->dev, "failed to register for %s\n",
-				led_dat->cdev.name);
+		ret = led_pwm_add(dev, priv, &led, child);
+		if (ret) {
 			of_node_put(child);
-			goto err;
+			break;
 		}
-		priv->num_leds++;
 	}
 
-	return 0;
-err:
 	return ret;
 }
 
@@ -202,12 +185,13 @@ static int led_pwm_probe(struct platform_device *pdev)
 
 	if (pdata) {
 		for (i = 0; i < count; i++) {
-			ret = led_pwm_add(&pdev->dev, priv, &pdata->leds[i]);
+			ret = led_pwm_add(&pdev->dev, priv, &pdata->leds[i],
+					  NULL);
 			if (ret)
 				break;
 		}
 	} else {
-		ret = led_pwm_create_of(pdev, priv);
+		ret = led_pwm_create_of(&pdev->dev, priv);
 	}
 
 	if (ret) {
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 129/222] leds: leds-pwm: implement PWM inversion
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (127 preceding siblings ...)
  2014-04-25 11:42 ` [PATCH 128/222] leds: leds-pwm: convert OF parsing code to use led_pwm_add() Russell King
@ 2014-04-25 11:42 ` Russell King
  2014-04-25 11:42 ` [PATCH 130/222] leds: leds-pwm: add DT support for LEDs wired to supply Russell King
                   ` (93 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:42 UTC (permalink / raw)
  To: linux-arm-kernel

Some PWM outputs are wired such that the LED they're controlling is
connected to supply rather than ground.  These PWMs may not support
output inversion, or when they do, disabling the PWM may set the
PWM output low, causing a "brightness" value of zero to turn the LED
fully on.

The platform data for this driver already indicates that this was
thought about, and we have the "active_low" property there already.
However, the implementation for this is missing.

Add the trivial implementation for this feature.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/leds/leds-pwm.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c
index 35c1c5f144dc..8bd225df14de 100644
--- a/drivers/leds/leds-pwm.c
+++ b/drivers/leds/leds-pwm.c
@@ -69,6 +69,10 @@ static void led_pwm_set(struct led_classdev *led_cdev,
 
 	duty *= brightness;
 	do_div(duty, max);
+
+	if (led_dat->active_low)
+		duty = led_dat->period - duty;
+
 	led_dat->duty = duty;
 
 	if (led_dat->can_sleep)
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 130/222] leds: leds-pwm: add DT support for LEDs wired to supply
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (128 preceding siblings ...)
  2014-04-25 11:42 ` [PATCH 129/222] leds: leds-pwm: implement PWM inversion Russell King
@ 2014-04-25 11:42 ` Russell King
  2014-04-25 11:42 ` [PATCH 131/222] ARM: add support for Cubox-i PWM-driven front panel LED Russell King
                   ` (92 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:42 UTC (permalink / raw)
  To: linux-arm-kernel

The non-DT driver allowed an active low property to be specified, but DT
is missing this in its description.  Add the property to the DT binding
document, making it optional.  It defaults to active high, which retains
compatibility with existing descriptions.

This should only be used for causes where the LED is wired to supply,
and the PWM does not sensibly support its own inversion.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 Documentation/devicetree/bindings/leds/leds-pwm.txt | 2 ++
 drivers/leds/leds-pwm.c                             | 1 +
 2 files changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/leds/leds-pwm.txt b/Documentation/devicetree/bindings/leds/leds-pwm.txt
index 7297107cf832..6c6583c35f2f 100644
--- a/Documentation/devicetree/bindings/leds/leds-pwm.txt
+++ b/Documentation/devicetree/bindings/leds/leds-pwm.txt
@@ -13,6 +13,8 @@ node's name represents the name of the corresponding LED.
   For the pwms and pwm-names property please refer to:
   Documentation/devicetree/bindings/pwm/pwm.txt
 - max-brightness : Maximum brightness possible for the LED
+- active-low : (optional) For PWMs where the LED is wired to supply
+  rather than ground.
 - label :  (optional)
   see Documentation/devicetree/bindings/leds/common.txt
 - linux,default-trigger :  (optional)
diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c
index 8bd225df14de..f5cf1b0f2748 100644
--- a/drivers/leds/leds-pwm.c
+++ b/drivers/leds/leds-pwm.c
@@ -154,6 +154,7 @@ static int led_pwm_create_of(struct device *dev, struct led_pwm_priv *priv)
 
 		led.default_trigger = of_get_property(child,
 						"linux,default-trigger", NULL);
+		led.active_low = of_property_read_bool(child, "active-low");
 		of_property_read_u32(child, "max-brightness",
 				     &led.max_brightness);
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 131/222] ARM: add support for Cubox-i PWM-driven front panel LED
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (129 preceding siblings ...)
  2014-04-25 11:42 ` [PATCH 130/222] leds: leds-pwm: add DT support for LEDs wired to supply Russell King
@ 2014-04-25 11:42 ` Russell King
  2014-04-25 11:42 ` [PATCH 132/222] ASoC: work around block transfer issues with imx-pcm-dma Russell King
                   ` (91 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:42 UTC (permalink / raw)
  To: linux-arm-kernel

The front panel LED on the Cubox-i is driven by one of the iMX6 PWM
channels, and is wired between the PWM output and supply.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/boot/dts/imx6qdl-cubox-i.dtsi | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi b/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
index c2a24888a276..c17602d4e4aa 100644
--- a/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
@@ -12,6 +12,19 @@
 		pinctrl-0 = <&pinctrl_cubox_i_ir>;
 	};
 
+	pwmleds {
+		compatible = "pwm-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_cubox_i_pwm1>;
+
+		front {
+			active-low;
+			label = "imx6:red:front";
+			max-brightness = <248>;
+			pwms = <&pwm1 0 50000>;
+		};
+	};
+
 	regulators {
 		compatible = "simple-bus";
 
@@ -82,6 +95,10 @@
 			>;
 		};
 
+		pinctrl_cubox_i_pwm1: cubox-i-pwm1-front-led {
+			fsl,pins = <MX6QDL_PAD_DISP0_DAT8__PWM1_OUT 0x1b0b0>;
+		};
+
 		pinctrl_cubox_i_spdif: cubox-i-spdif {
 			fsl,pins = <MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x13091>;
 		};
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 132/222] ASoC: work around block transfer issues with imx-pcm-dma
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (130 preceding siblings ...)
  2014-04-25 11:42 ` [PATCH 131/222] ARM: add support for Cubox-i PWM-driven front panel LED Russell King
@ 2014-04-25 11:42 ` Russell King
  2014-04-25 11:42 ` [PATCH 133/222] ata: ahci_imx: warn when disabling ahci link Russell King
                   ` (90 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:42 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 sound/soc/fsl/imx-pcm-dma.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c
index 2585ae44e634..a86d84854c7f 100644
--- a/sound/soc/fsl/imx-pcm-dma.c
+++ b/sound/soc/fsl/imx-pcm-dma.c
@@ -44,7 +44,7 @@ static const struct snd_pcm_hardware imx_pcm_hardware = {
 	.buffer_bytes_max = IMX_SSI_DMABUF_SIZE,
 	.period_bytes_min = 128,
 	.period_bytes_max = 65535, /* Limited by SDMA engine */
-	.periods_min = 2,
+	.periods_min = 4,
 	.periods_max = 255,
 	.fifo_size = 0,
 };
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 133/222] ata: ahci_imx: warn when disabling ahci link
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (131 preceding siblings ...)
  2014-04-25 11:42 ` [PATCH 132/222] ASoC: work around block transfer issues with imx-pcm-dma Russell King
@ 2014-04-25 11:42 ` Russell King
  2014-04-25 11:42 ` [PATCH 134/222] ARM: imx: keep PLLs in bypass while they're locking Russell King
                   ` (89 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:42 UTC (permalink / raw)
  To: linux-arm-kernel

When the AHCI link is disabled, it can't be re-enabled except by
resetting the entire SoC.  Rather than doing this silently print
some kernel messages to inform the user, along with how to avoid
this.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/ata/ahci_imx.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c
index 497c7abe1c7d..6a56a561a80b 100644
--- a/drivers/ata/ahci_imx.c
+++ b/drivers/ata/ahci_imx.c
@@ -160,6 +160,10 @@ static void ahci_imx_error_handler(struct ata_port *ap)
 	writel(reg_val | PORT_PHY_CTL_PDDQ_LOC, mmio + PORT_PHY_CTL);
 	imx_sata_disable(hpriv);
 	imxpriv->no_device = true;
+
+	dev_info(ap->dev, "no device found, disabling link.\n");
+	dev_info(ap->dev, "pass " MODULE_PARAM_PREFIX
+		 ".hotplug=1 to enable hotplug\n");
 }
 
 static int ahci_imx_softreset(struct ata_link *link, unsigned int *class,
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 134/222] ARM: imx: keep PLLs in bypass while they're locking
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (132 preceding siblings ...)
  2014-04-25 11:42 ` [PATCH 133/222] ata: ahci_imx: warn when disabling ahci link Russell King
@ 2014-04-25 11:42 ` Russell King
  2014-04-30 10:52   ` Dirk Behme
  2014-04-25 11:42 ` [PATCH 135/222] ARM: imx: set IPU to be derived from the 540MHz PLL3 PFD1 clock Russell King
                   ` (88 subsequent siblings)
  222 siblings, 1 reply; 232+ messages in thread
From: Russell King @ 2014-04-25 11:42 UTC (permalink / raw)
  To: linux-arm-kernel

Keep the PLL bypassed while we prepare a clock by powering up the PLL,
otherwise we can end up with improper output/gitches which prevents
further operation.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-imx/clk-pllv3.c | 27 +++++++++++++++++++++------
 1 file changed, 21 insertions(+), 6 deletions(-)

diff --git a/arch/arm/mach-imx/clk-pllv3.c b/arch/arm/mach-imx/clk-pllv3.c
index 61364050fccd..3776f974d1dc 100644
--- a/arch/arm/mach-imx/clk-pllv3.c
+++ b/arch/arm/mach-imx/clk-pllv3.c
@@ -273,9 +273,10 @@ static int clk_pllv3_av_set_rate(struct clk_hw *hw, unsigned long rate,
 	struct clk_pllv3 *pll = to_clk_pllv3(hw);
 	unsigned long min_rate = parent_rate * 27;
 	unsigned long max_rate = parent_rate * 54;
-	u32 val, div;
+	u32 val, newval, div;
 	u32 mfn, mfd = 1000000;
 	s64 temp64;
+	int ret;
 
 	if (rate < min_rate || rate > max_rate)
 		return -EINVAL;
@@ -287,13 +288,27 @@ static int clk_pllv3_av_set_rate(struct clk_hw *hw, unsigned long rate,
 	mfn = temp64;
 
 	val = readl_relaxed(pll->base);
-	val &= ~pll->div_mask;
-	val |= div;
-	writel_relaxed(val, pll->base);
+
+	/* set the PLL into bypass mode */
+	newval = val | BM_PLL_BYPASS;
+	writel_relaxed(newval, pll->base);
+
+	/* configure the new frequency */
+	newval &= ~pll->div_mask;
+	newval |= div;
+	writel_relaxed(newval, pll->base);
 	writel_relaxed(mfn, pll->base + PLL_NUM_OFFSET);
-	writel_relaxed(mfd, pll->base + PLL_DENOM_OFFSET);
+	writel(mfd, pll->base + PLL_DENOM_OFFSET);
 
-	return clk_pllv3_wait_lock(pll);
+	ret = clk_pllv3_wait_lock(pll);
+	if (ret == 0 && val & BM_PLL_POWER) {
+		/* only if it locked can we switch back to the PLL */
+		newval &= ~BM_PLL_BYPASS;
+		newval |= val & BM_PLL_BYPASS;
+		writel(newval, pll->base);
+	}
+
+	return ret;
 }
 
 static const struct clk_ops clk_pllv3_av_ops = {
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 135/222] ARM: imx: set IPU to be derived from the 540MHz PLL3 PFD1 clock
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (133 preceding siblings ...)
  2014-04-25 11:42 ` [PATCH 134/222] ARM: imx: keep PLLs in bypass while they're locking Russell King
@ 2014-04-25 11:42 ` Russell King
  2014-04-25 11:43 ` [PATCH 136/222] regulator: allow GPIO 0 to be used for an enable signal Russell King
                   ` (87 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:42 UTC (permalink / raw)
  To: linux-arm-kernel

Set the IPU muxer to derive the clock from the PLL3 FPD1 clock,
which increases its clock rate from 198MHz to 270MHz.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-imx/clk-imx6q.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c
index b0e7f9d2c245..f4d0b0e3e041 100644
--- a/arch/arm/mach-imx/clk-imx6q.c
+++ b/arch/arm/mach-imx/clk-imx6q.c
@@ -445,6 +445,10 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
 		clk_set_parent(clk[ldb_di1_sel], clk[pll5_video_div]);
 	}
 
+	if (cpu_is_imx6dl()) {
+		clk_set_parent(clk[ipu1_sel], clk[pll3_pfd1_540m]);
+	}
+
 	/*
 	 * The gpmi needs 100MHz frequency in the EDO/Sync mode,
 	 * We can not get the 100MHz from the pll2_pfd0_352m.
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 136/222] regulator: allow GPIO 0 to be used for an enable signal
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (134 preceding siblings ...)
  2014-04-25 11:42 ` [PATCH 135/222] ARM: imx: set IPU to be derived from the 540MHz PLL3 PFD1 clock Russell King
@ 2014-04-25 11:43 ` Russell King
  2014-04-25 11:43 ` [PATCH 137/222] ARM: dt: microsom: don't set bit 7 for ethernet mux settings Russell King
                   ` (86 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:43 UTC (permalink / raw)
  To: linux-arm-kernel

GPIO number 0 *is* legal and must be accepted.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/regulator/anatop-regulator.c | 1 +
 drivers/regulator/core.c             | 2 +-
 drivers/regulator/dummy.c            | 1 +
 drivers/regulator/fixed.c            | 4 +---
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c
index 7c397bb81e01..6da2fbbb9bd5 100644
--- a/drivers/regulator/anatop-regulator.c
+++ b/drivers/regulator/anatop-regulator.c
@@ -267,6 +267,7 @@ static int anatop_regulator_probe(struct platform_device *pdev)
 	config.driver_data = sreg;
 	config.of_node = pdev->dev.of_node;
 	config.regmap = sreg->anatop;
+	config.ena_gpio = -EINVAL;
 
 	/* Only core regulators have the ramp up delay configuration. */
 	if (sreg->control_reg && sreg->delay_bit_width) {
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 9a09f3cdbabb..19c4077374b6 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -3459,7 +3459,7 @@ regulator_register(const struct regulator_desc *regulator_desc,
 
 	dev_set_drvdata(&rdev->dev, rdev);
 
-	if (config->ena_gpio && gpio_is_valid(config->ena_gpio)) {
+	if (gpio_is_valid(config->ena_gpio)) {
 		ret = regulator_ena_gpio_request(rdev, config);
 		if (ret != 0) {
 			rdev_err(rdev, "Failed to request enable GPIO%d: %d\n",
diff --git a/drivers/regulator/dummy.c b/drivers/regulator/dummy.c
index 2436db9e2ca3..acc4ea593c95 100644
--- a/drivers/regulator/dummy.c
+++ b/drivers/regulator/dummy.c
@@ -48,6 +48,7 @@ static int dummy_regulator_probe(struct platform_device *pdev)
 
 	config.dev = &pdev->dev;
 	config.init_data = &dummy_initdata;
+	config.ena_gpio = -EINVAL;
 
 	dummy_regulator_rdev = regulator_register(&dummy_desc, &config);
 	if (IS_ERR(dummy_regulator_rdev)) {
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index c61f7e97e4f8..aabf10dc8a50 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -161,9 +161,7 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
 		drvdata->desc.n_voltages = 1;
 
 	drvdata->desc.fixed_uV = config->microvolts;
-
-	if (config->gpio >= 0)
-		cfg.ena_gpio = config->gpio;
+	cfg.ena_gpio = config->gpio;
 	cfg.ena_gpio_invert = !config->enable_high;
 	if (config->enabled_at_boot) {
 		if (config->enable_high)
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 137/222] ARM: dt: microsom: don't set bit 7 for ethernet mux settings
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (135 preceding siblings ...)
  2014-04-25 11:43 ` [PATCH 136/222] regulator: allow GPIO 0 to be used for an enable signal Russell King
@ 2014-04-25 11:43 ` Russell King
  2014-04-25 11:43 ` [PATCH 138/222] ARM: imx6q: clk: Parent DI clocks to video PLL via di_pre_sel Russell King
                   ` (85 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:43 UTC (permalink / raw)
  To: linux-arm-kernel

Bit 6,7 are marked as reserved for the ethernet RGMII pins, so avoid
setting these bits.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi b/arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi
index a3cb2fff8f61..d16066608e21 100644
--- a/arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi
@@ -26,25 +26,25 @@
 				/* GPIO16 -> AR8035 25MHz */
 				MX6QDL_PAD_GPIO_16__ENET_REF_CLK	0xc0000000
 				MX6QDL_PAD_RGMII_TXC__RGMII_TXC		0x80000000
-				MX6QDL_PAD_RGMII_TD0__RGMII_TD0		0x1b0b0
-				MX6QDL_PAD_RGMII_TD1__RGMII_TD1		0x1b0b0
-				MX6QDL_PAD_RGMII_TD2__RGMII_TD2		0x1b0b0
-				MX6QDL_PAD_RGMII_TD3__RGMII_TD3		0x1b0b0
-				MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL	0x1b0b0
+				MX6QDL_PAD_RGMII_TD0__RGMII_TD0		0x1b030
+				MX6QDL_PAD_RGMII_TD1__RGMII_TD1		0x1b030
+				MX6QDL_PAD_RGMII_TD2__RGMII_TD2		0x1b030
+				MX6QDL_PAD_RGMII_TD3__RGMII_TD3		0x1b030
+				MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL	0x1b030
 				/* AR8035 CLK_25M --> ENET_REF_CLK (V22) */
 				MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK	0x0a0b1
 				/* AR8035 pin strapping: IO voltage: pull up */
-				MX6QDL_PAD_RGMII_RXC__RGMII_RXC		0x1b0b0
+				MX6QDL_PAD_RGMII_RXC__RGMII_RXC		0x1b030
 				/* AR8035 pin strapping: PHYADDR#0: pull down */
-				MX6QDL_PAD_RGMII_RD0__RGMII_RD0		0x130b0
+				MX6QDL_PAD_RGMII_RD0__RGMII_RD0		0x13030
 				/* AR8035 pin strapping: PHYADDR#1: pull down */
-				MX6QDL_PAD_RGMII_RD1__RGMII_RD1		0x130b0
+				MX6QDL_PAD_RGMII_RD1__RGMII_RD1		0x13030
 				/* AR8035 pin strapping: MODE#1: pull up */
-				MX6QDL_PAD_RGMII_RD2__RGMII_RD2		0x1b0b0
+				MX6QDL_PAD_RGMII_RD2__RGMII_RD2		0x1b030
 				/* AR8035 pin strapping: MODE#3: pull up */
-				MX6QDL_PAD_RGMII_RD3__RGMII_RD3		0x1b0b0
+				MX6QDL_PAD_RGMII_RD3__RGMII_RD3		0x1b030
 				/* AR8035 pin strapping: MODE#0: pull down */
-				MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL	0x130b0
+				MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL	0x13030
 
 				/*
 				 * As the RMII pins are also connected to RGMII
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 138/222] ARM: imx6q: clk: Parent DI clocks to video PLL via di_pre_sel
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (136 preceding siblings ...)
  2014-04-25 11:43 ` [PATCH 137/222] ARM: dt: microsom: don't set bit 7 for ethernet mux settings Russell King
@ 2014-04-25 11:43 ` Russell King
  2014-04-25 11:43 ` [PATCH 139/222] ARM: i.MX6: ipu_di_sel clocks can set parent rates Russell King
                   ` (84 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:43 UTC (permalink / raw)
  To: linux-arm-kernel

From: Sascha Hauer <s.hauer@pengutronix.de>
To: linux-arm-kernel at lists.infradead.org

Route the video PLL to the display interface clocks via the di_pre_sel
and di_sel muxes by default.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-imx/clk-imx6q.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c
index f4d0b0e3e041..7d2b652497d2 100644
--- a/arch/arm/mach-imx/clk-imx6q.c
+++ b/arch/arm/mach-imx/clk-imx6q.c
@@ -449,6 +449,15 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
 		clk_set_parent(clk[ipu1_sel], clk[pll3_pfd1_540m]);
 	}
 
+	clk_set_parent(clk[ipu1_di0_pre_sel], clk[pll5_video_div]);
+	clk_set_parent(clk[ipu1_di1_pre_sel], clk[pll5_video_div]);
+	clk_set_parent(clk[ipu2_di0_pre_sel], clk[pll5_video_div]);
+	clk_set_parent(clk[ipu2_di1_pre_sel], clk[pll5_video_div]);
+	clk_set_parent(clk[ipu1_di0_sel], clk[ipu1_di0_pre]);
+	clk_set_parent(clk[ipu1_di1_sel], clk[ipu1_di1_pre]);
+	clk_set_parent(clk[ipu2_di0_sel], clk[ipu2_di0_pre]);
+	clk_set_parent(clk[ipu2_di1_sel], clk[ipu2_di1_pre]);
+
 	/*
 	 * The gpmi needs 100MHz frequency in the EDO/Sync mode,
 	 * We can not get the 100MHz from the pll2_pfd0_352m.
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 139/222] ARM: i.MX6: ipu_di_sel clocks can set parent rates
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (137 preceding siblings ...)
  2014-04-25 11:43 ` [PATCH 138/222] ARM: imx6q: clk: Parent DI clocks to video PLL via di_pre_sel Russell King
@ 2014-04-25 11:43 ` Russell King
  2014-04-25 11:43 ` [PATCH 140/222] ata: ahci_imx: allow hardware parameters to be specified in DT Russell King
                   ` (83 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:43 UTC (permalink / raw)
  To: linux-arm-kernel

From: Philipp Zabel <p.zabel@pengutronix.de>
To: linux-arm-kernel at lists.infradead.org

To obtain exact pixel clocks, allow the DI clock selectors to influence
the PLLs that they are derived from.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-imx/clk-imx6q.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c
index 7d2b652497d2..e7888a1c0aa3 100644
--- a/arch/arm/mach-imx/clk-imx6q.c
+++ b/arch/arm/mach-imx/clk-imx6q.c
@@ -258,14 +258,14 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
 	clk[ipu2_sel]         = imx_clk_mux("ipu2_sel",         base + 0x3c, 14, 2, ipu_sels,          ARRAY_SIZE(ipu_sels));
 	clk[ldb_di0_sel]      = imx_clk_mux_flags("ldb_di0_sel", base + 0x2c, 9,  3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT);
 	clk[ldb_di1_sel]      = imx_clk_mux_flags("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT);
-	clk[ipu1_di0_pre_sel] = imx_clk_mux("ipu1_di0_pre_sel", base + 0x34, 6,  3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels));
-	clk[ipu1_di1_pre_sel] = imx_clk_mux("ipu1_di1_pre_sel", base + 0x34, 15, 3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels));
-	clk[ipu2_di0_pre_sel] = imx_clk_mux("ipu2_di0_pre_sel", base + 0x38, 6,  3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels));
-	clk[ipu2_di1_pre_sel] = imx_clk_mux("ipu2_di1_pre_sel", base + 0x38, 15, 3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels));
-	clk[ipu1_di0_sel]     = imx_clk_mux("ipu1_di0_sel",     base + 0x34, 0,  3, ipu1_di0_sels,     ARRAY_SIZE(ipu1_di0_sels));
-	clk[ipu1_di1_sel]     = imx_clk_mux("ipu1_di1_sel",     base + 0x34, 9,  3, ipu1_di1_sels,     ARRAY_SIZE(ipu1_di1_sels));
-	clk[ipu2_di0_sel]     = imx_clk_mux("ipu2_di0_sel",     base + 0x38, 0,  3, ipu2_di0_sels,     ARRAY_SIZE(ipu2_di0_sels));
-	clk[ipu2_di1_sel]     = imx_clk_mux("ipu2_di1_sel",     base + 0x38, 9,  3, ipu2_di1_sels,     ARRAY_SIZE(ipu2_di1_sels));
+	clk[ipu1_di0_pre_sel] = imx_clk_mux_flags("ipu1_di0_pre_sel", base + 0x34, 6,  3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
+	clk[ipu1_di1_pre_sel] = imx_clk_mux_flags("ipu1_di1_pre_sel", base + 0x34, 15, 3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
+	clk[ipu2_di0_pre_sel] = imx_clk_mux_flags("ipu2_di0_pre_sel", base + 0x38, 6,  3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
+	clk[ipu2_di1_pre_sel] = imx_clk_mux_flags("ipu2_di1_pre_sel", base + 0x38, 15, 3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
+	clk[ipu1_di0_sel]     = imx_clk_mux_flags("ipu1_di0_sel",     base + 0x34, 0,  3, ipu1_di0_sels,     ARRAY_SIZE(ipu1_di0_sels), CLK_SET_RATE_PARENT);
+	clk[ipu1_di1_sel]     = imx_clk_mux_flags("ipu1_di1_sel",     base + 0x34, 9,  3, ipu1_di1_sels,     ARRAY_SIZE(ipu1_di1_sels), CLK_SET_RATE_PARENT);
+	clk[ipu2_di0_sel]     = imx_clk_mux_flags("ipu2_di0_sel",     base + 0x38, 0,  3, ipu2_di0_sels,     ARRAY_SIZE(ipu2_di0_sels), CLK_SET_RATE_PARENT);
+	clk[ipu2_di1_sel]     = imx_clk_mux_flags("ipu2_di1_sel",     base + 0x38, 9,  3, ipu2_di1_sels,     ARRAY_SIZE(ipu2_di1_sels), CLK_SET_RATE_PARENT);
 	clk[hsi_tx_sel]       = imx_clk_mux("hsi_tx_sel",       base + 0x30, 28, 1, hsi_tx_sels,       ARRAY_SIZE(hsi_tx_sels));
 	clk[pcie_axi_sel]     = imx_clk_mux("pcie_axi_sel",     base + 0x18, 10, 1, pcie_axi_sels,     ARRAY_SIZE(pcie_axi_sels));
 	clk[ssi1_sel]         = imx_clk_fixup_mux("ssi1_sel",   base + 0x1c, 10, 2, ssi_sels,          ARRAY_SIZE(ssi_sels),          imx_cscmr1_fixup);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 140/222] ata: ahci_imx: allow hardware parameters to be specified in DT
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (138 preceding siblings ...)
  2014-04-25 11:43 ` [PATCH 139/222] ARM: i.MX6: ipu_di_sel clocks can set parent rates Russell King
@ 2014-04-25 11:43 ` Russell King
  2014-04-25 11:43 ` [PATCH 141/222] ARM: cubox-i: add eSATA DT configuration Russell King
                   ` (82 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:43 UTC (permalink / raw)
  To: linux-arm-kernel

Various SATA phy parameters are board specific, and therefore need to
be configured.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/ata/ahci_imx.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 160 insertions(+), 8 deletions(-)

diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c
index 6a56a561a80b..fa5755f8dff2 100644
--- a/drivers/ata/ahci_imx.c
+++ b/drivers/ata/ahci_imx.c
@@ -46,6 +46,7 @@ struct imx_ahci_priv {
 	struct regmap *gpr;
 	bool no_device;
 	bool first_time;
+	u32 phy_params;
 };
 
 static int ahci_imx_hotplug;
@@ -90,14 +91,7 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv)
 				   IMX6Q_GPR13_SATA_TX_LVL_MASK |
 				   IMX6Q_GPR13_SATA_MPLL_CLK_EN |
 				   IMX6Q_GPR13_SATA_TX_EDGE_RATE,
-				   IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB |
-				   IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M |
-				   IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F |
-				   IMX6Q_GPR13_SATA_SPD_MODE_3P0G |
-				   IMX6Q_GPR13_SATA_MPLL_SS_EN |
-				   IMX6Q_GPR13_SATA_TX_ATTEN_9_16 |
-				   IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB |
-				   IMX6Q_GPR13_SATA_TX_LVL_1_025_V);
+				   imxpriv->phy_params);
 		regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
 				   IMX6Q_GPR13_SATA_MPLL_CLK_EN,
 				   IMX6Q_GPR13_SATA_MPLL_CLK_EN);
@@ -204,6 +198,152 @@ static const struct of_device_id imx_ahci_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, imx_ahci_of_match);
 
+struct reg_value {
+	u32 of_value;
+	u32 reg_value;
+};
+
+struct reg_property {
+	const char *name;
+	const struct reg_value *values;
+	size_t num_values;
+	u32 def_value;
+};
+
+static const struct reg_value gpr13_tx_level[] = {
+	{  937, IMX6Q_GPR13_SATA_TX_LVL_0_937_V },
+	{  947, IMX6Q_GPR13_SATA_TX_LVL_0_947_V },
+	{  957, IMX6Q_GPR13_SATA_TX_LVL_0_957_V },
+	{  966, IMX6Q_GPR13_SATA_TX_LVL_0_966_V },
+	{  976, IMX6Q_GPR13_SATA_TX_LVL_0_976_V },
+	{  986, IMX6Q_GPR13_SATA_TX_LVL_0_986_V },
+	{  996, IMX6Q_GPR13_SATA_TX_LVL_0_996_V },
+	{ 1005, IMX6Q_GPR13_SATA_TX_LVL_1_005_V },
+	{ 1015, IMX6Q_GPR13_SATA_TX_LVL_1_015_V },
+	{ 1025, IMX6Q_GPR13_SATA_TX_LVL_1_025_V },
+	{ 1035, IMX6Q_GPR13_SATA_TX_LVL_1_035_V },
+	{ 1045, IMX6Q_GPR13_SATA_TX_LVL_1_045_V },
+	{ 1054, IMX6Q_GPR13_SATA_TX_LVL_1_054_V },
+	{ 1064, IMX6Q_GPR13_SATA_TX_LVL_1_064_V },
+	{ 1074, IMX6Q_GPR13_SATA_TX_LVL_1_074_V },
+	{ 1084, IMX6Q_GPR13_SATA_TX_LVL_1_084_V },
+	{ 1094, IMX6Q_GPR13_SATA_TX_LVL_1_094_V },
+	{ 1104, IMX6Q_GPR13_SATA_TX_LVL_1_104_V },
+	{ 1113, IMX6Q_GPR13_SATA_TX_LVL_1_113_V },
+	{ 1123, IMX6Q_GPR13_SATA_TX_LVL_1_123_V },
+	{ 1133, IMX6Q_GPR13_SATA_TX_LVL_1_133_V },
+	{ 1143, IMX6Q_GPR13_SATA_TX_LVL_1_143_V },
+	{ 1152, IMX6Q_GPR13_SATA_TX_LVL_1_152_V },
+	{ 1162, IMX6Q_GPR13_SATA_TX_LVL_1_162_V },
+	{ 1172, IMX6Q_GPR13_SATA_TX_LVL_1_172_V },
+	{ 1182, IMX6Q_GPR13_SATA_TX_LVL_1_182_V },
+	{ 1191, IMX6Q_GPR13_SATA_TX_LVL_1_191_V },
+	{ 1201, IMX6Q_GPR13_SATA_TX_LVL_1_201_V },
+	{ 1211, IMX6Q_GPR13_SATA_TX_LVL_1_211_V },
+	{ 1221, IMX6Q_GPR13_SATA_TX_LVL_1_221_V },
+	{ 1230, IMX6Q_GPR13_SATA_TX_LVL_1_230_V },
+	{ 1240, IMX6Q_GPR13_SATA_TX_LVL_1_240_V }
+};
+
+static const struct reg_value gpr13_tx_boost[] = {
+	{    0, IMX6Q_GPR13_SATA_TX_BOOST_0_00_DB },
+	{  370, IMX6Q_GPR13_SATA_TX_BOOST_0_37_DB },
+	{  740, IMX6Q_GPR13_SATA_TX_BOOST_0_74_DB },
+	{  111, IMX6Q_GPR13_SATA_TX_BOOST_1_11_DB },
+	{  148, IMX6Q_GPR13_SATA_TX_BOOST_1_48_DB },
+	{  185, IMX6Q_GPR13_SATA_TX_BOOST_1_85_DB },
+	{  222, IMX6Q_GPR13_SATA_TX_BOOST_2_22_DB },
+	{  259, IMX6Q_GPR13_SATA_TX_BOOST_2_59_DB },
+	{  296, IMX6Q_GPR13_SATA_TX_BOOST_2_96_DB },
+	{  333, IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB },
+	{  370, IMX6Q_GPR13_SATA_TX_BOOST_3_70_DB },
+	{  407, IMX6Q_GPR13_SATA_TX_BOOST_4_07_DB },
+	{  444, IMX6Q_GPR13_SATA_TX_BOOST_4_44_DB },
+	{  481, IMX6Q_GPR13_SATA_TX_BOOST_4_81_DB },
+	{  528, IMX6Q_GPR13_SATA_TX_BOOST_5_28_DB },
+	{  575, IMX6Q_GPR13_SATA_TX_BOOST_5_75_DB }
+};
+
+static const struct reg_value gpr13_tx_atten[] = {
+	{  8, IMX6Q_GPR13_SATA_TX_ATTEN_8_16 },
+	{  9, IMX6Q_GPR13_SATA_TX_ATTEN_9_16 },
+	{ 10, IMX6Q_GPR13_SATA_TX_ATTEN_10_16 },
+	{ 12, IMX6Q_GPR13_SATA_TX_ATTEN_12_16 },
+	{ 14, IMX6Q_GPR13_SATA_TX_ATTEN_14_16 },
+	{ 16, IMX6Q_GPR13_SATA_TX_ATTEN_16_16 },
+};
+
+static const struct reg_value gpr13_rx_eq[] = {
+	{  500, IMX6Q_GPR13_SATA_RX_EQ_VAL_0_5_DB },
+	{ 1000, IMX6Q_GPR13_SATA_RX_EQ_VAL_1_0_DB },
+	{ 1500, IMX6Q_GPR13_SATA_RX_EQ_VAL_1_5_DB },
+	{ 2000, IMX6Q_GPR13_SATA_RX_EQ_VAL_2_0_DB },
+	{ 2500, IMX6Q_GPR13_SATA_RX_EQ_VAL_2_5_DB },
+	{ 3000, IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB },
+	{ 3500, IMX6Q_GPR13_SATA_RX_EQ_VAL_3_5_DB },
+	{ 4000, IMX6Q_GPR13_SATA_RX_EQ_VAL_4_0_DB },
+};
+
+static const struct reg_property gpr13_props[] = {
+	{
+		.name = "fsl,transmit-level-mV",
+		.values = gpr13_tx_level,
+		.num_values = ARRAY_SIZE(gpr13_tx_level),
+		.def_value = IMX6Q_GPR13_SATA_TX_LVL_1_025_V,
+	}, {
+		.name = "fsl,transmit-boost-mdB",
+		.values = gpr13_tx_boost,
+		.num_values = ARRAY_SIZE(gpr13_tx_boost),
+		.def_value = IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB,
+	}, {
+		.name = "fsl,transmit-atten-16ths",
+		.values = gpr13_tx_atten,
+		.num_values = ARRAY_SIZE(gpr13_tx_atten),
+		.def_value = IMX6Q_GPR13_SATA_TX_ATTEN_9_16,
+	}, {
+		.name = "fsl,receive-eq-mdB",
+		.values = gpr13_rx_eq,
+		.num_values = ARRAY_SIZE(gpr13_rx_eq),
+		.def_value = IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB,
+	},
+};
+
+static u32 imx_ahci_parse_props(struct device *dev,
+				const struct reg_property *prop, size_t num)
+{
+	struct device_node *np = dev->of_node;
+	u32 reg_value = 0;
+	int i, j;
+
+	for (i = 0; i < num; i++, prop++) {
+		u32 of_val;
+
+		if (of_property_read_u32(np, prop->name, &of_val)) {
+			dev_info(dev, "%s not specified, using %08x\n",
+				prop->name, prop->def_value);
+			reg_value |= prop->def_value;
+			continue;
+		}
+
+		for (j = 0; j < prop->num_values; j++) {
+			if (prop->values[j].of_value == of_val) {
+				dev_info(dev, "%s value %u, using %08x\n",
+					prop->name, of_val, prop->values[j].reg_value);
+				reg_value |= prop->values[j].reg_value;
+				break;
+			}
+		}
+
+		if (j == prop->num_values) {
+			dev_err(dev, "DT property %s is not a valid value\n",
+				prop->name);
+			reg_value |= prop->def_value;
+		}
+	}
+
+	return reg_value;
+}
+
 static int imx_ahci_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -231,6 +371,8 @@ static int imx_ahci_probe(struct platform_device *pdev)
 	}
 
 	if (imxpriv->type == AHCI_IMX6Q) {
+		u32 reg_value;
+
 		imxpriv->gpr = syscon_regmap_lookup_by_compatible(
 							"fsl,imx6q-iomuxc-gpr");
 		if (IS_ERR(imxpriv->gpr)) {
@@ -238,6 +380,16 @@ static int imx_ahci_probe(struct platform_device *pdev)
 				"failed to find fsl,imx6q-iomux-gpr regmap\n");
 			return PTR_ERR(imxpriv->gpr);
 		}
+
+		reg_value = imx_ahci_parse_props(dev, gpr13_props,
+						 ARRAY_SIZE(gpr13_props));
+
+		imxpriv->phy_params =
+				   IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M |
+				   IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F |
+				   IMX6Q_GPR13_SATA_SPD_MODE_3P0G |
+				   IMX6Q_GPR13_SATA_MPLL_SS_EN |
+				   reg_value;
 	}
 
 	hpriv = ahci_platform_get_resources(pdev);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 141/222] ARM: cubox-i: add eSATA DT configuration
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (139 preceding siblings ...)
  2014-04-25 11:43 ` [PATCH 140/222] ata: ahci_imx: allow hardware parameters to be specified in DT Russell King
@ 2014-04-25 11:43 ` Russell King
  2014-04-25 11:43 ` [PATCH 142/222] ahci_imx: add disable for spread-spectrum Russell King
                   ` (81 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:43 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/boot/dts/imx6q-cubox-i.dts | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm/boot/dts/imx6q-cubox-i.dts b/arch/arm/boot/dts/imx6q-cubox-i.dts
index bc5f31e3e892..941365d7ee65 100644
--- a/arch/arm/boot/dts/imx6q-cubox-i.dts
+++ b/arch/arm/boot/dts/imx6q-cubox-i.dts
@@ -13,4 +13,7 @@
 
 &sata {
 	status = "okay";
+	fsl,transmit-level-mV = <1104>;
+	fsl,transmit-boost-mdB = <0>;
+	fsl,transmit-atten-16ths = <9>;
 };
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 142/222] ahci_imx: add disable for spread-spectrum
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (140 preceding siblings ...)
  2014-04-25 11:43 ` [PATCH 141/222] ARM: cubox-i: add eSATA DT configuration Russell King
@ 2014-04-25 11:43 ` Russell King
  2014-04-25 11:43 ` [PATCH 143/222] imx-drm: imx-drm-core: fix imx_drm_encoder_get_mux_id Russell King
                   ` (80 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:43 UTC (permalink / raw)
  To: linux-arm-kernel

Spread-spectrum doesn't work with Cubox-i hardware, so we have to
disable this feature.  Add a DT property so that platforms can
indicate that this feature should not be enabled.

Having it as a negative property keeps existing DT files working.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/boot/dts/imx6q-cubox-i.dts |  1 +
 drivers/ata/ahci_imx.c              | 14 +++++++++++++-
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/imx6q-cubox-i.dts b/arch/arm/boot/dts/imx6q-cubox-i.dts
index 941365d7ee65..9efd8b0c8011 100644
--- a/arch/arm/boot/dts/imx6q-cubox-i.dts
+++ b/arch/arm/boot/dts/imx6q-cubox-i.dts
@@ -16,4 +16,5 @@
 	fsl,transmit-level-mV = <1104>;
 	fsl,transmit-boost-mdB = <0>;
 	fsl,transmit-atten-16ths = <9>;
+	fsl,no-spread-spectrum;
 };
diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c
index fa5755f8dff2..e4d5e0266fe0 100644
--- a/drivers/ata/ahci_imx.c
+++ b/drivers/ata/ahci_imx.c
@@ -208,6 +208,7 @@ struct reg_property {
 	const struct reg_value *values;
 	size_t num_values;
 	u32 def_value;
+	u32 set_value;
 };
 
 static const struct reg_value gpr13_tx_level[] = {
@@ -305,6 +306,10 @@ static const struct reg_property gpr13_props[] = {
 		.values = gpr13_rx_eq,
 		.num_values = ARRAY_SIZE(gpr13_rx_eq),
 		.def_value = IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB,
+	}, {
+		.name = "fsl,no-spread-spectrum",
+		.def_value = IMX6Q_GPR13_SATA_MPLL_SS_EN,
+		.set_value = 0,
 	},
 };
 
@@ -318,6 +323,14 @@ static u32 imx_ahci_parse_props(struct device *dev,
 	for (i = 0; i < num; i++, prop++) {
 		u32 of_val;
 
+		if (prop->num_values == 0) {
+			if (of_property_read_bool(np, prop->name))
+				reg_value |= prop->set_value;
+			else
+				reg_value |= prop->def_value;
+			continue;
+		}
+
 		if (of_property_read_u32(np, prop->name, &of_val)) {
 			dev_info(dev, "%s not specified, using %08x\n",
 				prop->name, prop->def_value);
@@ -388,7 +401,6 @@ static int imx_ahci_probe(struct platform_device *pdev)
 				   IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M |
 				   IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F |
 				   IMX6Q_GPR13_SATA_SPD_MODE_3P0G |
-				   IMX6Q_GPR13_SATA_MPLL_SS_EN |
 				   reg_value;
 	}
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 143/222] imx-drm: imx-drm-core: fix imx_drm_encoder_get_mux_id
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (141 preceding siblings ...)
  2014-04-25 11:43 ` [PATCH 142/222] ahci_imx: add disable for spread-spectrum Russell King
@ 2014-04-25 11:43 ` Russell King
  2014-04-25 11:43 ` [PATCH 144/222] imx-drm: imx-drm-core: skip components whose parent device is disabled Russell King
                   ` (79 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:43 UTC (permalink / raw)
  To: linux-arm-kernel

From: Philipp Zabel <p.zabel@pengutronix.de>
To: linux-arm-kernel at lists.infradead.org

The decoder mux id is equal to the port id of the encoder's input port
that is connected to the given crtc, not to the endpoint id (which is
arbitrary and usually zero).

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Tested-by: Shawn Guo <shawn.guo@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 4144a75e5f71..bc7f8bd227c7 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -517,7 +517,7 @@ int imx_drm_encoder_get_mux_id(struct device_node *node,
 		of_node_put(port);
 		if (port == imx_crtc->port) {
 			ret = of_graph_parse_endpoint(ep, &endpoint);
-			return ret ? ret : endpoint.id;
+			return ret ? ret : endpoint.port;
 		}
 	} while (ep);
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 144/222] imx-drm: imx-drm-core: skip components whose parent device is disabled
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (142 preceding siblings ...)
  2014-04-25 11:43 ` [PATCH 143/222] imx-drm: imx-drm-core: fix imx_drm_encoder_get_mux_id Russell King
@ 2014-04-25 11:43 ` Russell King
  2014-04-25 11:43 ` [PATCH 145/222] imx-drm: imx-ldb: add drm_panel support Russell King
                   ` (78 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:43 UTC (permalink / raw)
  To: linux-arm-kernel

From: Shawn Guo <shawn.guo@freescale.com>
To: linux-arm-kernel at lists.infradead.org

In a board setup which disables LDB device node completely by changing
status to 'disabled', and only enables HDMI device, we're running into
the problem that imx-drm master never succeeds in binding, and hence
HDMI does not come up either.

&ldb {
	status = "disabled";

	lvds-channel at 1 {
		...
		status = "okay";
	};
};

The imx-drm-core should really skip the LVDS channels no matter what
lvds-channel's status is, if LDB device is disabled.  Let's consider
such setup a misconfiguration, give a warning in there and not add the
component.

Signed-off-by: Shawn Guo <shawn.guo@freescale.com>
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index bc7f8bd227c7..c270c9ae6d27 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -675,6 +675,11 @@ static int imx_drm_platform_probe(struct platform_device *pdev)
 			if (!remote || !of_device_is_available(remote)) {
 				of_node_put(remote);
 				continue;
+			} else if (!of_device_is_available(remote->parent)) {
+				dev_warn(&pdev->dev, "parent device of %s is not available\n",
+					 remote->full_name);
+				of_node_put(remote);
+				continue;
 			}
 
 			ret = imx_drm_add_component(&pdev->dev, remote);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 145/222] imx-drm: imx-ldb: add drm_panel support
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (143 preceding siblings ...)
  2014-04-25 11:43 ` [PATCH 144/222] imx-drm: imx-drm-core: skip components whose parent device is disabled Russell King
@ 2014-04-25 11:43 ` Russell King
  2014-04-25 11:43 ` [PATCH 146/222] imx-drm: match ipu_di_signal_cfg's clk_pol with its description Russell King
                   ` (77 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:43 UTC (permalink / raw)
  To: linux-arm-kernel

From: Philipp Zabel <p.zabel@pengutronix.de>
To: linux-arm-kernel at lists.infradead.org

This patch allows to optionally attach the lvds-channel to a panel
supported by a drm_panel driver instead of supplying the modes via
device tree.

Before:

	ldb {
		...

		lvds-channel at 0 {
			...

			display-timings {
				native-timing = <&timing1>;
				timing1: etm0700g0dh6 {
					hactive = <800>;
					vactive = <480>;
					clock-frequency = <33260000>;
					hsync-len = <128>;
					hback-porch = <88>;
					hfront-porch = <40>;
					vsync-len = <2>;
					vback-porch = <33>;
					vfront-porch = <10>;
					hsync-active = <0>;
					vsync-active = <0>;
					...
				};
			};
			...
		};
	};

After:
	ldb {
		...

		lvds-channel at 0 {
			fsl,panel = <&panel>;
			...
		};
	};

	panel: panel {
		compatible = "edt,etm0700g0dh6", "simple-panel";
	};

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
[Fixed build error due to missing select on DRM_PANEL --rmk]
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/Kconfig   |  1 +
 drivers/staging/imx-drm/imx-ldb.c | 21 +++++++++++++++++++++
 2 files changed, 22 insertions(+)

diff --git a/drivers/staging/imx-drm/Kconfig b/drivers/staging/imx-drm/Kconfig
index c6e8ba7b3e4e..92fb52cbd3a2 100644
--- a/drivers/staging/imx-drm/Kconfig
+++ b/drivers/staging/imx-drm/Kconfig
@@ -35,6 +35,7 @@ config DRM_IMX_TVE
 config DRM_IMX_LDB
 	tristate "Support for LVDS displays"
 	depends on DRM_IMX && MFD_SYSCON
+	select DRM_PANEL
 	help
 	  Choose this to enable the internal LVDS Display Bridge (LDB)
 	  found on i.MX53 and i.MX6 processors.
diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c
index fe4c1ef4e7a5..3a3bacec2e11 100644
--- a/drivers/staging/imx-drm/imx-ldb.c
+++ b/drivers/staging/imx-drm/imx-ldb.c
@@ -24,6 +24,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_panel.h>
 #include <linux/mfd/syscon.h>
 #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
 #include <linux/of_address.h>
@@ -60,6 +61,7 @@ struct imx_ldb_channel {
 	struct imx_ldb *ldb;
 	struct drm_connector connector;
 	struct drm_encoder encoder;
+	struct drm_panel *panel;
 	struct device_node *child;
 	int chno;
 	void *edid;
@@ -96,6 +98,13 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector)
 	struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector);
 	int num_modes = 0;
 
+	if (imx_ldb_ch->panel && imx_ldb_ch->panel->funcs &&
+	    imx_ldb_ch->panel->funcs->get_modes) {
+		num_modes = imx_ldb_ch->panel->funcs->get_modes(imx_ldb_ch->panel);
+		if (num_modes > 0)
+			return num_modes;
+	}
+
 	if (imx_ldb_ch->edid) {
 		drm_mode_connector_update_edid_property(connector,
 							imx_ldb_ch->edid);
@@ -243,6 +252,8 @@ static void imx_ldb_encoder_commit(struct drm_encoder *encoder)
 	}
 
 	regmap_write(ldb->regmap, IOMUXC_GPR2, ldb->ldb_ctrl);
+
+	drm_panel_enable(imx_ldb_ch->panel);
 }
 
 static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder,
@@ -294,6 +305,8 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder)
 		 (ldb->ldb_ctrl & LDB_CH1_MODE_EN_MASK) == 0)
 		return;
 
+	drm_panel_disable(imx_ldb_ch->panel);
+
 	if (imx_ldb_ch == &ldb->channel[0])
 		ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK;
 	else if (imx_ldb_ch == &ldb->channel[1])
@@ -379,6 +392,9 @@ static int imx_ldb_register(struct drm_device *drm,
 	drm_connector_init(drm, &imx_ldb_ch->connector,
 			   &imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
 
+	if (imx_ldb_ch->panel)
+		drm_panel_attach(imx_ldb_ch->panel, &imx_ldb_ch->connector);
+
 	drm_mode_connector_attach_encoder(&imx_ldb_ch->connector,
 			&imx_ldb_ch->encoder);
 
@@ -493,6 +509,7 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
 
 	for_each_child_of_node(np, child) {
 		struct imx_ldb_channel *channel;
+		struct device_node *panel_node;
 
 		ret = of_property_read_u32(child, "reg", &i);
 		if (ret || i < 0 || i > 1)
@@ -556,6 +573,10 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
 			return -EINVAL;
 		}
 
+		panel_node = of_parse_phandle(child, "fsl,panel", 0);
+		if (panel_node)
+			channel->panel = of_drm_find_panel(panel_node);
+
 		ret = imx_ldb_register(drm, channel);
 		if (ret)
 			return ret;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 146/222] imx-drm: match ipu_di_signal_cfg's clk_pol with its description.
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (144 preceding siblings ...)
  2014-04-25 11:43 ` [PATCH 145/222] imx-drm: imx-ldb: add drm_panel support Russell King
@ 2014-04-25 11:43 ` Russell King
  2014-04-25 11:43 ` [PATCH 147/222] v4l2: add new V4L2_PIX_FMT_RGB666 pixel format Russell King
                   ` (76 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:43 UTC (permalink / raw)
  To: linux-arm-kernel

From: Denis Carikli <denis@eukrea.com>
To: linux-arm-kernel at lists.infradead.org

According to the datasheet, setting the di0_polarity_disp_clk
field in the GENERAL di register sets the output clock polarity
to active high.

Signed-off-by: Denis Carikli <denis@eukrea.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/ipu-v3/ipu-di.c | 2 +-
 drivers/staging/imx-drm/ipuv3-crtc.c    | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-di.c b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
index 82a9ebad697c..849b3e120ef0 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-di.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
@@ -595,7 +595,7 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
 		}
 	}
 
-	if (!sig->clk_pol)
+	if (sig->clk_pol)
 		di_gen |= DI_GEN_POLARITY_DISP_CLK;
 
 	ipu_di_write(di, di_gen, DI_GENERAL);
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
index c48f640db006..f2c9cd040043 100644
--- a/drivers/staging/imx-drm/ipuv3-crtc.c
+++ b/drivers/staging/imx-drm/ipuv3-crtc.c
@@ -158,7 +158,7 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,
 		sig_cfg.Vsync_pol = 1;
 
 	sig_cfg.enable_pol = 1;
-	sig_cfg.clk_pol = 1;
+	sig_cfg.clk_pol = 0;
 	sig_cfg.width = mode->hdisplay;
 	sig_cfg.height = mode->vdisplay;
 	sig_cfg.pixel_fmt = out_pixel_fmt;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 147/222] v4l2: add new V4L2_PIX_FMT_RGB666 pixel format.
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (145 preceding siblings ...)
  2014-04-25 11:43 ` [PATCH 146/222] imx-drm: match ipu_di_signal_cfg's clk_pol with its description Russell King
@ 2014-04-25 11:43 ` Russell King
  2014-04-25 11:44 ` [PATCH 148/222] imx-drm: add RGB666 support for parallel display Russell King
                   ` (75 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:43 UTC (permalink / raw)
  To: linux-arm-kernel

From: Denis Carikli <denis@eukrea.com>
To: linux-arm-kernel at lists.infradead.org

That new macro is needed by the imx_drm staging driver
  for supporting the QVGA display of the eukrea-cpuimx51 board.

Signed-off-by: Denis Carikli <denis@eukrea.com>
Acked-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 .../DocBook/media/v4l/pixfmt-packed-rgb.xml        | 39 ++++++++++++++++++++++
 include/uapi/linux/videodev2.h                     |  1 +
 2 files changed, 40 insertions(+)

diff --git a/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml b/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml
index e1c4f8b4c0b3..88a7fe1ecaf1 100644
--- a/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml
+++ b/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml
@@ -279,6 +279,45 @@ colorspace <constant>V4L2_COLORSPACE_SRGB</constant>.</para>
 	    <entry></entry>
 	    <entry></entry>
 	  </row>
+	  <row id="V4L2-PIX-FMT-RGB666">
+	    <entry><constant>V4L2_PIX_FMT_RGB666</constant></entry>
+	    <entry>'RGBH'</entry>
+	    <entry></entry>
+	    <entry>r<subscript>5</subscript></entry>
+	    <entry>r<subscript>4</subscript></entry>
+	    <entry>r<subscript>3</subscript></entry>
+	    <entry>r<subscript>2</subscript></entry>
+	    <entry>r<subscript>1</subscript></entry>
+	    <entry>r<subscript>0</subscript></entry>
+	    <entry>g<subscript>5</subscript></entry>
+	    <entry>g<subscript>4</subscript></entry>
+	    <entry></entry>
+	    <entry>g<subscript>3</subscript></entry>
+	    <entry>g<subscript>2</subscript></entry>
+	    <entry>g<subscript>1</subscript></entry>
+	    <entry>g<subscript>0</subscript></entry>
+	    <entry>b<subscript>5</subscript></entry>
+	    <entry>b<subscript>4</subscript></entry>
+	    <entry>b<subscript>3</subscript></entry>
+	    <entry>b<subscript>2</subscript></entry>
+	    <entry></entry>
+	    <entry>b<subscript>1</subscript></entry>
+	    <entry>b<subscript>0</subscript></entry>
+	    <entry></entry>
+	    <entry></entry>
+	    <entry></entry>
+	    <entry></entry>
+	    <entry></entry>
+	    <entry></entry>
+	    <entry></entry>
+	    <entry></entry>
+	    <entry></entry>
+	    <entry></entry>
+	    <entry></entry>
+	    <entry></entry>
+	    <entry></entry>
+	    <entry></entry>
+	  </row>
 	  <row id="V4L2-PIX-FMT-BGR24">
 	    <entry><constant>V4L2_PIX_FMT_BGR24</constant></entry>
 	    <entry>'BGR3'</entry>
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index ea468ee8fe21..d5d818a86676 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -299,6 +299,7 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R', 'G', 'B', 'Q') /* 16  RGB-5-5-5 BE  */
 #define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R', 'G', 'B', 'R') /* 16  RGB-5-6-5 BE  */
 #define V4L2_PIX_FMT_BGR666  v4l2_fourcc('B', 'G', 'R', 'H') /* 18  BGR-6-6-6	  */
+#define V4L2_PIX_FMT_RGB666  v4l2_fourcc('R', 'G', 'B', 'H') /* 18  RGB-6-6-6	  */
 #define V4L2_PIX_FMT_BGR24   v4l2_fourcc('B', 'G', 'R', '3') /* 24  BGR-8-8-8     */
 #define V4L2_PIX_FMT_RGB24   v4l2_fourcc('R', 'G', 'B', '3') /* 24  RGB-8-8-8     */
 #define V4L2_PIX_FMT_BGR32   v4l2_fourcc('B', 'G', 'R', '4') /* 32  BGR-8-8-8-8   */
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 148/222] imx-drm: add RGB666 support for parallel display.
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (146 preceding siblings ...)
  2014-04-25 11:43 ` [PATCH 147/222] v4l2: add new V4L2_PIX_FMT_RGB666 pixel format Russell King
@ 2014-04-25 11:44 ` Russell King
  2014-04-25 11:44 ` [PATCH 149/222] imx-drm: ipu-common: add ipu_map_irq to request non-IDMAC interrupts Russell King
                   ` (74 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:44 UTC (permalink / raw)
  To: linux-arm-kernel

From: Denis Carikli <denis@eukrea.com>
To: linux-arm-kernel at lists.infradead.org

Signed-off-by: Denis Carikli <denis@eukrea.com>
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 .../devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt          | 3 ++-
 drivers/staging/imx-drm/ipu-v3/ipu-dc.c                          | 9 +++++++++
 drivers/staging/imx-drm/parallel-display.c                       | 2 ++
 3 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
index 3be5ce7a9654..83137ef5a1ba 100644
--- a/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
+++ b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
@@ -60,7 +60,8 @@ Parallel display support
 - compatible: Should be "fsl,imx-parallel-display"
 Optional properties:
 - interface_pix_fmt: How this display is connected to the
-  display interface. Currently supported types: "rgb24", "rgb565", "bgr666"
+  display interface. Currently supported types: "rgb24", "rgb565", "bgr666",
+  "rgb666"
 - edid: verbatim EDID data block describing attached display.
 - ddc: phandle describing the i2c bus handling the display data
   channel
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
index d5de8bb5c803..6f9abe8a4575 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
@@ -92,6 +92,7 @@ enum ipu_dc_map {
 	IPU_DC_MAP_GBR24, /* TVEv2 */
 	IPU_DC_MAP_BGR666,
 	IPU_DC_MAP_BGR24,
+	IPU_DC_MAP_RGB666,
 };
 
 struct ipu_dc {
@@ -155,6 +156,8 @@ static int ipu_pixfmt_to_map(u32 fmt)
 		return IPU_DC_MAP_BGR666;
 	case V4L2_PIX_FMT_BGR24:
 		return IPU_DC_MAP_BGR24;
+	case V4L2_PIX_FMT_RGB666:
+		return IPU_DC_MAP_RGB666;
 	default:
 		return -EINVAL;
 	}
@@ -404,6 +407,12 @@ int ipu_dc_init(struct ipu_soc *ipu, struct device *dev,
 	ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 1, 15, 0xff); /* green */
 	ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 0, 23, 0xff); /* blue */
 
+	/* rgb666 */
+	ipu_dc_map_clear(priv, IPU_DC_MAP_RGB666);
+	ipu_dc_map_config(priv, IPU_DC_MAP_RGB666, 0, 5, 0xfc); /* blue */
+	ipu_dc_map_config(priv, IPU_DC_MAP_RGB666, 1, 11, 0xfc); /* green */
+	ipu_dc_map_config(priv, IPU_DC_MAP_RGB666, 2, 17, 0xfc); /* red */
+
 	return 0;
 }
 
diff --git a/drivers/staging/imx-drm/parallel-display.c b/drivers/staging/imx-drm/parallel-display.c
index c60b6c645f42..01b7ce50fc30 100644
--- a/drivers/staging/imx-drm/parallel-display.c
+++ b/drivers/staging/imx-drm/parallel-display.c
@@ -219,6 +219,8 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
 			imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB565;
 		else if (!strcmp(fmt, "bgr666"))
 			imxpd->interface_pix_fmt = V4L2_PIX_FMT_BGR666;
+		else if (!strcmp(fmt, "rgb666"))
+			imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB666;
 	}
 
 	panel_node = of_parse_phandle(np, "fsl,panel", 0);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 149/222] imx-drm: ipu-common: add ipu_map_irq to request non-IDMAC interrupts
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (147 preceding siblings ...)
  2014-04-25 11:44 ` [PATCH 148/222] imx-drm: add RGB666 support for parallel display Russell King
@ 2014-04-25 11:44 ` Russell King
  2014-04-25 11:44 ` [PATCH 150/222] imx-drm: ipu-common: add helpers to check for a busy IDMAC channel and to busywait for an interrupt Russell King
                   ` (73 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:44 UTC (permalink / raw)
  To: linux-arm-kernel

From: Philipp Zabel <p.zabel@pengutronix.de>
To: linux-arm-kernel at lists.infradead.org

This allows to request the DC related interrupts.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h |  1 +
 drivers/staging/imx-drm/ipu-v3/ipu-common.c | 19 +++++++++++++------
 2 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
index c4d14ead5837..2966e425990e 100644
--- a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
+++ b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
@@ -76,6 +76,7 @@ enum ipu_channel_irq {
 	IPU_IRQ_EOS = 192,
 };
 
+int ipu_map_irq(struct ipu_soc *ipu, int irq);
 int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
 		enum ipu_channel_irq irq);
 
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index ca85d3d70ae3..058551795677 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -933,15 +933,22 @@ static void ipu_err_irq_handler(unsigned int irq, struct irq_desc *desc)
 	chained_irq_exit(chip, desc);
 }
 
-int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
-		enum ipu_channel_irq irq_type)
+int ipu_map_irq(struct ipu_soc *ipu, int irq)
 {
-	int irq = irq_linear_revmap(ipu->domain, irq_type + channel->num);
+	int virq;
 
-	if (!irq)
-		irq = irq_create_mapping(ipu->domain, irq_type + channel->num);
+	virq = irq_linear_revmap(ipu->domain, irq);
+	if (!virq)
+		virq = irq_create_mapping(ipu->domain, irq);
+
+	return virq;
+}
+EXPORT_SYMBOL_GPL(ipu_map_irq);
 
-	return irq;
+int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
+		enum ipu_channel_irq irq_type)
+{
+	return ipu_map_irq(ipu, irq_type + channel->num);
 }
 EXPORT_SYMBOL_GPL(ipu_idmac_channel_irq);
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 150/222] imx-drm: ipu-common: add helpers to check for a busy IDMAC channel and to busywait for an interrupt
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (148 preceding siblings ...)
  2014-04-25 11:44 ` [PATCH 149/222] imx-drm: ipu-common: add ipu_map_irq to request non-IDMAC interrupts Russell King
@ 2014-04-25 11:44 ` Russell King
  2014-04-25 11:44 ` [PATCH 151/222] imx-drm: ipu-dmfc: wait for FIFOs to run empty before disabling Russell King
                   ` (72 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:44 UTC (permalink / raw)
  To: linux-arm-kernel

From: Philipp Zabel <p.zabel@pengutronix.de>
To: linux-arm-kernel at lists.infradead.org

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/ipu-v3/ipu-common.c | 22 ++++++++++++++++++++++
 drivers/staging/imx-drm/ipu-v3/ipu-prv.h    |  3 +++
 2 files changed, 25 insertions(+)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index 058551795677..8fb4c207f3f1 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -697,6 +697,12 @@ int ipu_idmac_enable_channel(struct ipuv3_channel *channel)
 }
 EXPORT_SYMBOL_GPL(ipu_idmac_enable_channel);
 
+bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno)
+{
+	return (ipu_idmac_read(ipu, IDMAC_CHA_BUSY(chno)) & idma_mask(chno));
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_channel_busy);
+
 int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms)
 {
 	struct ipu_soc *ipu = channel->ipu;
@@ -714,6 +720,22 @@ int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms)
 }
 EXPORT_SYMBOL_GPL(ipu_idmac_wait_busy);
 
+int ipu_wait_interrupt(struct ipu_soc *ipu, int irq, int ms)
+{
+	unsigned long timeout;
+
+	timeout = jiffies + msecs_to_jiffies(ms);
+	ipu_cm_write(ipu, BIT(irq % 32), IPU_INT_STAT(irq / 32));
+	while (!(ipu_cm_read(ipu, IPU_INT_STAT(irq / 32) & BIT(irq % 32)))) {
+		if (time_after(jiffies, timeout))
+			return -ETIMEDOUT;
+		cpu_relax();
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_wait_interrupt);
+
 int ipu_idmac_disable_channel(struct ipuv3_channel *channel)
 {
 	struct ipu_soc *ipu = channel->ipu;
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
index 4df00501adc2..bfc1b3366488 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
@@ -185,6 +185,9 @@ void ipu_srm_dp_sync_update(struct ipu_soc *ipu);
 int ipu_module_enable(struct ipu_soc *ipu, u32 mask);
 int ipu_module_disable(struct ipu_soc *ipu, u32 mask);
 
+bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno);
+int ipu_wait_interrupt(struct ipu_soc *ipu, int irq, int ms);
+
 int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
 		unsigned long base, u32 module, struct clk *ipu_clk);
 void ipu_di_exit(struct ipu_soc *ipu, int id);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 151/222] imx-drm: ipu-dmfc: wait for FIFOs to run empty before disabling
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (149 preceding siblings ...)
  2014-04-25 11:44 ` [PATCH 150/222] imx-drm: ipu-common: add helpers to check for a busy IDMAC channel and to busywait for an interrupt Russell King
@ 2014-04-25 11:44 ` Russell King
  2014-04-25 11:44 ` [PATCH 152/222] imx-drm: ipu-dc: wait for DC_FC_1 / DP_SF_END interrupt Russell King
                   ` (71 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:44 UTC (permalink / raw)
  To: linux-arm-kernel

From: Philipp Zabel <p.zabel@pengutronix.de>
To: linux-arm-kernel at lists.infradead.org

Disabling the DMFC module while there is still data in the FIFOs could
cause the "new frame before end of frame" error state when the DMFC is
enabled again.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c | 25 +++++++++++++++++++++++--
 1 file changed, 23 insertions(+), 2 deletions(-)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c
index 45213017fa4b..59f182b28fc1 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c
@@ -28,7 +28,12 @@
 #define DMFC_GENERAL1		0x0014
 #define DMFC_GENERAL2		0x0018
 #define DMFC_IC_CTRL		0x001c
-#define DMFC_STAT		0x0020
+#define DMFC_WR_CHAN_ALT	0x0020
+#define DMFC_WR_CHAN_DEF_ALT	0x0024
+#define DMFC_DP_CHAN_ALT	0x0028
+#define DMFC_DP_CHAN_DEF_ALT	0x002c
+#define DMFC_GENERAL1_ALT	0x0030
+#define DMFC_STAT		0x0034
 
 #define DMFC_WR_CHAN_1_28		0
 #define DMFC_WR_CHAN_2_41		8
@@ -133,6 +138,20 @@ int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc)
 }
 EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel);
 
+static void ipu_dmfc_wait_fifos(struct ipu_dmfc_priv *priv)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+
+	while ((readl(priv->base + DMFC_STAT) & 0x02fff000) != 0x02fff000) {
+		if (time_after(jiffies, timeout)) {
+			dev_warn(priv->dev,
+				 "Timeout waiting for DMFC FIFOs to clear\n");
+			break;
+		}
+		cpu_relax();
+	}
+}
+
 void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
 {
 	struct ipu_dmfc_priv *priv = dmfc->priv;
@@ -141,8 +160,10 @@ void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
 
 	priv->use_count--;
 
-	if (!priv->use_count)
+	if (!priv->use_count) {
+		ipu_dmfc_wait_fifos(priv);
 		ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN);
+	}
 
 	if (priv->use_count < 0)
 		priv->use_count = 0;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 152/222] imx-drm: ipu-dc: wait for DC_FC_1 / DP_SF_END interrupt
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (150 preceding siblings ...)
  2014-04-25 11:44 ` [PATCH 151/222] imx-drm: ipu-dmfc: wait for FIFOs to run empty before disabling Russell King
@ 2014-04-25 11:44 ` Russell King
  2014-04-25 11:44 ` [PATCH 153/222] imx-drm: ipu-dp: split disabling the DP foreground channel from disabling the DP module Russell King
                   ` (70 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:44 UTC (permalink / raw)
  To: linux-arm-kernel

From: Philipp Zabel <p.zabel@pengutronix.de>
To: linux-arm-kernel at lists.infradead.org

Wait for the DC Frame Complete or DP Sync Flow End interrupts
before disabling DC channels.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/ipu-v3/ipu-dc.c | 71 +++++++++++++++++++++++----------
 1 file changed, 50 insertions(+), 21 deletions(-)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
index 6f9abe8a4575..7f5734aef9f7 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
@@ -18,6 +18,7 @@
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/delay.h>
+#include <linux/interrupt.h>
 #include <linux/io.h>
 
 #include "../imx-drm.h"
@@ -111,6 +112,9 @@ struct ipu_dc_priv {
 	struct device		*dev;
 	struct ipu_dc		channels[IPU_DC_NUM_CHANNELS];
 	struct mutex		mutex;
+	struct completion	comp;
+	int			dc_irq;
+	int			dp_irq;
 };
 
 static void dc_link_event(struct ipu_dc *dc, int event, int addr, int priority)
@@ -242,38 +246,46 @@ void ipu_dc_enable_channel(struct ipu_dc *dc)
 }
 EXPORT_SYMBOL_GPL(ipu_dc_enable_channel);
 
+static irqreturn_t dc_irq_handler(int irq, void *dev_id)
+{
+	struct ipu_dc *dc = dev_id;
+	u32 reg;
+
+	reg = readl(dc->base + DC_WR_CH_CONF);
+	reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
+	writel(reg, dc->base + DC_WR_CH_CONF);
+
+	/* The Freescale BSP kernel clears DIx_COUNTER_RELEASE here */
+
+	complete(&dc->priv->comp);
+	return IRQ_HANDLED;
+}
+
 void ipu_dc_disable_channel(struct ipu_dc *dc)
 {
 	struct ipu_dc_priv *priv = dc->priv;
+	int irq, ret;
 	u32 val;
-	int irq = 0, timeout = 50;
 
+	/* TODO: Handle MEM_FG_SYNC differently from MEM_BG_SYNC */
 	if (dc->chno == 1)
-		irq = IPU_IRQ_DC_FC_1;
+		irq = priv->dc_irq;
 	else if (dc->chno == 5)
-		irq = IPU_IRQ_DP_SF_END;
+		irq = priv->dp_irq;
 	else
 		return;
 
-	/* should wait for the interrupt here */
-	mdelay(50);
+	init_completion(&priv->comp);
+	enable_irq(irq);
+	ret = wait_for_completion_timeout(&priv->comp, msecs_to_jiffies(50));
+	disable_irq(irq);
+	if (ret <= 0) {
+		dev_warn(priv->dev, "DC stop timeout after 50 ms\n");
 
-	if (dc->di == 0)
-		val = 0x00000002;
-	else
-		val = 0x00000020;
-
-	/* Wait for DC triple buffer to empty */
-	while ((readl(priv->dc_reg + DC_STAT) & val) != val) {
-		usleep_range(2000, 20000);
-		timeout -= 2;
-		if (timeout <= 0)
-			break;
+		val = readl(dc->base + DC_WR_CH_CONF);
+		val &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
+		writel(val, dc->base + DC_WR_CH_CONF);
 	}
-
-	val = readl(dc->base + DC_WR_CH_CONF);
-	val &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
-	writel(val, dc->base + DC_WR_CH_CONF);
 }
 EXPORT_SYMBOL_GPL(ipu_dc_disable_channel);
 
@@ -343,7 +355,7 @@ int ipu_dc_init(struct ipu_soc *ipu, struct device *dev,
 	struct ipu_dc_priv *priv;
 	static int channel_offsets[] = { 0, 0x1c, 0x38, 0x54, 0x58, 0x5c,
 		0x78, 0, 0x94, 0xb4};
-	int i;
+	int i, ret;
 
 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 	if (!priv)
@@ -364,6 +376,23 @@ int ipu_dc_init(struct ipu_soc *ipu, struct device *dev,
 		priv->channels[i].base = priv->dc_reg + channel_offsets[i];
 	}
 
+	priv->dc_irq = ipu_map_irq(ipu, IPU_IRQ_DC_FC_1);
+	if (!priv->dc_irq)
+		return -EINVAL;
+	ret = devm_request_irq(dev, priv->dc_irq, dc_irq_handler, 0, NULL,
+			       &priv->channels[1]);
+	if (ret < 0)
+		return ret;
+	disable_irq(priv->dc_irq);
+	priv->dp_irq = ipu_map_irq(ipu, IPU_IRQ_DP_SF_END);
+	if (!priv->dp_irq)
+		return -EINVAL;
+	ret = devm_request_irq(dev, priv->dp_irq, dc_irq_handler, 0, NULL,
+			       &priv->channels[5]);
+	if (ret < 0)
+		return ret;
+	disable_irq(priv->dp_irq);
+
 	writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(1) |
 			DC_WR_CH_CONF_PROG_DI_ID,
 			priv->channels[1].base + DC_WR_CH_CONF);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 153/222] imx-drm: ipu-dp: split disabling the DP foreground channel from disabling the DP module
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (151 preceding siblings ...)
  2014-04-25 11:44 ` [PATCH 152/222] imx-drm: ipu-dc: wait for DC_FC_1 / DP_SF_END interrupt Russell King
@ 2014-04-25 11:44 ` Russell King
  2014-04-25 11:44 ` [PATCH 154/222] imx-drm: imx-dp: when disabling the DP foreground channel, wait until the DP background channel is finished before disabling the IDMAC channel Russell King
                   ` (69 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:44 UTC (permalink / raw)
  To: linux-arm-kernel

From: Philipp Zabel <p.zabel@pengutronix.de>
To: linux-arm-kernel at lists.infradead.org

The former has to be done before disabling the DMFC, the latter has to be
done afterwards. Otherwise the DMFC FIFOs never get cleared properly.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h |  2 +
 drivers/staging/imx-drm/ipu-v3/ipu-dp.c     | 68 +++++++++++++++++++----------
 drivers/staging/imx-drm/ipuv3-plane.c       |  4 ++
 3 files changed, 51 insertions(+), 23 deletions(-)

diff --git a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
index 2966e425990e..8678ad18a3ef 100644
--- a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
+++ b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
@@ -153,8 +153,10 @@ void ipu_dmfc_put(struct dmfc_channel *dmfc);
 
 struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow);
 void ipu_dp_put(struct ipu_dp *);
+int ipu_dp_enable(struct ipu_soc *ipu);
 int ipu_dp_enable_channel(struct ipu_dp *dp);
 void ipu_dp_disable_channel(struct ipu_dp *dp);
+void ipu_dp_disable(struct ipu_soc *ipu);
 int ipu_dp_setup_channel(struct ipu_dp *dp,
 		enum ipu_color_space in, enum ipu_color_space out);
 int ipu_dp_set_window_pos(struct ipu_dp *, u16 x_pos, u16 y_pos);
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dp.c b/drivers/staging/imx-drm/ipu-v3/ipu-dp.c
index 58f87c8d7c07..6980fa125517 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-dp.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-dp.c
@@ -215,10 +215,9 @@ int ipu_dp_setup_channel(struct ipu_dp *dp,
 }
 EXPORT_SYMBOL_GPL(ipu_dp_setup_channel);
 
-int ipu_dp_enable_channel(struct ipu_dp *dp)
+int ipu_dp_enable(struct ipu_soc *ipu)
 {
-	struct ipu_flow *flow = to_flow(dp);
-	struct ipu_dp_priv *priv = flow->priv;
+	struct ipu_dp_priv *priv = ipu->dp_priv;
 
 	mutex_lock(&priv->mutex);
 
@@ -227,15 +226,28 @@ int ipu_dp_enable_channel(struct ipu_dp *dp)
 
 	priv->use_count++;
 
-	if (dp->foreground) {
-		u32 reg;
+	mutex_unlock(&priv->mutex);
 
-		reg = readl(flow->base + DP_COM_CONF);
-		reg |= DP_COM_CONF_FG_EN;
-		writel(reg, flow->base + DP_COM_CONF);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dp_enable);
 
-		ipu_srm_dp_sync_update(priv->ipu);
-	}
+int ipu_dp_enable_channel(struct ipu_dp *dp)
+{
+	struct ipu_flow *flow = to_flow(dp);
+	struct ipu_dp_priv *priv = flow->priv;
+	u32 reg;
+
+	if (!dp->foreground)
+		return 0;
+
+	mutex_lock(&priv->mutex);
+
+	reg = readl(flow->base + DP_COM_CONF);
+	reg |= DP_COM_CONF_FG_EN;
+	writel(reg, flow->base + DP_COM_CONF);
+
+	ipu_srm_dp_sync_update(priv->ipu);
 
 	mutex_unlock(&priv->mutex);
 
@@ -247,25 +259,35 @@ void ipu_dp_disable_channel(struct ipu_dp *dp)
 {
 	struct ipu_flow *flow = to_flow(dp);
 	struct ipu_dp_priv *priv = flow->priv;
+	u32 reg, csc;
+
+	if (!dp->foreground)
+		return;
 
 	mutex_lock(&priv->mutex);
 
-	priv->use_count--;
+	reg = readl(flow->base + DP_COM_CONF);
+	csc = reg & DP_COM_CONF_CSC_DEF_MASK;
+	if (csc == DP_COM_CONF_CSC_DEF_FG)
+		reg &= ~DP_COM_CONF_CSC_DEF_MASK;
 
-	if (dp->foreground) {
-		u32 reg, csc;
+	reg &= ~DP_COM_CONF_FG_EN;
+	writel(reg, flow->base + DP_COM_CONF);
 
-		reg = readl(flow->base + DP_COM_CONF);
-		csc = reg & DP_COM_CONF_CSC_DEF_MASK;
-		if (csc == DP_COM_CONF_CSC_DEF_FG)
-			reg &= ~DP_COM_CONF_CSC_DEF_MASK;
+	writel(0, flow->base + DP_FG_POS);
+	ipu_srm_dp_sync_update(priv->ipu);
 
-		reg &= ~DP_COM_CONF_FG_EN;
-		writel(reg, flow->base + DP_COM_CONF);
+	mutex_unlock(&priv->mutex);
+}
+EXPORT_SYMBOL_GPL(ipu_dp_disable_channel);
 
-		writel(0, flow->base + DP_FG_POS);
-		ipu_srm_dp_sync_update(priv->ipu);
-	}
+void ipu_dp_disable(struct ipu_soc *ipu)
+{
+	struct ipu_dp_priv *priv = ipu->dp_priv;
+
+	mutex_lock(&priv->mutex);
+
+	priv->use_count--;
 
 	if (!priv->use_count)
 		ipu_module_disable(priv->ipu, IPU_CONF_DP_EN);
@@ -275,7 +297,7 @@ void ipu_dp_disable_channel(struct ipu_dp *dp)
 
 	mutex_unlock(&priv->mutex);
 }
-EXPORT_SYMBOL_GPL(ipu_dp_disable_channel);
+EXPORT_SYMBOL_GPL(ipu_dp_disable);
 
 struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow)
 {
diff --git a/drivers/staging/imx-drm/ipuv3-plane.c b/drivers/staging/imx-drm/ipuv3-plane.c
index 27a8d735dae0..5697e59ddf1d 100644
--- a/drivers/staging/imx-drm/ipuv3-plane.c
+++ b/drivers/staging/imx-drm/ipuv3-plane.c
@@ -239,6 +239,8 @@ int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
 
 void ipu_plane_enable(struct ipu_plane *ipu_plane)
 {
+	if (ipu_plane->dp)
+		ipu_dp_enable(ipu_plane->ipu);
 	ipu_dmfc_enable_channel(ipu_plane->dmfc);
 	ipu_idmac_enable_channel(ipu_plane->ipu_ch);
 	if (ipu_plane->dp)
@@ -257,6 +259,8 @@ void ipu_plane_disable(struct ipu_plane *ipu_plane)
 		ipu_dp_disable_channel(ipu_plane->dp);
 	ipu_idmac_disable_channel(ipu_plane->ipu_ch);
 	ipu_dmfc_disable_channel(ipu_plane->dmfc);
+	if (ipu_plane->dp)
+		ipu_dp_disable(ipu_plane->ipu);
 }
 
 static void ipu_plane_dpms(struct ipu_plane *ipu_plane, int mode)
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 154/222] imx-drm: imx-dp: when disabling the DP foreground channel, wait until the DP background channel is finished before disabling the IDMAC channel
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (152 preceding siblings ...)
  2014-04-25 11:44 ` [PATCH 153/222] imx-drm: ipu-dp: split disabling the DP foreground channel from disabling the DP module Russell King
@ 2014-04-25 11:44 ` Russell King
  2014-04-25 11:44 ` [PATCH 155/222] imx-drm: ipuv3-crtc: change display enable/disable order Russell King
                   ` (68 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:44 UTC (permalink / raw)
  To: linux-arm-kernel

From: Philipp Zabel <p.zabel@pengutronix.de>
To: linux-arm-kernel at lists.infradead.org

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/ipu-v3/ipu-dp.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dp.c b/drivers/staging/imx-drm/ipu-v3/ipu-dp.c
index 6980fa125517..d90f82a87d19 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-dp.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-dp.c
@@ -277,6 +277,9 @@ void ipu_dp_disable_channel(struct ipu_dp *dp)
 	writel(0, flow->base + DP_FG_POS);
 	ipu_srm_dp_sync_update(priv->ipu);
 
+	if (ipu_idmac_channel_busy(priv->ipu, IPUV3_CHANNEL_MEM_BG_SYNC))
+		ipu_wait_interrupt(priv->ipu, IPU_IRQ_DP_SF_END, 50);
+
 	mutex_unlock(&priv->mutex);
 }
 EXPORT_SYMBOL_GPL(ipu_dp_disable_channel);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 155/222] imx-drm: ipuv3-crtc: change display enable/disable order
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (153 preceding siblings ...)
  2014-04-25 11:44 ` [PATCH 154/222] imx-drm: imx-dp: when disabling the DP foreground channel, wait until the DP background channel is finished before disabling the IDMAC channel Russell King
@ 2014-04-25 11:44 ` Russell King
  2014-04-25 11:44 ` [PATCH 156/222] imx-drm: ipu-dc: disable DC module when not in use Russell King
                   ` (67 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:44 UTC (permalink / raw)
  To: linux-arm-kernel

From: Philipp Zabel <p.zabel@pengutronix.de>
To: linux-arm-kernel at lists.infradead.org

Now that ipu_dc_disable_channel correctly waits for the channel to finish,
we can reorder the enable/disable order to first stop the DC and DI and
only then disable the IDMAC. Enabling is done the other way around: IDMAC
first, then DC, then DI.

This avoids an issue where sometimes the channel would not correctly start,
leading to non-working LVDS displays.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/ipuv3-crtc.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
index f2c9cd040043..ab667a191a36 100644
--- a/drivers/staging/imx-drm/ipuv3-crtc.c
+++ b/drivers/staging/imx-drm/ipuv3-crtc.c
@@ -63,9 +63,11 @@ static void ipu_fb_enable(struct ipu_crtc *ipu_crtc)
 	if (ipu_crtc->enabled)
 		return;
 
-	ipu_di_enable(ipu_crtc->di);
-	ipu_dc_enable_channel(ipu_crtc->dc);
+	/* TODO: Enable DC module here, right now it is never disabled */
 	ipu_plane_enable(ipu_crtc->plane[0]);
+	/* Start DC channel and DI after IDMAC */
+	ipu_dc_enable_channel(ipu_crtc->dc);
+	ipu_di_enable(ipu_crtc->di);
 
 	ipu_crtc->enabled = 1;
 }
@@ -75,9 +77,11 @@ static void ipu_fb_disable(struct ipu_crtc *ipu_crtc)
 	if (!ipu_crtc->enabled)
 		return;
 
-	ipu_plane_disable(ipu_crtc->plane[0]);
+	/* Stop DC channel and DI before IDMAC */
 	ipu_dc_disable_channel(ipu_crtc->dc);
 	ipu_di_disable(ipu_crtc->di);
+	ipu_plane_disable(ipu_crtc->plane[0]);
+	/* TODO: Disable DC module here */
 
 	ipu_crtc->enabled = 0;
 }
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 156/222] imx-drm: ipu-dc: disable DC module when not in use
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (154 preceding siblings ...)
  2014-04-25 11:44 ` [PATCH 155/222] imx-drm: ipuv3-crtc: change display enable/disable order Russell King
@ 2014-04-25 11:44 ` Russell King
  2014-04-25 11:45 ` [PATCH 157/222] imx-drm: imx-hdmi: fix hdmi hotplug detection initial state Russell King
                   ` (66 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:44 UTC (permalink / raw)
  To: linux-arm-kernel

From: Philipp Zabel <p.zabel@pengutronix.de>
To: linux-arm-kernel at lists.infradead.org

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h |  2 ++
 drivers/staging/imx-drm/ipu-v3/ipu-dc.c     | 14 ++++++++++++--
 drivers/staging/imx-drm/ipuv3-crtc.c        |  8 ++++++--
 3 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
index 8678ad18a3ef..c2c6fab05eaa 100644
--- a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
+++ b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
@@ -115,8 +115,10 @@ struct ipu_dc *ipu_dc_get(struct ipu_soc *ipu, int channel);
 void ipu_dc_put(struct ipu_dc *dc);
 int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced,
 		u32 pixel_fmt, u32 width);
+void ipu_dc_enable(struct ipu_soc *ipu);
 void ipu_dc_enable_channel(struct ipu_dc *dc);
 void ipu_dc_disable_channel(struct ipu_dc *dc);
+void ipu_dc_disable(struct ipu_soc *ipu);
 
 /*
  * IPU Display Interface (di) functions
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
index 7f5734aef9f7..97cf6fad2427 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
@@ -227,12 +227,16 @@ int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced,
 	writel(0x0, dc->base + DC_WR_CH_ADDR);
 	writel(width, priv->dc_reg + DC_DISP_CONF2(dc->di));
 
-	ipu_module_enable(priv->ipu, IPU_CONF_DC_EN);
-
 	return 0;
 }
 EXPORT_SYMBOL_GPL(ipu_dc_init_sync);
 
+void ipu_dc_enable(struct ipu_soc *ipu)
+{
+	ipu_module_enable(ipu, IPU_CONF_DC_EN);
+}
+EXPORT_SYMBOL_GPL(ipu_dc_enable);
+
 void ipu_dc_enable_channel(struct ipu_dc *dc)
 {
 	int di;
@@ -289,6 +293,12 @@ void ipu_dc_disable_channel(struct ipu_dc *dc)
 }
 EXPORT_SYMBOL_GPL(ipu_dc_disable_channel);
 
+void ipu_dc_disable(struct ipu_soc *ipu)
+{
+	ipu_module_disable(ipu, IPU_CONF_DC_EN);
+}
+EXPORT_SYMBOL_GPL(ipu_dc_disable);
+
 static void ipu_dc_map_config(struct ipu_dc_priv *priv, enum ipu_dc_map map,
 		int byte_num, int offset, int mask)
 {
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
index ab667a191a36..47bec5e17358 100644
--- a/drivers/staging/imx-drm/ipuv3-crtc.c
+++ b/drivers/staging/imx-drm/ipuv3-crtc.c
@@ -60,10 +60,12 @@ struct ipu_crtc {
 
 static void ipu_fb_enable(struct ipu_crtc *ipu_crtc)
 {
+	struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
+
 	if (ipu_crtc->enabled)
 		return;
 
-	/* TODO: Enable DC module here, right now it is never disabled */
+	ipu_dc_enable(ipu);
 	ipu_plane_enable(ipu_crtc->plane[0]);
 	/* Start DC channel and DI after IDMAC */
 	ipu_dc_enable_channel(ipu_crtc->dc);
@@ -74,6 +76,8 @@ static void ipu_fb_enable(struct ipu_crtc *ipu_crtc)
 
 static void ipu_fb_disable(struct ipu_crtc *ipu_crtc)
 {
+	struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
+
 	if (!ipu_crtc->enabled)
 		return;
 
@@ -81,7 +85,7 @@ static void ipu_fb_disable(struct ipu_crtc *ipu_crtc)
 	ipu_dc_disable_channel(ipu_crtc->dc);
 	ipu_di_disable(ipu_crtc->di);
 	ipu_plane_disable(ipu_crtc->plane[0]);
-	/* TODO: Disable DC module here */
+	ipu_dc_disable(ipu);
 
 	ipu_crtc->enabled = 0;
 }
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 157/222] imx-drm: imx-hdmi: fix hdmi hotplug detection initial state
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (155 preceding siblings ...)
  2014-04-25 11:44 ` [PATCH 156/222] imx-drm: ipu-dc: disable DC module when not in use Russell King
@ 2014-04-25 11:45 ` Russell King
  2014-04-25 11:46 ` [PATCH 158/222] dw-hdmi-audio: add audio driver Russell King
                   ` (65 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:45 UTC (permalink / raw)
  To: linux-arm-kernel

The initial state at boot is assumed to be disconnected, and we hope
to receive an interrupt to update the status.  Let's be more explicit
about the current state - reading the PHY status register tells us
the current level of the hotplug signal, which we can report back in
the _detect() method.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-hdmi.c | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index d47dedd2cdb4..6f5efcc89880 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -120,8 +120,6 @@ struct imx_hdmi {
 	struct clk *isfr_clk;
 	struct clk *iahb_clk;
 
-	enum drm_connector_status connector_status;
-
 	struct hdmi_data_info hdmi_data;
 	int vic;
 
@@ -1382,7 +1380,9 @@ static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector
 {
 	struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
 					     connector);
-	return hdmi->connector_status;
+
+	return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
+		connector_status_connected : connector_status_disconnected;
 }
 
 static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
@@ -1524,7 +1524,6 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
 
 			hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0);
 
-			hdmi->connector_status = connector_status_connected;
 			imx_hdmi_poweron(hdmi);
 		} else {
 			dev_dbg(hdmi->dev, "EVENT=plugout\n");
@@ -1532,7 +1531,6 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
 			hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD,
 				HDMI_PHY_POL0);
 
-			hdmi->connector_status = connector_status_disconnected;
 			imx_hdmi_poweroff(hdmi);
 		}
 		drm_helper_hpd_irq_event(hdmi->connector.dev);
@@ -1606,7 +1604,6 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 		return -ENOMEM;
 
 	hdmi->dev = dev;
-	hdmi->connector_status = connector_status_disconnected;
 	hdmi->sample_rate = 48000;
 	hdmi->ratio = 100;
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 158/222] dw-hdmi-audio: add audio driver
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (156 preceding siblings ...)
  2014-04-25 11:45 ` [PATCH 157/222] imx-drm: imx-hdmi: fix hdmi hotplug detection initial state Russell King
@ 2014-04-25 11:46 ` Russell King
  2014-04-25 11:46 ` [PATCH 159/222] dw-hdmi-audio: better hardware position tracking Russell King
                   ` (64 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:46 UTC (permalink / raw)
  To: linux-arm-kernel

Add ALSA based HDMI audio driver for imx-hdmi.  The imx-hdmi is a
Synopsis DesignWare module, so let's name it after that.  The only
buffer format supported is its own special IEC958 based format, which
is not compatible with any ALSA format.  To avoid doing too much data
manipulation within the driver, we support only ALSAs IEC958 LE, and
24-bit PCM formats for 2 to 6 channels.

This allows us to modify the buffer in place as each period is passed
for DMA without needing a separate buffer.

A more desirable solution would be to have this conversion in userspace,
but ALSA does not appear to allow such transformations outside of
libasound itself.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/Kconfig         |   8 +
 drivers/staging/imx-drm/Makefile        |   1 +
 drivers/staging/imx-drm/dw-hdmi-audio.c | 547 ++++++++++++++++++++++++++++++++
 drivers/staging/imx-drm/dw-hdmi-audio.h |  14 +
 drivers/staging/imx-drm/imx-hdmi.c      |  29 ++
 5 files changed, 599 insertions(+)
 create mode 100644 drivers/staging/imx-drm/dw-hdmi-audio.c
 create mode 100644 drivers/staging/imx-drm/dw-hdmi-audio.h

diff --git a/drivers/staging/imx-drm/Kconfig b/drivers/staging/imx-drm/Kconfig
index 92fb52cbd3a2..66ed3e5f132a 100644
--- a/drivers/staging/imx-drm/Kconfig
+++ b/drivers/staging/imx-drm/Kconfig
@@ -61,3 +61,11 @@ config DRM_IMX_HDMI
 	depends on DRM_IMX
 	help
 	  Choose this if you want to use HDMI on i.MX6.
+
+config DRM_DW_HDMI_AUDIO
+	tristate "Synopsis Designware Audio interface"
+	depends on DRM_IMX_HDMI != n
+	help
+	  Support the Audio interface which is part of the Synopsis
+	  Designware HDMI block.  This is used in conjunction with
+	  the i.MX HDMI driver.
diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
index 129e3a3f59f1..34c8b9990a66 100644
--- a/drivers/staging/imx-drm/Makefile
+++ b/drivers/staging/imx-drm/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += ipu-v3/
 imx-ipuv3-crtc-objs  := ipuv3-crtc.o ipuv3-plane.o
 obj-$(CONFIG_DRM_IMX_IPUV3)	+= imx-ipuv3-crtc.o
 obj-$(CONFIG_DRM_IMX_HDMI) += imx-hdmi.o
+obj-$(CONFIG_DRM_DW_HDMI_AUDIO) += dw-hdmi-audio.o
diff --git a/drivers/staging/imx-drm/dw-hdmi-audio.c b/drivers/staging/imx-drm/dw-hdmi-audio.c
new file mode 100644
index 000000000000..e7d41249c817
--- /dev/null
+++ b/drivers/staging/imx-drm/dw-hdmi-audio.c
@@ -0,0 +1,547 @@
+/*
+ * DesignWare HDMI audio driver
+ *
+ * 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.
+ *
+ * Written and tested against the (alleged) DW HDMI Tx found in iMX6S.
+ */
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <sound/asoundef.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+
+#include "dw-hdmi-audio.h"
+
+#define DRIVER_NAME "dw-hdmi-audio"
+
+/* Provide some bits rather than bit offsets */
+enum {
+	HDMI_AHB_DMA_CONF0_SW_FIFO_RST = BIT(7),
+	HDMI_AHB_DMA_CONF0_EN_HLOCK = BIT(3),
+	HDMI_AHB_DMA_START_START = BIT(0),
+	HDMI_AHB_DMA_STOP_STOP = BIT(0),
+	HDMI_IH_MUTE_AHBDMAAUD_STAT0_ERROR = BIT(5),
+	HDMI_IH_MUTE_AHBDMAAUD_STAT0_LOST = BIT(4),
+	HDMI_IH_MUTE_AHBDMAAUD_STAT0_RETRY = BIT(3),
+	HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE = BIT(2),
+	HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL = BIT(1),
+	HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY = BIT(0),
+	HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL =
+		HDMI_IH_MUTE_AHBDMAAUD_STAT0_ERROR |
+		HDMI_IH_MUTE_AHBDMAAUD_STAT0_LOST |
+		HDMI_IH_MUTE_AHBDMAAUD_STAT0_RETRY |
+		HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE |
+		HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL |
+		HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY,
+	HDMI_IH_AHBDMAAUD_STAT0_ERROR = BIT(5),
+	HDMI_IH_AHBDMAAUD_STAT0_LOST = BIT(4),
+	HDMI_IH_AHBDMAAUD_STAT0_RETRY = BIT(3),
+	HDMI_IH_AHBDMAAUD_STAT0_DONE = BIT(2),
+	HDMI_IH_AHBDMAAUD_STAT0_BUFFFULL = BIT(1),
+	HDMI_IH_AHBDMAAUD_STAT0_BUFFEMPTY = BIT(0),
+	HDMI_IH_AHBDMAAUD_STAT0_ALL =
+		HDMI_IH_AHBDMAAUD_STAT0_ERROR |
+		HDMI_IH_AHBDMAAUD_STAT0_LOST |
+		HDMI_IH_AHBDMAAUD_STAT0_RETRY |
+		HDMI_IH_AHBDMAAUD_STAT0_DONE |
+		HDMI_IH_AHBDMAAUD_STAT0_BUFFFULL |
+		HDMI_IH_AHBDMAAUD_STAT0_BUFFEMPTY,
+	HDMI_AHB_DMA_CONF0_INCR16 = 2 << 1,
+	HDMI_AHB_DMA_CONF0_INCR8 = 1 << 1,
+	HDMI_AHB_DMA_CONF0_INCR4 = 0,
+	HDMI_AHB_DMA_CONF0_BURST_MODE = BIT(0),
+	HDMI_AHB_DMA_MASK_DONE = BIT(7),
+	HDMI_REVISION_ID = 0x0001,
+	HDMI_IH_AHBDMAAUD_STAT0 = 0x0109,
+	HDMI_IH_MUTE_AHBDMAAUD_STAT0 = 0x0189,
+	HDMI_AHB_DMA_CONF0 = 0x3600,
+	HDMI_AHB_DMA_START = 0x3601,
+	HDMI_AHB_DMA_STOP = 0x3602,
+	HDMI_AHB_DMA_THRSLD = 0x3603,
+	HDMI_AHB_DMA_STRADDR0 = 0x3604,
+	HDMI_AHB_DMA_STPADDR0 = 0x3608,
+	HDMI_AHB_DMA_MASK = 0x3614,
+	HDMI_AHB_DMA_POL = 0x3615,
+	HDMI_AHB_DMA_CONF1 = 0x3616,
+	HDMI_AHB_DMA_BUFFPOL = 0x361a,
+};
+
+struct snd_dw_hdmi {
+	struct snd_card *card;
+	struct snd_pcm *pcm;
+	struct dw_hdmi_audio_data data;
+	struct snd_pcm_substream *substream;
+	void (*reformat)(struct snd_dw_hdmi *, size_t, size_t);
+	void *buf_src;
+	void *buf_dst;
+	dma_addr_t buf_addr;
+	unsigned buf_offset;
+	unsigned buf_period;
+	unsigned buf_size;
+	unsigned channels;
+	uint8_t revision;
+	uint8_t iec_offset;
+	uint8_t cs[192][8];
+};
+
+static void dw_hdmi_writel(unsigned long val, void __iomem *ptr)
+{
+	writeb_relaxed(val, ptr);
+	writeb_relaxed(val >> 8, ptr + 1);
+	writeb_relaxed(val >> 16, ptr + 2);
+	writeb_relaxed(val >> 24, ptr + 3);
+}
+
+/*
+ * Convert to hardware format: The userspace buffer contains IEC958 samples,
+ * with the PCUV bits in bits 31..28 and audio samples in bits 27..4.  We
+ * need these to be in bits 27..24, with the IEC B bit in bit 28, and audio
+ * samples in 23..0.
+ *
+ * Default preamble in bits 3..0: 8 = block start, 4 = even 2 = odd
+ *
+ * Ideally, we could do with having the data properly formatted in userspace.
+ */
+static void dw_hdmi_reformat_iec958(struct snd_dw_hdmi *dw,
+	size_t offset, size_t bytes)
+{
+	uint32_t *src = dw->buf_src + offset;
+	uint32_t *dst = dw->buf_dst + offset;
+	uint32_t *end = dw->buf_src + offset + bytes;
+
+	do {
+		uint32_t b, sample = *src++;
+
+		b = (sample & 8) << (28 - 3);
+
+		sample >>= 4;
+
+		*dst++ = sample | b;
+	} while (src < end);
+}
+
+static uint32_t parity(uint32_t sample)
+{
+	sample ^= sample >> 16;
+	sample ^= sample >> 8;
+	sample ^= sample >> 4;
+	sample ^= sample >> 2;
+	sample ^= sample >> 1;
+	return (sample & 1) << 27;
+}
+
+static void dw_hdmi_reformat_s24(struct snd_dw_hdmi *dw,
+	size_t offset, size_t bytes)
+{
+	uint32_t *src = dw->buf_src + offset;
+	uint32_t *dst = dw->buf_dst + offset;
+	uint32_t *end = dw->buf_src + offset + bytes;
+
+	do {
+		unsigned i;
+		uint8_t *cs;
+
+		cs = dw->cs[dw->iec_offset++];
+		if (dw->iec_offset >= 192)
+			dw->iec_offset = 0;
+
+		i = dw->channels;
+		do {
+			uint32_t sample = *src++;
+
+			sample &= ~0xff000000;
+			sample |= *cs++ << 24;
+			sample |= parity(sample & ~0xf8000000);
+
+			*dst++ = sample;
+		} while (--i);
+	} while (src < end);
+}
+
+static void dw_hdmi_create_cs(struct snd_dw_hdmi *dw,
+	struct snd_pcm_runtime *runtime)
+{
+	uint8_t cs[4];
+	unsigned ch, i, j;
+
+	cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE;
+	cs[1] = IEC958_AES1_CON_GENERAL;
+	cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC;
+	cs[3] = IEC958_AES3_CON_CLOCK_1000PPM;
+
+	switch (runtime->rate) {
+	case 32000:
+		cs[3] |= IEC958_AES3_CON_FS_32000;
+		break;
+	case 44100:
+		cs[3] |= IEC958_AES3_CON_FS_44100;
+		break;
+	case 48000:
+		cs[3] |= IEC958_AES3_CON_FS_48000;
+		break;
+	case 88200:
+		cs[3] |= IEC958_AES3_CON_FS_88200;
+		break;
+	case 96000:
+		cs[3] |= IEC958_AES3_CON_FS_96000;
+		break;
+	case 176400:
+		cs[3] |= IEC958_AES3_CON_FS_176400;
+		break;
+	case 192000:
+		cs[3] |= IEC958_AES3_CON_FS_192000;
+		break;
+	}
+
+	memset(dw->cs, 0, sizeof(dw->cs));
+
+	for (ch = 0; ch < 8; ch++) {
+		cs[2] &= ~IEC958_AES2_CON_CHANNEL;
+		cs[2] |= (ch + 1) << 4;
+
+		for (i = 0; i < ARRAY_SIZE(cs); i++) {
+			unsigned c = cs[i];
+
+			for (j = 0; j < 8; j++, c >>= 1)
+				dw->cs[i * 8 + j][ch] = (c & 1) << 2;
+		}
+	}
+	dw->cs[0][0] |= BIT(4);
+}
+
+static void dw_hdmi_start_dma(struct snd_dw_hdmi *dw)
+{
+	void __iomem *base = dw->data.base;
+	unsigned offset = dw->buf_offset;
+	unsigned period = dw->buf_period;
+	u32 start, stop;
+
+	dw->reformat(dw, offset, period);
+
+	/* Clear all irqs before enabling irqs and starting DMA */
+	writeb_relaxed(HDMI_IH_AHBDMAAUD_STAT0_ALL,
+		       base + HDMI_IH_AHBDMAAUD_STAT0);
+
+	start = dw->buf_addr + offset;
+	stop = start + period - 1;
+
+	/* Setup the hardware start/stop addresses */
+	dw_hdmi_writel(start, base + HDMI_AHB_DMA_STRADDR0);
+	dw_hdmi_writel(stop, base + HDMI_AHB_DMA_STPADDR0);
+
+	writeb_relaxed((u8)~HDMI_AHB_DMA_MASK_DONE, base + HDMI_AHB_DMA_MASK);
+	writeb(HDMI_AHB_DMA_START_START, base + HDMI_AHB_DMA_START);
+}
+
+static void dw_hdmi_stop_dma(struct snd_dw_hdmi *dw)
+{
+	dw->substream = NULL;
+
+	/* Disable interrupts before disabling DMA */
+	writeb_relaxed(~0, dw->data.base + HDMI_AHB_DMA_MASK);
+	writeb_relaxed(HDMI_AHB_DMA_STOP_STOP, dw->data.base + HDMI_AHB_DMA_STOP);
+}
+
+static irqreturn_t snd_dw_hdmi_irq(int irq, void *data)
+{
+	struct snd_dw_hdmi *dw = data;
+	struct snd_pcm_substream *substream;
+	unsigned stat;
+
+	stat = readb_relaxed(dw->data.base + HDMI_IH_AHBDMAAUD_STAT0);
+	if (!stat)
+		return IRQ_NONE;
+
+	writeb_relaxed(stat, dw->data.base + HDMI_IH_AHBDMAAUD_STAT0);
+
+	substream = dw->substream;
+	if (stat & HDMI_IH_AHBDMAAUD_STAT0_DONE && substream) {
+		dw->buf_offset += dw->buf_period;
+		if (dw->buf_offset >= dw->buf_size)
+			dw->buf_offset = 0;
+
+		snd_pcm_period_elapsed(substream);
+		if (dw->substream)
+			dw_hdmi_start_dma(dw);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static struct snd_pcm_hardware dw_hdmi_hw = {
+	.info = SNDRV_PCM_INFO_INTERLEAVED |
+		SNDRV_PCM_INFO_BLOCK_TRANSFER |
+		SNDRV_PCM_INFO_MMAP |
+		SNDRV_PCM_INFO_MMAP_VALID,
+	.formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE |
+		   SNDRV_PCM_FMTBIT_S24_LE,
+	.rates = SNDRV_PCM_RATE_32000 |
+		 SNDRV_PCM_RATE_44100 |
+		 SNDRV_PCM_RATE_48000 |
+		 SNDRV_PCM_RATE_88200 |
+		 SNDRV_PCM_RATE_96000 |
+		 SNDRV_PCM_RATE_176400 |
+		 SNDRV_PCM_RATE_192000,
+	.channels_min = 2,
+	.channels_max = 8,
+	.buffer_bytes_max = 64 * 1024,
+	.period_bytes_min = 256,
+	.period_bytes_max = 8192,	/* ERR004323: must limit to 8k */
+	.periods_min = 2,
+	.periods_max = 16,
+	.fifo_size = 0,
+};
+
+static int dw_hdmi_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_dw_hdmi *dw = substream->private_data;
+	void __iomem *base = dw->data.base;
+	int ret;
+
+	/* Clear FIFO */
+	writeb_relaxed(HDMI_AHB_DMA_CONF0_SW_FIFO_RST,
+		       base + HDMI_AHB_DMA_CONF0);
+
+	/* Configure interrupt polarities */
+	writeb_relaxed(~0, base + HDMI_AHB_DMA_POL);
+	writeb_relaxed(~0, base + HDMI_AHB_DMA_BUFFPOL);
+
+	/* Keep interrupts masked, and clear any pending */
+	writeb_relaxed(~0, base + HDMI_AHB_DMA_MASK);
+	writeb_relaxed(~0, base + HDMI_IH_AHBDMAAUD_STAT0);
+
+	ret = request_irq(dw->data.irq, snd_dw_hdmi_irq, IRQF_SHARED,
+			  "dw-hdmi-audio", dw);
+	if (ret)
+		return ret;
+
+	/* Un-mute done interrupt */
+	writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL &
+		       ~HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE,
+		       base + HDMI_IH_MUTE_AHBDMAAUD_STAT0);
+
+	runtime->hw = dw_hdmi_hw;
+	snd_pcm_limit_hw_rates(runtime);
+
+	return 0;
+}
+
+static int dw_hdmi_close(struct snd_pcm_substream *substream)
+{
+	struct snd_dw_hdmi *dw = substream->private_data;
+
+	/* Mute all interrupts */
+	writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL,
+		       dw->data.base + HDMI_IH_MUTE_AHBDMAAUD_STAT0);
+
+	free_irq(dw->data.irq, dw);
+
+	return 0;
+}
+
+static int dw_hdmi_hw_free(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static int dw_hdmi_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	return snd_pcm_lib_alloc_vmalloc_buffer(substream,
+						params_buffer_bytes(params));
+}
+
+static int dw_hdmi_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_dw_hdmi *dw = substream->private_data;
+	uint8_t threshold, conf0, conf1;
+
+	/* Setup as per 3.0.5 FSL 4.1.0 BSP */
+	switch (dw->revision) {
+	case 0x0a:
+		conf0 = HDMI_AHB_DMA_CONF0_BURST_MODE |
+			HDMI_AHB_DMA_CONF0_INCR4;
+		if (runtime->channels == 2)
+			threshold = 126;
+		else
+			threshold = 124;
+		break;
+	case 0x1a:
+		conf0 = HDMI_AHB_DMA_CONF0_BURST_MODE |
+			HDMI_AHB_DMA_CONF0_INCR8;
+		threshold = 128;
+		break;
+	default:
+		/* NOTREACHED */
+		return -EINVAL;
+	}
+
+	dw->data.set_sample_rate(dw->data.hdmi, runtime->rate);
+
+	/* Minimum number of bytes in the fifo. */
+	runtime->hw.fifo_size = threshold * 32;
+
+	conf0 |= HDMI_AHB_DMA_CONF0_EN_HLOCK;
+	conf1 = (1 << runtime->channels) - 1;
+
+	writeb_relaxed(threshold, dw->data.base + HDMI_AHB_DMA_THRSLD);
+	writeb_relaxed(conf0, dw->data.base + HDMI_AHB_DMA_CONF0);
+	writeb_relaxed(conf1, dw->data.base + HDMI_AHB_DMA_CONF1);
+
+	switch (runtime->format) {
+	case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
+		dw->reformat = dw_hdmi_reformat_iec958;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		dw_hdmi_create_cs(dw, runtime);
+		dw->reformat = dw_hdmi_reformat_s24;
+		break;
+	}
+	dw->iec_offset = 0;
+	dw->channels = runtime->channels;
+	dw->buf_src  = runtime->dma_area;
+	dw->buf_dst  = substream->dma_buffer.area;
+	dw->buf_addr = substream->dma_buffer.addr;
+	dw->buf_period = snd_pcm_lib_period_bytes(substream);
+	dw->buf_size = snd_pcm_lib_buffer_bytes(substream);
+
+	return 0;
+}
+
+static int dw_hdmi_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_dw_hdmi *dw = substream->private_data;
+	int ret = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		dw->buf_offset = 0;
+		dw->substream = substream;
+		dw_hdmi_start_dma(dw);
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+		dw_hdmi_stop_dma(dw);
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static snd_pcm_uframes_t dw_hdmi_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_dw_hdmi *dw = substream->private_data;
+
+	return bytes_to_frames(runtime, dw->buf_offset);
+}
+
+static struct snd_pcm_ops snd_dw_hdmi_ops = {
+	.open = dw_hdmi_open,
+	.close = dw_hdmi_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = dw_hdmi_hw_params,
+	.hw_free = dw_hdmi_hw_free,
+	.prepare = dw_hdmi_prepare,
+	.trigger = dw_hdmi_trigger,
+	.pointer = dw_hdmi_pointer,
+	.page = snd_pcm_lib_get_vmalloc_page,
+};
+
+static int snd_dw_hdmi_probe(struct platform_device *pdev)
+{
+	const struct dw_hdmi_audio_data *data = pdev->dev.platform_data;
+	struct device *dev = pdev->dev.parent;
+	struct snd_dw_hdmi *dw;
+	struct snd_card *card;
+	struct snd_pcm *pcm;
+	unsigned revision;
+	int ret;
+
+	writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL,
+		       data->base + HDMI_IH_MUTE_AHBDMAAUD_STAT0);
+	revision = readb_relaxed(data->base + HDMI_REVISION_ID);
+	if (revision != 0x0a && revision != 0x1a) {
+		dev_err(dev, "dw-hdmi-audio: unknown revision 0x%02x\n",
+			revision);
+		return -ENXIO;
+	}
+
+	ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+			      THIS_MODULE, sizeof(struct snd_dw_hdmi), &card);
+	if (ret < 0)
+		return ret;
+
+	snd_card_set_dev(card, dev);
+
+	strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver));
+	strlcpy(card->shortname, "DW-HDMI", sizeof(card->shortname));
+	snprintf(card->longname, sizeof(card->longname),
+		 "%s rev 0x%02x, irq %d", card->shortname, revision,
+		 data->irq);
+
+	dw = card->private_data;
+	dw->card = card;
+	dw->data = *data;
+	dw->revision = revision;
+
+	ret = snd_pcm_new(card, "DW HDMI", 0, 1, 0, &pcm);
+	if (ret < 0)
+		goto err;
+
+	dw->pcm = pcm;
+	pcm->private_data = dw;
+	strlcpy(pcm->name, DRIVER_NAME, sizeof(pcm->name));
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_dw_hdmi_ops);
+
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+			dev, 64 * 1024, 64 * 1024);
+
+	ret = snd_card_register(card);
+	if (ret < 0)
+		goto err;
+
+	platform_set_drvdata(pdev, dw);
+
+	return 0;
+
+err:
+	snd_card_free(card);
+	return ret;
+}
+
+static int snd_dw_hdmi_remove(struct platform_device *pdev)
+{
+	struct snd_dw_hdmi *dw = platform_get_drvdata(pdev);
+
+	snd_card_free(dw->card);
+
+	return 0;
+}
+
+static struct platform_driver snd_dw_hdmi_driver = {
+	.probe	= snd_dw_hdmi_probe,
+	.remove	= snd_dw_hdmi_remove,
+	.driver	= {
+		.name = "dw-hdmi-audio",
+		.owner = THIS_MODULE,
+	},
+};
+
+module_platform_driver(snd_dw_hdmi_driver);
+
+MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/imx-drm/dw-hdmi-audio.h b/drivers/staging/imx-drm/dw-hdmi-audio.h
new file mode 100644
index 000000000000..f01979d49efd
--- /dev/null
+++ b/drivers/staging/imx-drm/dw-hdmi-audio.h
@@ -0,0 +1,14 @@
+#ifndef DW_HDMI_AUDIO_H
+#define DW_HDMI_AUDIO_H
+
+struct imx_hdmi;
+
+struct dw_hdmi_audio_data {
+	phys_addr_t phys;
+	void __iomem *base;
+	int irq;
+	struct imx_hdmi *hdmi;
+	void (*set_sample_rate)(struct imx_hdmi *, unsigned);
+};
+
+#endif
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 6f5efcc89880..af4cba51e255 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -28,6 +28,7 @@
 #include <drm/drm_edid.h>
 #include <drm/drm_encoder_slave.h>
 
+#include "dw-hdmi-audio.h"
 #include "ipu-v3/imx-ipu-v3.h"
 #include "imx-hdmi.h"
 #include "imx-drm.h"
@@ -115,6 +116,7 @@ struct imx_hdmi {
 	struct drm_connector connector;
 	struct drm_encoder encoder;
 
+	struct platform_device *audio;
 	enum imx_hdmi_devtype dev_type;
 	struct device *dev;
 	struct clk *isfr_clk;
@@ -360,6 +362,12 @@ static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi)
 	hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
 }
 
+static void imx_hdmi_set_sample_rate(struct imx_hdmi *hdmi, unsigned rate)
+{
+	hdmi->sample_rate = rate;
+	hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
+}
+
 /*
  * this submodule is responsible for the video data synchronization.
  * for example, for RGB 4:4:4 input, the data map is defined as
@@ -1590,11 +1598,13 @@ MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids);
 static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 {
 	struct platform_device *pdev = to_platform_device(dev);
+	struct platform_device_info pdevinfo;
 	const struct of_device_id *of_id =
 				of_match_device(imx_hdmi_dt_ids, dev);
 	struct drm_device *drm = data;
 	struct device_node *np = dev->of_node;
 	struct device_node *ddc_node;
+	struct dw_hdmi_audio_data audio;
 	struct imx_hdmi *hdmi;
 	struct resource *iores;
 	int ret, irq;
@@ -1708,6 +1718,22 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 	/* Unmute interrupts */
 	hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
 
+	memset(&pdevinfo, 0, sizeof(pdevinfo));
+	pdevinfo.parent = dev;
+	pdevinfo.id = PLATFORM_DEVID_AUTO;
+
+	audio.phys = iores->start;
+	audio.base = hdmi->regs;
+	audio.irq = irq;
+	audio.hdmi = hdmi;
+	audio.set_sample_rate = imx_hdmi_set_sample_rate;
+
+	pdevinfo.name = "dw-hdmi-audio";
+	pdevinfo.data = &audio;
+	pdevinfo.size_data = sizeof(audio);
+	pdevinfo.dma_mask = DMA_BIT_MASK(32);
+	hdmi->audio = platform_device_register_full(&pdevinfo);
+
 	dev_set_drvdata(dev, hdmi);
 
 	return 0;
@@ -1725,6 +1751,9 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master,
 {
 	struct imx_hdmi *hdmi = dev_get_drvdata(dev);
 
+	if (!IS_ERR(hdmi->audio))
+		platform_device_unregister(hdmi->audio);
+
 	/* Disable all interrupts */
 	hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 159/222] dw-hdmi-audio: better hardware position tracking
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (157 preceding siblings ...)
  2014-04-25 11:46 ` [PATCH 158/222] dw-hdmi-audio: add audio driver Russell King
@ 2014-04-25 11:46 ` Russell King
  2014-04-25 11:46 ` [PATCH 160/222] dw-hdmi-audio: parse ELD from HDMI driver Russell King
                   ` (63 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:46 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/dw-hdmi-audio.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/staging/imx-drm/dw-hdmi-audio.c b/drivers/staging/imx-drm/dw-hdmi-audio.c
index e7d41249c817..9c27df0112d2 100644
--- a/drivers/staging/imx-drm/dw-hdmi-audio.c
+++ b/drivers/staging/imx-drm/dw-hdmi-audio.c
@@ -238,6 +238,11 @@ static void dw_hdmi_start_dma(struct snd_dw_hdmi *dw)
 
 	writeb_relaxed((u8)~HDMI_AHB_DMA_MASK_DONE, base + HDMI_AHB_DMA_MASK);
 	writeb(HDMI_AHB_DMA_START_START, base + HDMI_AHB_DMA_START);
+
+	offset += period;
+	if (offset >= dw->buf_size)
+		offset = 0;
+	dw->buf_offset = offset;
 }
 
 static void dw_hdmi_stop_dma(struct snd_dw_hdmi *dw)
@@ -263,10 +268,6 @@ static irqreturn_t snd_dw_hdmi_irq(int irq, void *data)
 
 	substream = dw->substream;
 	if (stat & HDMI_IH_AHBDMAAUD_STAT0_DONE && substream) {
-		dw->buf_offset += dw->buf_period;
-		if (dw->buf_offset >= dw->buf_size)
-			dw->buf_offset = 0;
-
 		snd_pcm_period_elapsed(substream);
 		if (dw->substream)
 			dw_hdmi_start_dma(dw);
@@ -427,6 +428,7 @@ static int dw_hdmi_trigger(struct snd_pcm_substream *substream, int cmd)
 		dw->buf_offset = 0;
 		dw->substream = substream;
 		dw_hdmi_start_dma(dw);
+		substream->runtime->delay = substream->runtime->period_size;
 		break;
 
 	case SNDRV_PCM_TRIGGER_STOP:
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 160/222] dw-hdmi-audio: parse ELD from HDMI driver
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (158 preceding siblings ...)
  2014-04-25 11:46 ` [PATCH 159/222] dw-hdmi-audio: better hardware position tracking Russell King
@ 2014-04-25 11:46 ` Russell King
  2014-04-25 11:48 ` [PATCH 161/222] dw-hdmi-audio: try to fix burbling audio Russell King
                   ` (62 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:46 UTC (permalink / raw)
  To: linux-arm-kernel

Parse the ELD (EDID like data) stored from the HDMI driver to restrict
the sample rates and channels which are available to ALSA.  This causes
the ALSA device to reflect the capabilities of the overall audio path,
not just what is supported at the HDMI source interface level.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/dw-hdmi-audio.c | 51 +++++++++++++++++++++++++++++++++
 drivers/staging/imx-drm/dw-hdmi-audio.h |  1 +
 drivers/staging/imx-drm/imx-hdmi.c      |  3 ++
 3 files changed, 55 insertions(+)

diff --git a/drivers/staging/imx-drm/dw-hdmi-audio.c b/drivers/staging/imx-drm/dw-hdmi-audio.c
index 9c27df0112d2..b2595b0a82ce 100644
--- a/drivers/staging/imx-drm/dw-hdmi-audio.c
+++ b/drivers/staging/imx-drm/dw-hdmi-audio.c
@@ -300,6 +300,56 @@ static struct snd_pcm_hardware dw_hdmi_hw = {
 	.fifo_size = 0,
 };
 
+static unsigned rates_mask[] = {
+	SNDRV_PCM_RATE_32000,
+	SNDRV_PCM_RATE_44100,
+	SNDRV_PCM_RATE_48000,
+	SNDRV_PCM_RATE_88200,
+	SNDRV_PCM_RATE_96000,
+	SNDRV_PCM_RATE_176400,
+	SNDRV_PCM_RATE_192000,
+};
+
+static void dw_hdmi_parse_eld(struct snd_dw_hdmi *dw,
+	struct snd_pcm_runtime *runtime)
+{
+	u8 *sad, *eld = dw->data.eld;
+	unsigned eld_ver,  mnl, sad_count, rates, rate_mask, i;
+	unsigned max_channels;
+
+	eld_ver = eld[0] >> 3;
+	if (eld_ver != 2 && eld_ver != 31)
+		return;
+
+	mnl = eld[4] & 0x1f;
+	if (mnl > 16)
+		return;
+
+	sad_count = eld[5] >> 4;
+	sad = eld + 20 + mnl;
+
+	/* Start from the basic audio settings */
+	max_channels = 2;
+	rates = 7;
+	while (sad_count > 0) {
+		switch (sad[0] & 0x78) {
+		case 0x08: /* PCM */
+			max_channels = max(max_channels, (sad[0] & 7) + 1u);
+			rates |= sad[1];
+			break;
+		}
+		sad += 3;
+		sad_count -= 1;
+	}
+
+	for (rate_mask = i = 0; i < ARRAY_SIZE(rates_mask); i++)
+		if (rates & 1 << i)
+			rate_mask |= rates_mask[i];
+
+	runtime->hw.rates &= rate_mask;
+	runtime->hw.channels_max = min(runtime->hw.channels_max, max_channels);
+}
+
 static int dw_hdmi_open(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
@@ -330,6 +380,7 @@ static int dw_hdmi_open(struct snd_pcm_substream *substream)
 		       base + HDMI_IH_MUTE_AHBDMAAUD_STAT0);
 
 	runtime->hw = dw_hdmi_hw;
+	dw_hdmi_parse_eld(dw, runtime);
 	snd_pcm_limit_hw_rates(runtime);
 
 	return 0;
diff --git a/drivers/staging/imx-drm/dw-hdmi-audio.h b/drivers/staging/imx-drm/dw-hdmi-audio.h
index f01979d49efd..2d91d709381d 100644
--- a/drivers/staging/imx-drm/dw-hdmi-audio.h
+++ b/drivers/staging/imx-drm/dw-hdmi-audio.h
@@ -8,6 +8,7 @@ struct dw_hdmi_audio_data {
 	void __iomem *base;
 	int irq;
 	struct imx_hdmi *hdmi;
+	u8 *eld;
 	void (*set_sample_rate)(struct imx_hdmi *, unsigned);
 };
 
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index af4cba51e255..ac72649448a8 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -1410,6 +1410,8 @@ static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
 
 		drm_mode_connector_update_edid_property(connector, edid);
 		ret = drm_add_edid_modes(connector, edid);
+		/* Store the ELD */
+		drm_edid_to_eld(connector, edid);
 		kfree(edid);
 	} else {
 		dev_dbg(hdmi->dev, "failed to get edid\n");
@@ -1726,6 +1728,7 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 	audio.base = hdmi->regs;
 	audio.irq = irq;
 	audio.hdmi = hdmi;
+	audio.eld = hdmi->connector.eld;
 	audio.set_sample_rate = imx_hdmi_set_sample_rate;
 
 	pdevinfo.name = "dw-hdmi-audio";
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 161/222] dw-hdmi-audio: try to fix burbling audio
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (159 preceding siblings ...)
  2014-04-25 11:46 ` [PATCH 160/222] dw-hdmi-audio: parse ELD from HDMI driver Russell King
@ 2014-04-25 11:48 ` Russell King
  2014-04-25 11:48 ` [PATCH 162/222] dw-hdmi-audio: try implementing ERR005174 " Russell King
                   ` (61 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:48 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/dw-hdmi-audio.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/staging/imx-drm/dw-hdmi-audio.c b/drivers/staging/imx-drm/dw-hdmi-audio.c
index b2595b0a82ce..05fe6024fe17 100644
--- a/drivers/staging/imx-drm/dw-hdmi-audio.c
+++ b/drivers/staging/imx-drm/dw-hdmi-audio.c
@@ -61,6 +61,7 @@ enum {
 	HDMI_REVISION_ID = 0x0001,
 	HDMI_IH_AHBDMAAUD_STAT0 = 0x0109,
 	HDMI_IH_MUTE_AHBDMAAUD_STAT0 = 0x0189,
+	HDMI_AUD_N1 = 0x3200,
 	HDMI_AHB_DMA_CONF0 = 0x3600,
 	HDMI_AHB_DMA_START = 0x3601,
 	HDMI_AHB_DMA_STOP = 0x3602,
@@ -479,6 +480,13 @@ static int dw_hdmi_trigger(struct snd_pcm_substream *substream, int cmd)
 		dw->buf_offset = 0;
 		dw->substream = substream;
 		dw_hdmi_start_dma(dw);
+		if (dw->revision == 0x0a) {
+			void __iomem *base = dw->data.base;
+			unsigned val;
+
+			val = readb_relaxed(base + HDMI_AUD_N1);
+			writeb_relaxed(val, base + HDMI_AUD_N1);
+		}
 		substream->runtime->delay = substream->runtime->period_size;
 		break;
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 162/222] dw-hdmi-audio: try implementing ERR005174 to fix burbling audio
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (160 preceding siblings ...)
  2014-04-25 11:48 ` [PATCH 161/222] dw-hdmi-audio: try to fix burbling audio Russell King
@ 2014-04-25 11:48 ` Russell King
  2014-04-25 11:48 ` [PATCH 163/222] dw-hdmi-audio: another attempt at fixing burbling Russell King
                   ` (60 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:48 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/dw-hdmi-audio.c | 35 +++++++++++++++++++++++++++------
 1 file changed, 29 insertions(+), 6 deletions(-)

diff --git a/drivers/staging/imx-drm/dw-hdmi-audio.c b/drivers/staging/imx-drm/dw-hdmi-audio.c
index 05fe6024fe17..f70fe00f9c41 100644
--- a/drivers/staging/imx-drm/dw-hdmi-audio.c
+++ b/drivers/staging/imx-drm/dw-hdmi-audio.c
@@ -7,6 +7,7 @@
  *
  * Written and tested against the (alleged) DW HDMI Tx found in iMX6S.
  */
+#include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
@@ -68,6 +69,8 @@ enum {
 	HDMI_AHB_DMA_THRSLD = 0x3603,
 	HDMI_AHB_DMA_STRADDR0 = 0x3604,
 	HDMI_AHB_DMA_STPADDR0 = 0x3608,
+	HDMI_AHB_DMA_STAT = 0x3612,
+	HDMI_AHB_DMA_STAT_FULL = BIT(1),
 	HDMI_AHB_DMA_MASK = 0x3614,
 	HDMI_AHB_DMA_POL = 0x3615,
 	HDMI_AHB_DMA_CONF1 = 0x3616,
@@ -473,20 +476,40 @@ static int dw_hdmi_prepare(struct snd_pcm_substream *substream)
 static int dw_hdmi_trigger(struct snd_pcm_substream *substream, int cmd)
 {
 	struct snd_dw_hdmi *dw = substream->private_data;
-	int ret = 0;
+	void __iomem *base = dw->data.base;
+	unsigned val[3];
+	unsigned timeout = 10000;
+	int ret = 0, i;
+	bool err005174;
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
+		err005174 = dw->revision == 0x0a;
+		if (err005174) {
+			for (i = 2; i >= 0; i--) {
+				val[i] = readb_relaxed(base + HDMI_AUD_N1 + i);
+				writeb_relaxed(0, base + HDMI_AUD_N1 + i);
+			}
+		}
+
 		dw->buf_offset = 0;
 		dw->substream = substream;
 		dw_hdmi_start_dma(dw);
-		if (dw->revision == 0x0a) {
-			void __iomem *base = dw->data.base;
-			unsigned val;
 
-			val = readb_relaxed(base + HDMI_AUD_N1);
-			writeb_relaxed(val, base + HDMI_AUD_N1);
+		if (err005174) {
+			do {
+				if (readb_relaxed(base + HDMI_AHB_DMA_STAT) & HDMI_AHB_DMA_STAT_FULL)
+					break;
+				udelay(1);
+			} while (timeout--);
+
+			if (!(readb_relaxed(base + HDMI_AHB_DMA_STAT) & HDMI_AHB_DMA_STAT_FULL))
+				pr_info("timeout!\n");
+
+			for (i = 2; i >= 0; i--)
+				writeb_relaxed(val[i], base + HDMI_AUD_N1 + i);
 		}
+
 		substream->runtime->delay = substream->runtime->period_size;
 		break;
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 163/222] dw-hdmi-audio: another attempt at fixing burbling
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (161 preceding siblings ...)
  2014-04-25 11:48 ` [PATCH 162/222] dw-hdmi-audio: try implementing ERR005174 " Russell King
@ 2014-04-25 11:48 ` Russell King
  2014-04-25 11:48 ` [PATCH 164/222] dw-hdmi-audio: basic suspend/resume support Russell King
                   ` (59 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:48 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/dw-hdmi-audio.c | 25 ++++++++++---------------
 1 file changed, 10 insertions(+), 15 deletions(-)

diff --git a/drivers/staging/imx-drm/dw-hdmi-audio.c b/drivers/staging/imx-drm/dw-hdmi-audio.c
index f70fe00f9c41..185c1de2c8ef 100644
--- a/drivers/staging/imx-drm/dw-hdmi-audio.c
+++ b/drivers/staging/imx-drm/dw-hdmi-audio.c
@@ -63,6 +63,7 @@ enum {
 	HDMI_IH_AHBDMAAUD_STAT0 = 0x0109,
 	HDMI_IH_MUTE_AHBDMAAUD_STAT0 = 0x0189,
 	HDMI_AUD_N1 = 0x3200,
+	HDMI_AUD_CTS1 = 0x3203,
 	HDMI_AHB_DMA_CONF0 = 0x3600,
 	HDMI_AHB_DMA_START = 0x3601,
 	HDMI_AHB_DMA_STOP = 0x3602,
@@ -477,8 +478,7 @@ static int dw_hdmi_trigger(struct snd_pcm_substream *substream, int cmd)
 {
 	struct snd_dw_hdmi *dw = substream->private_data;
 	void __iomem *base = dw->data.base;
-	unsigned val[3];
-	unsigned timeout = 10000;
+	unsigned n[3], cts[3];
 	int ret = 0, i;
 	bool err005174;
 
@@ -486,9 +486,11 @@ static int dw_hdmi_trigger(struct snd_pcm_substream *substream, int cmd)
 	case SNDRV_PCM_TRIGGER_START:
 		err005174 = dw->revision == 0x0a;
 		if (err005174) {
-			for (i = 2; i >= 0; i--) {
-				val[i] = readb_relaxed(base + HDMI_AUD_N1 + i);
+			for (i = 2; i >= 1; i--) {
+				n[i] = readb_relaxed(base + HDMI_AUD_N1 + i);
+				cts[i] = readb_relaxed(base + HDMI_AUD_CTS1 + i);
 				writeb_relaxed(0, base + HDMI_AUD_N1 + i);
+				writeb_relaxed(0, base + HDMI_AUD_CTS1 + i);
 			}
 		}
 
@@ -497,17 +499,10 @@ static int dw_hdmi_trigger(struct snd_pcm_substream *substream, int cmd)
 		dw_hdmi_start_dma(dw);
 
 		if (err005174) {
-			do {
-				if (readb_relaxed(base + HDMI_AHB_DMA_STAT) & HDMI_AHB_DMA_STAT_FULL)
-					break;
-				udelay(1);
-			} while (timeout--);
-
-			if (!(readb_relaxed(base + HDMI_AHB_DMA_STAT) & HDMI_AHB_DMA_STAT_FULL))
-				pr_info("timeout!\n");
-
-			for (i = 2; i >= 0; i--)
-				writeb_relaxed(val[i], base + HDMI_AUD_N1 + i);
+			for (i = 2; i >= 1; i--)
+				writeb_relaxed(cts[i], base + HDMI_AUD_CTS1 + i);
+			for (i = 2; i >= 1; i--)
+				writeb_relaxed(n[i], base + HDMI_AUD_N1 + i);
 		}
 
 		substream->runtime->delay = substream->runtime->period_size;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 164/222] dw-hdmi-audio: basic suspend/resume support
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (162 preceding siblings ...)
  2014-04-25 11:48 ` [PATCH 163/222] dw-hdmi-audio: another attempt at fixing burbling Russell King
@ 2014-04-25 11:48 ` Russell King
  2014-04-25 11:48 ` [PATCH 165/222] cec: add generic HDMI CEC driver Russell King
                   ` (58 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:48 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/dw-hdmi-audio.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/drivers/staging/imx-drm/dw-hdmi-audio.c b/drivers/staging/imx-drm/dw-hdmi-audio.c
index 185c1de2c8ef..2280094fc6ff 100644
--- a/drivers/staging/imx-drm/dw-hdmi-audio.c
+++ b/drivers/staging/imx-drm/dw-hdmi-audio.c
@@ -611,12 +611,40 @@ static int snd_dw_hdmi_remove(struct platform_device *pdev)
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int snd_dw_hdmi_suspend(struct device *dev)
+{
+	struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
+
+	snd_power_change_state(dw->card, SNDRV_CTL_POWER_D3cold);
+	snd_pcm_suspend_all(dw->pcm);
+
+	return 0;
+}
+
+static int snd_dw_hdmi_resume(struct device *dev)
+{
+	struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
+
+	snd_power_change_state(dw->card, SNDRV_CTL_POWER_D0);
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(snd_dw_hdmi_pm, snd_dw_hdmi_suspend,
+			 snd_dw_hdmi_resume);
+#define PM_OPS &snd_dw_hdmi_pm
+#else
+#define PM_OPS NULL
+#endif
+
 static struct platform_driver snd_dw_hdmi_driver = {
 	.probe	= snd_dw_hdmi_probe,
 	.remove	= snd_dw_hdmi_remove,
 	.driver	= {
 		.name = "dw-hdmi-audio",
 		.owner = THIS_MODULE,
+		.pm = PM_OPS,
 	},
 };
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 165/222] cec: add generic HDMI CEC driver
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (163 preceding siblings ...)
  2014-04-25 11:48 ` [PATCH 164/222] dw-hdmi-audio: basic suspend/resume support Russell King
@ 2014-04-25 11:48 ` Russell King
  2014-04-25 11:48 ` [PATCH 166/222] imx-drm: dw-hdmi-cec: add " Russell King
                   ` (57 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:48 UTC (permalink / raw)
  To: linux-arm-kernel

Add a generic userspace API to support HDMI Consumer Electronics Control
interfaces.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/Kconfig              |   2 +
 drivers/Makefile             |   1 +
 drivers/cec/Kconfig          |  14 ++
 drivers/cec/Makefile         |   1 +
 drivers/cec/cec-dev.c        | 384 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/cec-dev.h      |  69 ++++++++
 include/uapi/linux/cec-dev.h |  34 ++++
 7 files changed, 505 insertions(+)
 create mode 100644 drivers/cec/Kconfig
 create mode 100644 drivers/cec/Makefile
 create mode 100644 drivers/cec/cec-dev.c
 create mode 100644 include/linux/cec-dev.h
 create mode 100644 include/uapi/linux/cec-dev.h

diff --git a/drivers/Kconfig b/drivers/Kconfig
index 0a0a90f52d26..05a21b857996 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -174,4 +174,6 @@ source "drivers/powercap/Kconfig"
 
 source "drivers/mcb/Kconfig"
 
+source "drivers/cec/Kconfig"
+
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index e3ced91b1784..5600518a17dd 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -157,3 +157,4 @@ obj-$(CONFIG_NTB)		+= ntb/
 obj-$(CONFIG_FMC)		+= fmc/
 obj-$(CONFIG_POWERCAP)		+= powercap/
 obj-$(CONFIG_MCB)		+= mcb/
+obj-$(CONFIG_CEC)		+= cec/
diff --git a/drivers/cec/Kconfig b/drivers/cec/Kconfig
new file mode 100644
index 000000000000..d67cfb83de6a
--- /dev/null
+++ b/drivers/cec/Kconfig
@@ -0,0 +1,14 @@
+#
+# Consumer Electroncs Control support
+#
+
+menu "Consumer Electronics Control devices"
+
+config CEC
+	bool
+
+config HDMI_CEC_CORE
+	tristate
+	select CEC
+
+endmenu
diff --git a/drivers/cec/Makefile b/drivers/cec/Makefile
new file mode 100644
index 000000000000..b94278bc8321
--- /dev/null
+++ b/drivers/cec/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_HDMI_CEC_CORE) += cec-dev.o
diff --git a/drivers/cec/cec-dev.c b/drivers/cec/cec-dev.c
new file mode 100644
index 000000000000..ba58d8217851
--- /dev/null
+++ b/drivers/cec/cec-dev.c
@@ -0,0 +1,384 @@
+/*
+ * HDMI Consumer Electronics Control
+ *
+ * This provides the user API for communication with HDMI CEC complaint
+ * devices in kernel drivers, and is based upon the protocol developed
+ * by Freescale for their i.MX SoCs.
+ *
+ * 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/cec-dev.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+struct cec_event {
+	struct cec_user_event usr;
+	struct list_head node;
+};
+
+static struct class *cec_class;
+static int cec_major;
+
+static void cec_dev_send_message(struct cec_dev *cec_dev, u8 *msg,
+	size_t count)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&cec_dev->lock, flags);
+	cec_dev->retries = 5;
+	cec_dev->write_busy = 1;
+	cec_dev->send_message(cec_dev, msg, count);
+	spin_unlock_irqrestore(&cec_dev->lock, flags);
+}
+
+void cec_dev_event(struct cec_dev *cec_dev, int type, u8 *msg, size_t len)
+{
+	struct cec_event *event;
+	unsigned long flags;
+
+	event = kzalloc(sizeof(*event), GFP_ATOMIC);
+	if (event) {
+		event->usr.event_type = type;
+		event->usr.msg_len = len;
+		if (msg)
+			memcpy(event->usr.msg, msg, len);
+
+		spin_lock_irqsave(&cec_dev->lock, flags);
+		list_add_tail(&event->node, &cec_dev->events);
+		spin_unlock_irqrestore(&cec_dev->lock, flags);
+		wake_up(&cec_dev->waitq);
+	}
+}
+EXPORT_SYMBOL_GPL(cec_dev_event);
+
+static int cec_dev_lock_write(struct cec_dev *cec_dev, struct file *file)
+	__acquires(cec_dev->mutex)
+{
+	int ret;
+
+	do {
+		if (file->f_flags & O_NONBLOCK) {
+			if (cec_dev->write_busy)
+				return -EAGAIN;
+		} else {
+			ret = wait_event_interruptible(cec_dev->waitq,
+						       !cec_dev->write_busy);
+			if (ret)
+				break;
+		}
+
+		ret = mutex_lock_interruptible(&cec_dev->mutex);
+		if (ret)
+			break;
+
+		if (!cec_dev->write_busy)
+			break;
+
+		mutex_unlock(&cec_dev->mutex);
+	} while (1);
+
+	return ret;
+}
+
+static ssize_t cec_dev_read(struct file *file, char __user *buf,
+	size_t count, loff_t *ppos)
+{
+	struct cec_dev *cec_dev = file->private_data;
+	ssize_t ret;
+
+	if (count > sizeof(struct cec_user_event))
+		count = sizeof(struct cec_user_event);
+
+	if (!access_ok(VERIFY_WRITE, buf, count))
+		return -EFAULT;
+
+	do {
+		struct cec_event *event = NULL;
+		unsigned long flags;
+
+		spin_lock_irqsave(&cec_dev->lock, flags);
+		if (!list_empty(&cec_dev->events)) {
+			event = list_first_entry(&cec_dev->events,
+					struct cec_event, node);
+			list_del(&event->node);
+		}
+		spin_unlock_irqrestore(&cec_dev->lock, flags);
+
+		if (event) {
+			ret = __copy_to_user(buf, &event->usr, count) ?
+				 -EFAULT : count;
+			kfree(event);
+			break;
+		}
+
+		if (file->f_flags & O_NONBLOCK) {
+			ret = -EAGAIN;
+			break;
+		}
+
+		ret = wait_event_interruptible(cec_dev->waitq,
+					       !list_empty(&cec_dev->events));
+		if (ret)
+			break;
+	} while (1);
+
+	return ret;
+}
+
+static ssize_t cec_dev_write(struct file *file, const char __user *buf,
+	size_t count, loff_t *ppos)
+{
+	struct cec_dev *cec_dev = file->private_data;
+	u8 msg[MAX_MESSAGE_LEN];
+	int ret;
+
+	if (count > sizeof(msg))
+		return -E2BIG;
+
+	if (copy_from_user(msg, buf, count))
+		return -EFAULT;
+
+	ret = cec_dev_lock_write(cec_dev, file);
+	if (ret)
+		return ret;
+
+	cec_dev_send_message(cec_dev, msg, count);
+
+	mutex_unlock(&cec_dev->mutex);
+
+	return count;
+}
+
+static long cec_dev_ioctl(struct file *file, u_int cmd, unsigned long arg)
+{
+	struct cec_dev *cec_dev = file->private_data;
+	int ret;
+
+	switch (cmd) {
+	case HDMICEC_IOC_O_SETLOGICALADDRESS:
+	case HDMICEC_IOC_SETLOGICALADDRESS:
+		if (arg > 15) {
+			ret = -EINVAL;
+			break;
+		}
+
+		ret = cec_dev_lock_write(cec_dev, file);
+		if (ret == 0) {
+			unsigned char msg[1];
+
+			cec_dev->addresses = BIT(arg);
+			cec_dev->set_address(cec_dev, cec_dev->addresses);
+
+			/*
+			 * Send a ping message with the source and destination
+			 * set to our address; the result indicates whether
+			 * unit has chosen our address simultaneously.
+			 */
+			msg[0] = arg << 4 | arg;
+			cec_dev_send_message(cec_dev, msg, sizeof(msg));
+			mutex_unlock(&cec_dev->mutex);
+		}
+		break;
+
+	case HDMICEC_IOC_STARTDEVICE:
+		ret = mutex_lock_interruptible(&cec_dev->mutex);
+		if (ret == 0) {
+			cec_dev->addresses = BIT(15);
+			cec_dev->set_address(cec_dev, cec_dev->addresses);
+			mutex_unlock(&cec_dev->mutex);
+		}
+		break;
+
+	case HDMICEC_IOC_STOPDEVICE:
+		ret = 0;
+		break;
+
+	case HDMICEC_IOC_GETPHYADDRESS:
+		ret = put_user(cec_dev->physical, (u16 __user *)arg);
+		ret = -ENOIOCTLCMD;
+		break;
+
+	default:
+		ret = -ENOIOCTLCMD;
+		break;
+	}
+
+	return ret;
+}
+
+static unsigned cec_dev_poll(struct file *file, poll_table *wait)
+{
+	struct cec_dev *cec_dev = file->private_data;
+	unsigned mask = 0;
+
+	poll_wait(file, &cec_dev->waitq, wait);
+
+	if (cec_dev->write_busy == 0)
+		mask |= POLLOUT | POLLWRNORM;
+	if (!list_empty(&cec_dev->events))
+		mask |= POLLIN | POLLRDNORM;
+
+	return mask;
+}
+
+static int cec_dev_release(struct inode *inode, struct file *file)
+{
+	struct cec_dev *cec_dev = file->private_data;
+
+	mutex_lock(&cec_dev->mutex);
+	if (cec_dev->users >= 1)
+		cec_dev->users -= 1;
+	if (cec_dev->users == 0) {
+		/*
+		 * Wait for any write to complete before shutting down.
+		 * A message should complete in a maximum of 2.75ms *
+		 * 160 bits + 4.7ms, or 444.7ms.  Let's call that 500ms.
+		 * If we time out, shutdown anyway.
+		 */
+		wait_event_timeout(cec_dev->waitq, !cec_dev->write_busy,
+				   msecs_to_jiffies(500));
+
+		cec_dev->release(cec_dev);
+
+		while (!list_empty(&cec_dev->events)) {
+			struct cec_event *event;
+
+			event = list_first_entry(&cec_dev->events,
+					struct cec_event, node);
+			list_del(&event->node);
+			kfree(event);
+		}
+	}
+	mutex_unlock(&cec_dev->mutex);
+	return 0;
+}
+
+static int cec_dev_open(struct inode *inode, struct file *file)
+{
+	struct cec_dev *cec_dev = container_of(inode->i_cdev, struct cec_dev,
+					       cdev);
+	int ret = 0;
+
+	nonseekable_open(inode, file);
+
+	file->private_data = cec_dev;
+
+	ret = mutex_lock_interruptible(&cec_dev->mutex);
+	if (ret)
+		return ret;
+
+	if (cec_dev->users++ == 0) {
+		cec_dev->addresses = BIT(15);
+
+		ret = cec_dev->open(cec_dev);
+		if (ret < 0)
+			cec_dev->users = 0;
+	}
+	mutex_unlock(&cec_dev->mutex);
+
+	return ret;
+}
+
+static const struct file_operations hdmi_cec_fops = {
+	.owner = THIS_MODULE,
+	.read = cec_dev_read,
+	.write = cec_dev_write,
+	.open = cec_dev_open,
+	.unlocked_ioctl = cec_dev_ioctl,
+	.release = cec_dev_release,
+	.poll = cec_dev_poll,
+};
+
+void cec_dev_init(struct cec_dev *cec_dev, struct module *module)
+{
+	cec_dev->devn = MKDEV(cec_major, 0);
+
+	INIT_LIST_HEAD(&cec_dev->events);
+	init_waitqueue_head(&cec_dev->waitq);
+	spin_lock_init(&cec_dev->lock);
+	mutex_init(&cec_dev->mutex);
+
+	cec_dev->addresses = BIT(15);
+
+	cdev_init(&cec_dev->cdev, &hdmi_cec_fops);
+	cec_dev->cdev.owner = module;
+}
+EXPORT_SYMBOL_GPL(cec_dev_init);
+
+int cec_dev_add(struct cec_dev *cec_dev, struct device *dev, const char *name)
+{
+	struct device *cd;
+	int ret;
+
+	ret = cdev_add(&cec_dev->cdev, cec_dev->devn, 1);
+	if (ret < 0)
+		goto err_cdev;
+
+	cd = device_create(cec_class, dev, cec_dev->devn, NULL, name);
+	if (IS_ERR(cd)) {
+		ret = PTR_ERR(cd);
+		dev_err(dev, "can't create device: %d\n", ret);
+		goto err_dev;
+	}
+
+	return 0;
+
+ err_dev:
+	cdev_del(&cec_dev->cdev);
+ err_cdev:
+	return ret;
+}
+EXPORT_SYMBOL_GPL(cec_dev_add);
+
+void cec_dev_remove(struct cec_dev *cec_dev)
+{
+	device_destroy(cec_class, cec_dev->devn);
+	cdev_del(&cec_dev->cdev);
+}
+EXPORT_SYMBOL_GPL(cec_dev_remove);
+
+static int cec_init(void)
+{
+	dev_t dev;
+	int ret;
+
+	cec_class = class_create(THIS_MODULE, "hdmi-cec");
+	if (IS_ERR(cec_class)) {
+		ret = PTR_ERR(cec_class);
+		pr_err("cec: can't create cec class: %d\n", ret);
+		goto err_class;
+	}
+
+	ret = alloc_chrdev_region(&dev, 0, 1, "hdmi-cec");
+	if (ret) {
+		pr_err("cec: can't create character devices: %d\n", ret);
+		goto err_chrdev;
+	}
+
+	cec_major = MAJOR(dev);
+
+	return 0;
+
+ err_chrdev:
+	class_destroy(cec_class);
+ err_class:
+	return ret;
+}
+subsys_initcall(cec_init);
+
+static void cec_exit(void)
+{
+	unregister_chrdev_region(MKDEV(cec_major, 0), 1);
+	class_destroy(cec_class);
+}
+module_exit(cec_exit);
+
+MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>");
+MODULE_DESCRIPTION("Generic HDMI CEC driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/cec-dev.h b/include/linux/cec-dev.h
new file mode 100644
index 000000000000..76a7d7f6a72d
--- /dev/null
+++ b/include/linux/cec-dev.h
@@ -0,0 +1,69 @@
+#ifndef _LINUX_CEC_DEV_H
+#define _LINUX_CEC_DEV_H
+
+#include <linux/cdev.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+
+#include <uapi/linux/cec-dev.h>
+
+struct device;
+
+struct cec_dev {
+	struct cdev cdev;
+	dev_t devn;
+
+	struct mutex mutex;
+	unsigned users;
+
+	spinlock_t lock;
+	wait_queue_head_t waitq;
+	struct list_head events;
+	u8 write_busy;
+
+	u8 retries;
+	u16 addresses;
+	u16 physical;
+
+	int (*open)(struct cec_dev *);
+	void (*release)(struct cec_dev *);
+	void (*send_message)(struct cec_dev *, u8 *, size_t);
+	void (*set_address)(struct cec_dev *, unsigned);
+};
+
+void cec_dev_event(struct cec_dev *cec_dev, int type, u8 *msg, size_t len);
+
+static inline void cec_dev_receive(struct cec_dev *cec_dev, u8 *msg,
+	unsigned len)
+{
+	cec_dev_event(cec_dev, MESSAGE_TYPE_RECEIVE_SUCCESS, msg, len);
+}
+
+static inline void cec_dev_send_complete(struct cec_dev *cec_dev, int ack)
+{
+	cec_dev->retries = 0;
+	cec_dev->write_busy = 0;
+
+	cec_dev_event(cec_dev, ack ? MESSAGE_TYPE_SEND_SUCCESS :
+		      MESSAGE_TYPE_NOACK, NULL, 0);
+}
+
+static inline void cec_dev_disconnect(struct cec_dev *cec_dev)
+{
+	cec_dev->physical = 0;
+	cec_dev_event(cec_dev, MESSAGE_TYPE_DISCONNECTED, NULL, 0);
+}
+
+static inline void cec_dev_connect(struct cec_dev *cec_dev, u32 phys)
+{
+	cec_dev->physical = phys;
+	cec_dev_event(cec_dev, MESSAGE_TYPE_CONNECTED, NULL, 0);
+}
+
+void cec_dev_init(struct cec_dev *cec_dev, struct module *);
+int cec_dev_add(struct cec_dev *cec_dev, struct device *, const char *name);
+void cec_dev_remove(struct cec_dev *cec_dev);
+
+#endif
diff --git a/include/uapi/linux/cec-dev.h b/include/uapi/linux/cec-dev.h
new file mode 100644
index 000000000000..fb7a41704c77
--- /dev/null
+++ b/include/uapi/linux/cec-dev.h
@@ -0,0 +1,34 @@
+#ifndef _UAPI_LINUX_CEC_DEV_H
+#define _UAPI_LINUX_CEC_DEV_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+#define MAX_MESSAGE_LEN 16
+
+enum {
+	HDMICEC_IOC_MAGIC = 'H',
+	/* This is wrong: we pass the argument as a number, not a pointer */
+	HDMICEC_IOC_O_SETLOGICALADDRESS	= _IOW(HDMICEC_IOC_MAGIC, 1, unsigned char),
+	HDMICEC_IOC_SETLOGICALADDRESS	= _IO(HDMICEC_IOC_MAGIC, 1),
+	HDMICEC_IOC_STARTDEVICE		= _IO(HDMICEC_IOC_MAGIC, 2),
+	HDMICEC_IOC_STOPDEVICE		= _IO(HDMICEC_IOC_MAGIC, 3),
+	HDMICEC_IOC_GETPHYADDRESS	= _IOR(HDMICEC_IOC_MAGIC, 4, unsigned char[4]),
+};
+
+enum {
+	MESSAGE_TYPE_RECEIVE_SUCCESS = 1,
+	MESSAGE_TYPE_NOACK,
+	MESSAGE_TYPE_DISCONNECTED,
+	MESSAGE_TYPE_CONNECTED,
+	MESSAGE_TYPE_SEND_SUCCESS,
+	MESSAGE_TYPE_SEND_ERROR,
+};
+
+struct cec_user_event {
+	__u32 event_type;
+	__u32 msg_len;
+	__u8 msg[MAX_MESSAGE_LEN];
+};
+
+#endif
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 166/222] imx-drm: dw-hdmi-cec: add HDMI CEC driver
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (164 preceding siblings ...)
  2014-04-25 11:48 ` [PATCH 165/222] cec: add generic HDMI CEC driver Russell King
@ 2014-04-25 11:48 ` Russell King
  2014-04-25 11:48 ` [PATCH 167/222] ARM: imx: add HDMI support for SolidRun HummingBoard and Cubox-i Russell King
                   ` (56 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:48 UTC (permalink / raw)
  To: linux-arm-kernel

This adds a HDMI Consumer Electronics Control driver, making use of the
generic HDMI CEC driver to provide a common user API for these devices.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/Kconfig       |   9 ++
 drivers/staging/imx-drm/Makefile      |   1 +
 drivers/staging/imx-drm/dw-hdmi-cec.c | 205 ++++++++++++++++++++++++++++++++++
 drivers/staging/imx-drm/dw-hdmi-cec.h |  16 +++
 drivers/staging/imx-drm/imx-hdmi.c    |  63 +++++++++--
 5 files changed, 284 insertions(+), 10 deletions(-)
 create mode 100644 drivers/staging/imx-drm/dw-hdmi-cec.c
 create mode 100644 drivers/staging/imx-drm/dw-hdmi-cec.h

diff --git a/drivers/staging/imx-drm/Kconfig b/drivers/staging/imx-drm/Kconfig
index 66ed3e5f132a..52516a7cf26f 100644
--- a/drivers/staging/imx-drm/Kconfig
+++ b/drivers/staging/imx-drm/Kconfig
@@ -69,3 +69,12 @@ config DRM_DW_HDMI_AUDIO
 	  Support the Audio interface which is part of the Synopsis
 	  Designware HDMI block.  This is used in conjunction with
 	  the i.MX HDMI driver.
+
+config DRM_DW_HDMI_CEC
+	tristate "Synopsis Designware CEC interface"
+	depends on DRM_IMX_HDMI != n
+	select HDMI_CEC_CORE
+	help
+	  Support the CEC interface which is part of the Synposis
+	  Designware HDMI block.  This is used in conjunction with
+	  the i.MX HDMI driver.
diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
index 34c8b9990a66..2295a6805d69 100644
--- a/drivers/staging/imx-drm/Makefile
+++ b/drivers/staging/imx-drm/Makefile
@@ -12,3 +12,4 @@ imx-ipuv3-crtc-objs  := ipuv3-crtc.o ipuv3-plane.o
 obj-$(CONFIG_DRM_IMX_IPUV3)	+= imx-ipuv3-crtc.o
 obj-$(CONFIG_DRM_IMX_HDMI) += imx-hdmi.o
 obj-$(CONFIG_DRM_DW_HDMI_AUDIO) += dw-hdmi-audio.o
+obj-$(CONFIG_DRM_DW_HDMI_CEC) += dw-hdmi-cec.o
diff --git a/drivers/staging/imx-drm/dw-hdmi-cec.c b/drivers/staging/imx-drm/dw-hdmi-cec.c
new file mode 100644
index 000000000000..c94b75aa037b
--- /dev/null
+++ b/drivers/staging/imx-drm/dw-hdmi-cec.c
@@ -0,0 +1,205 @@
+/* http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/tree/drivers/mxc/hdmi-cec/mxc_hdmi-cec.c?h=imx_3.0.35_4.1.0 */
+#include <linux/cec-dev.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include "imx-hdmi.h"
+#include "dw-hdmi-cec.h"
+
+#define DEV_NAME "mxc_hdmi_cec"
+
+enum {
+	CEC_STAT_DONE		= BIT(0),
+	CEC_STAT_EOM		= BIT(1),
+	CEC_STAT_NACK		= BIT(2),
+	CEC_STAT_ARBLOST	= BIT(3),
+	CEC_STAT_ERROR_INIT	= BIT(4),
+	CEC_STAT_ERROR_FOLL	= BIT(5),
+	CEC_STAT_WAKEUP		= BIT(6),
+
+	CEC_CTRL_START		= BIT(0),
+	CEC_CTRL_NORMAL		= 1 << 1,
+};
+
+struct dw_hdmi_cec {
+	struct cec_dev cec;
+
+	struct device *dev;
+	void __iomem *base;
+	const struct dw_hdmi_cec_ops *ops;
+	void *ops_data;
+	int irq;
+};
+
+static void dw_hdmi_set_address(struct cec_dev *cec_dev, unsigned addresses)
+{
+	struct dw_hdmi_cec *cec = container_of(cec_dev, struct dw_hdmi_cec, cec);
+
+	writeb(addresses & 255, cec->base + HDMI_CEC_ADDR_L);
+	writeb(addresses >> 8, cec->base + HDMI_CEC_ADDR_H);
+}
+
+static void dw_hdmi_send_message(struct cec_dev *cec_dev, u8 *msg,
+	size_t count)
+{
+	struct dw_hdmi_cec *cec = container_of(cec_dev, struct dw_hdmi_cec, cec);
+	unsigned i;
+
+	for (i = 0; i < count; i++)
+		writeb(msg[i], cec->base + HDMI_CEC_TX_DATA0 + i);
+
+	writeb(count, cec->base + HDMI_CEC_TX_CNT);
+	writeb(CEC_CTRL_NORMAL | CEC_CTRL_START, cec->base + HDMI_CEC_CTRL);
+}
+
+static irqreturn_t dw_hdmi_cec_irq(int irq, void *data)
+{
+	struct dw_hdmi_cec *cec = data;
+	struct cec_dev *cec_dev = &cec->cec;
+	unsigned stat = readb(cec->base + HDMI_IH_CEC_STAT0);
+
+	if (stat == 0)
+		return IRQ_NONE;
+
+	writeb(stat, cec->base + HDMI_IH_CEC_STAT0);
+
+	if (stat & CEC_STAT_ERROR_INIT) {
+		if (cec->cec.retries) {
+			unsigned v = readb(cec->base + HDMI_CEC_CTRL);
+			writeb(v | CEC_CTRL_START, cec->base + HDMI_CEC_CTRL);
+			cec->cec.retries -= 1;
+		} else {
+			cec->cec.write_busy = 0;
+			cec_dev_event(cec_dev, MESSAGE_TYPE_SEND_ERROR, NULL, 0);
+		}
+	} else if (stat & (CEC_STAT_DONE | CEC_STAT_NACK))
+		cec_dev_send_complete(cec_dev, stat & CEC_STAT_DONE);
+
+	if (stat & CEC_STAT_EOM) {
+		unsigned len, i;
+		u8 msg[MAX_MESSAGE_LEN];
+
+		len = readb(cec->base + HDMI_CEC_RX_CNT);
+		if (len > sizeof(msg))
+			len = sizeof(msg);
+
+		for (i = 0; i < len; i++)
+			msg[i] = readb(cec->base + HDMI_CEC_RX_DATA0 + i);
+
+		writeb(0, cec->base + HDMI_CEC_LOCK);
+
+		cec_dev_receive(cec_dev, msg, len);
+	}
+
+	return IRQ_HANDLED;
+}
+EXPORT_SYMBOL(dw_hdmi_cec_irq);
+
+static void dw_hdmi_cec_release(struct cec_dev *cec_dev)
+{
+	struct dw_hdmi_cec *cec = container_of(cec_dev, struct dw_hdmi_cec, cec);
+
+	writeb(~0, cec->base + HDMI_CEC_MASK);
+	writeb(~0, cec->base + HDMI_IH_MUTE_CEC_STAT0);
+	writeb(0, cec->base + HDMI_CEC_POLARITY);
+
+	free_irq(cec->irq, cec);
+
+	cec->ops->disable(cec->ops_data);
+}
+
+static int dw_hdmi_cec_open(struct cec_dev *cec_dev)
+{
+	struct dw_hdmi_cec *cec = container_of(cec_dev, struct dw_hdmi_cec, cec);
+	unsigned irqs;
+	int ret;
+
+	writeb(0, cec->base + HDMI_CEC_CTRL);
+	writeb(~0, cec->base + HDMI_IH_CEC_STAT0);
+	writeb(0, cec->base + HDMI_CEC_LOCK);
+
+	ret = request_irq(cec->irq, dw_hdmi_cec_irq, IRQF_SHARED,
+			  DEV_NAME, cec);
+	if (ret < 0)
+		return ret;
+
+	dw_hdmi_set_address(cec_dev, cec_dev->addresses);
+
+	cec->ops->enable(cec->ops_data);
+
+	irqs = CEC_STAT_ERROR_INIT | CEC_STAT_NACK | CEC_STAT_EOM |
+	       CEC_STAT_DONE;
+	writeb(irqs, cec->base + HDMI_CEC_POLARITY);
+	writeb(~irqs, cec->base + HDMI_CEC_MASK);
+	writeb(~irqs, cec->base + HDMI_IH_MUTE_CEC_STAT0);
+
+	return 0;
+}
+
+static int dw_hdmi_cec_probe(struct platform_device *pdev)
+{
+	struct dw_hdmi_cec_data *data = dev_get_platdata(&pdev->dev);
+	struct dw_hdmi_cec *cec;
+
+	if (!data)
+		return -ENXIO;
+
+	cec = devm_kzalloc(&pdev->dev, sizeof(*cec), GFP_KERNEL);
+	if (!cec)
+		return -ENOMEM;
+
+	cec->dev = &pdev->dev;
+	cec->base = data->base;
+	cec->irq = data->irq;
+	cec->ops = data->ops;
+	cec->ops_data = data->ops_data;
+	cec->cec.open = dw_hdmi_cec_open;
+	cec->cec.release = dw_hdmi_cec_release;
+	cec->cec.send_message = dw_hdmi_send_message;
+	cec->cec.set_address = dw_hdmi_set_address;
+
+	cec_dev_init(&cec->cec, THIS_MODULE);
+
+	/* FIXME: soft-reset the CEC interface */
+
+	dw_hdmi_set_address(&cec->cec, cec->cec.addresses);
+	writeb(0, cec->base + HDMI_CEC_TX_CNT);
+	writeb(~0, cec->base + HDMI_CEC_MASK);
+	writeb(~0, cec->base + HDMI_IH_MUTE_CEC_STAT0);
+	writeb(0, cec->base + HDMI_CEC_POLARITY);
+
+	/*
+	 * Our device is just a convenience - we want to link to the real
+	 * hardware device here, so that userspace can see the association
+	 * between the HDMI hardware and its associated CEC chardev.
+	 */
+	return cec_dev_add(&cec->cec, cec->dev->parent, DEV_NAME);
+}
+
+static int dw_hdmi_cec_remove(struct platform_device *pdev)
+{
+	struct dw_hdmi_cec *cec = platform_get_drvdata(pdev);
+
+	cec_dev_remove(&cec->cec);
+
+	return 0;
+}
+
+static struct platform_driver dw_hdmi_cec_driver = {
+	.probe	= dw_hdmi_cec_probe,
+	.remove	= dw_hdmi_cec_remove,
+	.driver = {
+		.name = "dw-hdmi-cec",
+		.owner = THIS_MODULE,
+	},
+};
+module_platform_driver(dw_hdmi_cec_driver);
+
+MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>");
+MODULE_DESCRIPTION("Synopsis Designware HDMI CEC driver for i.MX");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS(PLATFORM_MODULE_PREFIX "dw-hdmi-cec");
diff --git a/drivers/staging/imx-drm/dw-hdmi-cec.h b/drivers/staging/imx-drm/dw-hdmi-cec.h
new file mode 100644
index 000000000000..5ff40cc237a8
--- /dev/null
+++ b/drivers/staging/imx-drm/dw-hdmi-cec.h
@@ -0,0 +1,16 @@
+#ifndef DW_HDMI_CEC_H
+#define DW_HDMI_CEC_H
+
+struct dw_hdmi_cec_ops {
+	void (*enable)(void *);
+	void (*disable)(void *);
+};
+
+struct dw_hdmi_cec_data {
+	void __iomem *base;
+	int irq;
+	const struct dw_hdmi_cec_ops *ops;
+	void *ops_data;
+};
+
+#endif
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index ac72649448a8..c3bd89d34d40 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -29,6 +29,7 @@
 #include <drm/drm_encoder_slave.h>
 
 #include "dw-hdmi-audio.h"
+#include "dw-hdmi-cec.h"
 #include "ipu-v3/imx-ipu-v3.h"
 #include "imx-hdmi.h"
 #include "imx-drm.h"
@@ -117,6 +118,7 @@ struct imx_hdmi {
 	struct drm_encoder encoder;
 
 	struct platform_device *audio;
+	struct platform_device *cec;
 	enum imx_hdmi_devtype dev_type;
 	struct device *dev;
 	struct clk *isfr_clk;
@@ -126,6 +128,7 @@ struct imx_hdmi {
 	int vic;
 
 	u8 edid[HDMI_EDID_LEN];
+	u8 mc_clkdis;
 	bool cable_plugin;
 
 	bool phy_enabled;
@@ -1154,8 +1157,6 @@ static void imx_hdmi_phy_disable(struct imx_hdmi *hdmi)
 /* HDMI Initialization Step B.4 */
 static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
 {
-	u8 clkdis;
-
 	/* control period minimum duration */
 	hdmi_writeb(hdmi, 12, HDMI_FC_CTRLDUR);
 	hdmi_writeb(hdmi, 32, HDMI_FC_EXCTRLDUR);
@@ -1167,23 +1168,28 @@ static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
 	hdmi_writeb(hdmi, 0x21, HDMI_FC_CH2PREAM);
 
 	/* Enable pixel clock and tmds data path */
-	clkdis = 0x7F;
-	clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE;
-	hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+	hdmi->mc_clkdis |= HDMI_MC_CLKDIS_HDCPCLK_DISABLE |
+			   HDMI_MC_CLKDIS_CSCCLK_DISABLE |
+			   HDMI_MC_CLKDIS_AUDCLK_DISABLE |
+			   HDMI_MC_CLKDIS_PREPCLK_DISABLE |
+			   HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
+	hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE;
+	hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
 
-	clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
-	hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+	hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
+	hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
 
 	/* Enable csc path */
 	if (is_color_space_conversion(hdmi)) {
-		clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;
-		hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+		hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;
+		hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
 	}
 }
 
 static void hdmi_enable_audio_clk(struct imx_hdmi *hdmi)
 {
-	hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS);
+	hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE;
+	hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
 }
 
 /* Workaround to clear the overflow condition */
@@ -1579,6 +1585,27 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
 	return 0;
 }
 
+static void imx_hdmi_cec_enable(void *data)
+{
+	struct imx_hdmi *hdmi = data;
+
+	hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_CECCLK_DISABLE;
+	hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
+}
+
+static void imx_hdmi_cec_disable(void *data)
+{
+	struct imx_hdmi *hdmi = data;
+
+	hdmi->mc_clkdis |= HDMI_MC_CLKDIS_CECCLK_DISABLE;
+	hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
+}
+
+static const struct dw_hdmi_cec_ops imx_hdmi_cec_ops = {
+	.enable = imx_hdmi_cec_enable,
+	.disable = imx_hdmi_cec_disable,
+};
+
 static struct platform_device_id imx_hdmi_devtype[] = {
 	{
 		.name = "imx6q-hdmi",
@@ -1607,6 +1634,7 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 	struct device_node *np = dev->of_node;
 	struct device_node *ddc_node;
 	struct dw_hdmi_audio_data audio;
+	struct dw_hdmi_cec_data cec;
 	struct imx_hdmi *hdmi;
 	struct resource *iores;
 	int ret, irq;
@@ -1618,6 +1646,7 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 	hdmi->dev = dev;
 	hdmi->sample_rate = 48000;
 	hdmi->ratio = 100;
+	hdmi->mc_clkdis = 0x7f;
 
 	if (of_id) {
 		const struct platform_device_id *device_id = of_id->data;
@@ -1737,6 +1766,18 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 	pdevinfo.dma_mask = DMA_BIT_MASK(32);
 	hdmi->audio = platform_device_register_full(&pdevinfo);
 
+	cec.base = hdmi->regs;
+	cec.irq = irq;
+	cec.ops = &imx_hdmi_cec_ops;
+	cec.ops_data = hdmi;
+
+	pdevinfo.name = "dw-hdmi-cec";
+	pdevinfo.data = &cec;
+	pdevinfo.size_data = sizeof(cec);
+	pdevinfo.dma_mask = 0;
+
+	hdmi->cec = platform_device_register_full(&pdevinfo);
+
 	dev_set_drvdata(dev, hdmi);
 
 	return 0;
@@ -1756,6 +1797,8 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master,
 
 	if (!IS_ERR(hdmi->audio))
 		platform_device_unregister(hdmi->audio);
+	if (!IS_ERR(hdmi->cec))
+		platform_device_unregister(hdmi->cec);
 
 	/* Disable all interrupts */
 	hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 167/222] ARM: imx: add HDMI support for SolidRun HummingBoard and Cubox-i
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (165 preceding siblings ...)
  2014-04-25 11:48 ` [PATCH 166/222] imx-drm: dw-hdmi-cec: add " Russell King
@ 2014-04-25 11:48 ` Russell King
  2014-04-25 11:48 ` [PATCH 168/222] ARM: imx: enable HDMI DRM support for imx_v6_v7_defconfig Russell King
                   ` (55 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:48 UTC (permalink / raw)
  To: linux-arm-kernel

Add the HDMI DT configuration for the SolidRun HummingBoard and Cubox-i.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/boot/dts/imx6dl-hummingboard.dts | 28 ++++++++++++++++++++++++++++
 arch/arm/boot/dts/imx6qdl-cubox-i.dtsi    | 28 ++++++++++++++++++++++++++++
 2 files changed, 56 insertions(+)

diff --git a/arch/arm/boot/dts/imx6dl-hummingboard.dts b/arch/arm/boot/dts/imx6dl-hummingboard.dts
index 5bfae54fb780..d3095f58bf7b 100644
--- a/arch/arm/boot/dts/imx6dl-hummingboard.dts
+++ b/arch/arm/boot/dts/imx6dl-hummingboard.dts
@@ -67,6 +67,14 @@
 	status = "okay";
 };
 
+&hdmi {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_hummingboard_hdmi>;
+	ddc-i2c-bus = <&i2c2>;
+	status = "okay";
+	crtcs = <&ipu1 0>;
+};
+
 &i2c1 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_hummingboard_i2c1>;
@@ -82,6 +90,13 @@
 	 */
 };
 
+&i2c2 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_hummingboard_i2c2>;
+	status = "okay";
+};
+
 &iomuxc {
 	hummingboard {
 		pinctrl_hummingboard_flexcan1: hummingboard-flexcan1 {
@@ -97,6 +112,12 @@
 			>;
 		};
 
+		pinctrl_hummingboard_hdmi: hummingboard-hdmi {
+			fsl,pins = <
+				MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0
+			>;
+		};
+
 		pinctrl_hummingboard_i2c1: hummingboard-i2c1 {
 			fsl,pins = <
 				MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1
@@ -104,6 +125,13 @@
 			>;
 		};
 
+		pinctrl_hummingboard_i2c2: hummingboard-i2c2 {
+			fsl,pins = <
+				MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1
+				MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1
+			>;
+		};
+
 		pinctrl_hummingboard_spdif: hummingboard-spdif {
 			fsl,pins = <MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x13091>;
 		};
diff --git a/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi b/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
index c2a24888a276..5b9e7bceedaa 100644
--- a/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
@@ -55,6 +55,21 @@
 	};
 };
 
+&hdmi {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_cubox_i_hdmi>;
+	ddc-i2c-bus = <&i2c2>;
+	status = "okay";
+	crtcs = <&ipu1 0>;
+};
+
+&i2c2 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_cubox_i_i2c2>;
+	status = "okay";
+};
+
 &i2c3 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_cubox_i_i2c3>;
@@ -69,6 +84,19 @@
 
 &iomuxc {
 	cubox_i {
+		pinctrl_cubox_i_hdmi: cubox-i-hdmi {
+			fsl,pins = <
+				MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0
+			>;
+		};
+
+		pinctrl_cubox_i_i2c2: cubox-i-i2c2 {
+			fsl,pins = <
+				MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1
+				MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1
+			>;
+		};
+
 		pinctrl_cubox_i_i2c3: cubox-i-i2c3 {
 			fsl,pins = <
 				MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 168/222] ARM: imx: enable HDMI DRM support for imx_v6_v7_defconfig
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (166 preceding siblings ...)
  2014-04-25 11:48 ` [PATCH 167/222] ARM: imx: add HDMI support for SolidRun HummingBoard and Cubox-i Russell King
@ 2014-04-25 11:48 ` Russell King
  2014-04-25 11:49 ` [PATCH 169/222] drm/i915: don't disable disconnected outputs Russell King
                   ` (54 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:48 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/configs/imx_v6_v7_defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index 09e974392fa1..ea50d34f7944 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -245,6 +245,7 @@ CONFIG_DRM_IMX_TVE=y
 CONFIG_DRM_IMX_LDB=y
 CONFIG_DRM_IMX_IPUV3_CORE=y
 CONFIG_DRM_IMX_IPUV3=y
+CONFIG_DRM_IMX_HDMI=y
 CONFIG_COMMON_CLK_DEBUG=y
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_PWM=y
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 169/222] drm/i915: don't disable disconnected outputs
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (167 preceding siblings ...)
  2014-04-25 11:48 ` [PATCH 168/222] ARM: imx: enable HDMI DRM support for imx_v6_v7_defconfig Russell King
@ 2014-04-25 11:49 ` Russell King
  2014-04-25 11:49 ` [PATCH 170/222] drm: add generic ddc connector Russell King
                   ` (53 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:49 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Conflicts:
	drivers/gpu/drm/drm_crtc_helper.c
---
 drivers/gpu/drm/drm_crtc_helper.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index c43825e8f5c1..039dbcd1dd98 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -281,16 +281,10 @@ drm_encoder_disable(struct drm_encoder *encoder)
 static void __drm_helper_disable_unused_functions(struct drm_device *dev)
 {
 	struct drm_encoder *encoder;
-	struct drm_connector *connector;
 	struct drm_crtc *crtc;
 
 	drm_warn_on_modeset_not_all_locked(dev);
 
-	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-		if (!connector->encoder)
-			continue;
-	}
-
 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
 		if (!drm_helper_encoder_in_use(encoder)) {
 			drm_encoder_disable(encoder);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 170/222] drm: add generic ddc connector
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (168 preceding siblings ...)
  2014-04-25 11:49 ` [PATCH 169/222] drm/i915: don't disable disconnected outputs Russell King
@ 2014-04-25 11:49 ` Russell King
  2014-04-25 11:49 ` [PATCH 171/222] ARM: l2c: trial at enabling some Cortex-A9 optimisations Russell King
                   ` (52 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:49 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/Makefile            |  1 +
 drivers/staging/imx-drm/drm-ddc-connector.c | 92 +++++++++++++++++++++++++++++
 drivers/staging/imx-drm/drm-ddc-connector.h | 26 ++++++++
 drivers/staging/imx-drm/imx-hdmi.c          | 82 ++++++-------------------
 drivers/staging/imx-drm/imx-tve.c           | 63 ++++----------------
 5 files changed, 150 insertions(+), 114 deletions(-)
 create mode 100644 drivers/staging/imx-drm/drm-ddc-connector.c
 create mode 100644 drivers/staging/imx-drm/drm-ddc-connector.h

diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
index 2295a6805d69..5eabd5e4e456 100644
--- a/drivers/staging/imx-drm/Makefile
+++ b/drivers/staging/imx-drm/Makefile
@@ -3,6 +3,7 @@ imxdrm-objs := imx-drm-core.o
 
 obj-$(CONFIG_DRM_IMX) += imxdrm.o
 
+obj-$(CONFIG_DRM_IMX) += drm-ddc-connector.o
 obj-$(CONFIG_DRM_IMX_PARALLEL_DISPLAY) += parallel-display.o
 obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o
 obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
diff --git a/drivers/staging/imx-drm/drm-ddc-connector.c b/drivers/staging/imx-drm/drm-ddc-connector.c
new file mode 100644
index 000000000000..a36ed4b06ebe
--- /dev/null
+++ b/drivers/staging/imx-drm/drm-ddc-connector.c
@@ -0,0 +1,92 @@
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+
+#include "drm-ddc-connector.h"
+
+static enum drm_connector_status
+drm_ddc_connector_detect(struct drm_connector *connector, bool force)
+{
+	struct drm_ddc_connector *ddc_conn = to_ddc_conn(connector);
+
+	return ddc_conn->detect ? ddc_conn->detect(connector, force) :
+		connector_status_connected;
+}
+
+int drm_ddc_connector_get_modes(struct drm_connector *connector)
+{
+	struct drm_ddc_connector *ddc_conn = to_ddc_conn(connector);
+	struct edid *edid;
+	int ret = 0;
+
+	if (!ddc_conn->ddc)
+		return 0;
+
+	edid = drm_get_edid(connector, ddc_conn->ddc);
+	if (edid) {
+		drm_mode_connector_update_edid_property(connector, edid);
+		ret = drm_add_edid_modes(connector, edid);
+		/* Store the ELD */
+		drm_edid_to_eld(connector, edid);
+		kfree(edid);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(drm_ddc_connector_get_modes);
+
+static void drm_ddc_connector_destroy(struct drm_connector *connector)
+{
+	struct drm_ddc_connector *ddc_conn = to_ddc_conn(connector);
+
+	drm_sysfs_connector_remove(connector);
+	drm_connector_cleanup(connector);
+	if (ddc_conn->ddc)
+		i2c_put_adapter(ddc_conn->ddc);
+}
+
+static const struct drm_connector_funcs drm_ddc_connector_funcs = {
+	.dpms = drm_helper_connector_dpms,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.detect = drm_ddc_connector_detect,
+	.destroy = drm_ddc_connector_destroy,
+};
+
+int drm_ddc_connector_add(struct drm_device *drm,
+	struct drm_ddc_connector *ddc_conn, int connector_type)
+{
+	drm_connector_init(drm, &ddc_conn->connector, &drm_ddc_connector_funcs,
+			   connector_type);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(drm_ddc_connector_add);
+
+struct drm_ddc_connector *drm_ddc_connector_create(struct drm_device *drm,
+	struct device_node *np, void *private)
+{
+	struct drm_ddc_connector *ddc_conn;
+	struct device_node *ddc_node;
+
+	ddc_conn = devm_kzalloc(drm->dev, sizeof(*ddc_conn), GFP_KERNEL);
+	if (!ddc_conn)
+		return ERR_PTR(-ENOMEM);
+
+	ddc_conn->private = private;
+
+	ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
+	if (ddc_node) {
+		ddc_conn->ddc = of_find_i2c_adapter_by_node(ddc_node);
+		of_node_put(ddc_node);
+		if (!ddc_conn->ddc)
+			return ERR_PTR(-EPROBE_DEFER);
+	}
+
+	return ddc_conn;
+}
+EXPORT_SYMBOL_GPL(drm_ddc_connector_create);
+
+MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>");
+MODULE_DESCRIPTION("Generic DRM DDC connector module");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/imx-drm/drm-ddc-connector.h b/drivers/staging/imx-drm/drm-ddc-connector.h
new file mode 100644
index 000000000000..38068e5105d3
--- /dev/null
+++ b/drivers/staging/imx-drm/drm-ddc-connector.h
@@ -0,0 +1,26 @@
+#ifndef DRM_DDC_CONNECTOR_H
+#define DRM_DDC_CONNECTOR_H
+
+struct drm_ddc_connector {
+	struct i2c_adapter *ddc;
+	struct drm_connector connector;
+	enum drm_connector_status (*detect)(struct drm_connector *, bool);
+	void *private;
+};
+
+#define to_ddc_conn(c) container_of(c, struct drm_ddc_connector, connector)
+
+int drm_ddc_connector_get_modes(struct drm_connector *connector);
+int drm_ddc_connector_add(struct drm_device *drm,
+	struct drm_ddc_connector *ddc_conn, int connector_type);
+struct drm_ddc_connector *drm_ddc_connector_create(struct drm_device *drm,
+	struct device_node *np, void *private);
+
+static inline void *drm_ddc_private(struct drm_connector *connector)
+{
+	struct drm_ddc_connector *ddc_conn = to_ddc_conn(connector);
+
+	return ddc_conn->private;
+}
+
+#endif
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index c3bd89d34d40..627b4b608794 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -28,6 +28,7 @@
 #include <drm/drm_edid.h>
 #include <drm/drm_encoder_slave.h>
 
+#include "drm-ddc-connector.h"
 #include "dw-hdmi-audio.h"
 #include "dw-hdmi-cec.h"
 #include "ipu-v3/imx-ipu-v3.h"
@@ -114,7 +115,7 @@ struct hdmi_data_info {
 };
 
 struct imx_hdmi {
-	struct drm_connector connector;
+	struct drm_ddc_connector *ddc_conn;
 	struct drm_encoder encoder;
 
 	struct platform_device *audio;
@@ -135,7 +136,6 @@ struct imx_hdmi {
 	struct drm_display_mode previous_mode;
 
 	struct regmap *regmap;
-	struct i2c_adapter *ddc;
 	void __iomem *regs;
 
 	unsigned int sample_rate;
@@ -1392,45 +1392,16 @@ static void imx_hdmi_poweroff(struct imx_hdmi *hdmi)
 static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector
 							*connector, bool force)
 {
-	struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
-					     connector);
+	struct imx_hdmi *hdmi = drm_ddc_private(connector);
 
 	return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
 		connector_status_connected : connector_status_disconnected;
 }
 
-static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
-{
-	struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
-					     connector);
-	struct edid *edid;
-	int ret;
-
-	if (!hdmi->ddc)
-		return 0;
-
-	edid = drm_get_edid(connector, hdmi->ddc);
-	if (edid) {
-		dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n",
-			edid->width_cm, edid->height_cm);
-
-		drm_mode_connector_update_edid_property(connector, edid);
-		ret = drm_add_edid_modes(connector, edid);
-		/* Store the ELD */
-		drm_edid_to_eld(connector, edid);
-		kfree(edid);
-	} else {
-		dev_dbg(hdmi->dev, "failed to get edid\n");
-	}
-
-	return 0;
-}
-
 static struct drm_encoder *imx_hdmi_connector_best_encoder(struct drm_connector
 							   *connector)
 {
-	struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
-					     connector);
+	struct imx_hdmi *hdmi = drm_ddc_private(connector);
 
 	return &hdmi->encoder;
 }
@@ -1499,15 +1470,8 @@ static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = {
 	.disable = imx_hdmi_encoder_disable,
 };
 
-static struct drm_connector_funcs imx_hdmi_connector_funcs = {
-	.dpms = drm_helper_connector_dpms,
-	.fill_modes = drm_helper_probe_single_connector_modes,
-	.detect = imx_hdmi_connector_detect,
-	.destroy = imx_drm_connector_destroy,
-};
-
 static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
-	.get_modes = imx_hdmi_connector_get_modes,
+	.get_modes = drm_ddc_connector_get_modes,
 	.mode_valid = imx_drm_connector_mode_valid,
 	.best_encoder = imx_hdmi_connector_best_encoder,
 };
@@ -1549,7 +1513,7 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
 
 			imx_hdmi_poweroff(hdmi);
 		}
-		drm_helper_hpd_irq_event(hdmi->connector.dev);
+		drm_helper_hpd_irq_event(hdmi->ddc_conn->connector.dev);
 	}
 
 	hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
@@ -1567,20 +1531,17 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
 	if (ret)
 		return ret;
 
-	hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
+	hdmi->ddc_conn->connector.polled = DRM_CONNECTOR_POLL_HPD;
 
 	drm_encoder_helper_add(&hdmi->encoder, &imx_hdmi_encoder_helper_funcs);
 	drm_encoder_init(drm, &hdmi->encoder, &imx_hdmi_encoder_funcs,
 			 DRM_MODE_ENCODER_TMDS);
 
-	drm_connector_helper_add(&hdmi->connector,
+	drm_connector_helper_add(&hdmi->ddc_conn->connector,
 			&imx_hdmi_connector_helper_funcs);
-	drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs,
-			   DRM_MODE_CONNECTOR_HDMIA);
+	drm_ddc_connector_add(drm, hdmi->ddc_conn, DRM_MODE_CONNECTOR_HDMIA);
 
-	hdmi->connector.encoder = &hdmi->encoder;
-
-	drm_mode_connector_attach_encoder(&hdmi->connector, &hdmi->encoder);
+	drm_mode_connector_attach_encoder(&hdmi->ddc_conn->connector, &hdmi->encoder);
 
 	return 0;
 }
@@ -1632,7 +1593,6 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 				of_match_device(imx_hdmi_dt_ids, dev);
 	struct drm_device *drm = data;
 	struct device_node *np = dev->of_node;
-	struct device_node *ddc_node;
 	struct dw_hdmi_audio_data audio;
 	struct dw_hdmi_cec_data cec;
 	struct imx_hdmi *hdmi;
@@ -1643,6 +1603,12 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 	if (!hdmi)
 		return -ENOMEM;
 
+	hdmi->ddc_conn = drm_ddc_connector_create(drm, np, hdmi);
+	if (IS_ERR(hdmi->ddc_conn))
+		return PTR_ERR(hdmi->ddc_conn);
+
+	hdmi->ddc_conn->detect = imx_hdmi_connector_detect;
+
 	hdmi->dev = dev;
 	hdmi->sample_rate = 48000;
 	hdmi->ratio = 100;
@@ -1653,17 +1619,6 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 		hdmi->dev_type = device_id->driver_data;
 	}
 
-	ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
-	if (ddc_node) {
-		hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
-		if (!hdmi->ddc)
-			dev_dbg(hdmi->dev, "failed to read ddc node\n");
-
-		of_node_put(ddc_node);
-	} else {
-		dev_dbg(hdmi->dev, "no ddc property found\n");
-	}
-
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0)
 		return -EINVAL;
@@ -1757,7 +1712,7 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 	audio.base = hdmi->regs;
 	audio.irq = irq;
 	audio.hdmi = hdmi;
-	audio.eld = hdmi->connector.eld;
+	audio.eld = hdmi->ddc_conn->connector.eld;
 	audio.set_sample_rate = imx_hdmi_set_sample_rate;
 
 	pdevinfo.name = "dw-hdmi-audio";
@@ -1803,12 +1758,11 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master,
 	/* Disable all interrupts */
 	hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
 
-	hdmi->connector.funcs->destroy(&hdmi->connector);
+	hdmi->ddc_conn->connector.funcs->destroy(&hdmi->ddc_conn->connector);
 	hdmi->encoder.funcs->destroy(&hdmi->encoder);
 
 	clk_disable_unprepare(hdmi->iahb_clk);
 	clk_disable_unprepare(hdmi->isfr_clk);
-	i2c_put_adapter(hdmi->ddc);
 }
 
 static const struct component_ops hdmi_ops = {
diff --git a/drivers/staging/imx-drm/imx-tve.c b/drivers/staging/imx-drm/imx-tve.c
index 575533f4fd64..6eafba5072ad 100644
--- a/drivers/staging/imx-drm/imx-tve.c
+++ b/drivers/staging/imx-drm/imx-tve.c
@@ -22,7 +22,6 @@
 #include <linux/clk-provider.h>
 #include <linux/component.h>
 #include <linux/module.h>
-#include <linux/i2c.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/spinlock.h>
@@ -31,6 +30,7 @@
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_crtc_helper.h>
 
+#include "drm-ddc-connector.h"
 #include "ipu-v3/imx-ipu-v3.h"
 #include "imx-drm.h"
 
@@ -111,7 +111,7 @@ enum {
 };
 
 struct imx_tve {
-	struct drm_connector connector;
+	struct drm_ddc_connector *ddc_conn;
 	struct drm_encoder encoder;
 	struct device *dev;
 	spinlock_t lock;	/* register lock */
@@ -120,7 +120,6 @@ struct imx_tve {
 
 	struct regmap *regmap;
 	struct regulator *dac_reg;
-	struct i2c_adapter *ddc;
 	struct clk *clk;
 	struct clk *di_sel_clk;
 	struct clk_hw clk_hw_di;
@@ -219,35 +218,10 @@ static int tve_setup_vga(struct imx_tve *tve)
 	return 0;
 }
 
-static enum drm_connector_status imx_tve_connector_detect(
-				struct drm_connector *connector, bool force)
-{
-	return connector_status_connected;
-}
-
-static int imx_tve_connector_get_modes(struct drm_connector *connector)
-{
-	struct imx_tve *tve = con_to_tve(connector);
-	struct edid *edid;
-	int ret = 0;
-
-	if (!tve->ddc)
-		return 0;
-
-	edid = drm_get_edid(connector, tve->ddc);
-	if (edid) {
-		drm_mode_connector_update_edid_property(connector, edid);
-		ret = drm_add_edid_modes(connector, edid);
-		kfree(edid);
-	}
-
-	return ret;
-}
-
 static int imx_tve_connector_mode_valid(struct drm_connector *connector,
 					struct drm_display_mode *mode)
 {
-	struct imx_tve *tve = con_to_tve(connector);
+	struct imx_tve *tve = to_ddc_conn(connector)->private;
 	unsigned long rate;
 	int ret;
 
@@ -274,7 +248,7 @@ static int imx_tve_connector_mode_valid(struct drm_connector *connector,
 static struct drm_encoder *imx_tve_connector_best_encoder(
 		struct drm_connector *connector)
 {
-	struct imx_tve *tve = con_to_tve(connector);
+	struct imx_tve *tve = drm_ddc_private(connector);
 
 	return &tve->encoder;
 }
@@ -362,15 +336,8 @@ static void imx_tve_encoder_disable(struct drm_encoder *encoder)
 	tve_disable(tve);
 }
 
-static struct drm_connector_funcs imx_tve_connector_funcs = {
-	.dpms = drm_helper_connector_dpms,
-	.fill_modes = drm_helper_probe_single_connector_modes,
-	.detect = imx_tve_connector_detect,
-	.destroy = imx_drm_connector_destroy,
-};
-
 static struct drm_connector_helper_funcs imx_tve_connector_helper_funcs = {
-	.get_modes = imx_tve_connector_get_modes,
+	.get_modes = drm_ddc_connector_get_modes,
 	.best_encoder = imx_tve_connector_best_encoder,
 	.mode_valid = imx_tve_connector_mode_valid,
 };
@@ -513,12 +480,11 @@ static int imx_tve_register(struct drm_device *drm, struct imx_tve *tve)
 	drm_encoder_init(drm, &tve->encoder, &imx_tve_encoder_funcs,
 			 encoder_type);
 
-	drm_connector_helper_add(&tve->connector,
+	drm_connector_helper_add(&tve->ddc_conn->connector,
 			&imx_tve_connector_helper_funcs);
-	drm_connector_init(drm, &tve->connector, &imx_tve_connector_funcs,
-			   DRM_MODE_CONNECTOR_VGA);
+	drm_ddc_connector_add(drm, tve->ddc_conn, DRM_MODE_CONNECTOR_VGA);
 
-	drm_mode_connector_attach_encoder(&tve->connector, &tve->encoder);
+	drm_mode_connector_attach_encoder(&tve->ddc_conn->connector, &tve->encoder);
 
 	return 0;
 }
@@ -567,7 +533,6 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data)
 	struct platform_device *pdev = to_platform_device(dev);
 	struct drm_device *drm = data;
 	struct device_node *np = dev->of_node;
-	struct device_node *ddc_node;
 	struct imx_tve *tve;
 	struct resource *res;
 	void __iomem *base;
@@ -579,15 +544,13 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data)
 	if (!tve)
 		return -ENOMEM;
 
+	tve->ddc_conn = drm_ddc_connector_create(drm, np, tve);
+	if (IS_ERR(tve->ddc_conn))
+		return PTR_ERR(tve->ddc_conn);
+
 	tve->dev = dev;
 	spin_lock_init(&tve->lock);
 
-	ddc_node = of_parse_phandle(np, "i2c-ddc-bus", 0);
-	if (ddc_node) {
-		tve->ddc = of_find_i2c_adapter_by_node(ddc_node);
-		of_node_put(ddc_node);
-	}
-
 	tve->mode = of_get_tve_mode(np);
 	if (tve->mode != TVE_MODE_VGA) {
 		dev_err(dev, "only VGA mode supported, currently\n");
@@ -694,7 +657,7 @@ static void imx_tve_unbind(struct device *dev, struct device *master,
 {
 	struct imx_tve *tve = dev_get_drvdata(dev);
 
-	tve->connector.funcs->destroy(&tve->connector);
+	tve->ddc_conn->connector.funcs->destroy(&tve->ddc_conn->connector);
 	tve->encoder.funcs->destroy(&tve->encoder);
 
 	if (!IS_ERR(tve->dac_reg))
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 171/222] ARM: l2c: trial at enabling some Cortex-A9 optimisations
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (169 preceding siblings ...)
  2014-04-25 11:49 ` [PATCH 170/222] drm: add generic ddc connector Russell King
@ 2014-04-25 11:49 ` Russell King
  2014-04-25 11:49 ` [PATCH 172/222] ARM: l2c: move L2 cache register saving to a more sensible location Russell King
                   ` (51 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:49 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/include/asm/hardware/cache-l2x0.h |  8 ++++
 arch/arm/mm/cache-l2x0.c                   | 73 ++++++++++++++++++++++++++++--
 2 files changed, 78 insertions(+), 3 deletions(-)

diff --git a/arch/arm/include/asm/hardware/cache-l2x0.h b/arch/arm/include/asm/hardware/cache-l2x0.h
index 84bbd31b8910..3a5ec1c25659 100644
--- a/arch/arm/include/asm/hardware/cache-l2x0.h
+++ b/arch/arm/include/asm/hardware/cache-l2x0.h
@@ -134,6 +134,14 @@
 
 #define L310_ADDR_FILTER_EN		1
 
+#define L310_PREFETCH_CTRL_OFFSET_MASK		0x1f
+#define L310_PREFETCH_CTRL_DBL_LINEFILL_INCR	BIT(23)
+#define L310_PREFETCH_CTRL_PREFETCH_DROP	BIT(24)
+#define L310_PREFETCH_CTRL_DBL_LINEFILL_WRAP	BIT(27)
+#define L310_PREFETCH_CTRL_DATA_PREFETCH	BIT(28)
+#define L310_PREFETCH_CTRL_INSTR_PREFETCH	BIT(29)
+#define L310_PREFETCH_CTRL_DBL_LINEFILL		BIT(30)
+
 #define L2X0_CTRL_EN			1
 
 #define L2X0_WAY_SIZE_SHIFT		3
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 5de7f6c56306..c25977feabe1 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -16,14 +16,17 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
+#include <linux/cpu.h>
 #include <linux/err.h>
 #include <linux/init.h>
+#include <linux/smp.h>
 #include <linux/spinlock.h>
 #include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 
 #include <asm/cacheflush.h>
+#include <asm/cp15.h>
 #include <asm/cputype.h>
 #include <asm/hardware/cache-l2x0.h>
 #include "cache-tauros3.h"
@@ -618,7 +621,24 @@ static void l2c310_resume(void)
 				      L310_POWER_CTRL);
 
 		l2c_enable(base, l2x0_saved_regs.aux_ctrl, 8);
+
+		/* Re-enable full-line-of-zeros for Cortex-A9 */
+		if (l2x0_saved_regs.aux_ctrl & L310_AUX_CTRL_FULL_LINE_ZERO)
+			set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1));
+	}
+}
+
+static int l2c310_cpu_enable_flz(struct notifier_block *nb, unsigned long act, void *data)
+{
+	switch (act & ~CPU_TASKS_FROZEN) {
+	case CPU_STARTING:
+		set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1));
+		break;
+	case CPU_DYING:
+		set_auxcr(get_auxcr() & ~(BIT(3) | BIT(2) | BIT(1)));
+		break;
 	}
+	return NOTIFY_OK;
 }
 
 static void __init l2c310_enable(void __iomem *base, u32 aux, unsigned num_lock)
@@ -636,7 +656,42 @@ static void __init l2c310_enable(void __iomem *base, u32 aux, unsigned num_lock)
 		}
 	}
 
+	if (cortex_a9) {
+		u32 aux_cur = readl_relaxed(base + L2X0_AUX_CTRL);
+		u32 acr = get_auxcr();
+
+		pr_debug("Cortex-A9 ACR=0x%08x\n", acr);
+
+		if (acr & BIT(3) && !(aux_cur & L310_AUX_CTRL_FULL_LINE_ZERO))
+			pr_err("L2C-310: full line of zeros enabled in Cortex-A9 but not L2C-310 - invalid\n");
+
+		if (aux & L310_AUX_CTRL_FULL_LINE_ZERO && !(acr & BIT(3)))
+			pr_err("L2C-310: enabling full line of zeros but not enabled in Cortex-A9\n");
+
+		if (!(aux & L310_AUX_CTRL_FULL_LINE_ZERO) && !outer_cache.write_sec) {
+			aux |= L310_AUX_CTRL_FULL_LINE_ZERO;
+			pr_info("L2C-310 full line of zeros enabled for Cortex-A9\n");
+		}
+	} else if (aux & (L310_AUX_CTRL_FULL_LINE_ZERO | L310_AUX_CTRL_EARLY_BRESP)) {
+		pr_err("L2C-310: disabling Cortex-A9 specific feature bits\n");
+		aux &= ~(L310_AUX_CTRL_FULL_LINE_ZERO | L310_AUX_CTRL_EARLY_BRESP);
+	}
+
+	if (aux & (L310_AUX_CTRL_DATA_PREFETCH | L310_AUX_CTRL_INSTR_PREFETCH)) {
+		u32 prefetch = readl_relaxed(base + L310_PREFETCH_CTRL);
+
+		pr_info("L2C-310 %s%s prefetch enabled, offset %u lines\n",
+			aux & L310_AUX_CTRL_INSTR_PREFETCH ? "I" : "",
+			aux & L310_AUX_CTRL_DATA_PREFETCH ? "D" : "",
+			1 + (prefetch & L310_PREFETCH_CTRL_OFFSET_MASK));
+	}
+
 	l2c_enable(base, aux, num_lock);
+
+	if (aux & L310_AUX_CTRL_FULL_LINE_ZERO) {
+		set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1));
+		cpu_notifier(l2c310_cpu_enable_flz, 0);
+	}
 }
 
 static void __init l2c310_fixup(void __iomem *base, u32 cache_id,
@@ -692,6 +747,18 @@ static void __init l2c310_fixup(void __iomem *base, u32 cache_id,
 	}
 }
 
+static void l2c310_disable(void)
+{
+	/*
+	 * If full-line-of-zeros is enabled, we must first disable it in the
+	 * Cortex-A9 auxiliary control register before disabling the L2 cache.
+	 */
+	if (l2x0_saved_regs.aux_ctrl & L310_AUX_CTRL_FULL_LINE_ZERO)
+		set_auxcr(get_auxcr() & ~(BIT(3) | BIT(2) | BIT(1)));
+
+	l2c_disable();
+}
+
 static const struct l2c_init_data l2c310_init_fns __initconst = {
 	.type = "L2C-310",
 	.way_size_0 = SZ_8K,
@@ -704,7 +771,7 @@ static const struct l2c_init_data l2c310_init_fns __initconst = {
 		.clean_range = l2c210_clean_range,
 		.flush_range = l2c210_flush_range,
 		.flush_all = l2c210_flush_all,
-		.disable = l2c_disable,
+		.disable = l2c310_disable,
 		.sync = l2c210_sync,
 		.resume = l2c310_resume,
 	},
@@ -966,7 +1033,7 @@ static const struct l2c_init_data of_l2c310_data __initconst = {
 		.clean_range = l2c210_clean_range,
 		.flush_range = l2c210_flush_range,
 		.flush_all   = l2c210_flush_all,
-		.disable     = l2c_disable,
+		.disable     = l2c310_disable,
 		.sync        = l2c210_sync,
 		.resume      = l2c310_resume,
 	},
@@ -1313,7 +1380,7 @@ static const struct l2c_init_data of_bcm_l2x0_data __initconst = {
 		.clean_range = bcm_clean_range,
 		.flush_range = bcm_flush_range,
 		.flush_all   = l2c210_flush_all,
-		.disable     = l2c_disable,
+		.disable     = l2c310_disable,
 		.sync        = l2c210_sync,
 		.resume      = l2c310_resume,
 	},
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 172/222] ARM: l2c: move L2 cache register saving to a more sensible location
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (170 preceding siblings ...)
  2014-04-25 11:49 ` [PATCH 171/222] ARM: l2c: trial at enabling some Cortex-A9 optimisations Russell King
@ 2014-04-25 11:49 ` Russell King
  2014-04-25 11:50 ` [PATCH 173/222] ARM: l2c: always enable low power modes Russell King
                   ` (50 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:49 UTC (permalink / raw)
  To: linux-arm-kernel

Move the L2 cache register saving to a more sensible location - after
the cache has been enabled, and fixups have been run.  We move the
saving of the auxiliary control register into the ->save function as
well which makes everything operate in a sane and maintainable way.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 34 ++++++++++++++++++++++------------
 1 file changed, 22 insertions(+), 12 deletions(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index c25977feabe1..8c5219f6c104 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -202,6 +202,11 @@ static void l2x0_disable(void)
 	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
 }
 
+static void l2c_save(void __iomem *base)
+{
+	l2x0_saved_regs.aux_ctrl = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
+}
+
 /*
  * L2C-210 specific code.
  *
@@ -295,6 +300,7 @@ static const struct l2c_init_data l2c210_data __initconst = {
 	.way_size_0 = SZ_8K,
 	.num_lock = 1,
 	.enable = l2c_enable,
+	.save = l2c_save,
 	.outer_cache = {
 		.inv_range = l2c210_inv_range,
 		.clean_range = l2c210_clean_range,
@@ -439,6 +445,7 @@ static const struct l2c_init_data l2c220_data = {
 	.way_size_0 = SZ_8K,
 	.num_lock = 1,
 	.enable = l2c_enable,
+	.save = l2c_save,
 	.outer_cache = {
 		.inv_range = l2c220_inv_range,
 		.clean_range = l2c220_clean_range,
@@ -570,6 +577,8 @@ static void __init l2c310_save(void __iomem *base)
 {
 	unsigned revision;
 
+	l2c_save(base);
+
 	l2x0_saved_regs.tag_latency = readl_relaxed(base +
 		L310_TAG_LATENCY_CTRL);
 	l2x0_saved_regs.data_latency = readl_relaxed(base +
@@ -792,13 +801,6 @@ static void __init __l2c_init(const struct l2c_init_data *data,
 	if (aux_val & aux_mask)
 		pr_alert("L2C: platform provided aux values permit register corruption.\n");
 
-	/*
-	 * It is strange to save the register state before initialisation,
-	 * but hey, this is what the DT implementations decided to do.
-	 */
-	if (data->save)
-		data->save(l2x0_base);
-
 	old_aux = aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
 	aux &= aux_mask;
 	aux |= aux_val;
@@ -860,13 +862,17 @@ static void __init __l2c_init(const struct l2c_init_data *data,
 	if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN))
 		data->enable(l2x0_base, aux, data->num_lock);
 
-	/* Re-read it in case some bits are reserved. */
-	aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
+	outer_cache = fns;
 
-	/* Save the value for resuming. */
-	l2x0_saved_regs.aux_ctrl = aux;
+	/*
+	 * It is strange to save the register state before initialisation,
+	 * but hey, this is what the DT implementations decided to do.
+	 */
+	if (data->save)
+		data->save(l2x0_base);
 
-	outer_cache = fns;
+	/* Re-read it in case some bits are reserved. */
+	aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
 
 	pr_info("%s cache controller enabled, %d ways, %d kB\n",
 		data->type, ways, l2x0_size >> 10);
@@ -948,6 +954,7 @@ static const struct l2c_init_data of_l2c210_data __initconst = {
 	.num_lock = 1,
 	.of_parse = l2x0_of_parse,
 	.enable = l2c_enable,
+	.save = l2c_save,
 	.outer_cache = {
 		.inv_range   = l2c210_inv_range,
 		.clean_range = l2c210_clean_range,
@@ -965,6 +972,7 @@ static const struct l2c_init_data of_l2c220_data __initconst = {
 	.num_lock = 1,
 	.of_parse = l2x0_of_parse,
 	.enable = l2c_enable,
+	.save = l2c_save,
 	.outer_cache = {
 		.inv_range   = l2c220_inv_range,
 		.clean_range = l2c220_clean_range,
@@ -1388,6 +1396,8 @@ static const struct l2c_init_data of_bcm_l2x0_data __initconst = {
 
 static void __init tauros3_save(void __iomem *base)
 {
+	l2c_save(base);
+
 	l2x0_saved_regs.aux2_ctrl =
 		readl_relaxed(base + TAUROS3_AUX2_CTRL);
 	l2x0_saved_regs.prefetch_ctrl =
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 173/222] ARM: l2c: always enable low power modes
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (171 preceding siblings ...)
  2014-04-25 11:49 ` [PATCH 172/222] ARM: l2c: move L2 cache register saving to a more sensible location Russell King
@ 2014-04-25 11:50 ` Russell King
  2014-04-25 11:50 ` [PATCH 174/222] ARM: l2c: imx: remove direct write to power control register Russell King
                   ` (49 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:50 UTC (permalink / raw)
  To: linux-arm-kernel

Always enable the L2C low power modes on L2C-310 R3P0 and newer parts.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 Documentation/devicetree/bindings/arm/l2cc.txt |  2 --
 arch/arm/mm/cache-l2x0.c                       | 22 ++++++++++++----------
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/l2cc.txt b/Documentation/devicetree/bindings/arm/l2cc.txt
index e0dd400ecea6..b513cb8196fe 100644
--- a/Documentation/devicetree/bindings/arm/l2cc.txt
+++ b/Documentation/devicetree/bindings/arm/l2cc.txt
@@ -40,8 +40,6 @@ implementations of the L2 cache controller with compatible programming models.
 - arm,filter-ranges : <start length> Starting address and length of window to
   filter. Addresses in the filter window are directed to the M1 port. Other
   addresses will go to the M0 port.
-- arm,dynamic-clk-gating : Enables dynamic clock gating (PL310)
-- arm,standby-mode : Enables standby mode (PL310)
 - interrupts : 1 combined interrupt.
 - cache-id-part: cache id part number to be used if it is not present
   on hardware
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 8c5219f6c104..333ef64873f9 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -695,6 +695,18 @@ static void __init l2c310_enable(void __iomem *base, u32 aux, unsigned num_lock)
 			1 + (prefetch & L310_PREFETCH_CTRL_OFFSET_MASK));
 	}
 
+	/* r3p0 or later has power control register */
+	if (rev >= L310_CACHE_ID_RTL_R3P0) {
+		u32 power_ctrl;
+
+		l2c_write_sec(L310_DYNAMIC_CLK_GATING_EN | L310_STNDBY_MODE_EN,
+			      base, L310_POWER_CTRL);
+		power_ctrl = readl_relaxed(base + L310_POWER_CTRL);
+		pr_info("L2C-310 dynamic clock gating %sabled, standby mode %sabled\n",
+			power_ctrl & L310_DYNAMIC_CLK_GATING_EN ? "en" : "dis",
+			power_ctrl & L310_STNDBY_MODE_EN ? "en" : "dis");
+	}
+
 	l2c_enable(base, aux, num_lock);
 
 	if (aux & L310_AUX_CTRL_FULL_LINE_ZERO) {
@@ -990,7 +1002,6 @@ static void __init l2c310_of_parse(const struct device_node *np,
 	u32 data[3] = { 0, 0, 0 };
 	u32 tag[3] = { 0, 0, 0 };
 	u32 filter[2] = { 0, 0 };
-	u32 val;
 
 	of_property_read_u32_array(np, "arm,tag-latency", tag, ARRAY_SIZE(tag));
 	if (tag[0] && tag[1] && tag[2])
@@ -1017,15 +1028,6 @@ static void __init l2c310_of_parse(const struct device_node *np,
 		writel_relaxed((filter[0] & ~(SZ_1M - 1)) | L310_ADDR_FILTER_EN,
 			       l2x0_base + L310_ADDR_FILTER_START);
 	}
-
-	val = 0;
-	if (of_property_read_bool(np, "arm,dynamic-clk-gating"))
-		val |= L310_DYNAMIC_CLK_GATING_EN;
-	if (of_property_read_bool(np, "arm,standby-mode"))
-		val |= L310_STNDBY_MODE_EN;
-
-	if (val)
-		l2c_write_sec(val, l2x0_base, L310_POWER_CTRL);
 }
 
 static const struct l2c_init_data of_l2c310_data __initconst = {
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 174/222] ARM: l2c: imx: remove direct write to power control register
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (172 preceding siblings ...)
  2014-04-25 11:50 ` [PATCH 173/222] ARM: l2c: always enable low power modes Russell King
@ 2014-04-25 11:50 ` Russell King
  2014-04-25 11:50 ` [PATCH 175/222] ARM: l2c: omap2: avoid reading directly from the L2 registers in platform code Russell King
                   ` (48 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:50 UTC (permalink / raw)
  To: linux-arm-kernel

Now that we handle this in core code, we don't need platforms enabling
the low power modes directly.

Acked-by: Shawn Guo <shawn.guo@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-imx/system.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/arch/arm/mach-imx/system.c b/arch/arm/mach-imx/system.c
index 59013a81107b..3b0733edb68c 100644
--- a/arch/arm/mach-imx/system.c
+++ b/arch/arm/mach-imx/system.c
@@ -138,8 +138,6 @@ void __init imx_init_l2cache(void)
 	if (cpu_is_imx6q())
 		val &= ~(1 << 30 | 1 << 23);
 	writel_relaxed(val, l2x0_base + L310_PREFETCH_CTRL);
-	val = L310_DYNAMIC_CLK_GATING_EN | L310_STNDBY_MODE_EN;
-	writel_relaxed(val, l2x0_base + L310_POWER_CTRL);
 
 	iounmap(l2x0_base);
 	of_node_put(np);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 175/222] ARM: l2c: omap2: avoid reading directly from the L2 registers in platform code
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (173 preceding siblings ...)
  2014-04-25 11:50 ` [PATCH 174/222] ARM: l2c: imx: remove direct write to power control register Russell King
@ 2014-04-25 11:50 ` Russell King
  2014-04-25 11:50 ` [PATCH 176/222] ARM: l2c: provide common PL310 early resume code Russell King
                   ` (47 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:50 UTC (permalink / raw)
  To: linux-arm-kernel

Avoid reading directly from the L2 registers in platform code.  The L2
code will have already saved the register values itself into the
l2x0_saved_regs structure, so platform code should just move these
values to where they're required.

This is safe because the L2x0 will have been initialised by an early
initcall, whereas the OMAP4 PM code is initialised late.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-omap2/omap-mpuss-lowpower.c | 16 ++++++----------
 1 file changed, 6 insertions(+), 10 deletions(-)

diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
index ba43f49fbb59..61cb77f8cf12 100644
--- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c
+++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
@@ -187,19 +187,15 @@ static void l2x0_pwrst_prepare(unsigned int cpu_id, unsigned int save_state)
  * in every restore MPUSS OFF path.
  */
 #ifdef CONFIG_CACHE_L2X0
-static void save_l2x0_context(void)
+static void __init save_l2x0_context(void)
 {
-	u32 val;
-	void __iomem *l2x0_base = omap4_get_l2cache_base();
-	if (l2x0_base) {
-		val = __raw_readl(l2x0_base + L2X0_AUX_CTRL);
-		__raw_writel(val, sar_base + L2X0_AUXCTRL_OFFSET);
-		val = __raw_readl(l2x0_base + L310_PREFETCH_CTRL);
-		__raw_writel(val, sar_base + L2X0_PREFETCH_CTRL_OFFSET);
-	}
+	__raw_writel(l2x0_saved_regs.aux_ctrl,
+		     sar_base + L2X0_AUXCTRL_OFFSET);
+	__raw_writel(l2x0_saved_regs.prefetch_ctrl,
+		     sar_base + L2X0_PREFETCH_CTRL_OFFSET);
 }
 #else
-static void save_l2x0_context(void)
+static void __init save_l2x0_context(void)
 {}
 #endif
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 176/222] ARM: l2c: provide common PL310 early resume code
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (174 preceding siblings ...)
  2014-04-25 11:50 ` [PATCH 175/222] ARM: l2c: omap2: avoid reading directly from the L2 registers in platform code Russell King
@ 2014-04-25 11:50 ` Russell King
  2014-04-25 11:50 ` [PATCH 177/222] ARM: l2c: exynos: convert to common l2c310 early resume functionality Russell King
                   ` (46 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:50 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/Makefile          |  2 +-
 arch/arm/mm/l2c-l2x0-resume.S | 58 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 59 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/mm/l2c-l2x0-resume.S

diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index de5a6a27081b..91da64de440f 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -97,6 +97,6 @@ AFLAGS_proc-v7.o	:=-Wa,-march=armv7-a
 
 obj-$(CONFIG_OUTER_CACHE)	+= l2c-common.o
 obj-$(CONFIG_CACHE_FEROCEON_L2)	+= cache-feroceon-l2.o
-obj-$(CONFIG_CACHE_L2X0)	+= cache-l2x0.o
+obj-$(CONFIG_CACHE_L2X0)	+= cache-l2x0.o l2c-l2x0-resume.o
 obj-$(CONFIG_CACHE_XSC3L2)	+= cache-xsc3l2.o
 obj-$(CONFIG_CACHE_TAUROS2)	+= cache-tauros2.o
diff --git a/arch/arm/mm/l2c-l2x0-resume.S b/arch/arm/mm/l2c-l2x0-resume.S
new file mode 100644
index 000000000000..99b05f21a59a
--- /dev/null
+++ b/arch/arm/mm/l2c-l2x0-resume.S
@@ -0,0 +1,58 @@
+/*
+ * L2C-310 early resume code.  This can be used by platforms to restore
+ * the settings of their L2 cache controller before restoring the
+ * processor state.
+ *
+ * This code can only be used to if you are running in the secure world.
+ */
+#include <linux/linkage.h>
+#include <asm/hardware/cache-l2x0.h>
+
+	.text
+
+ENTRY(l2c310_early_resume)
+	adr	r0, 1f
+	ldr	r2, [r0]
+	add	r0, r2, r0
+
+	ldmia	r0, {r1, r2, r3, r4, r5, r6, r7, r8}
+	@ r1 = phys address of L2C-310 controller
+	@ r2 = aux_ctrl
+	@ r3 = tag_latency
+	@ r4 = data_latency
+	@ r5 = filter_start
+	@ r6 = filter_end
+	@ r7 = prefetch_ctrl
+	@ r8 = pwr_ctrl
+
+	@ Check that the address has been initialised
+	teq	r1, #0
+	moveq	pc, lr
+
+	@ The prefetch and power control registers are revision dependent
+	@ and can be written whether or not the L2 cache is enabled
+	ldr	r0, [r1, #L2X0_CACHE_ID]
+	and	r0, r0, #L2X0_CACHE_ID_RTL_MASK
+	cmp	r0, #L310_CACHE_ID_RTL_R2P0
+	strcs	r7, [r1, #L310_PREFETCH_CTRL]
+	cmp	r0, #L310_CACHE_ID_RTL_R3P0
+	strcs	r8, [r1, #L310_POWER_CTRL]
+
+	@ Don't setup the L2 cache if it is already enabled
+	ldr	r0, [r1, #L2X0_CTRL]
+	tst	r0, #L2X0_CTRL_EN
+	movne	pc, lr
+
+	str	r3, [r1, #L310_TAG_LATENCY_CTRL]
+	str	r4, [r1, #L310_DATA_LATENCY_CTRL]
+	str	r6, [r1, #L310_ADDR_FILTER_END]
+	str	r5, [r1, #L310_ADDR_FILTER_START]
+
+	str	r2, [r1, #L2X0_AUX_CTRL]
+	mov	r9, #L2X0_CTRL_EN
+	str	r9, [r1, #L2X0_CTRL]
+	mov	pc, lr
+ENDPROC(l2c310_early_resume)
+
+	.align
+1:	.long	l2x0_saved_regs - .
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 177/222] ARM: l2c: exynos: convert to common l2c310 early resume functionality
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (175 preceding siblings ...)
  2014-04-25 11:50 ` [PATCH 176/222] ARM: l2c: provide common PL310 early resume code Russell King
@ 2014-04-25 11:50 ` Russell King
  2014-04-25 11:50 ` [PATCH 178/222] ARM: l2c: tegra: " Russell King
                   ` (45 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:50 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-exynos/common.h     |  1 -
 arch/arm/mach-exynos/exynos.c     | 12 +-----------
 arch/arm/mach-exynos/sleep.S      | 30 +-----------------------------
 arch/arm/plat-samsung/s5p-sleep.S |  1 -
 4 files changed, 2 insertions(+), 42 deletions(-)

diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h
index 9ef3f83efaff..88c619d1e145 100644
--- a/arch/arm/mach-exynos/common.h
+++ b/arch/arm/mach-exynos/common.h
@@ -55,7 +55,6 @@ enum sys_powerdown {
 	NUM_SYS_POWERDOWN,
 };
 
-extern unsigned long l2x0_regs_phys;
 struct exynos_pmu_conf {
 	void __iomem *reg;
 	unsigned int val[NUM_SYS_POWERDOWN];
diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c
index a51bf25e7523..fbfc29df3299 100644
--- a/arch/arm/mach-exynos/exynos.c
+++ b/arch/arm/mach-exynos/exynos.c
@@ -318,17 +318,7 @@ core_initcall(exynos_core_init);
 
 static int __init exynos4_l2x0_cache_init(void)
 {
-	int ret;
-
-	ret = l2x0_of_init(0x3c400001, 0xc20fffff);
-	if (ret)
-		return ret;
-
-	if (IS_ENABLED(CONFIG_S5P_SLEEP)) {
-		l2x0_regs_phys = virt_to_phys(&l2x0_saved_regs);
-		clean_dcache_area(&l2x0_regs_phys, sizeof(unsigned long));
-	}
-	return 0;
+	return l2x0_of_init(0x3c400001, 0xc20fffff);
 }
 early_initcall(exynos4_l2x0_cache_init);
 
diff --git a/arch/arm/mach-exynos/sleep.S b/arch/arm/mach-exynos/sleep.S
index 7e0af530511e..108a45f4bb62 100644
--- a/arch/arm/mach-exynos/sleep.S
+++ b/arch/arm/mach-exynos/sleep.S
@@ -16,8 +16,6 @@
  */
 
 #include <linux/linkage.h>
-#include <asm/asm-offsets.h>
-#include <asm/hardware/cache-l2x0.h>
 
 #define CPU_MASK	0xff0ffff0
 #define CPU_CORTEX_A9	0x410fc090
@@ -53,33 +51,7 @@ ENTRY(exynos_cpu_resume)
 	and	r0, r0, r1
 	ldr	r1, =CPU_CORTEX_A9
 	cmp	r0, r1
-	bne	skip_l2_resume
-	adr	r0, l2x0_regs_phys
-	ldr	r0, [r0]
-	cmp	r0, #0
-	beq	skip_l2_resume
-	ldr	r1, [r0, #L2X0_R_PHY_BASE]
-	ldr	r2, [r1, #L2X0_CTRL]
-	tst	r2, #0x1
-	bne	skip_l2_resume
-	ldr	r2, [r0, #L2X0_R_AUX_CTRL]
-	str	r2, [r1, #L2X0_AUX_CTRL]
-	ldr	r2, [r0, #L2X0_R_TAG_LATENCY]
-	str	r2, [r1, #L310_TAG_LATENCY_CTRL]
-	ldr	r2, [r0, #L2X0_R_DATA_LATENCY]
-	str	r2, [r1, #L310_DATA_LATENCY_CTRL]
-	ldr	r2, [r0, #L2X0_R_PREFETCH_CTRL]
-	str	r2, [r1, #L310_PREFETCH_CTRL]
-	ldr	r2, [r0, #L2X0_R_PWR_CTRL]
-	str	r2, [r1, #L310_POWER_CTRL]
-	mov	r2, #1
-	str	r2, [r1, #L2X0_CTRL]
-skip_l2_resume:
+	bleq	l2c310_early_resume
 #endif
 	b	cpu_resume
 ENDPROC(exynos_cpu_resume)
-#ifdef CONFIG_CACHE_L2X0
-	.globl l2x0_regs_phys
-l2x0_regs_phys:
-	.long	0
-#endif
diff --git a/arch/arm/plat-samsung/s5p-sleep.S b/arch/arm/plat-samsung/s5p-sleep.S
index c5001659bdf8..25c68ceb9e2b 100644
--- a/arch/arm/plat-samsung/s5p-sleep.S
+++ b/arch/arm/plat-samsung/s5p-sleep.S
@@ -22,7 +22,6 @@
 */
 
 #include <linux/linkage.h>
-#include <asm/asm-offsets.h>
 
 	.data
 	.align
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 178/222] ARM: l2c: tegra: convert to common l2c310 early resume functionality
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (176 preceding siblings ...)
  2014-04-25 11:50 ` [PATCH 177/222] ARM: l2c: exynos: convert to common l2c310 early resume functionality Russell King
@ 2014-04-25 11:50 ` Russell King
  2014-04-25 11:50 ` [PATCH 179/222] ARM: l2c: imx: " Russell King
                   ` (44 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:50 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-tegra/pm.h            |  2 --
 arch/arm/mach-tegra/reset-handler.S | 11 +++--------
 arch/arm/mach-tegra/sleep.h         | 31 -------------------------------
 arch/arm/mach-tegra/tegra.c         |  6 +-----
 4 files changed, 4 insertions(+), 46 deletions(-)

diff --git a/arch/arm/mach-tegra/pm.h b/arch/arm/mach-tegra/pm.h
index 6e92a7c2ecbd..f4a89698e5b0 100644
--- a/arch/arm/mach-tegra/pm.h
+++ b/arch/arm/mach-tegra/pm.h
@@ -35,8 +35,6 @@ void tegra20_sleep_core_init(void);
 void tegra30_lp1_iram_hook(void);
 void tegra30_sleep_core_init(void);
 
-extern unsigned long l2x0_saved_regs_addr;
-
 void tegra_clear_cpu_in_lp2(void);
 bool tegra_set_cpu_in_lp2(void);
 
diff --git a/arch/arm/mach-tegra/reset-handler.S b/arch/arm/mach-tegra/reset-handler.S
index 8c1ba4fea384..578d4d1ad648 100644
--- a/arch/arm/mach-tegra/reset-handler.S
+++ b/arch/arm/mach-tegra/reset-handler.S
@@ -19,7 +19,6 @@
 
 #include <asm/cache.h>
 #include <asm/asm-offsets.h>
-#include <asm/hardware/cache-l2x0.h>
 
 #include "flowctrl.h"
 #include "fuse.h"
@@ -78,8 +77,10 @@ ENTRY(tegra_resume)
 	str	r1, [r0]
 #endif
 
+#ifdef CONFIG_CACHE_L2X0
 	/* L2 cache resume & re-enable */
-	l2_cache_resume r0, r1, r2, l2x0_saved_regs_addr
+	bl	l2c310_early_resume
+#endif
 end_ca9_scu_l2_resume:
 	mov32	r9, 0xc0f
 	cmp	r8, r9
@@ -89,12 +90,6 @@ end_ca9_scu_l2_resume:
 ENDPROC(tegra_resume)
 #endif
 
-#ifdef CONFIG_CACHE_L2X0
-	.globl	l2x0_saved_regs_addr
-l2x0_saved_regs_addr:
-	.long	0
-#endif
-
 	.align L1_CACHE_SHIFT
 ENTRY(__tegra_cpu_reset_handler_start)
 
diff --git a/arch/arm/mach-tegra/sleep.h b/arch/arm/mach-tegra/sleep.h
index a032820d2fac..339fe42cd6fb 100644
--- a/arch/arm/mach-tegra/sleep.h
+++ b/arch/arm/mach-tegra/sleep.h
@@ -120,37 +120,6 @@
 	mov	\tmp1, \tmp1, lsr #8
 .endm
 
-/* Macro to resume & re-enable L2 cache */
-#ifndef L2X0_CTRL_EN
-#define L2X0_CTRL_EN	1
-#endif
-
-#ifdef CONFIG_CACHE_L2X0
-.macro l2_cache_resume, tmp1, tmp2, tmp3, phys_l2x0_saved_regs
-	W(adr)	\tmp1, \phys_l2x0_saved_regs
-	ldr	\tmp1, [\tmp1]
-	ldr	\tmp2, [\tmp1, #L2X0_R_PHY_BASE]
-	ldr	\tmp3, [\tmp2, #L2X0_CTRL]
-	tst	\tmp3, #L2X0_CTRL_EN
-	bne	exit_l2_resume
-	ldr	\tmp3, [\tmp1, #L2X0_R_TAG_LATENCY]
-	str	\tmp3, [\tmp2, #L310_TAG_LATENCY_CTRL]
-	ldr	\tmp3, [\tmp1, #L2X0_R_DATA_LATENCY]
-	str	\tmp3, [\tmp2, #L310_DATA_LATENCY_CTRL]
-	ldr	\tmp3, [\tmp1, #L2X0_R_PREFETCH_CTRL]
-	str	\tmp3, [\tmp2, #L310_PREFETCH_CTRL]
-	ldr	\tmp3, [\tmp1, #L2X0_R_PWR_CTRL]
-	str	\tmp3, [\tmp2, #L310_POWER_CTRL]
-	ldr	\tmp3, [\tmp1, #L2X0_R_AUX_CTRL]
-	str	\tmp3, [\tmp2, #L2X0_AUX_CTRL]
-	mov	\tmp3, #L2X0_CTRL_EN
-	str	\tmp3, [\tmp2, #L2X0_CTRL]
-exit_l2_resume:
-.endm
-#else /* CONFIG_CACHE_L2X0 */
-.macro l2_cache_resume, tmp1, tmp2, tmp3, phys_l2x0_saved_regs
-.endm
-#endif /* CONFIG_CACHE_L2X0 */
 #else
 void tegra_pen_lock(void);
 void tegra_pen_unlock(void);
diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c
index fb802e24b647..1bc49f9db015 100644
--- a/arch/arm/mach-tegra/tegra.c
+++ b/arch/arm/mach-tegra/tegra.c
@@ -73,11 +73,7 @@ u32 tegra_uart_config[3] = {
 static void __init tegra_init_cache(void)
 {
 #ifdef CONFIG_CACHE_L2X0
-	int ret;
-
-	ret = l2x0_of_init(0x3c400001, 0xc20fc3fe);
-	if (!ret)
-		l2x0_saved_regs_addr = virt_to_phys(&l2x0_saved_regs);
+	l2x0_of_init(0x3c400001, 0xc20fc3fe);
 #endif
 }
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 179/222] ARM: l2c: imx: convert to common l2c310 early resume functionality
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (177 preceding siblings ...)
  2014-04-25 11:50 ` [PATCH 178/222] ARM: l2c: tegra: " Russell King
@ 2014-04-25 11:50 ` Russell King
  2014-04-25 11:50 ` [PATCH 180/222] ARM: l2c: always enable non-secure access to lockdown registers Russell King
                   ` (43 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:50 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-imx/suspend-imx6.S | 24 +++---------------------
 1 file changed, 3 insertions(+), 21 deletions(-)

diff --git a/arch/arm/mach-imx/suspend-imx6.S b/arch/arm/mach-imx/suspend-imx6.S
index 20048ff05739..fe123b079c05 100644
--- a/arch/arm/mach-imx/suspend-imx6.S
+++ b/arch/arm/mach-imx/suspend-imx6.S
@@ -334,28 +334,10 @@ ENDPROC(imx6_suspend)
  * turned into relative ones.
  */
 
-#ifdef CONFIG_CACHE_L2X0
-	.macro	pl310_resume
-	adr	r0, l2x0_saved_regs_offset
-	ldr	r2, [r0]
-	add	r2, r2, r0
-	ldr	r0, [r2, #L2X0_R_PHY_BASE]	@ get physical base of l2x0
-	ldr	r1, [r2, #L2X0_R_AUX_CTRL]	@ get aux_ctrl value
-	str	r1, [r0, #L2X0_AUX_CTRL]	@ restore aux_ctrl
-	mov	r1, #0x1
-	str	r1, [r0, #L2X0_CTRL]		@ re-enable L2
-	.endm
-
-l2x0_saved_regs_offset:
-	.word	l2x0_saved_regs - .
-
-#else
-	.macro	pl310_resume
-	.endm
-#endif
-
 ENTRY(v7_cpu_resume)
 	bl	v7_invalidate_l1
-	pl310_resume
+#ifdef CONFIG_CACHE_L2X0
+	bl	l2c310_early_resume
+#endif
 	b	cpu_resume
 ENDPROC(v7_cpu_resume)
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 180/222] ARM: l2c: always enable non-secure access to lockdown registers
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (178 preceding siblings ...)
  2014-04-25 11:50 ` [PATCH 179/222] ARM: l2c: imx: " Russell King
@ 2014-04-25 11:50 ` Russell King
  2014-04-25 11:55 ` [PATCH 181/222] ARM: l2c: omap2+: get rid of redundant cache replacement policy setting Russell King
                   ` (42 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:50 UTC (permalink / raw)
  To: linux-arm-kernel

Since we always write to these during the cache initialisation, it is
a good idea to always have the non-secure access bit set.  Set it in
core code and remove it from OMAP4.  Remove the NS access bit for the
interrupt registers from OMAP4 as well - nothing in the kernel accesses
that yet, and we can add it in core code when we have the need.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-omap2/omap4-common.c |  6 ++----
 arch/arm/mm/cache-l2x0.c           | 23 +++++++++++++++++++++--
 2 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c
index 06c6a181d6ad..df3f53195c57 100644
--- a/arch/arm/mach-omap2/omap4-common.c
+++ b/arch/arm/mach-omap2/omap4-common.c
@@ -214,17 +214,15 @@ static int __init omap_l2_cache_init(void)
 
 	/* 16-way associativity, parity disabled, way size - 64KB (es2.0 +) */
 	aux_ctrl = L310_AUX_CTRL_CACHE_REPLACE_RR |
-		   L310_AUX_CTRL_NS_LOCKDOWN |
-		   L310_AUX_CTRL_NS_INT_CTRL |
 		   L2C_AUX_CTRL_SHARED_OVERRIDE |
 		   L310_AUX_CTRL_DATA_PREFETCH |
 		   L310_AUX_CTRL_INSTR_PREFETCH;
 
 	outer_cache.write_sec = omap4_l2c310_write_sec;
 	if (of_have_populated_dt())
-		l2x0_of_init(aux_ctrl, 0xc19fffff);
+		l2x0_of_init(aux_ctrl, 0xcd9fffff);
 	else
-		l2x0_init(l2cache_base, aux_ctrl, 0xc19fffff);
+		l2x0_init(l2cache_base, aux_ctrl, 0xcd9fffff);
 
 	return 0;
 }
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 333ef64873f9..efc5cabf70e0 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -440,11 +440,23 @@ static void l2c220_sync(void)
 	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
 }
 
+static void l2c220_enable(void __iomem *base, u32 aux, unsigned num_lock)
+{
+	/*
+	 * Always enable non-secure access to the lockdown registers -
+	 * we write to them as part of the L2C enable sequence so they
+	 * need to be accessible.
+	 */
+	aux |= L220_AUX_CTRL_NS_LOCKDOWN;
+
+	l2c_enable(base, aux, num_lock);
+}
+
 static const struct l2c_init_data l2c220_data = {
 	.type = "L2C-220",
 	.way_size_0 = SZ_8K,
 	.num_lock = 1,
-	.enable = l2c_enable,
+	.enable = l2c220_enable,
 	.save = l2c_save,
 	.outer_cache = {
 		.inv_range = l2c220_inv_range,
@@ -707,6 +719,13 @@ static void __init l2c310_enable(void __iomem *base, u32 aux, unsigned num_lock)
 			power_ctrl & L310_STNDBY_MODE_EN ? "en" : "dis");
 	}
 
+	/*
+	 * Always enable non-secure access to the lockdown registers -
+	 * we write to them as part of the L2C enable sequence so they
+	 * need to be accessible.
+	 */
+	aux |= L310_AUX_CTRL_NS_LOCKDOWN;
+
 	l2c_enable(base, aux, num_lock);
 
 	if (aux & L310_AUX_CTRL_FULL_LINE_ZERO) {
@@ -983,7 +1002,7 @@ static const struct l2c_init_data of_l2c220_data __initconst = {
 	.way_size_0 = SZ_8K,
 	.num_lock = 1,
 	.of_parse = l2x0_of_parse,
-	.enable = l2c_enable,
+	.enable = l2c220_enable,
 	.save = l2c_save,
 	.outer_cache = {
 		.inv_range   = l2c220_inv_range,
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 181/222] ARM: l2c: omap2+: get rid of redundant cache replacement policy setting
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (179 preceding siblings ...)
  2014-04-25 11:50 ` [PATCH 180/222] ARM: l2c: always enable non-secure access to lockdown registers Russell King
@ 2014-04-25 11:55 ` Russell King
  2014-04-25 11:55 ` [PATCH 182/222] ARM: l2c: omap2+: get rid of init call Russell King
                   ` (41 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:55 UTC (permalink / raw)
  To: linux-arm-kernel

From: Sekhar Nori <nsekhar@ti.com>
To: linux-arm-kernel at lists.infradead.org

L2 cache initialization for OMAP4 redundantly sets the cache policy to
Round-Robin. This is not needed since thats the PL310 default anyway.

Removing this reduces the number of platform specific aux control
settings.

Signed-off-by: Sekhar Nori <nsekhar@ti.com>
Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-omap2/omap4-common.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c
index df3f53195c57..6927d5b120fe 100644
--- a/arch/arm/mach-omap2/omap4-common.c
+++ b/arch/arm/mach-omap2/omap4-common.c
@@ -213,16 +213,15 @@ static int __init omap_l2_cache_init(void)
 		return -ENOMEM;
 
 	/* 16-way associativity, parity disabled, way size - 64KB (es2.0 +) */
-	aux_ctrl = L310_AUX_CTRL_CACHE_REPLACE_RR |
-		   L2C_AUX_CTRL_SHARED_OVERRIDE |
+	aux_ctrl = L2C_AUX_CTRL_SHARED_OVERRIDE |
 		   L310_AUX_CTRL_DATA_PREFETCH |
 		   L310_AUX_CTRL_INSTR_PREFETCH;
 
 	outer_cache.write_sec = omap4_l2c310_write_sec;
 	if (of_have_populated_dt())
-		l2x0_of_init(aux_ctrl, 0xcd9fffff);
+		l2x0_of_init(aux_ctrl, 0xcf9fffff);
 	else
-		l2x0_init(l2cache_base, aux_ctrl, 0xcd9fffff);
+		l2x0_init(l2cache_base, aux_ctrl, 0xcf9fffff);
 
 	return 0;
 }
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 182/222] ARM: l2c: omap2+: get rid of init call
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (180 preceding siblings ...)
  2014-04-25 11:55 ` [PATCH 181/222] ARM: l2c: omap2+: get rid of redundant cache replacement policy setting Russell King
@ 2014-04-25 11:55 ` Russell King
  2014-04-25 11:55 ` [PATCH 183/222] ARM: l2c: AM43x: add L2 cache support Russell King
                   ` (40 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:55 UTC (permalink / raw)
  To: linux-arm-kernel

From: Sekhar Nori <nsekhar@ti.com>
To: linux-arm-kernel at lists.infradead.org

Get rid of init call to initialize L2 cache.  Instead use the init_early
machine hook. This helps in using the initialization routine across
SoCs without the need of ugly cpu_is_*() checks.

Signed-off-by: Sekhar Nori <nsekhar@ti.com>
Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-omap2/common.h       |  1 +
 arch/arm/mach-omap2/io.c           |  1 +
 arch/arm/mach-omap2/omap4-common.c | 10 +---------
 3 files changed, 3 insertions(+), 9 deletions(-)

diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h
index d88aff7baff8..ff029737c8f0 100644
--- a/arch/arm/mach-omap2/common.h
+++ b/arch/arm/mach-omap2/common.h
@@ -91,6 +91,7 @@ extern void omap3_sync32k_timer_init(void);
 extern void omap3_secure_sync32k_timer_init(void);
 extern void omap3_gptimer_timer_init(void);
 extern void omap4_local_timer_init(void);
+int omap_l2_cache_init(void);
 extern void omap5_realtime_timer_init(void);
 
 void omap2420_init_early(void);
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index f14f9ac2dca1..b28299b5afd5 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -640,6 +640,7 @@ void __init omap4430_init_early(void)
 	omap44xx_clockdomains_init();
 	omap44xx_hwmod_init();
 	omap_hwmod_init_postsetup();
+	omap_l2_cache_init();
 	omap_clk_soc_init = omap4xxx_dt_clk_init;
 }
 
diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c
index 6927d5b120fe..c41ff8b638e1 100644
--- a/arch/arm/mach-omap2/omap4-common.c
+++ b/arch/arm/mach-omap2/omap4-common.c
@@ -196,17 +196,10 @@ static void omap4_l2c310_write_sec(unsigned long val, unsigned reg)
 	omap_smc1(smc_op, val);
 }
 
-static int __init omap_l2_cache_init(void)
+int __init omap_l2_cache_init(void)
 {
 	u32 aux_ctrl;
 
-	/*
-	 * To avoid code running on other OMAPs in
-	 * multi-omap builds
-	 */
-	if (!cpu_is_omap44xx())
-		return -ENODEV;
-
 	/* Static mapping, never released */
 	l2cache_base = ioremap(OMAP44XX_L2CACHE_BASE, SZ_4K);
 	if (WARN_ON(!l2cache_base))
@@ -225,7 +218,6 @@ static int __init omap_l2_cache_init(void)
 
 	return 0;
 }
-omap_early_initcall(omap_l2_cache_init);
 #endif
 
 void __iomem *omap4_get_sar_ram_base(void)
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 183/222] ARM: l2c: AM43x: add L2 cache support
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (181 preceding siblings ...)
  2014-04-25 11:55 ` [PATCH 182/222] ARM: l2c: omap2+: get rid of init call Russell King
@ 2014-04-25 11:55 ` Russell King
  2014-04-25 11:55 ` [PATCH 184/222] ARM: l2c: permit flush_all() on large flush_range() XXX Needs more thought XXX Russell King
                   ` (39 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:55 UTC (permalink / raw)
  To: linux-arm-kernel

From: Sekhar Nori <nsekhar@ti.com>
To: linux-arm-kernel at lists.infradead.org

Add support for L2 cache controller (PL310) on AM437x SoC.

Signed-off-by: Sekhar Nori <nsekhar@ti.com>
Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-omap2/Kconfig | 1 +
 arch/arm/mach-omap2/io.c    | 1 +
 2 files changed, 2 insertions(+)

diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index cb31d4390d52..0ba482638ebf 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -65,6 +65,7 @@ config SOC_AM43XX
 	select ARCH_HAS_OPP
 	select ARM_GIC
 	select MACH_OMAP_GENERIC
+	select MIGHT_HAVE_CACHE_L2X0
 
 config SOC_DRA7XX
 	bool "TI DRA7XX"
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index b28299b5afd5..4e2df49991ad 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -609,6 +609,7 @@ void __init am43xx_init_early(void)
 	am43xx_clockdomains_init();
 	am43xx_hwmod_init();
 	omap_hwmod_init_postsetup();
+	omap_l2_cache_init();
 	omap_clk_soc_init = am43xx_dt_clk_init;
 }
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 184/222] ARM: l2c: permit flush_all() on large flush_range() XXX Needs more thought XXX
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (182 preceding siblings ...)
  2014-04-25 11:55 ` [PATCH 183/222] ARM: l2c: AM43x: add L2 cache support Russell King
@ 2014-04-25 11:55 ` Russell King
  2014-04-25 11:55 ` [PATCH 185/222] mmc: sdio_irq: rework sdio irq handling Russell King
                   ` (38 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:55 UTC (permalink / raw)
  To: linux-arm-kernel

In order to allow flush_all() to be used in normal operation, we need
some locking to prevent any other cache operations being issued while
a background flush_all() operation is proceeding.  The read-write
spinlock provides what's necessary here, but we must avoid bringing
lockdep issues into this code.  Hence we continue to use the raw_*
operations, and use the arch read/write spinlock implementation
directly.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/cache-l2x0.c | 90 ++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 79 insertions(+), 11 deletions(-)

diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index efc5cabf70e0..40bc281f2463 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -56,6 +56,54 @@ struct l2x0_regs l2x0_saved_regs;
 /*
  * Common code for all cache controllers.
  */
+#ifdef CONFIG_SMP
+static arch_rwlock_t l2c_rw_lock = __ARCH_RW_LOCK_UNLOCKED;
+
+static unsigned long l2c_lock_exclusive(void)
+{
+	unsigned long flags;
+	raw_local_irq_save(flags);
+	arch_write_lock(&l2c_rw_lock);
+	return flags;
+}
+
+static void l2c_unlock_exclusive(unsigned long flags)
+{
+	arch_write_unlock(&l2c_rw_lock);
+	raw_local_irq_restore(flags);
+}
+
+static void l2c_lock_shared(void)
+{
+	arch_read_lock(&l2c_rw_lock);
+}
+
+static void l2c_unlock_shared(void)
+{
+	arch_read_unlock(&l2c_rw_lock);
+}
+#else
+static unsigned long l2c_lock_exclusive(void)
+{
+	unsigned long flags;
+	raw_local_irq_save(flags);
+	return flags;
+}
+
+static void l2c_unlock_exclusive(unsigned long flags)
+{
+	raw_local_irq_restore(flags);
+}
+
+static void l2c_lock_shared(void)
+{
+}
+
+static void l2c_unlock_shared(void)
+{
+}
+#endif
+
 static inline void l2c_wait_mask(void __iomem *reg, unsigned long mask)
 {
 	/* wait for cache operation by line or way to complete */
@@ -239,6 +287,7 @@ static void l2c210_inv_range(unsigned long start, unsigned long end)
 {
 	void __iomem *base = l2x0_base;
 
+	l2c_lock_shared();
 	if (start & (CACHE_LINE_SIZE - 1)) {
 		start &= ~(CACHE_LINE_SIZE - 1);
 		writel_relaxed(start, base + L2X0_CLEAN_INV_LINE_PA);
@@ -252,6 +301,7 @@ static void l2c210_inv_range(unsigned long start, unsigned long end)
 
 	__l2c210_op_pa_range(base + L2X0_INV_LINE_PA, start, end);
 	__l2c210_cache_sync(base);
+	l2c_unlock_shared();
 }
 
 static void l2c210_clean_range(unsigned long start, unsigned long end)
@@ -259,8 +309,10 @@ static void l2c210_clean_range(unsigned long start, unsigned long end)
 	void __iomem *base = l2x0_base;
 
 	start &= ~(CACHE_LINE_SIZE - 1);
+	l2c_lock_shared();
 	__l2c210_op_pa_range(base + L2X0_CLEAN_LINE_PA, start, end);
 	__l2c210_cache_sync(base);
+	l2c_unlock_shared();
 }
 
 static void l2c210_flush_range(unsigned long start, unsigned long end)
@@ -268,23 +320,33 @@ static void l2c210_flush_range(unsigned long start, unsigned long end)
 	void __iomem *base = l2x0_base;
 
 	start &= ~(CACHE_LINE_SIZE - 1);
+	if ((end - start) >= l2x0_size) {
+		outer_cache.flush_all();
+		return;
+	}
+
+	l2c_lock_shared();
 	__l2c210_op_pa_range(base + L2X0_CLEAN_INV_LINE_PA, start, end);
 	__l2c210_cache_sync(base);
+	l2c_unlock_shared();
 }
 
 static void l2c210_flush_all(void)
 {
 	void __iomem *base = l2x0_base;
+	unsigned long flags;
 
-	BUG_ON(!irqs_disabled());
-
+	flags = l2c_lock_exclusive();
 	__l2c_op_way(base + L2X0_CLEAN_INV_WAY);
 	__l2c210_cache_sync(base);
+	l2c_unlock_exclusive(flags);
 }
 
 static void l2c210_sync(void)
 {
+	l2c_lock_shared();
 	__l2c210_cache_sync(l2x0_base);
+	l2c_unlock_shared();
 }
 
 static void l2c210_resume(void)
@@ -521,7 +583,7 @@ static void l2c310_inv_range_erratum(unsigned long start, unsigned long end)
 		unsigned long flags;
 
 		/* Erratum 588369 for both clean+invalidate operations */
-		raw_spin_lock_irqsave(&l2x0_lock, flags);
+		flags = l2c_lock_exclusive();
 		l2c_set_debug(base, 0x03);
 
 		if (start & (CACHE_LINE_SIZE - 1)) {
@@ -538,20 +600,26 @@ static void l2c310_inv_range_erratum(unsigned long start, unsigned long end)
 		}
 
 		l2c_set_debug(base, 0x00);
-		raw_spin_unlock_irqrestore(&l2x0_lock, flags);
+		l2c_unlock_exclusive(flags);
 	}
 
+	l2c_lock_shared();
 	__l2c210_op_pa_range(base + L2X0_INV_LINE_PA, start, end);
 	__l2c210_cache_sync(base);
+	l2c_unlock_shared();
 }
 
 static void l2c310_flush_range_erratum(unsigned long start, unsigned long end)
 {
-	raw_spinlock_t *lock = &l2x0_lock;
 	unsigned long flags;
 	void __iomem *base = l2x0_base;
 
-	raw_spin_lock_irqsave(lock, flags);
+	if ((end - start) >= l2x0_size) {
+		outer_cache.flush_all();
+		return;
+	}
+
+	flags = l2c_lock_exclusive();
 	while (start < end) {
 		unsigned long blk_end = start + min(end - start, 4096UL);
 
@@ -564,12 +632,12 @@ static void l2c310_flush_range_erratum(unsigned long start, unsigned long end)
 		l2c_set_debug(base, 0x00);
 
 		if (blk_end < end) {
-			raw_spin_unlock_irqrestore(lock, flags);
-			raw_spin_lock_irqsave(lock, flags);
+			l2c_unlock_exclusive(flags);
+			flags = l2c_lock_exclusive();
 		}
 	}
-	raw_spin_unlock_irqrestore(lock, flags);
 	__l2c210_cache_sync(base);
+	l2c_unlock_exclusive(flags);
 }
 
 static void l2c310_flush_all_erratum(void)
@@ -577,12 +645,12 @@ static void l2c310_flush_all_erratum(void)
 	void __iomem *base = l2x0_base;
 	unsigned long flags;
 
-	raw_spin_lock_irqsave(&l2x0_lock, flags);
+	flags = l2c_lock_exclusive();
 	l2c_set_debug(base, 0x03);
 	__l2c_op_way(base + L2X0_CLEAN_INV_WAY);
 	l2c_set_debug(base, 0x00);
 	__l2c210_cache_sync(base);
-	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
+	l2c_unlock_exclusive(flags);
 }
 
 static void __init l2c310_save(void __iomem *base)
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 185/222] mmc: sdio_irq: rework sdio irq handling
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (183 preceding siblings ...)
  2014-04-25 11:55 ` [PATCH 184/222] ARM: l2c: permit flush_all() on large flush_range() XXX Needs more thought XXX Russell King
@ 2014-04-25 11:55 ` Russell King
  2014-04-25 11:55 ` [PATCH 186/222] mmc: sdhci: clean up interrupt handling Russell King
                   ` (37 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:55 UTC (permalink / raw)
  To: linux-arm-kernel

Rather than the SDIO support spawning it's own thread for handling card
interrupts, use the generic IRQ infrastructure for this, triggering it
from the host interface's interrupt handling directly.

This avoids a race between the parent thread waiting to receive an
interrupt response from the card, and the slow startup from the sdio
irq thread, which can occur as a result of high system load (eg, while
udev is running.)

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/core/sdio_irq.c | 41 +++++++++++++++++++++++++++++++----------
 include/linux/mmc/host.h    |  3 +++
 2 files changed, 34 insertions(+), 10 deletions(-)

diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
index aaa90460ed23..5cc13c8d35bb 100644
--- a/drivers/mmc/core/sdio_irq.c
+++ b/drivers/mmc/core/sdio_irq.c
@@ -90,6 +90,15 @@ static int process_sdio_pending_irqs(struct mmc_host *host)
 	return ret;
 }
 
+void sdio_run_irqs(struct mmc_host *host)
+{
+	mmc_claim_host(host);
+	host->sdio_irq_pending = true;
+	process_sdio_pending_irqs(host);
+	mmc_release_host(host);
+}
+EXPORT_SYMBOL_GPL(sdio_run_irqs);
+
 static int sdio_irq_thread(void *_host)
 {
 	struct mmc_host *host = _host;
@@ -189,14 +198,20 @@ static int sdio_card_irq_get(struct mmc_card *card)
 	WARN_ON(!host->claimed);
 
 	if (!host->sdio_irqs++) {
-		atomic_set(&host->sdio_irq_thread_abort, 0);
-		host->sdio_irq_thread =
-			kthread_run(sdio_irq_thread, host, "ksdioirqd/%s",
-				mmc_hostname(host));
-		if (IS_ERR(host->sdio_irq_thread)) {
-			int err = PTR_ERR(host->sdio_irq_thread);
-			host->sdio_irqs--;
-			return err;
+		if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) {
+			atomic_set(&host->sdio_irq_thread_abort, 0);
+			host->sdio_irq_thread =
+				kthread_run(sdio_irq_thread, host,
+					    "ksdioirqd/%s", mmc_hostname(host));
+			if (IS_ERR(host->sdio_irq_thread)) {
+				int err = PTR_ERR(host->sdio_irq_thread);
+				host->sdio_irqs--;
+				return err;
+			}
+		} else {
+			mmc_host_clk_hold(host);
+			host->ops->enable_sdio_irq(host, 1);
+			mmc_host_clk_release(host);
 		}
 	}
 
@@ -211,8 +226,14 @@ static int sdio_card_irq_put(struct mmc_card *card)
 	BUG_ON(host->sdio_irqs < 1);
 
 	if (!--host->sdio_irqs) {
-		atomic_set(&host->sdio_irq_thread_abort, 1);
-		kthread_stop(host->sdio_irq_thread);
+		if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) {
+			atomic_set(&host->sdio_irq_thread_abort, 1);
+			kthread_stop(host->sdio_irq_thread);
+		} else {
+			mmc_host_clk_hold(host);
+			host->ops->enable_sdio_irq(host, 0);
+			mmc_host_clk_release(host);
+		}
 	}
 
 	return 0;
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index cb61ea4d6945..4c0f94679898 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -278,6 +278,7 @@ struct mmc_host {
 #define MMC_CAP2_PACKED_CMD	(MMC_CAP2_PACKED_RD | \
 				 MMC_CAP2_PACKED_WR)
 #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)	/* Don't power up before scan */
+#define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 15)
 
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 
@@ -391,6 +392,8 @@ static inline void mmc_signal_sdio_irq(struct mmc_host *host)
 	wake_up_process(host->sdio_irq_thread);
 }
 
+void sdio_run_irqs(struct mmc_host *host);
+
 #ifdef CONFIG_REGULATOR
 int mmc_regulator_get_ocrmask(struct regulator *supply);
 int mmc_regulator_set_ocr(struct mmc_host *mmc,
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 186/222] mmc: sdhci: clean up interrupt handling
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (184 preceding siblings ...)
  2014-04-25 11:55 ` [PATCH 185/222] mmc: sdio_irq: rework sdio irq handling Russell King
@ 2014-04-25 11:55 ` Russell King
  2014-04-25 11:55 ` [PATCH 187/222] mmc: sdhci: clean up sdio interrupt enable handling Russell King
                   ` (36 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:55 UTC (permalink / raw)
  To: linux-arm-kernel

sdhci interrupt handling is a mess; there is a lot of code doing very
similar things.  Let's clean this up a bit:

1. set's clear down cmd, data and bus power interrupts in one go - we're
   always going to handle these.
2. use a do { } while () loop for looping while there are pending
   interrupts.
3. group clearing of bits in intmask into one place.

This results in the code becoming simpler and easier to read.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci.c | 124 ++++++++++++++++++++++-------------------------
 1 file changed, 58 insertions(+), 66 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 9a79fc4b60ca..79838de6b278 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2426,7 +2426,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
 {
 	irqreturn_t result;
 	struct sdhci_host *host = dev_id;
-	u32 intmask, unexpected = 0;
+	u32 intmask, mask, unexpected = 0;
 	int cardint = 0, max_loops = 16;
 
 	spin_lock(&host->lock);
@@ -2437,88 +2437,80 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
 	}
 
 	intmask = sdhci_readl(host, SDHCI_INT_STATUS);
-
 	if (!intmask || intmask == 0xffffffff) {
 		result = IRQ_NONE;
 		goto out;
 	}
 
-again:
-	DBG("*** %s got interrupt: 0x%08x\n",
-		mmc_hostname(host->mmc), intmask);
-
-	if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
-		u32 present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
-			      SDHCI_CARD_PRESENT;
-
-		/*
-		 * There is a observation on i.mx esdhc.  INSERT bit will be
-		 * immediately set again when it gets cleared, if a card is
-		 * inserted.  We have to mask the irq to prevent interrupt
-		 * storm which will freeze the system.  And the REMOVE gets
-		 * the same situation.
-		 *
-		 * More testing are needed here to ensure it works for other
-		 * platforms though.
-		 */
-		sdhci_mask_irqs(host, present ? SDHCI_INT_CARD_INSERT :
-						SDHCI_INT_CARD_REMOVE);
-		sdhci_unmask_irqs(host, present ? SDHCI_INT_CARD_REMOVE :
-						  SDHCI_INT_CARD_INSERT);
-
-		sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT |
-			     SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS);
-		intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);
-		tasklet_schedule(&host->card_tasklet);
-	}
+	do {
+		/* Clear selected interrupts. */
+		mask = intmask & (SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK |
+				  SDHCI_INT_BUS_POWER);
+		sdhci_writel(host, mask, SDHCI_INT_STATUS);
 
-	if (intmask & SDHCI_INT_CMD_MASK) {
-		sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK,
-			SDHCI_INT_STATUS);
-		sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
-	}
+		DBG("*** %s got interrupt: 0x%08x\n",
+			mmc_hostname(host->mmc), intmask);
 
-	if (intmask & SDHCI_INT_DATA_MASK) {
-		sdhci_writel(host, intmask & SDHCI_INT_DATA_MASK,
-			SDHCI_INT_STATUS);
-		sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
-	}
+		if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
+			u32 present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
+				      SDHCI_CARD_PRESENT;
 
-	intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);
+			/*
+			 * There is a observation on i.mx esdhc.  INSERT
+			 * bit will be immediately set again when it gets
+			 * cleared, if a card is inserted.  We have to mask
+			 * the irq to prevent interrupt storm which will
+			 * freeze the system.  And the REMOVE gets the
+			 * same situation.
+			 *
+			 * More testing are needed here to ensure it works
+			 * for other platforms though.
+			 */
+			sdhci_mask_irqs(host, present ? SDHCI_INT_CARD_INSERT :
+							SDHCI_INT_CARD_REMOVE);
+			sdhci_unmask_irqs(host, present ? SDHCI_INT_CARD_REMOVE :
+							  SDHCI_INT_CARD_INSERT);
+
+			sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT |
+				     SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS);
+			tasklet_schedule(&host->card_tasklet);
+		}
 
-	intmask &= ~SDHCI_INT_ERROR;
+		if (intmask & SDHCI_INT_CMD_MASK)
+			sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
 
-	if (intmask & SDHCI_INT_BUS_POWER) {
-		pr_err("%s: Card is consuming too much power!\n",
-			mmc_hostname(host->mmc));
-		sdhci_writel(host, SDHCI_INT_BUS_POWER, SDHCI_INT_STATUS);
-	}
+		if (intmask & SDHCI_INT_DATA_MASK)
+			sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
 
-	intmask &= ~SDHCI_INT_BUS_POWER;
+		if (intmask & SDHCI_INT_BUS_POWER)
+			pr_err("%s: Card is consuming too much power!\n",
+				mmc_hostname(host->mmc));
 
-	if (intmask & SDHCI_INT_CARD_INT)
-		cardint = 1;
+		if (intmask & SDHCI_INT_CARD_INT)
+			cardint = 1;
 
-	intmask &= ~SDHCI_INT_CARD_INT;
+		intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE |
+			     SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK |
+			     SDHCI_INT_ERROR | SDHCI_INT_BUS_POWER |
+			     SDHCI_INT_CARD_INT);
 
-	if (intmask) {
-		unexpected |= intmask;
-		sdhci_writel(host, intmask, SDHCI_INT_STATUS);
-	}
+		if (intmask) {
+			unexpected |= intmask;
+			sdhci_writel(host, intmask, SDHCI_INT_STATUS);
+		}
 
-	result = IRQ_HANDLED;
+		result = IRQ_HANDLED;
 
-	intmask = sdhci_readl(host, SDHCI_INT_STATUS);
+		intmask = sdhci_readl(host, SDHCI_INT_STATUS);
 
-	/*
-	 * If we know we'll call the driver to signal SDIO IRQ, disregard
-	 * further indications of Card Interrupt in the status to avoid a
-	 * needless loop.
-	 */
-	if (cardint)
-		intmask &= ~SDHCI_INT_CARD_INT;
-	if (intmask && --max_loops)
-		goto again;
+		/*
+		 * If we know we'll call the driver to signal SDIO IRQ,
+		 * disregard further indications of Card Interrupt in
+		 * the status to avoid a needless loop.
+		 */
+		if (cardint)
+			intmask &= ~SDHCI_INT_CARD_INT;
+	} while (intmask && --max_loops);
 out:
 	spin_unlock(&host->lock);
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 187/222] mmc: sdhci: clean up sdio interrupt enable handling
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (185 preceding siblings ...)
  2014-04-25 11:55 ` [PATCH 186/222] mmc: sdhci: clean up interrupt handling Russell King
@ 2014-04-25 11:55 ` Russell King
  2014-04-25 11:55 ` [PATCH 188/222] mmc: sdhci: convert to new SDIO IRQ handling Russell King
                   ` (35 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:55 UTC (permalink / raw)
  To: linux-arm-kernel

We don't need to change the SDHCI_SDIO_IRQ_ENABLED flag when we're
merely receiving an interrupt - IRQ handling thread in the MMC core
will either re-enable or disable the interrupt via the enable_sdio_irq
callback, which will update this status appropriately.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci.c | 35 +++++++++++++++++------------------
 1 file changed, 17 insertions(+), 18 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 79838de6b278..239d90d77ac4 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1709,24 +1709,14 @@ static int sdhci_get_ro(struct mmc_host *mmc)
 
 static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable)
 {
-	if (host->flags & SDHCI_DEVICE_DEAD)
-		goto out;
-
-	if (enable)
-		host->flags |= SDHCI_SDIO_IRQ_ENABLED;
-	else
-		host->flags &= ~SDHCI_SDIO_IRQ_ENABLED;
-
 	/* SDIO IRQ will be enabled as appropriate in runtime resume */
-	if (host->runtime_suspended)
-		goto out;
-
-	if (enable)
-		sdhci_unmask_irqs(host, SDHCI_INT_CARD_INT);
-	else
-		sdhci_mask_irqs(host, SDHCI_INT_CARD_INT);
-out:
-	mmiowb();
+	if (!(host->flags & SDHCI_DEVICE_DEAD) || host->runtime_suspended) {
+		if (enable)
+			sdhci_unmask_irqs(host, SDHCI_INT_CARD_INT);
+		else
+			sdhci_mask_irqs(host, SDHCI_INT_CARD_INT);
+		mmiowb();
+	}
 }
 
 static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
@@ -1734,9 +1724,18 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
 	struct sdhci_host *host = mmc_priv(mmc);
 	unsigned long flags;
 
+	sdhci_runtime_pm_get(host);
+
 	spin_lock_irqsave(&host->lock, flags);
+	if (enable)
+		host->flags |= SDHCI_SDIO_IRQ_ENABLED;
+	else
+		host->flags &= ~SDHCI_SDIO_IRQ_ENABLED;
+
 	sdhci_enable_sdio_irq_nolock(host, enable);
 	spin_unlock_irqrestore(&host->lock, flags);
+
+	sdhci_runtime_pm_put(host);
 }
 
 static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
@@ -2721,7 +2720,7 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
 	host->runtime_suspended = false;
 
 	/* Enable SDIO IRQ */
-	if ((host->flags & SDHCI_SDIO_IRQ_ENABLED))
+	if (host->flags & SDHCI_SDIO_IRQ_ENABLED)
 		sdhci_enable_sdio_irq_nolock(host, true);
 
 	/* Enable Card Detection */
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 188/222] mmc: sdhci: convert to new SDIO IRQ handling
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (186 preceding siblings ...)
  2014-04-25 11:55 ` [PATCH 187/222] mmc: sdhci: clean up sdio interrupt enable handling Russell King
@ 2014-04-25 11:55 ` Russell King
  2014-04-25 11:55 ` [PATCH 189/222] mmc: sdhci: push card_tasklet into threaded irq handler Russell King
                   ` (34 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:55 UTC (permalink / raw)
  To: linux-arm-kernel

Use a generic threaded interrupt handler for SDIO interrupt handling,
rather than allowing the SDIO core code to buggily spawn its own
thread.  This results in host drivers to be more in control of how
SDIO interrupts are acknowledged in the hardware, rather than having
the internals of the SDIO core placed upon them, possibly resulting
in sub-standard handling.

At least one SDHCI implementation specifies a very specific sequence
to deal with a card interrupt.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci.c  | 62 +++++++++++++++++++++++++++++------------------
 include/linux/mmc/sdhci.h |  2 ++
 2 files changed, 41 insertions(+), 23 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 239d90d77ac4..3e10f96681f8 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2423,10 +2423,10 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
 
 static irqreturn_t sdhci_irq(int irq, void *dev_id)
 {
-	irqreturn_t result;
+	irqreturn_t result = IRQ_NONE;
 	struct sdhci_host *host = dev_id;
 	u32 intmask, mask, unexpected = 0;
-	int cardint = 0, max_loops = 16;
+	int max_loops = 16;
 
 	spin_lock(&host->lock);
 
@@ -2485,8 +2485,11 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
 			pr_err("%s: Card is consuming too much power!\n",
 				mmc_hostname(host->mmc));
 
-		if (intmask & SDHCI_INT_CARD_INT)
-			cardint = 1;
+		if (intmask & SDHCI_INT_CARD_INT) {
+			sdhci_enable_sdio_irq_nolock(host, false);
+			host->thread_isr |= SDHCI_INT_CARD_INT;
+			result = IRQ_WAKE_THREAD;
+		}
 
 		intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE |
 			     SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK |
@@ -2498,17 +2501,10 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
 			sdhci_writel(host, intmask, SDHCI_INT_STATUS);
 		}
 
-		result = IRQ_HANDLED;
+		if (result == IRQ_NONE)
+			result = IRQ_HANDLED;
 
 		intmask = sdhci_readl(host, SDHCI_INT_STATUS);
-
-		/*
-		 * If we know we'll call the driver to signal SDIO IRQ,
-		 * disregard further indications of Card Interrupt in
-		 * the status to avoid a needless loop.
-		 */
-		if (cardint)
-			intmask &= ~SDHCI_INT_CARD_INT;
 	} while (intmask && --max_loops);
 out:
 	spin_unlock(&host->lock);
@@ -2518,15 +2514,33 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
 			   mmc_hostname(host->mmc), unexpected);
 		sdhci_dumpregs(host);
 	}
-	/*
-	 * We have to delay this as it calls back into the driver.
-	 */
-	if (cardint)
-		mmc_signal_sdio_irq(host->mmc);
 
 	return result;
 }
 
+static irqreturn_t sdhci_thread_irq(int irq, void *dev_id)
+{
+	struct sdhci_host *host = dev_id;
+	unsigned long flags;
+	u32 isr;
+
+	spin_lock_irqsave(&host->lock, flags);
+	isr = host->thread_isr;
+	host->thread_isr = 0;
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	if (isr & SDHCI_INT_CARD_INT) {
+		sdio_run_irqs(host->mmc);
+
+		spin_lock_irqsave(&host->lock, flags);
+		if (host->flags & SDHCI_SDIO_IRQ_ENABLED)
+			sdhci_enable_sdio_irq_nolock(host, true);
+		spin_unlock_irqrestore(&host->lock, flags);
+	}
+
+	return isr ? IRQ_HANDLED : IRQ_NONE;
+}
+
 /*****************************************************************************\
  *                                                                           *
  * Suspend/resume                                                            *
@@ -2596,8 +2610,9 @@ int sdhci_resume_host(struct sdhci_host *host)
 	}
 
 	if (!device_may_wakeup(mmc_dev(host->mmc))) {
-		ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
-				  mmc_hostname(host->mmc), host);
+		ret = request_threaded_irq(host->irq, sdhci_irq,
+					   sdhci_thread_irq, IRQF_SHARED,
+					   mmc_hostname(host->mmc), host);
 		if (ret)
 			return ret;
 	} else {
@@ -2676,7 +2691,7 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host)
 	sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
 	spin_unlock_irqrestore(&host->lock, flags);
 
-	synchronize_irq(host->irq);
+	synchronize_hardirq(host->irq);
 
 	spin_lock_irqsave(&host->lock, flags);
 	host->runtime_suspended = true;
@@ -2932,6 +2947,7 @@ int sdhci_add_host(struct sdhci_host *host)
 	mmc->max_busy_timeout = (1 << 27) / host->timeout_clk;
 
 	mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
+	mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
 
 	if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12)
 		host->flags |= SDHCI_AUTO_CMD12;
@@ -3221,8 +3237,8 @@ int sdhci_add_host(struct sdhci_host *host)
 
 	sdhci_init(host, 0);
 
-	ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
-		mmc_hostname(mmc), host);
+	ret = request_threaded_irq(host->irq, sdhci_irq, sdhci_thread_irq,
+				   IRQF_SHARED,	mmc_hostname(mmc), host);
 	if (ret) {
 		pr_err("%s: Failed to request IRQ %d: %d\n",
 		       mmc_hostname(mmc), host->irq, ret);
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index 7be12b883485..d1aa97b77dd9 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -177,6 +177,8 @@ struct sdhci_host {
 	unsigned int            ocr_avail_mmc;
 	u32 ocr_mask;		/* available voltages */
 
+	u32			thread_isr;
+
 	wait_queue_head_t	buf_ready_int;	/* Waitqueue for Buffer Read Ready interrupt */
 	unsigned int		tuning_done;	/* Condition flag set when CMD19 succeeds */
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 189/222] mmc: sdhci: push card_tasklet into threaded irq handler
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (187 preceding siblings ...)
  2014-04-25 11:55 ` [PATCH 188/222] mmc: sdhci: convert to new SDIO IRQ handling Russell King
@ 2014-04-25 11:55 ` Russell King
  2014-04-25 11:55 ` [PATCH 190/222] mmc: sdhci: allow sdio interrupts while sdhci runtime suspended Russell King
                   ` (33 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:55 UTC (permalink / raw)
  To: linux-arm-kernel

There's no requirement to have the card tasklet separate now that we
have a threaded interrupt handler, so kill this and move the called
code into the threaded part of the handler.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci.c  | 23 +++++++++--------------
 include/linux/mmc/sdhci.h |  3 +--
 2 files changed, 10 insertions(+), 16 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 3e10f96681f8..9090329847f8 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2123,15 +2123,6 @@ static const struct mmc_host_ops sdhci_ops = {
  *                                                                           *
 \*****************************************************************************/
 
-static void sdhci_tasklet_card(unsigned long param)
-{
-	struct sdhci_host *host = (struct sdhci_host*)param;
-
-	sdhci_card_event(host->mmc);
-
-	mmc_detect_change(host->mmc, msecs_to_jiffies(200));
-}
-
 static void sdhci_tasklet_finish(unsigned long param)
 {
 	struct sdhci_host *host;
@@ -2472,7 +2463,10 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
 
 			sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT |
 				     SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS);
-			tasklet_schedule(&host->card_tasklet);
+
+			host->thread_isr |= intmask & (SDHCI_INT_CARD_INSERT |
+						       SDHCI_INT_CARD_REMOVE);
+			result = IRQ_WAKE_THREAD;
 		}
 
 		if (intmask & SDHCI_INT_CMD_MASK)
@@ -2529,6 +2523,11 @@ static irqreturn_t sdhci_thread_irq(int irq, void *dev_id)
 	host->thread_isr = 0;
 	spin_unlock_irqrestore(&host->lock, flags);
 
+	if (isr & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
+		sdhci_card_event(host->mmc);
+		mmc_detect_change(host->mmc, msecs_to_jiffies(200));
+	}
+
 	if (isr & SDHCI_INT_CARD_INT) {
 		sdio_run_irqs(host->mmc);
 
@@ -3219,8 +3218,6 @@ int sdhci_add_host(struct sdhci_host *host)
 	/*
 	 * Init tasklets.
 	 */
-	tasklet_init(&host->card_tasklet,
-		sdhci_tasklet_card, (unsigned long)host);
 	tasklet_init(&host->finish_tasklet,
 		sdhci_tasklet_finish, (unsigned long)host);
 
@@ -3285,7 +3282,6 @@ int sdhci_add_host(struct sdhci_host *host)
 	free_irq(host->irq, host);
 #endif
 untasklet:
-	tasklet_kill(&host->card_tasklet);
 	tasklet_kill(&host->finish_tasklet);
 
 	return ret;
@@ -3329,7 +3325,6 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
 
 	del_timer_sync(&host->timer);
 
-	tasklet_kill(&host->card_tasklet);
 	tasklet_kill(&host->finish_tasklet);
 
 	if (host->vmmc) {
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index d1aa97b77dd9..f1c8e14e8751 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -164,8 +164,7 @@ struct sdhci_host {
 	dma_addr_t adma_addr;	/* Mapped ADMA descr. table */
 	dma_addr_t align_addr;	/* Mapped bounce buffer */
 
-	struct tasklet_struct card_tasklet;	/* Tasklet structures */
-	struct tasklet_struct finish_tasklet;
+	struct tasklet_struct finish_tasklet;	/* Tasklet structures */
 
 	struct timer_list timer;	/* Timer for timeouts */
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 190/222] mmc: sdhci: allow sdio interrupts while sdhci runtime suspended
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (188 preceding siblings ...)
  2014-04-25 11:55 ` [PATCH 189/222] mmc: sdhci: push card_tasklet into threaded irq handler Russell King
@ 2014-04-25 11:55 ` Russell King
  2014-04-25 11:56 ` [PATCH 191/222] mmc: sdhci: more efficient interrupt enable register handling Russell King
                   ` (32 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:55 UTC (permalink / raw)
  To: linux-arm-kernel

Allow SDIO interrupts to be received while the SDHCI host is runtime
suspended.  We do this by leaving the AHB clock enabled while the
host is runtime suspended so we can access the SDHCI registers, and
so read and raise the SDIO card interrupt.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci-esdhc-imx.c | 12 ++++++++----
 drivers/mmc/host/sdhci.c           |  7 +++----
 drivers/mmc/host/sdhci.h           |  5 +++++
 3 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index b841bb7cd371..b0b4eea8d232 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -1170,8 +1170,10 @@ static int sdhci_esdhc_runtime_suspend(struct device *dev)
 
 	ret = sdhci_runtime_suspend_host(host);
 
-	clk_disable_unprepare(imx_data->clk_per);
-	clk_disable_unprepare(imx_data->clk_ipg);
+	if (!sdhci_sdio_irq_enabled(host)) {
+		clk_disable_unprepare(imx_data->clk_per);
+		clk_disable_unprepare(imx_data->clk_ipg);
+	}
 	clk_disable_unprepare(imx_data->clk_ahb);
 
 	return ret;
@@ -1183,8 +1185,10 @@ static int sdhci_esdhc_runtime_resume(struct device *dev)
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 	struct pltfm_imx_data *imx_data = pltfm_host->priv;
 
-	clk_prepare_enable(imx_data->clk_per);
-	clk_prepare_enable(imx_data->clk_ipg);
+	if (!sdhci_sdio_irq_enabled(host)) {
+		clk_prepare_enable(imx_data->clk_per);
+		clk_prepare_enable(imx_data->clk_ipg);
+	}
 	clk_prepare_enable(imx_data->clk_ahb);
 
 	return sdhci_runtime_resume_host(host);
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 9090329847f8..0f67d8dc2100 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1709,8 +1709,7 @@ static int sdhci_get_ro(struct mmc_host *mmc)
 
 static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable)
 {
-	/* SDIO IRQ will be enabled as appropriate in runtime resume */
-	if (!(host->flags & SDHCI_DEVICE_DEAD) || host->runtime_suspended) {
+	if (!(host->flags & SDHCI_DEVICE_DEAD)) {
 		if (enable)
 			sdhci_unmask_irqs(host, SDHCI_INT_CARD_INT);
 		else
@@ -2421,7 +2420,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
 
 	spin_lock(&host->lock);
 
-	if (host->runtime_suspended) {
+	if (host->runtime_suspended && !sdhci_sdio_irq_enabled(host)) {
 		spin_unlock(&host->lock);
 		return IRQ_NONE;
 	}
@@ -2687,7 +2686,7 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host)
 	}
 
 	spin_lock_irqsave(&host->lock, flags);
-	sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
+	sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK & ~SDHCI_INT_CARD_INT);
 	spin_unlock_irqrestore(&host->lock, flags);
 
 	synchronize_hardirq(host->irq);
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 0a3ed01887db..fc6f81d2f377 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -397,6 +397,11 @@ extern void sdhci_remove_host(struct sdhci_host *host, int dead);
 extern void sdhci_send_command(struct sdhci_host *host,
 				struct mmc_command *cmd);
 
+static inline bool sdhci_sdio_irq_enabled(struct sdhci_host *host)
+{
+	return !!(host->flags & SDHCI_SDIO_IRQ_ENABLED);
+}
+
 #ifdef CONFIG_PM
 extern int sdhci_suspend_host(struct sdhci_host *host);
 extern int sdhci_resume_host(struct sdhci_host *host);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 191/222] mmc: sdhci: more efficient interrupt enable register handling
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (189 preceding siblings ...)
  2014-04-25 11:55 ` [PATCH 190/222] mmc: sdhci: allow sdio interrupts while sdhci runtime suspended Russell King
@ 2014-04-25 11:56 ` Russell King
  2014-04-25 11:57 ` [PATCH 192/222] mmc: sdhci: plug hole in disabling card detection interrupts Russell King
                   ` (31 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:56 UTC (permalink / raw)
  To: linux-arm-kernel

Rather than wasting cycles read-modify-writing the interrupt enable
registers, cache the value locally instead.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci.c  | 98 +++++++++++++++++++++++------------------------
 include/linux/mmc/sdhci.h |  3 ++
 2 files changed, 50 insertions(+), 51 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 0f67d8dc2100..02a59b051343 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -131,27 +131,6 @@ static void sdhci_dumpregs(struct sdhci_host *host)
  *                                                                           *
 \*****************************************************************************/
 
-static void sdhci_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set)
-{
-	u32 ier;
-
-	ier = sdhci_readl(host, SDHCI_INT_ENABLE);
-	ier &= ~clear;
-	ier |= set;
-	sdhci_writel(host, ier, SDHCI_INT_ENABLE);
-	sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE);
-}
-
-static void sdhci_unmask_irqs(struct sdhci_host *host, u32 irqs)
-{
-	sdhci_clear_set_irqs(host, 0, irqs);
-}
-
-static void sdhci_mask_irqs(struct sdhci_host *host, u32 irqs)
-{
-	sdhci_clear_set_irqs(host, irqs, 0);
-}
-
 static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
 {
 	u32 present, irqs;
@@ -165,9 +144,12 @@ static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
 	irqs = present ? SDHCI_INT_CARD_REMOVE : SDHCI_INT_CARD_INSERT;
 
 	if (enable)
-		sdhci_unmask_irqs(host, irqs);
+		host->ier |= irqs;
 	else
-		sdhci_mask_irqs(host, irqs);
+		host->ier &= ~irqs;
+
+	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 }
 
 static void sdhci_enable_card_detection(struct sdhci_host *host)
@@ -183,17 +165,12 @@ static void sdhci_disable_card_detection(struct sdhci_host *host)
 static void sdhci_reset(struct sdhci_host *host, u8 mask)
 {
 	unsigned long timeout;
-	u32 uninitialized_var(ier);
-
 	if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
 		if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) &
 			SDHCI_CARD_PRESENT))
 			return;
 	}
 
-	if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
-		ier = sdhci_readl(host, SDHCI_INT_ENABLE);
-
 	if (host->ops->platform_reset_enter)
 		host->ops->platform_reset_enter(host, mask);
 
@@ -224,8 +201,10 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
 	if (host->ops->platform_reset_exit)
 		host->ops->platform_reset_exit(host, mask);
 
-	if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
-		sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, ier);
+	if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET) {
+		sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+		sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+	}
 
 	if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
 		if ((host->ops->enable_dma) && (mask & SDHCI_RESET_ALL))
@@ -242,11 +221,14 @@ static void sdhci_init(struct sdhci_host *host, int soft)
 	else
 		sdhci_reset(host, SDHCI_RESET_ALL);
 
-	sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK,
-		SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
-		SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX |
-		SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |
-		SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE);
+	host->ier = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
+		    SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT |
+		    SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC |
+		    SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END |
+		    SDHCI_INT_RESPONSE;
+
+	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 
 	if (soft) {
 		/* force clock reconfiguration */
@@ -721,9 +703,12 @@ static void sdhci_set_transfer_irqs(struct sdhci_host *host)
 	u32 dma_irqs = SDHCI_INT_DMA_END | SDHCI_INT_ADMA_ERROR;
 
 	if (host->flags & SDHCI_REQ_USE_DMA)
-		sdhci_clear_set_irqs(host, pio_irqs, dma_irqs);
+		host->ier = (host->ier & ~pio_irqs) | dma_irqs;
 	else
-		sdhci_clear_set_irqs(host, dma_irqs, pio_irqs);
+		host->ier = (host->ier & ~dma_irqs) | pio_irqs;
+
+	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 }
 
 static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
@@ -1711,9 +1696,12 @@ static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable)
 {
 	if (!(host->flags & SDHCI_DEVICE_DEAD)) {
 		if (enable)
-			sdhci_unmask_irqs(host, SDHCI_INT_CARD_INT);
+			host->ier |= SDHCI_INT_CARD_INT;
 		else
-			sdhci_mask_irqs(host, SDHCI_INT_CARD_INT);
+			host->ier &= ~SDHCI_INT_CARD_INT;
+
+		sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+		sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 		mmiowb();
 	}
 }
@@ -1855,7 +1843,6 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 {
 	struct sdhci_host *host;
 	u16 ctrl;
-	u32 ier;
 	int tuning_loop_counter = MAX_TUNING_LOOP;
 	unsigned long timeout;
 	int err = 0;
@@ -1909,8 +1896,8 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 	 * to make sure we don't hit a controller bug, we _only_
 	 * enable Buffer Read Ready interrupt here.
 	 */
-	ier = sdhci_readl(host, SDHCI_INT_ENABLE);
-	sdhci_clear_set_irqs(host, ier, SDHCI_INT_DATA_AVAIL);
+	sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_INT_ENABLE);
+	sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_SIGNAL_ENABLE);
 
 	/*
 	 * Issue CMD19 repeatedly till Execute Tuning is set to 0 or the number
@@ -2042,7 +2029,8 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 	if (err && (host->flags & SDHCI_USING_RETUNING_TIMER))
 		err = 0;
 
-	sdhci_clear_set_irqs(host, SDHCI_INT_DATA_AVAIL, ier);
+	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 	spin_unlock_irqrestore(&host->lock, flags);
 	sdhci_runtime_pm_put(host);
 
@@ -2455,10 +2443,12 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
 			 * More testing are needed here to ensure it works
 			 * for other platforms though.
 			 */
-			sdhci_mask_irqs(host, present ? SDHCI_INT_CARD_INSERT :
-							SDHCI_INT_CARD_REMOVE);
-			sdhci_unmask_irqs(host, present ? SDHCI_INT_CARD_REMOVE :
-							  SDHCI_INT_CARD_INSERT);
+			host->ier &= ~(SDHCI_INT_CARD_INSERT |
+				       SDHCI_INT_CARD_REMOVE);
+			host->ier |= present ? SDHCI_INT_CARD_REMOVE :
+					       SDHCI_INT_CARD_INSERT;
+			sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+			sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 
 			sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT |
 				     SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS);
@@ -2587,7 +2577,9 @@ int sdhci_suspend_host(struct sdhci_host *host)
 	}
 
 	if (!device_may_wakeup(mmc_dev(host->mmc))) {
-		sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
+		host->ier = 0;
+		sdhci_writel(host, 0, SDHCI_INT_ENABLE);
+		sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
 		free_irq(host->irq, host);
 	} else {
 		sdhci_enable_irq_wakeups(host);
@@ -2686,7 +2678,9 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host)
 	}
 
 	spin_lock_irqsave(&host->lock, flags);
-	sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK & ~SDHCI_INT_CARD_INT);
+	host->ier &= SDHCI_INT_CARD_INT;
+	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 	spin_unlock_irqrestore(&host->lock, flags);
 
 	synchronize_hardirq(host->irq);
@@ -3277,7 +3271,8 @@ int sdhci_add_host(struct sdhci_host *host)
 #ifdef SDHCI_USE_LEDS_CLASS
 reset:
 	sdhci_reset(host, SDHCI_RESET_ALL);
-	sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
+	sdhci_writel(host, 0, SDHCI_INT_ENABLE);
+	sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
 	free_irq(host->irq, host);
 #endif
 untasklet:
@@ -3319,7 +3314,8 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
 	if (!dead)
 		sdhci_reset(host, SDHCI_RESET_ALL);
 
-	sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
+	sdhci_writel(host, 0, SDHCI_INT_ENABLE);
+	sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
 	free_irq(host->irq, host);
 
 	del_timer_sync(&host->timer);
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index f1c8e14e8751..9361d8ef509d 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -178,6 +178,9 @@ struct sdhci_host {
 
 	u32			thread_isr;
 
+	/* cached registers */
+	u32			ier;
+
 	wait_queue_head_t	buf_ready_int;	/* Waitqueue for Buffer Read Ready interrupt */
 	unsigned int		tuning_done;	/* Condition flag set when CMD19 succeeds */
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 192/222] mmc: sdhci: plug hole in disabling card detection interrupts
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (190 preceding siblings ...)
  2014-04-25 11:56 ` [PATCH 191/222] mmc: sdhci: more efficient interrupt enable register handling Russell King
@ 2014-04-25 11:57 ` Russell King
  2014-04-25 11:57 ` [PATCH 193/222] mmc: sdhci: convert generic bus width setup to library function Russell King
                   ` (30 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:57 UTC (permalink / raw)
  To: linux-arm-kernel

When we disable card detection interrupts, we should disable both the
insert and remove interrupts irrespective of the current state - this
avoids races between the hardware card detect changing state before
we've read that updated state and altered the interrupt mask.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci.c | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 02a59b051343..e7e4c18a1ff5 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -133,20 +133,21 @@ static void sdhci_dumpregs(struct sdhci_host *host)
 
 static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
 {
-	u32 present, irqs;
+	u32 present;
 
 	if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) ||
 	    (host->mmc->caps & MMC_CAP_NONREMOVABLE))
 		return;
 
-	present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
-			      SDHCI_CARD_PRESENT;
-	irqs = present ? SDHCI_INT_CARD_REMOVE : SDHCI_INT_CARD_INSERT;
+	if (enable) {
+		present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
+				      SDHCI_CARD_PRESENT;
 
-	if (enable)
-		host->ier |= irqs;
-	else
-		host->ier &= ~irqs;
+		host->ier |= present ? SDHCI_INT_CARD_REMOVE :
+				       SDHCI_INT_CARD_INSERT;
+	} else {
+		host->ier &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT);
+	}
 
 	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
 	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 193/222] mmc: sdhci: convert generic bus width setup to library function
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (191 preceding siblings ...)
  2014-04-25 11:57 ` [PATCH 192/222] mmc: sdhci: plug hole in disabling card detection interrupts Russell King
@ 2014-04-25 11:57 ` Russell King
  2014-04-25 11:57 ` [PATCH 194/222] mmc: sdhci: convert reset into a " Russell King
                   ` (29 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:57 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci-acpi.c      |  2 ++
 drivers/mmc/host/sdhci-bcm-kona.c  |  1 +
 drivers/mmc/host/sdhci-bcm2835.c   |  1 +
 drivers/mmc/host/sdhci-cns3xxx.c   |  1 +
 drivers/mmc/host/sdhci-dove.c      |  1 +
 drivers/mmc/host/sdhci-esdhc-imx.c |  6 ++---
 drivers/mmc/host/sdhci-of-arasan.c |  1 +
 drivers/mmc/host/sdhci-of-esdhc.c  |  6 ++---
 drivers/mmc/host/sdhci-of-hlwd.c   |  1 +
 drivers/mmc/host/sdhci-pci.c       |  6 ++---
 drivers/mmc/host/sdhci-pltfm.c     |  1 +
 drivers/mmc/host/sdhci-pxav2.c     |  6 ++---
 drivers/mmc/host/sdhci-pxav3.c     |  1 +
 drivers/mmc/host/sdhci-s3c.c       |  8 +++----
 drivers/mmc/host/sdhci-sirf.c      |  1 +
 drivers/mmc/host/sdhci-spear.c     |  2 +-
 drivers/mmc/host/sdhci-tegra.c     |  5 ++---
 drivers/mmc/host/sdhci.c           | 45 +++++++++++++++++++-------------------
 drivers/mmc/host/sdhci.h           |  5 +++--
 19 files changed, 50 insertions(+), 50 deletions(-)

diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c
index ebb3f392b589..0e4ba0a4cd71 100644
--- a/drivers/mmc/host/sdhci-acpi.c
+++ b/drivers/mmc/host/sdhci-acpi.c
@@ -103,10 +103,12 @@ static void sdhci_acpi_int_hw_reset(struct sdhci_host *host)
 
 static const struct sdhci_ops sdhci_acpi_ops_dflt = {
 	.enable_dma = sdhci_acpi_enable_dma,
+	.set_bus_width = sdhci_set_bus_width,
 };
 
 static const struct sdhci_ops sdhci_acpi_ops_int = {
 	.enable_dma = sdhci_acpi_enable_dma,
+	.set_bus_width = sdhci_set_bus_width,
 	.hw_reset   = sdhci_acpi_int_hw_reset,
 };
 
diff --git a/drivers/mmc/host/sdhci-bcm-kona.c b/drivers/mmc/host/sdhci-bcm-kona.c
index 6f166e63b817..06cdb8abb25e 100644
--- a/drivers/mmc/host/sdhci-bcm-kona.c
+++ b/drivers/mmc/host/sdhci-bcm-kona.c
@@ -209,6 +209,7 @@ static struct sdhci_ops sdhci_bcm_kona_ops = {
 	.get_max_clock = sdhci_bcm_kona_get_max_clk,
 	.get_timeout_clock = sdhci_bcm_kona_get_timeout_clock,
 	.platform_send_init_74_clocks = sdhci_bcm_kona_init_74_clocks,
+	.set_bus_width = sdhci_set_bus_width,
 	.card_event = sdhci_bcm_kona_card_event,
 };
 
diff --git a/drivers/mmc/host/sdhci-bcm2835.c b/drivers/mmc/host/sdhci-bcm2835.c
index f6d8d67c545f..7ab69af979b4 100644
--- a/drivers/mmc/host/sdhci-bcm2835.c
+++ b/drivers/mmc/host/sdhci-bcm2835.c
@@ -133,6 +133,7 @@ static const struct sdhci_ops bcm2835_sdhci_ops = {
 	.read_b = bcm2835_sdhci_readb,
 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
 	.get_min_clock = bcm2835_sdhci_get_min_clock,
+	.set_bus_width = sdhci_set_bus_width,
 };
 
 static const struct sdhci_pltfm_data bcm2835_sdhci_pdata = {
diff --git a/drivers/mmc/host/sdhci-cns3xxx.c b/drivers/mmc/host/sdhci-cns3xxx.c
index f2cc26633cb2..5e0cc9c47887 100644
--- a/drivers/mmc/host/sdhci-cns3xxx.c
+++ b/drivers/mmc/host/sdhci-cns3xxx.c
@@ -82,6 +82,7 @@ static void sdhci_cns3xxx_set_clock(struct sdhci_host *host, unsigned int clock)
 static const struct sdhci_ops sdhci_cns3xxx_ops = {
 	.get_max_clock	= sdhci_cns3xxx_get_max_clk,
 	.set_clock	= sdhci_cns3xxx_set_clock,
+	.set_bus_width	= sdhci_set_bus_width,
 };
 
 static const struct sdhci_pltfm_data sdhci_cns3xxx_pdata = {
diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c
index 736d7a2eb7ec..8fc547a7048a 100644
--- a/drivers/mmc/host/sdhci-dove.c
+++ b/drivers/mmc/host/sdhci-dove.c
@@ -86,6 +86,7 @@ static u32 sdhci_dove_readl(struct sdhci_host *host, int reg)
 static const struct sdhci_ops sdhci_dove_ops = {
 	.read_w	= sdhci_dove_readw,
 	.read_l	= sdhci_dove_readl,
+	.set_bus_width = sdhci_set_bus_width,
 };
 
 static const struct sdhci_pltfm_data sdhci_dove_pdata = {
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index b0b4eea8d232..568239d84cbe 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -668,7 +668,7 @@ static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
 	return -ENOSYS;
 }
 
-static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width)
+static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width)
 {
 	u32 ctrl;
 
@@ -686,8 +686,6 @@ static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width)
 
 	esdhc_clrset_le(host, ESDHC_CTRL_BUSWIDTH_MASK, ctrl,
 			SDHCI_HOST_CONTROL);
-
-	return 0;
 }
 
 static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val)
@@ -888,7 +886,7 @@ static struct sdhci_ops sdhci_esdhc_ops = {
 	.get_max_clock = esdhc_pltfm_get_max_clock,
 	.get_min_clock = esdhc_pltfm_get_min_clock,
 	.get_ro = esdhc_pltfm_get_ro,
-	.platform_bus_width = esdhc_pltfm_bus_width,
+	.set_bus_width = esdhc_pltfm_set_bus_width,
 	.set_uhs_signaling = esdhc_set_uhs_signaling,
 };
 
diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
index f7c7cf62437d..9bb1dd263a45 100644
--- a/drivers/mmc/host/sdhci-of-arasan.c
+++ b/drivers/mmc/host/sdhci-of-arasan.c
@@ -54,6 +54,7 @@ static unsigned int sdhci_arasan_get_timeout_clock(struct sdhci_host *host)
 static struct sdhci_ops sdhci_arasan_ops = {
 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
 	.get_timeout_clock = sdhci_arasan_get_timeout_clock,
+	.set_bus_width = sdhci_set_bus_width,
 };
 
 static struct sdhci_pltfm_data sdhci_arasan_pdata = {
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index 0b249970b119..86b8326e77c3 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -269,7 +269,7 @@ static void esdhc_of_platform_init(struct sdhci_host *host)
 		host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ;
 }
 
-static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width)
+static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width)
 {
 	u32 ctrl;
 
@@ -289,8 +289,6 @@ static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width)
 
 	clrsetbits_be32(host->ioaddr + SDHCI_HOST_CONTROL,
 			ESDHC_CTRL_BUSWIDTH_MASK, ctrl);
-
-	return 0;
 }
 
 static const struct sdhci_ops sdhci_esdhc_ops = {
@@ -310,7 +308,7 @@ static const struct sdhci_ops sdhci_esdhc_ops = {
 	.platform_resume = esdhc_of_resume,
 #endif
 	.adma_workaround = esdhci_of_adma_workaround,
-	.platform_bus_width = esdhc_pltfm_bus_width,
+	.set_bus_width = esdhc_pltfm_set_bus_width,
 };
 
 static const struct sdhci_pltfm_data sdhci_esdhc_pdata = {
diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c
index 57c514a81ca5..4d5d0015e392 100644
--- a/drivers/mmc/host/sdhci-of-hlwd.c
+++ b/drivers/mmc/host/sdhci-of-hlwd.c
@@ -58,6 +58,7 @@ static const struct sdhci_ops sdhci_hlwd_ops = {
 	.write_l = sdhci_hlwd_writel,
 	.write_w = sdhci_hlwd_writew,
 	.write_b = sdhci_hlwd_writeb,
+	.set_bus_width = sdhci_set_bus_width,
 };
 
 static const struct sdhci_pltfm_data sdhci_hlwd_pdata = {
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index fdc612120362..8c4e9c2909b7 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -1031,7 +1031,7 @@ static int sdhci_pci_enable_dma(struct sdhci_host *host)
 	return 0;
 }
 
-static int sdhci_pci_bus_width(struct sdhci_host *host, int width)
+static void sdhci_pci_set_bus_width(struct sdhci_host *host, int width)
 {
 	u8 ctrl;
 
@@ -1052,8 +1052,6 @@ static int sdhci_pci_bus_width(struct sdhci_host *host, int width)
 	}
 
 	sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
-
-	return 0;
 }
 
 static void sdhci_pci_gpio_hw_reset(struct sdhci_host *host)
@@ -1081,7 +1079,7 @@ static void sdhci_pci_hw_reset(struct sdhci_host *host)
 
 static const struct sdhci_ops sdhci_pci_ops = {
 	.enable_dma	= sdhci_pci_enable_dma,
-	.platform_bus_width	= sdhci_pci_bus_width,
+	.set_bus_width	= sdhci_pci_set_bus_width,
 	.hw_reset		= sdhci_pci_hw_reset,
 };
 
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
index bef250e95418..40b0fe224f9d 100644
--- a/drivers/mmc/host/sdhci-pltfm.c
+++ b/drivers/mmc/host/sdhci-pltfm.c
@@ -45,6 +45,7 @@ unsigned int sdhci_pltfm_clk_get_max_clock(struct sdhci_host *host)
 EXPORT_SYMBOL_GPL(sdhci_pltfm_clk_get_max_clock);
 
 static const struct sdhci_ops sdhci_pltfm_ops = {
+	.set_bus_width = sdhci_set_bus_width,
 };
 
 #ifdef CONFIG_OF
diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c
index d51e061ec576..d24c282e5eb8 100644
--- a/drivers/mmc/host/sdhci-pxav2.c
+++ b/drivers/mmc/host/sdhci-pxav2.c
@@ -88,7 +88,7 @@ static void pxav2_set_private_registers(struct sdhci_host *host, u8 mask)
 	}
 }
 
-static int pxav2_mmc_set_width(struct sdhci_host *host, int width)
+static void pxav2_mmc_set_bus_width(struct sdhci_host *host, int width)
 {
 	u8 ctrl;
 	u16 tmp;
@@ -107,14 +107,12 @@ static int pxav2_mmc_set_width(struct sdhci_host *host, int width)
 	}
 	writew(tmp, host->ioaddr + SD_CE_ATA_2);
 	writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
-
-	return 0;
 }
 
 static const struct sdhci_ops pxav2_sdhci_ops = {
 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
 	.platform_reset_exit = pxav2_set_private_registers,
-	.platform_bus_width = pxav2_mmc_set_width,
+	.set_bus_width = pxav2_mmc_set_bus_width,
 };
 
 #ifdef CONFIG_OF
diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c
index 2fd73b38c303..b06db03b6d81 100644
--- a/drivers/mmc/host/sdhci-pxav3.c
+++ b/drivers/mmc/host/sdhci-pxav3.c
@@ -227,6 +227,7 @@ static const struct sdhci_ops pxav3_sdhci_ops = {
 	.set_uhs_signaling = pxav3_set_uhs_signaling,
 	.platform_send_init_74_clocks = pxav3_gen_init_74_clocks,
 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
+	.set_bus_width = sdhci_set_bus_width,
 };
 
 static struct sdhci_pltfm_data sdhci_pxav3_pdata = {
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
index d61eb5a70833..181d8c962f26 100644
--- a/drivers/mmc/host/sdhci-s3c.c
+++ b/drivers/mmc/host/sdhci-s3c.c
@@ -329,14 +329,14 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
 }
 
 /**
- * sdhci_s3c_platform_bus_width - support 8bit buswidth
+ * sdhci_s3c_set_bus_width - support 8bit buswidth
  * @host: The SDHCI host being queried
  * @width: MMC_BUS_WIDTH_ macro for the bus width being requested
  *
  * We have 8-bit width support but is not a v3 controller.
  * So we add platform_bus_width() and support 8bit width.
  */
-static int sdhci_s3c_platform_bus_width(struct sdhci_host *host, int width)
+static void sdhci_s3c_set_bus_width(struct sdhci_host *host, int width)
 {
 	u8 ctrl;
 
@@ -358,15 +358,13 @@ static int sdhci_s3c_platform_bus_width(struct sdhci_host *host, int width)
 	}
 
 	sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
-
-	return 0;
 }
 
 static struct sdhci_ops sdhci_s3c_ops = {
 	.get_max_clock		= sdhci_s3c_get_max_clk,
 	.set_clock		= sdhci_s3c_set_clock,
 	.get_min_clock		= sdhci_s3c_get_min_clock,
-	.platform_bus_width	= sdhci_s3c_platform_bus_width,
+	.set_bus_width		= sdhci_s3c_set_bus_width,
 };
 
 static void sdhci_s3c_notify_change(struct platform_device *dev, int state)
diff --git a/drivers/mmc/host/sdhci-sirf.c b/drivers/mmc/host/sdhci-sirf.c
index 696122c1b468..16fcd48f9556 100644
--- a/drivers/mmc/host/sdhci-sirf.c
+++ b/drivers/mmc/host/sdhci-sirf.c
@@ -29,6 +29,7 @@ static unsigned int sdhci_sirf_get_max_clk(struct sdhci_host *host)
 
 static struct sdhci_ops sdhci_sirf_ops = {
 	.get_max_clock	= sdhci_sirf_get_max_clk,
+	.set_bus_width = sdhci_set_bus_width,
 };
 
 static struct sdhci_pltfm_data sdhci_sirf_pdata = {
diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c
index 0316dec3f006..dc8967b657ed 100644
--- a/drivers/mmc/host/sdhci-spear.c
+++ b/drivers/mmc/host/sdhci-spear.c
@@ -38,7 +38,7 @@ struct spear_sdhci {
 
 /* sdhci ops */
 static const struct sdhci_ops sdhci_pltfm_ops = {
-	/* Nothing to do for now. */
+	.set_bus_width = sdhci_set_bus_width,
 };
 
 #ifdef CONFIG_OF
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index a835898a68dd..feed799b827a 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -127,7 +127,7 @@ static void tegra_sdhci_reset_exit(struct sdhci_host *host, u8 mask)
 	}
 }
 
-static int tegra_sdhci_buswidth(struct sdhci_host *host, int bus_width)
+static void tegra_sdhci_set_bus_width(struct sdhci_host *host, int bus_width)
 {
 	u32 ctrl;
 
@@ -144,7 +144,6 @@ static int tegra_sdhci_buswidth(struct sdhci_host *host, int bus_width)
 			ctrl &= ~SDHCI_CTRL_4BITBUS;
 	}
 	sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
-	return 0;
 }
 
 static const struct sdhci_ops tegra_sdhci_ops = {
@@ -152,7 +151,7 @@ static const struct sdhci_ops tegra_sdhci_ops = {
 	.read_l     = tegra_sdhci_readl,
 	.read_w     = tegra_sdhci_readw,
 	.write_l    = tegra_sdhci_writel,
-	.platform_bus_width = tegra_sdhci_buswidth,
+	.set_bus_width = tegra_sdhci_set_bus_width,
 	.platform_reset_exit = tegra_sdhci_reset_exit,
 };
 
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index e7e4c18a1ff5..5be0f4023cd2 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1413,6 +1413,27 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
+void sdhci_set_bus_width(struct sdhci_host *host, int width)
+{
+	u8 ctrl;
+
+	ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
+	if (width == MMC_BUS_WIDTH_8) {
+		ctrl &= ~SDHCI_CTRL_4BITBUS;
+		if (host->version >= SDHCI_SPEC_300)
+			ctrl |= SDHCI_CTRL_8BITBUS;
+	} else {
+		if (host->version >= SDHCI_SPEC_300)
+			ctrl &= ~SDHCI_CTRL_8BITBUS;
+		if (width == MMC_BUS_WIDTH_4)
+			ctrl |= SDHCI_CTRL_4BITBUS;
+		else
+			ctrl &= ~SDHCI_CTRL_4BITBUS;
+	}
+	sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+}
+EXPORT_SYMBOL_GPL(sdhci_set_bus_width);
+
 static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 {
 	unsigned long flags;
@@ -1458,29 +1479,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 	if (host->ops->platform_send_init_74_clocks)
 		host->ops->platform_send_init_74_clocks(host, ios->power_mode);
 
-	/*
-	 * If your platform has 8-bit width support but is not a v3 controller,
-	 * or if it requires special setup code, you should implement that in
-	 * platform_bus_width().
-	 */
-	if (host->ops->platform_bus_width) {
-		host->ops->platform_bus_width(host, ios->bus_width);
-	} else {
-		ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
-		if (ios->bus_width == MMC_BUS_WIDTH_8) {
-			ctrl &= ~SDHCI_CTRL_4BITBUS;
-			if (host->version >= SDHCI_SPEC_300)
-				ctrl |= SDHCI_CTRL_8BITBUS;
-		} else {
-			if (host->version >= SDHCI_SPEC_300)
-				ctrl &= ~SDHCI_CTRL_8BITBUS;
-			if (ios->bus_width == MMC_BUS_WIDTH_4)
-				ctrl |= SDHCI_CTRL_4BITBUS;
-			else
-				ctrl &= ~SDHCI_CTRL_4BITBUS;
-		}
-		sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
-	}
+	host->ops->set_bus_width(host, ios->bus_width);
 
 	ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
 
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index fc6f81d2f377..0301f928eb11 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -281,8 +281,7 @@ struct sdhci_ops {
 	unsigned int	(*get_max_clock)(struct sdhci_host *host);
 	unsigned int	(*get_min_clock)(struct sdhci_host *host);
 	unsigned int	(*get_timeout_clock)(struct sdhci_host *host);
-	int		(*platform_bus_width)(struct sdhci_host *host,
-					       int width);
+	void		(*set_bus_width)(struct sdhci_host *host, int width);
 	void (*platform_send_init_74_clocks)(struct sdhci_host *host,
 					     u8 power_mode);
 	unsigned int    (*get_ro)(struct sdhci_host *host);
@@ -402,6 +401,8 @@ static inline bool sdhci_sdio_irq_enabled(struct sdhci_host *host)
 	return !!(host->flags & SDHCI_SDIO_IRQ_ENABLED);
 }
 
+void sdhci_set_bus_width(struct sdhci_host *host, int width);
+
 #ifdef CONFIG_PM
 extern int sdhci_suspend_host(struct sdhci_host *host);
 extern int sdhci_resume_host(struct sdhci_host *host);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 194/222] mmc: sdhci: convert reset into a library function
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (192 preceding siblings ...)
  2014-04-25 11:57 ` [PATCH 193/222] mmc: sdhci: convert generic bus width setup to library function Russell King
@ 2014-04-25 11:57 ` Russell King
  2014-04-25 11:57 ` [PATCH 195/222] mmc: sdhci: move FSL ESDHC reset handling quirk into esdhc code Russell King
                   ` (28 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:57 UTC (permalink / raw)
  To: linux-arm-kernel

Rather than having platform_reset_enter/platform_reset_exit methods,
turn the core of the reset handling into a library function which
platforms can call at the appropriate moment in their (new) reset
method.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci-acpi.c      |  2 ++
 drivers/mmc/host/sdhci-bcm-kona.c  |  1 +
 drivers/mmc/host/sdhci-bcm2835.c   |  1 +
 drivers/mmc/host/sdhci-cns3xxx.c   |  1 +
 drivers/mmc/host/sdhci-dove.c      |  1 +
 drivers/mmc/host/sdhci-esdhc-imx.c |  1 +
 drivers/mmc/host/sdhci-of-arasan.c |  1 +
 drivers/mmc/host/sdhci-of-esdhc.c  |  1 +
 drivers/mmc/host/sdhci-of-hlwd.c   |  1 +
 drivers/mmc/host/sdhci-pci.c       |  1 +
 drivers/mmc/host/sdhci-pltfm.c     |  1 +
 drivers/mmc/host/sdhci-pxav2.c     |  6 +++--
 drivers/mmc/host/sdhci-pxav3.c     |  6 +++--
 drivers/mmc/host/sdhci-s3c.c       |  1 +
 drivers/mmc/host/sdhci-sirf.c      |  1 +
 drivers/mmc/host/sdhci-spear.c     |  1 +
 drivers/mmc/host/sdhci-tegra.c     |  6 +++--
 drivers/mmc/host/sdhci.c           | 47 +++++++++++++++++++-------------------
 drivers/mmc/host/sdhci.h           |  4 ++--
 19 files changed, 53 insertions(+), 31 deletions(-)

diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c
index 0e4ba0a4cd71..aca84a682551 100644
--- a/drivers/mmc/host/sdhci-acpi.c
+++ b/drivers/mmc/host/sdhci-acpi.c
@@ -104,11 +104,13 @@ static void sdhci_acpi_int_hw_reset(struct sdhci_host *host)
 static const struct sdhci_ops sdhci_acpi_ops_dflt = {
 	.enable_dma = sdhci_acpi_enable_dma,
 	.set_bus_width = sdhci_set_bus_width,
+	.reset = sdhci_reset,
 };
 
 static const struct sdhci_ops sdhci_acpi_ops_int = {
 	.enable_dma = sdhci_acpi_enable_dma,
 	.set_bus_width = sdhci_set_bus_width,
+	.reset = sdhci_reset,
 	.hw_reset   = sdhci_acpi_int_hw_reset,
 };
 
diff --git a/drivers/mmc/host/sdhci-bcm-kona.c b/drivers/mmc/host/sdhci-bcm-kona.c
index 06cdb8abb25e..7b97bfab910d 100644
--- a/drivers/mmc/host/sdhci-bcm-kona.c
+++ b/drivers/mmc/host/sdhci-bcm-kona.c
@@ -210,6 +210,7 @@ static struct sdhci_ops sdhci_bcm_kona_ops = {
 	.get_timeout_clock = sdhci_bcm_kona_get_timeout_clock,
 	.platform_send_init_74_clocks = sdhci_bcm_kona_init_74_clocks,
 	.set_bus_width = sdhci_set_bus_width,
+	.reset = sdhci_reset,
 	.card_event = sdhci_bcm_kona_card_event,
 };
 
diff --git a/drivers/mmc/host/sdhci-bcm2835.c b/drivers/mmc/host/sdhci-bcm2835.c
index 7ab69af979b4..289b1c80d5fc 100644
--- a/drivers/mmc/host/sdhci-bcm2835.c
+++ b/drivers/mmc/host/sdhci-bcm2835.c
@@ -134,6 +134,7 @@ static const struct sdhci_ops bcm2835_sdhci_ops = {
 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
 	.get_min_clock = bcm2835_sdhci_get_min_clock,
 	.set_bus_width = sdhci_set_bus_width,
+	.reset = sdhci_reset,
 };
 
 static const struct sdhci_pltfm_data bcm2835_sdhci_pdata = {
diff --git a/drivers/mmc/host/sdhci-cns3xxx.c b/drivers/mmc/host/sdhci-cns3xxx.c
index 5e0cc9c47887..87af66bb1ea8 100644
--- a/drivers/mmc/host/sdhci-cns3xxx.c
+++ b/drivers/mmc/host/sdhci-cns3xxx.c
@@ -83,6 +83,7 @@ static const struct sdhci_ops sdhci_cns3xxx_ops = {
 	.get_max_clock	= sdhci_cns3xxx_get_max_clk,
 	.set_clock	= sdhci_cns3xxx_set_clock,
 	.set_bus_width	= sdhci_set_bus_width,
+	.reset          = sdhci_reset,
 };
 
 static const struct sdhci_pltfm_data sdhci_cns3xxx_pdata = {
diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c
index 8fc547a7048a..1408cc11d881 100644
--- a/drivers/mmc/host/sdhci-dove.c
+++ b/drivers/mmc/host/sdhci-dove.c
@@ -87,6 +87,7 @@ static const struct sdhci_ops sdhci_dove_ops = {
 	.read_w	= sdhci_dove_readw,
 	.read_l	= sdhci_dove_readl,
 	.set_bus_width = sdhci_set_bus_width,
+	.reset = sdhci_reset,
 };
 
 static const struct sdhci_pltfm_data sdhci_dove_pdata = {
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 568239d84cbe..b1d74fa33c5f 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -888,6 +888,7 @@ static struct sdhci_ops sdhci_esdhc_ops = {
 	.get_ro = esdhc_pltfm_get_ro,
 	.set_bus_width = esdhc_pltfm_set_bus_width,
 	.set_uhs_signaling = esdhc_set_uhs_signaling,
+	.reset = sdhci_reset,
 };
 
 static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
index 9bb1dd263a45..faef21740584 100644
--- a/drivers/mmc/host/sdhci-of-arasan.c
+++ b/drivers/mmc/host/sdhci-of-arasan.c
@@ -55,6 +55,7 @@ static struct sdhci_ops sdhci_arasan_ops = {
 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
 	.get_timeout_clock = sdhci_arasan_get_timeout_clock,
 	.set_bus_width = sdhci_set_bus_width,
+	.reset = sdhci_reset,
 };
 
 static struct sdhci_pltfm_data sdhci_arasan_pdata = {
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index 86b8326e77c3..4530f9957f20 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -309,6 +309,7 @@ static const struct sdhci_ops sdhci_esdhc_ops = {
 #endif
 	.adma_workaround = esdhci_of_adma_workaround,
 	.set_bus_width = esdhc_pltfm_set_bus_width,
+	.reset = sdhci_reset,
 };
 
 static const struct sdhci_pltfm_data sdhci_esdhc_pdata = {
diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c
index 4d5d0015e392..fb01958cb18e 100644
--- a/drivers/mmc/host/sdhci-of-hlwd.c
+++ b/drivers/mmc/host/sdhci-of-hlwd.c
@@ -59,6 +59,7 @@ static const struct sdhci_ops sdhci_hlwd_ops = {
 	.write_w = sdhci_hlwd_writew,
 	.write_b = sdhci_hlwd_writeb,
 	.set_bus_width = sdhci_set_bus_width,
+	.reset = sdhci_reset,
 };
 
 static const struct sdhci_pltfm_data sdhci_hlwd_pdata = {
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index 8c4e9c2909b7..87f9dd91f68c 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -1080,6 +1080,7 @@ static void sdhci_pci_hw_reset(struct sdhci_host *host)
 static const struct sdhci_ops sdhci_pci_ops = {
 	.enable_dma	= sdhci_pci_enable_dma,
 	.set_bus_width	= sdhci_pci_set_bus_width,
+	.reset		= sdhci_reset,
 	.hw_reset		= sdhci_pci_hw_reset,
 };
 
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
index 40b0fe224f9d..bfbf467b61c7 100644
--- a/drivers/mmc/host/sdhci-pltfm.c
+++ b/drivers/mmc/host/sdhci-pltfm.c
@@ -46,6 +46,7 @@ EXPORT_SYMBOL_GPL(sdhci_pltfm_clk_get_max_clock);
 
 static const struct sdhci_ops sdhci_pltfm_ops = {
 	.set_bus_width = sdhci_set_bus_width,
+	.reset = sdhci_reset,
 };
 
 #ifdef CONFIG_OF
diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c
index d24c282e5eb8..2eee0c8b88eb 100644
--- a/drivers/mmc/host/sdhci-pxav2.c
+++ b/drivers/mmc/host/sdhci-pxav2.c
@@ -51,11 +51,13 @@
 #define MMC_CARD		0x1000
 #define MMC_WIDTH		0x0100
 
-static void pxav2_set_private_registers(struct sdhci_host *host, u8 mask)
+static void pxav2_reset(struct sdhci_host *host, u8 mask)
 {
 	struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc));
 	struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data;
 
+	sdhci_reset(host, mask);
+
 	if (mask == SDHCI_RESET_ALL) {
 		u16 tmp = 0;
 
@@ -111,8 +113,8 @@ static void pxav2_mmc_set_bus_width(struct sdhci_host *host, int width)
 
 static const struct sdhci_ops pxav2_sdhci_ops = {
 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
-	.platform_reset_exit = pxav2_set_private_registers,
 	.set_bus_width = pxav2_mmc_set_bus_width,
+	.reset         = pxav2_reset,
 };
 
 #ifdef CONFIG_OF
diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c
index b06db03b6d81..86564233ae93 100644
--- a/drivers/mmc/host/sdhci-pxav3.c
+++ b/drivers/mmc/host/sdhci-pxav3.c
@@ -112,11 +112,13 @@ static int mv_conf_mbus_windows(struct platform_device *pdev,
 	return 0;
 }
 
-static void pxav3_set_private_registers(struct sdhci_host *host, u8 mask)
+static void pxav3_reset(struct sdhci_host *host, u8 mask)
 {
 	struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc));
 	struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data;
 
+	sdhci_reset(host, mask);
+
 	if (mask == SDHCI_RESET_ALL) {
 		/*
 		 * tune timing of read data/command when crc error happen
@@ -223,11 +225,11 @@ static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
 }
 
 static const struct sdhci_ops pxav3_sdhci_ops = {
-	.platform_reset_exit = pxav3_set_private_registers,
 	.set_uhs_signaling = pxav3_set_uhs_signaling,
 	.platform_send_init_74_clocks = pxav3_gen_init_74_clocks,
 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
 	.set_bus_width = sdhci_set_bus_width,
+	.reset = pxav3_reset,
 };
 
 static struct sdhci_pltfm_data sdhci_pxav3_pdata = {
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
index 181d8c962f26..8e26172a97de 100644
--- a/drivers/mmc/host/sdhci-s3c.c
+++ b/drivers/mmc/host/sdhci-s3c.c
@@ -365,6 +365,7 @@ static struct sdhci_ops sdhci_s3c_ops = {
 	.set_clock		= sdhci_s3c_set_clock,
 	.get_min_clock		= sdhci_s3c_get_min_clock,
 	.set_bus_width		= sdhci_s3c_set_bus_width,
+	.reset			= sdhci_reset,
 };
 
 static void sdhci_s3c_notify_change(struct platform_device *dev, int state)
diff --git a/drivers/mmc/host/sdhci-sirf.c b/drivers/mmc/host/sdhci-sirf.c
index 16fcd48f9556..5d79e10e1ba2 100644
--- a/drivers/mmc/host/sdhci-sirf.c
+++ b/drivers/mmc/host/sdhci-sirf.c
@@ -30,6 +30,7 @@ static unsigned int sdhci_sirf_get_max_clk(struct sdhci_host *host)
 static struct sdhci_ops sdhci_sirf_ops = {
 	.get_max_clock	= sdhci_sirf_get_max_clk,
 	.set_bus_width = sdhci_set_bus_width,
+	.reset = sdhci_reset,
 };
 
 static struct sdhci_pltfm_data sdhci_sirf_pdata = {
diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c
index dc8967b657ed..c2a2bedc8813 100644
--- a/drivers/mmc/host/sdhci-spear.c
+++ b/drivers/mmc/host/sdhci-spear.c
@@ -39,6 +39,7 @@ struct spear_sdhci {
 /* sdhci ops */
 static const struct sdhci_ops sdhci_pltfm_ops = {
 	.set_bus_width = sdhci_set_bus_width,
+	.reset = sdhci_reset,
 };
 
 #ifdef CONFIG_OF
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index feed799b827a..7754c0319fda 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -108,12 +108,14 @@ static unsigned int tegra_sdhci_get_ro(struct sdhci_host *host)
 	return mmc_gpio_get_ro(host->mmc);
 }
 
-static void tegra_sdhci_reset_exit(struct sdhci_host *host, u8 mask)
+static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask)
 {
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 	struct sdhci_tegra *tegra_host = pltfm_host->priv;
 	const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
 
+	sdhci_reset(host, mask);
+
 	if (!(mask & SDHCI_RESET_ALL))
 		return;
 
@@ -152,7 +154,7 @@ static const struct sdhci_ops tegra_sdhci_ops = {
 	.read_w     = tegra_sdhci_readw,
 	.write_l    = tegra_sdhci_writel,
 	.set_bus_width = tegra_sdhci_set_bus_width,
-	.platform_reset_exit = tegra_sdhci_reset_exit,
+	.reset      = tegra_sdhci_reset,
 };
 
 static const struct sdhci_pltfm_data sdhci_tegra20_pdata = {
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 5be0f4023cd2..4095754647a9 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -163,17 +163,9 @@ static void sdhci_disable_card_detection(struct sdhci_host *host)
 	sdhci_set_card_detection(host, false);
 }
 
-static void sdhci_reset(struct sdhci_host *host, u8 mask)
+void sdhci_reset(struct sdhci_host *host, u8 mask)
 {
 	unsigned long timeout;
-	if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
-		if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) &
-			SDHCI_CARD_PRESENT))
-			return;
-	}
-
-	if (host->ops->platform_reset_enter)
-		host->ops->platform_reset_enter(host, mask);
 
 	sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
 
@@ -198,9 +190,18 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
 		timeout--;
 		mdelay(1);
 	}
+}
+EXPORT_SYMBOL_GPL(sdhci_reset);
+
+static void sdhci_do_reset(struct sdhci_host *host, u8 mask)
+{
+	if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
+		if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) &
+			SDHCI_CARD_PRESENT))
+			return;
+	}
 
-	if (host->ops->platform_reset_exit)
-		host->ops->platform_reset_exit(host, mask);
+	host->ops->reset(host, mask);
 
 	if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET) {
 		sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
@@ -218,9 +219,9 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
 static void sdhci_init(struct sdhci_host *host, int soft)
 {
 	if (soft)
-		sdhci_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA);
+		sdhci_do_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA);
 	else
-		sdhci_reset(host, SDHCI_RESET_ALL);
+		sdhci_do_reset(host, SDHCI_RESET_ALL);
 
 	host->ier = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
 		    SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT |
@@ -962,8 +963,8 @@ static void sdhci_finish_data(struct sdhci_host *host)
 		 * upon error conditions.
 		 */
 		if (data->error) {
-			sdhci_reset(host, SDHCI_RESET_CMD);
-			sdhci_reset(host, SDHCI_RESET_DATA);
+			sdhci_do_reset(host, SDHCI_RESET_CMD);
+			sdhci_do_reset(host, SDHCI_RESET_DATA);
 		}
 
 		sdhci_send_command(host, data->stop);
@@ -1585,7 +1586,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 	 * it on each ios seems to solve the problem.
 	 */
 	if(host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS)
-		sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+		sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
 
 	mmiowb();
 	spin_unlock_irqrestore(&host->lock, flags);
@@ -2081,8 +2082,8 @@ static void sdhci_card_event(struct mmc_host *mmc)
 		pr_err("%s: Resetting controller.\n",
 			mmc_hostname(host->mmc));
 
-		sdhci_reset(host, SDHCI_RESET_CMD);
-		sdhci_reset(host, SDHCI_RESET_DATA);
+		sdhci_do_reset(host, SDHCI_RESET_CMD);
+		sdhci_do_reset(host, SDHCI_RESET_DATA);
 
 		host->mrq->cmd->error = -ENOMEDIUM;
 		tasklet_schedule(&host->finish_tasklet);
@@ -2150,8 +2151,8 @@ static void sdhci_tasklet_finish(unsigned long param)
 
 		/* Spec says we should do both at the same time, but Ricoh
 		   controllers do not like that. */
-		sdhci_reset(host, SDHCI_RESET_CMD);
-		sdhci_reset(host, SDHCI_RESET_DATA);
+		sdhci_do_reset(host, SDHCI_RESET_CMD);
+		sdhci_do_reset(host, SDHCI_RESET_DATA);
 	}
 
 	host->mrq = NULL;
@@ -2786,7 +2787,7 @@ int sdhci_add_host(struct sdhci_host *host)
 	if (debug_quirks2)
 		host->quirks2 = debug_quirks2;
 
-	sdhci_reset(host, SDHCI_RESET_ALL);
+	sdhci_do_reset(host, SDHCI_RESET_ALL);
 
 	host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
 	host->version = (host->version & SDHCI_SPEC_VER_MASK)
@@ -3270,7 +3271,7 @@ int sdhci_add_host(struct sdhci_host *host)
 
 #ifdef SDHCI_USE_LEDS_CLASS
 reset:
-	sdhci_reset(host, SDHCI_RESET_ALL);
+	sdhci_do_reset(host, SDHCI_RESET_ALL);
 	sdhci_writel(host, 0, SDHCI_INT_ENABLE);
 	sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
 	free_irq(host->irq, host);
@@ -3312,7 +3313,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
 #endif
 
 	if (!dead)
-		sdhci_reset(host, SDHCI_RESET_ALL);
+		sdhci_do_reset(host, SDHCI_RESET_ALL);
 
 	sdhci_writel(host, 0, SDHCI_INT_ENABLE);
 	sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 0301f928eb11..7d84cb3b0e00 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -285,8 +285,7 @@ struct sdhci_ops {
 	void (*platform_send_init_74_clocks)(struct sdhci_host *host,
 					     u8 power_mode);
 	unsigned int    (*get_ro)(struct sdhci_host *host);
-	void	(*platform_reset_enter)(struct sdhci_host *host, u8 mask);
-	void	(*platform_reset_exit)(struct sdhci_host *host, u8 mask);
+	void		(*reset)(struct sdhci_host *host, u8 mask);
 	int	(*platform_execute_tuning)(struct sdhci_host *host, u32 opcode);
 	int	(*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
 	void	(*hw_reset)(struct sdhci_host *host);
@@ -402,6 +401,7 @@ static inline bool sdhci_sdio_irq_enabled(struct sdhci_host *host)
 }
 
 void sdhci_set_bus_width(struct sdhci_host *host, int width);
+void sdhci_reset(struct sdhci_host *host, u8 mask);
 
 #ifdef CONFIG_PM
 extern int sdhci_suspend_host(struct sdhci_host *host);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 195/222] mmc: sdhci: move FSL ESDHC reset handling quirk into esdhc code
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (193 preceding siblings ...)
  2014-04-25 11:57 ` [PATCH 194/222] mmc: sdhci: convert reset into a " Russell King
@ 2014-04-25 11:57 ` Russell King
  2014-04-25 11:58 ` [PATCH 196/222] mmc: sdhci: avoid sync'ing the SG if there's no misalignment Russell King
                   ` (27 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:57 UTC (permalink / raw)
  To: linux-arm-kernel

The Freescale esdhc driver is the only driver which needs the interrupt
registers restored after a reset.  Move this quirk to be part of the
ESDHC driver implementation.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci-esdhc-imx.c | 10 +++++++++-
 drivers/mmc/host/sdhci-esdhc.h     |  3 +--
 drivers/mmc/host/sdhci.c           |  5 -----
 include/linux/mmc/sdhci.h          |  2 --
 4 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index b1d74fa33c5f..812c5772d900 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -876,6 +876,14 @@ static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
 	return esdhc_change_pinstate(host, uhs);
 }
 
+static void esdhc_reset(struct sdhci_host *host, u8 mask)
+{
+	sdhci_reset(host, mask);
+
+	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+}
+
 static struct sdhci_ops sdhci_esdhc_ops = {
 	.read_l = esdhc_readl_le,
 	.read_w = esdhc_readw_le,
@@ -888,7 +896,7 @@ static struct sdhci_ops sdhci_esdhc_ops = {
 	.get_ro = esdhc_pltfm_get_ro,
 	.set_bus_width = esdhc_pltfm_set_bus_width,
 	.set_uhs_signaling = esdhc_set_uhs_signaling,
-	.reset = sdhci_reset,
+	.reset = esdhc_reset,
 };
 
 static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h
index a7d9f95a7b03..de69bddc3afc 100644
--- a/drivers/mmc/host/sdhci-esdhc.h
+++ b/drivers/mmc/host/sdhci-esdhc.h
@@ -22,8 +22,7 @@
 				SDHCI_QUIRK_NO_BUSY_IRQ | \
 				SDHCI_QUIRK_NONSTANDARD_CLOCK | \
 				SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | \
-				SDHCI_QUIRK_PIO_NEEDS_DELAY | \
-				SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
+				SDHCI_QUIRK_PIO_NEEDS_DELAY)
 
 #define ESDHC_SYSTEM_CONTROL	0x2c
 #define ESDHC_CLOCK_MASK	0x0000fff0
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 4095754647a9..e77d4cbd5bad 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -203,11 +203,6 @@ static void sdhci_do_reset(struct sdhci_host *host, u8 mask)
 
 	host->ops->reset(host, mask);
 
-	if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET) {
-		sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
-		sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
-	}
-
 	if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
 		if ((host->ops->enable_dma) && (mask & SDHCI_RESET_ALL))
 			host->ops->enable_dma(host);
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index 9361d8ef509d..02919ef99419 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -61,8 +61,6 @@ struct sdhci_host {
 #define SDHCI_QUIRK_NONSTANDARD_CLOCK			(1<<17)
 /* Controller does not like fast PIO transfers */
 #define SDHCI_QUIRK_PIO_NEEDS_DELAY			(1<<18)
-/* Controller losing signal/interrupt enable states after reset */
-#define SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET		(1<<19)
 /* Controller has to be forced to use block size of 2048 bytes */
 #define SDHCI_QUIRK_FORCE_BLK_SZ_2048			(1<<20)
 /* Controller cannot do multi-block transfers */
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 196/222] mmc: sdhci: avoid sync'ing the SG if there's no misalignment
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (194 preceding siblings ...)
  2014-04-25 11:57 ` [PATCH 195/222] mmc: sdhci: move FSL ESDHC reset handling quirk into esdhc code Russell King
@ 2014-04-25 11:58 ` Russell King
  2014-04-25 11:58 ` [PATCH 197/222] mmc: sdhci: convert ADMA descriptors to a coherent allocation Russell King
                   ` (26 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:58 UTC (permalink / raw)
  To: linux-arm-kernel

On read, we don't need to sync the whole scatterlist and then check
whether any segments need copying - if we check first, we avoid
potentially expensive cache handling.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index e77d4cbd5bad..aca9081857e0 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -602,6 +602,7 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
 	u8 *align;
 	char *buffer;
 	unsigned long flags;
+	bool has_unaligned;
 
 	if (data->flags & MMC_DATA_READ)
 		direction = DMA_FROM_DEVICE;
@@ -614,7 +615,15 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
 	dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
 		128 * 4, direction);
 
-	if (data->flags & MMC_DATA_READ) {
+	/* Do a quick scan of the SG list for any unaligned mappings */
+	has_unaligned = false;
+	for_each_sg(data->sg, sg, host->sg_count, i)
+		if (sg_dma_address(sg) & 3) {
+			has_unaligned = true;
+			break;
+		}
+
+	if (has_unaligned && data->flags & MMC_DATA_READ) {
 		dma_sync_sg_for_cpu(mmc_dev(host->mmc), data->sg,
 			data->sg_len, direction);
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 197/222] mmc: sdhci: convert ADMA descriptors to a coherent allocation
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (195 preceding siblings ...)
  2014-04-25 11:58 ` [PATCH 196/222] mmc: sdhci: avoid sync'ing the SG if there's no misalignment Russell King
@ 2014-04-25 11:58 ` Russell King
  2014-04-25 11:58 ` [PATCH 198/222] mmc: sdhci: clean up sdhci_update_clock()/sdhci_set_clock() Russell King
                   ` (25 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:58 UTC (permalink / raw)
  To: linux-arm-kernel

Rather than using the streaming API, use the coherent allocator to
provide this memory, thereby eliminating cache flushing of it each
time we map and unmap it.  This results in a 7.5% increase in
transfer speed with a UHS-1 card operating in 3.3v mode at a clock
of 49.5MHz.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci.c | 43 ++++++++++++++++++++++---------------------
 1 file changed, 22 insertions(+), 21 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index aca9081857e0..90445ad245d9 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -44,6 +44,8 @@
 
 #define MAX_TUNING_LOOP 40
 
+#define ADMA_SIZE	((128 * 2 + 1) * 4)
+
 static unsigned int debug_quirks = 0;
 static unsigned int debug_quirks2;
 
@@ -481,11 +483,6 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
 	else
 		direction = DMA_TO_DEVICE;
 
-	/*
-	 * The ADMA descriptor table is mapped further down as we
-	 * need to fill it with data first.
-	 */
-
 	host->align_addr = dma_map_single(mmc_dev(host->mmc),
 		host->align_buffer, 128 * 4, direction);
 	if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr))
@@ -546,7 +543,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
 		 * If this triggers then we have a calculation bug
 		 * somewhere. :/
 		 */
-		WARN_ON((desc - host->adma_desc) > (128 * 2 + 1) * 4);
+		WARN_ON((desc - host->adma_desc) > ADMA_SIZE);
 	}
 
 	if (host->quirks & SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC) {
@@ -574,17 +571,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
 			host->align_addr, 128 * 4, direction);
 	}
 
-	host->adma_addr = dma_map_single(mmc_dev(host->mmc),
-		host->adma_desc, (128 * 2 + 1) * 4, DMA_TO_DEVICE);
-	if (dma_mapping_error(mmc_dev(host->mmc), host->adma_addr))
-		goto unmap_entries;
-	BUG_ON(host->adma_addr & 0x3);
-
 	return 0;
 
-unmap_entries:
-	dma_unmap_sg(mmc_dev(host->mmc), data->sg,
-		data->sg_len, direction);
 unmap_align:
 	dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
 		128 * 4, direction);
@@ -609,9 +597,6 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
 	else
 		direction = DMA_TO_DEVICE;
 
-	dma_unmap_single(mmc_dev(host->mmc), host->adma_addr,
-		(128 * 2 + 1) * 4, DMA_TO_DEVICE);
-
 	dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
 		128 * 4, direction);
 
@@ -2851,15 +2836,29 @@ int sdhci_add_host(struct sdhci_host *host)
 		 * (128) and potentially one alignment transfer for
 		 * each of those entries.
 		 */
-		host->adma_desc = kmalloc((128 * 2 + 1) * 4, GFP_KERNEL);
+		host->adma_desc = dma_alloc_coherent(mmc_dev(host->mmc),
+						     ADMA_SIZE, &host->adma_addr,
+						     GFP_KERNEL);
 		host->align_buffer = kmalloc(128 * 4, GFP_KERNEL);
 		if (!host->adma_desc || !host->align_buffer) {
-			kfree(host->adma_desc);
+			dma_free_coherent(mmc_dev(host->mmc), ADMA_SIZE,
+					  host->adma_desc, host->adma_addr);
 			kfree(host->align_buffer);
 			pr_warning("%s: Unable to allocate ADMA "
 				"buffers. Falling back to standard DMA.\n",
 				mmc_hostname(mmc));
 			host->flags &= ~SDHCI_USE_ADMA;
+			host->adma_desc = NULL;
+			host->align_buffer = NULL;
+		} else if (host->adma_addr & 3) {
+			pr_warning("%s: unable to allocate aligned ADMA descriptor\n",
+				   mmc_hostname(mmc));
+			host->flags &= ~SDHCI_USE_ADMA;
+			dma_free_coherent(mmc_dev(host->mmc), ADMA_SIZE,
+					  host->adma_desc, host->adma_addr);
+			kfree(host->align_buffer);
+			host->adma_desc = NULL;
+			host->align_buffer = NULL;
 		}
 	}
 
@@ -3337,7 +3336,9 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
 		regulator_put(host->vqmmc);
 	}
 
-	kfree(host->adma_desc);
+	if (host->adma_desc)
+		dma_free_coherent(mmc_dev(host->mmc), ADMA_SIZE,
+				  host->adma_desc, host->adma_addr);
 	kfree(host->align_buffer);
 
 	host->adma_desc = NULL;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 198/222] mmc: sdhci: clean up sdhci_update_clock()/sdhci_set_clock()
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (196 preceding siblings ...)
  2014-04-25 11:58 ` [PATCH 197/222] mmc: sdhci: convert ADMA descriptors to a coherent allocation Russell King
@ 2014-04-25 11:58 ` Russell King
  2014-04-25 11:58 ` [PATCH 199/222] mmc: sdhci: move setting host->clock into sdhci_do_set_ios() Russell King
                   ` (24 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:58 UTC (permalink / raw)
  To: linux-arm-kernel

Only one caller to sdhci_set_clock() needs to check whether the
requested clock frequency was the same as the currently set frequency,
yet we work around this in several other sites via sdhci_update_clock().
Rather than doing this, move those checks out into sdhci_do_set_ios(),
which then allows sdhci_update_clock() to be eliminated.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci-cns3xxx.c |  3 ---
 drivers/mmc/host/sdhci.c         | 21 +++++----------------
 2 files changed, 5 insertions(+), 19 deletions(-)

diff --git a/drivers/mmc/host/sdhci-cns3xxx.c b/drivers/mmc/host/sdhci-cns3xxx.c
index 87af66bb1ea8..fa11f63b78a0 100644
--- a/drivers/mmc/host/sdhci-cns3xxx.c
+++ b/drivers/mmc/host/sdhci-cns3xxx.c
@@ -30,9 +30,6 @@ static void sdhci_cns3xxx_set_clock(struct sdhci_host *host, unsigned int clock)
 	u16 clk;
 	unsigned long timeout;
 
-	if (clock == host->clock)
-		return;
-
 	sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
 
 	if (clock == 0)
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 90445ad245d9..062ea3a064d3 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1119,9 +1119,6 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 	u16 clk = 0;
 	unsigned long timeout;
 
-	if (clock && clock == host->clock)
-		return;
-
 	host->mmc->actual_clock = 0;
 
 	if (host->ops->set_clock) {
@@ -1228,15 +1225,6 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 	host->clock = clock;
 }
 
-static inline void sdhci_update_clock(struct sdhci_host *host)
-{
-	unsigned int clock;
-
-	clock = host->clock;
-	host->clock = 0;
-	sdhci_set_clock(host, clock);
-}
-
 static int sdhci_set_power(struct sdhci_host *host, unsigned short power)
 {
 	u8 pwr = 0;
@@ -1453,7 +1441,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 		!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN))
 		sdhci_enable_preset_value(host, false);
 
-	sdhci_set_clock(host, ios->clock);
+	if (!ios->clock || ios->clock != host->clock)
+		sdhci_set_clock(host, ios->clock);
 
 	if (ios->power_mode == MMC_POWER_OFF)
 		vdd_bit = sdhci_set_power(host, -1);
@@ -1521,7 +1510,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 			sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
 
 			/* Re-enable SD Clock */
-			sdhci_update_clock(host);
+			sdhci_set_clock(host, host->clock);
 		}
 
 
@@ -1565,7 +1554,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 		}
 
 		/* Re-enable SD Clock */
-		sdhci_update_clock(host);
+		sdhci_set_clock(host, host->clock);
 	} else
 		sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
 
@@ -2136,7 +2125,7 @@ static void sdhci_tasklet_finish(unsigned long param)
 		/* Some controllers need this kick or reset won't work here */
 		if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET)
 			/* This is to force an update */
-			sdhci_update_clock(host);
+			sdhci_set_clock(host, host->clock);
 
 		/* Spec says we should do both at the same time, but Ricoh
 		   controllers do not like that. */
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 199/222] mmc: sdhci: move setting host->clock into sdhci_do_set_ios()
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (197 preceding siblings ...)
  2014-04-25 11:58 ` [PATCH 198/222] mmc: sdhci: clean up sdhci_update_clock()/sdhci_set_clock() Russell King
@ 2014-04-25 11:58 ` Russell King
  2014-04-25 11:58 ` [PATCH 200/222] mmc: sdhci: move setting mmc->actual_clock into set_clock handlers Russell King
                   ` (23 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:58 UTC (permalink / raw)
  To: linux-arm-kernel

We don't need implementations to do this, since the only time it's
necessary is when we change the clock, and the only place that happens
is in sdhci_do_set_ios().  So, move it there, and remove it from the
iMX platform backend.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci-cns3xxx.c   | 4 +---
 drivers/mmc/host/sdhci-esdhc-imx.c | 4 +---
 drivers/mmc/host/sdhci-of-esdhc.c  | 4 +---
 drivers/mmc/host/sdhci-s3c.c       | 3 ---
 drivers/mmc/host/sdhci.c           | 9 ++++-----
 5 files changed, 7 insertions(+), 17 deletions(-)

diff --git a/drivers/mmc/host/sdhci-cns3xxx.c b/drivers/mmc/host/sdhci-cns3xxx.c
index fa11f63b78a0..f11fb908ad78 100644
--- a/drivers/mmc/host/sdhci-cns3xxx.c
+++ b/drivers/mmc/host/sdhci-cns3xxx.c
@@ -33,7 +33,7 @@ static void sdhci_cns3xxx_set_clock(struct sdhci_host *host, unsigned int clock)
 	sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
 
 	if (clock == 0)
-		goto out;
+		return;
 
 	while (host->max_clk / div > clock) {
 		/*
@@ -72,8 +72,6 @@ static void sdhci_cns3xxx_set_clock(struct sdhci_host *host, unsigned int clock)
 
 	clk |= SDHCI_CLOCK_CARD_EN;
 	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
-out:
-	host->clock = clock;
 }
 
 static const struct sdhci_ops sdhci_cns3xxx_ops = {
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 812c5772d900..1e68a77c9987 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -605,7 +605,7 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
 			writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
 					host->ioaddr + ESDHC_VENDOR_SPEC);
 		}
-		goto out;
+		return;
 	}
 
 	if (esdhc_is_usdhc(imx_data) && !imx_data->is_ddr)
@@ -645,8 +645,6 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
 	}
 
 	mdelay(1);
-out:
-	host->clock = clock;
 }
 
 static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index 4530f9957f20..d814b3ecb1f7 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -205,7 +205,7 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
 	u32 temp;
 
 	if (clock == 0)
-		goto out;
+		return;
 
 	/* Workaround to reduce the clock frequency for p1010 esdhc */
 	if (of_find_compatible_node(NULL, NULL, "fsl,p1010-esdhc")) {
@@ -238,8 +238,6 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
 		| (pre_div << ESDHC_PREDIV_SHIFT));
 	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
 	mdelay(1);
-out:
-	host->clock = clock;
 }
 
 #ifdef CONFIG_PM
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
index 8e26172a97de..6b424a6f79c4 100644
--- a/drivers/mmc/host/sdhci-s3c.c
+++ b/drivers/mmc/host/sdhci-s3c.c
@@ -298,7 +298,6 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
 	/* If the clock is going off, set to 0 at clock control register */
 	if (clock == 0) {
 		sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
-		host->clock = clock;
 		return;
 	}
 
@@ -306,8 +305,6 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
 
 	clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock);
 
-	host->clock = clock;
-
 	clk = SDHCI_CLOCK_INT_EN;
 	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
 
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 062ea3a064d3..d22bc21b3517 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1130,7 +1130,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 	sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
 
 	if (clock == 0)
-		goto out;
+		return;
 
 	if (host->version >= SDHCI_SPEC_300) {
 		if (sdhci_readw(host, SDHCI_HOST_CONTROL2) &
@@ -1220,9 +1220,6 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 
 	clk |= SDHCI_CLOCK_CARD_EN;
 	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
-
-out:
-	host->clock = clock;
 }
 
 static int sdhci_set_power(struct sdhci_host *host, unsigned short power)
@@ -1441,8 +1438,10 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 		!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN))
 		sdhci_enable_preset_value(host, false);
 
-	if (!ios->clock || ios->clock != host->clock)
+	if (!ios->clock || ios->clock != host->clock) {
 		sdhci_set_clock(host, ios->clock);
+		host->clock = ios->clock;
+	}
 
 	if (ios->power_mode == MMC_POWER_OFF)
 		vdd_bit = sdhci_set_power(host, -1);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 200/222] mmc: sdhci: move setting mmc->actual_clock into set_clock handlers
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (198 preceding siblings ...)
  2014-04-25 11:58 ` [PATCH 199/222] mmc: sdhci: move setting host->clock into sdhci_do_set_ios() Russell King
@ 2014-04-25 11:58 ` Russell King
  2014-04-25 11:58 ` [PATCH 201/222] mmc: sdhci: convert sdhci_set_clock() into a library function Russell King
                   ` (22 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:58 UTC (permalink / raw)
  To: linux-arm-kernel

Move the setting of mmc->actual_clock to zero into the set_clock
handlers themselves.  This will allow us to clean up the calling
logic for the set_clock() method, and turn sdhci_set_clock() into
a library function.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci-cns3xxx.c   | 2 ++
 drivers/mmc/host/sdhci-esdhc-imx.c | 2 ++
 drivers/mmc/host/sdhci-of-esdhc.c  | 3 ++-
 drivers/mmc/host/sdhci-s3c.c       | 4 ++++
 drivers/mmc/host/sdhci.c           | 4 ++--
 5 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/host/sdhci-cns3xxx.c b/drivers/mmc/host/sdhci-cns3xxx.c
index f11fb908ad78..416f4a4c2e35 100644
--- a/drivers/mmc/host/sdhci-cns3xxx.c
+++ b/drivers/mmc/host/sdhci-cns3xxx.c
@@ -30,6 +30,8 @@ static void sdhci_cns3xxx_set_clock(struct sdhci_host *host, unsigned int clock)
 	u16 clk;
 	unsigned long timeout;
 
+	host->mmc->actual_clock = 0;
+
 	sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
 
 	if (clock == 0)
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 1e68a77c9987..ce8939ff97a4 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -600,6 +600,8 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
 	u32 temp, val;
 
 	if (clock == 0) {
+		host->mmc->actual_clock = 0;
+
 		if (esdhc_is_usdhc(imx_data)) {
 			val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
 			writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index d814b3ecb1f7..c4f8cd3f83c8 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -199,11 +199,12 @@ static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
 
 static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
 {
-
 	int pre_div = 2;
 	int div = 1;
 	u32 temp;
 
+	host->mmc->actual_clock = 0;
+
 	if (clock == 0)
 		return;
 
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
index 6b424a6f79c4..464059c91a24 100644
--- a/drivers/mmc/host/sdhci-s3c.c
+++ b/drivers/mmc/host/sdhci-s3c.c
@@ -161,6 +161,8 @@ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock)
 	int src;
 	u32 ctrl;
 
+	host->mmc->actual_clock = 0;
+
 	/* don't bother if the clock is going off. */
 	if (clock == 0)
 		return;
@@ -295,6 +297,8 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
 	unsigned long timeout;
 	u16 clk = 0;
 
+	host->mmc->actual_clock = 0;
+
 	/* If the clock is going off, set to 0 at clock control register */
 	if (clock == 0) {
 		sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index d22bc21b3517..acad1bf32aee 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1119,14 +1119,14 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 	u16 clk = 0;
 	unsigned long timeout;
 
-	host->mmc->actual_clock = 0;
-
 	if (host->ops->set_clock) {
 		host->ops->set_clock(host, clock);
 		if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK)
 			return;
 	}
 
+	host->mmc->actual_clock = 0;
+
 	sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
 
 	if (clock == 0)
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 201/222] mmc: sdhci: convert sdhci_set_clock() into a library function
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (199 preceding siblings ...)
  2014-04-25 11:58 ` [PATCH 200/222] mmc: sdhci: move setting mmc->actual_clock into set_clock handlers Russell King
@ 2014-04-25 11:58 ` Russell King
  2014-04-25 11:59 ` [PATCH 202/222] mmc: sdhci-esdhc-imx: avoid DMA to kernel stack Russell King
                   ` (21 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:58 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci-acpi.c      |  2 ++
 drivers/mmc/host/sdhci-bcm-kona.c  |  1 +
 drivers/mmc/host/sdhci-bcm2835.c   |  1 +
 drivers/mmc/host/sdhci-cns3xxx.c   |  3 +--
 drivers/mmc/host/sdhci-dove.c      |  1 +
 drivers/mmc/host/sdhci-esdhc.h     |  1 -
 drivers/mmc/host/sdhci-of-arasan.c |  1 +
 drivers/mmc/host/sdhci-of-hlwd.c   |  1 +
 drivers/mmc/host/sdhci-pci.c       |  1 +
 drivers/mmc/host/sdhci-pltfm.c     |  1 +
 drivers/mmc/host/sdhci-pxav2.c     |  1 +
 drivers/mmc/host/sdhci-pxav3.c     |  1 +
 drivers/mmc/host/sdhci-s3c.c       | 19 ++++++++++++++-----
 drivers/mmc/host/sdhci-sirf.c      |  1 +
 drivers/mmc/host/sdhci-spear.c     |  1 +
 drivers/mmc/host/sdhci-tegra.c     |  1 +
 drivers/mmc/host/sdhci.c           | 17 ++++++-----------
 drivers/mmc/host/sdhci.h           |  1 +
 include/linux/mmc/sdhci.h          |  2 --
 19 files changed, 36 insertions(+), 21 deletions(-)

diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c
index aca84a682551..323e2a688563 100644
--- a/drivers/mmc/host/sdhci-acpi.c
+++ b/drivers/mmc/host/sdhci-acpi.c
@@ -102,12 +102,14 @@ static void sdhci_acpi_int_hw_reset(struct sdhci_host *host)
 }
 
 static const struct sdhci_ops sdhci_acpi_ops_dflt = {
+	.set_clock = sdhci_set_clock,
 	.enable_dma = sdhci_acpi_enable_dma,
 	.set_bus_width = sdhci_set_bus_width,
 	.reset = sdhci_reset,
 };
 
 static const struct sdhci_ops sdhci_acpi_ops_int = {
+	.set_clock = sdhci_set_clock,
 	.enable_dma = sdhci_acpi_enable_dma,
 	.set_bus_width = sdhci_set_bus_width,
 	.reset = sdhci_reset,
diff --git a/drivers/mmc/host/sdhci-bcm-kona.c b/drivers/mmc/host/sdhci-bcm-kona.c
index 7b97bfab910d..e610811c09b0 100644
--- a/drivers/mmc/host/sdhci-bcm-kona.c
+++ b/drivers/mmc/host/sdhci-bcm-kona.c
@@ -206,6 +206,7 @@ static void sdhci_bcm_kona_init_74_clocks(struct sdhci_host *host,
 }
 
 static struct sdhci_ops sdhci_bcm_kona_ops = {
+	.set_clock = sdhci_set_clock,
 	.get_max_clock = sdhci_bcm_kona_get_max_clk,
 	.get_timeout_clock = sdhci_bcm_kona_get_timeout_clock,
 	.platform_send_init_74_clocks = sdhci_bcm_kona_init_74_clocks,
diff --git a/drivers/mmc/host/sdhci-bcm2835.c b/drivers/mmc/host/sdhci-bcm2835.c
index 289b1c80d5fc..74906d6008e1 100644
--- a/drivers/mmc/host/sdhci-bcm2835.c
+++ b/drivers/mmc/host/sdhci-bcm2835.c
@@ -131,6 +131,7 @@ static const struct sdhci_ops bcm2835_sdhci_ops = {
 	.read_l = bcm2835_sdhci_readl,
 	.read_w = bcm2835_sdhci_readw,
 	.read_b = bcm2835_sdhci_readb,
+	.set_clock = sdhci_set_clock,
 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
 	.get_min_clock = bcm2835_sdhci_get_min_clock,
 	.set_bus_width = sdhci_set_bus_width,
diff --git a/drivers/mmc/host/sdhci-cns3xxx.c b/drivers/mmc/host/sdhci-cns3xxx.c
index 416f4a4c2e35..587d73ef33ff 100644
--- a/drivers/mmc/host/sdhci-cns3xxx.c
+++ b/drivers/mmc/host/sdhci-cns3xxx.c
@@ -89,8 +89,7 @@ static const struct sdhci_pltfm_data sdhci_cns3xxx_pdata = {
 		  SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
 		  SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
 		  SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
-		  SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
-		  SDHCI_QUIRK_NONSTANDARD_CLOCK,
+		  SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
 };
 
 static int sdhci_cns3xxx_probe(struct platform_device *pdev)
diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c
index 1408cc11d881..8ef4ab52f8e0 100644
--- a/drivers/mmc/host/sdhci-dove.c
+++ b/drivers/mmc/host/sdhci-dove.c
@@ -86,6 +86,7 @@ static u32 sdhci_dove_readl(struct sdhci_host *host, int reg)
 static const struct sdhci_ops sdhci_dove_ops = {
 	.read_w	= sdhci_dove_readw,
 	.read_l	= sdhci_dove_readl,
+	.set_clock = sdhci_set_clock,
 	.set_bus_width = sdhci_set_bus_width,
 	.reset = sdhci_reset,
 };
diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h
index de69bddc3afc..3497cfaf683c 100644
--- a/drivers/mmc/host/sdhci-esdhc.h
+++ b/drivers/mmc/host/sdhci-esdhc.h
@@ -20,7 +20,6 @@
 
 #define ESDHC_DEFAULT_QUIRKS	(SDHCI_QUIRK_FORCE_BLK_SZ_2048 | \
 				SDHCI_QUIRK_NO_BUSY_IRQ | \
-				SDHCI_QUIRK_NONSTANDARD_CLOCK | \
 				SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | \
 				SDHCI_QUIRK_PIO_NEEDS_DELAY)
 
diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
index faef21740584..f0ee594f25d1 100644
--- a/drivers/mmc/host/sdhci-of-arasan.c
+++ b/drivers/mmc/host/sdhci-of-arasan.c
@@ -52,6 +52,7 @@ static unsigned int sdhci_arasan_get_timeout_clock(struct sdhci_host *host)
 }
 
 static struct sdhci_ops sdhci_arasan_ops = {
+	.set_clock = sdhci_set_clock,
 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
 	.get_timeout_clock = sdhci_arasan_get_timeout_clock,
 	.set_bus_width = sdhci_set_bus_width,
diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c
index fb01958cb18e..a4a1f0f2c0a0 100644
--- a/drivers/mmc/host/sdhci-of-hlwd.c
+++ b/drivers/mmc/host/sdhci-of-hlwd.c
@@ -58,6 +58,7 @@ static const struct sdhci_ops sdhci_hlwd_ops = {
 	.write_l = sdhci_hlwd_writel,
 	.write_w = sdhci_hlwd_writew,
 	.write_b = sdhci_hlwd_writeb,
+	.set_clock = sdhci_set_clock,
 	.set_bus_width = sdhci_set_bus_width,
 	.reset = sdhci_reset,
 };
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index 87f9dd91f68c..b3a28f6b170e 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -1078,6 +1078,7 @@ static void sdhci_pci_hw_reset(struct sdhci_host *host)
 }
 
 static const struct sdhci_ops sdhci_pci_ops = {
+	.set_clock	= sdhci_set_clock,
 	.enable_dma	= sdhci_pci_enable_dma,
 	.set_bus_width	= sdhci_pci_set_bus_width,
 	.reset		= sdhci_reset,
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
index bfbf467b61c7..1fb89f44bd58 100644
--- a/drivers/mmc/host/sdhci-pltfm.c
+++ b/drivers/mmc/host/sdhci-pltfm.c
@@ -45,6 +45,7 @@ unsigned int sdhci_pltfm_clk_get_max_clock(struct sdhci_host *host)
 EXPORT_SYMBOL_GPL(sdhci_pltfm_clk_get_max_clock);
 
 static const struct sdhci_ops sdhci_pltfm_ops = {
+	.set_clock = sdhci_set_clock,
 	.set_bus_width = sdhci_set_bus_width,
 	.reset = sdhci_reset,
 };
diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c
index 2eee0c8b88eb..db5257bf032e 100644
--- a/drivers/mmc/host/sdhci-pxav2.c
+++ b/drivers/mmc/host/sdhci-pxav2.c
@@ -112,6 +112,7 @@ static void pxav2_mmc_set_bus_width(struct sdhci_host *host, int width)
 }
 
 static const struct sdhci_ops pxav2_sdhci_ops = {
+	.set_clock     = sdhci_set_clock,
 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
 	.set_bus_width = pxav2_mmc_set_bus_width,
 	.reset         = pxav2_reset,
diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c
index 86564233ae93..8a40e079a57e 100644
--- a/drivers/mmc/host/sdhci-pxav3.c
+++ b/drivers/mmc/host/sdhci-pxav3.c
@@ -225,6 +225,7 @@ static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
 }
 
 static const struct sdhci_ops pxav3_sdhci_ops = {
+	.set_clock = sdhci_set_clock,
 	.set_uhs_signaling = pxav3_set_uhs_signaling,
 	.platform_send_init_74_clocks = pxav3_gen_init_74_clocks,
 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
index 464059c91a24..0ac075dfd844 100644
--- a/drivers/mmc/host/sdhci-s3c.c
+++ b/drivers/mmc/host/sdhci-s3c.c
@@ -58,6 +58,8 @@ struct sdhci_s3c {
 	struct clk		*clk_io;
 	struct clk		*clk_bus[MAX_BUS_CLK];
 	unsigned long		clk_rates[MAX_BUS_CLK];
+
+	bool			no_divider;
 };
 
 /**
@@ -70,6 +72,7 @@ struct sdhci_s3c {
  */
 struct sdhci_s3c_drv_data {
 	unsigned int	sdhci_quirks;
+	bool		no_divider;
 };
 
 static inline struct sdhci_s3c *to_s3c(struct sdhci_host *host)
@@ -119,7 +122,7 @@ static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost,
 	 * If controller uses a non-standard clock division, find the best clock
 	 * speed possible with selected clock source and skip the division.
 	 */
-	if (ourhost->host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) {
+	if (ourhost->no_divider) {
 		rate = clk_round_rate(clksrc, wanted);
 		return wanted - rate;
 	}
@@ -164,8 +167,10 @@ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock)
 	host->mmc->actual_clock = 0;
 
 	/* don't bother if the clock is going off. */
-	if (clock == 0)
+	if (clock == 0) {
+		sdhci_set_clock(host, clock);
 		return;
+	}
 
 	for (src = 0; src < MAX_BUS_CLK; src++) {
 		delta = sdhci_s3c_consider_clock(ourhost, src, clock);
@@ -217,6 +222,8 @@ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock)
 	if (clock < 25 * 1000000)
 		ctrl |= (S3C_SDHCI_CTRL3_FCSEL3 | S3C_SDHCI_CTRL3_FCSEL2);
 	writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL3);
+
+	sdhci_set_clock(host, clock);
 }
 
 /**
@@ -606,8 +613,10 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
 	/* Setup quirks for the controller */
 	host->quirks |= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC;
 	host->quirks |= SDHCI_QUIRK_NO_HISPD_BIT;
-	if (drv_data)
+	if (drv_data) {
 		host->quirks |= drv_data->sdhci_quirks;
+		sc->no_divider = drv_data->no_divider;
+	}
 
 #ifndef CONFIG_MMC_SDHCI_S3C_DMA
 
@@ -656,7 +665,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
 	 * If controller does not have internal clock divider,
 	 * we can use overriding functions instead of default.
 	 */
-	if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) {
+	if (sc->no_divider) {
 		sdhci_s3c_ops.set_clock = sdhci_cmu_set_clock;
 		sdhci_s3c_ops.get_min_clock = sdhci_cmu_get_min_clock;
 		sdhci_s3c_ops.get_max_clock = sdhci_cmu_get_max_clock;
@@ -797,7 +806,7 @@ static const struct dev_pm_ops sdhci_s3c_pmops = {
 
 #if defined(CONFIG_CPU_EXYNOS4210) || defined(CONFIG_SOC_EXYNOS4212)
 static struct sdhci_s3c_drv_data exynos4_sdhci_drv_data = {
-	.sdhci_quirks = SDHCI_QUIRK_NONSTANDARD_CLOCK,
+	.no_divider = true,
 };
 #define EXYNOS4_SDHCI_DRV_DATA ((kernel_ulong_t)&exynos4_sdhci_drv_data)
 #else
diff --git a/drivers/mmc/host/sdhci-sirf.c b/drivers/mmc/host/sdhci-sirf.c
index 5d79e10e1ba2..3b775348b470 100644
--- a/drivers/mmc/host/sdhci-sirf.c
+++ b/drivers/mmc/host/sdhci-sirf.c
@@ -28,6 +28,7 @@ static unsigned int sdhci_sirf_get_max_clk(struct sdhci_host *host)
 }
 
 static struct sdhci_ops sdhci_sirf_ops = {
+	.set_clock = sdhci_set_clock,
 	.get_max_clock	= sdhci_sirf_get_max_clk,
 	.set_bus_width = sdhci_set_bus_width,
 	.reset = sdhci_reset,
diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c
index c2a2bedc8813..8bf64ab36720 100644
--- a/drivers/mmc/host/sdhci-spear.c
+++ b/drivers/mmc/host/sdhci-spear.c
@@ -38,6 +38,7 @@ struct spear_sdhci {
 
 /* sdhci ops */
 static const struct sdhci_ops sdhci_pltfm_ops = {
+	.set_clock = sdhci_set_clock,
 	.set_bus_width = sdhci_set_bus_width,
 	.reset = sdhci_reset,
 };
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index 7754c0319fda..a0a8b5cc3b0c 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -153,6 +153,7 @@ static const struct sdhci_ops tegra_sdhci_ops = {
 	.read_l     = tegra_sdhci_readl,
 	.read_w     = tegra_sdhci_readw,
 	.write_l    = tegra_sdhci_writel,
+	.set_clock  = sdhci_set_clock,
 	.set_bus_width = tegra_sdhci_set_bus_width,
 	.reset      = tegra_sdhci_reset,
 };
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index acad1bf32aee..bbf8d8bcfde6 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1112,19 +1112,13 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host)
 	return preset;
 }
 
-static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
+void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 {
 	int div = 0; /* Initialized for compiler warning */
 	int real_div = div, clk_mul = 1;
 	u16 clk = 0;
 	unsigned long timeout;
 
-	if (host->ops->set_clock) {
-		host->ops->set_clock(host, clock);
-		if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK)
-			return;
-	}
-
 	host->mmc->actual_clock = 0;
 
 	sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
@@ -1221,6 +1215,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 	clk |= SDHCI_CLOCK_CARD_EN;
 	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
 }
+EXPORT_SYMBOL_GPL(sdhci_set_clock);
 
 static int sdhci_set_power(struct sdhci_host *host, unsigned short power)
 {
@@ -1439,7 +1434,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 		sdhci_enable_preset_value(host, false);
 
 	if (!ios->clock || ios->clock != host->clock) {
-		sdhci_set_clock(host, ios->clock);
+		host->ops->set_clock(host, ios->clock);
 		host->clock = ios->clock;
 	}
 
@@ -1509,7 +1504,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 			sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
 
 			/* Re-enable SD Clock */
-			sdhci_set_clock(host, host->clock);
+			host->ops->set_clock(host, host->clock);
 		}
 
 
@@ -1553,7 +1548,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 		}
 
 		/* Re-enable SD Clock */
-		sdhci_set_clock(host, host->clock);
+		host->ops->set_clock(host, host->clock);
 	} else
 		sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
 
@@ -2124,7 +2119,7 @@ static void sdhci_tasklet_finish(unsigned long param)
 		/* Some controllers need this kick or reset won't work here */
 		if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET)
 			/* This is to force an update */
-			sdhci_set_clock(host, host->clock);
+			host->ops->set_clock(host, host->clock);
 
 		/* Spec says we should do both at the same time, but Ricoh
 		   controllers do not like that. */
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 7d84cb3b0e00..ac20195f667b 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -400,6 +400,7 @@ static inline bool sdhci_sdio_irq_enabled(struct sdhci_host *host)
 	return !!(host->flags & SDHCI_SDIO_IRQ_ENABLED);
 }
 
+void sdhci_set_clock(struct sdhci_host *host, unsigned int clock);
 void sdhci_set_bus_width(struct sdhci_host *host, int width);
 void sdhci_reset(struct sdhci_host *host, u8 mask);
 
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index 02919ef99419..72a90baf111f 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -57,8 +57,6 @@ struct sdhci_host {
 #define SDHCI_QUIRK_BROKEN_CARD_DETECTION		(1<<15)
 /* Controller reports inverted write-protect state */
 #define SDHCI_QUIRK_INVERTED_WRITE_PROTECT		(1<<16)
-/* Controller has nonstandard clock management */
-#define SDHCI_QUIRK_NONSTANDARD_CLOCK			(1<<17)
 /* Controller does not like fast PIO transfers */
 #define SDHCI_QUIRK_PIO_NEEDS_DELAY			(1<<18)
 /* Controller has to be forced to use block size of 2048 bytes */
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 202/222] mmc: sdhci-esdhc-imx: avoid DMA to kernel stack
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (200 preceding siblings ...)
  2014-04-25 11:58 ` [PATCH 201/222] mmc: sdhci: convert sdhci_set_clock() into a library function Russell King
@ 2014-04-25 11:59 ` Russell King
  2014-04-25 11:59 ` [PATCH 203/222] mmc: sdhci-esdhc-imx: comment runtime_pm_get_sync() in esdhc_prepare_tuning() Russell King
                   ` (20 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:59 UTC (permalink / raw)
  To: linux-arm-kernel

sdhci-esdhc-imx tries to DMA to the kernel stack when tuning the
interface, which causes dma-debug to complain.  Fix this by kmallocing
a buffer to hold the received tuning pattern.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci-esdhc-imx.c | 25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index ce8939ff97a4..5acfe2fc4fe0 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -711,13 +711,12 @@ static void esdhc_request_done(struct mmc_request *mrq)
 	complete(&mrq->completion);
 }
 
-static int esdhc_send_tuning_cmd(struct sdhci_host *host, u32 opcode)
+static int esdhc_send_tuning_cmd(struct sdhci_host *host, u32 opcode,
+				 struct scatterlist *sg)
 {
 	struct mmc_command cmd = {0};
 	struct mmc_request mrq = {NULL};
 	struct mmc_data data = {0};
-	struct scatterlist sg;
-	char tuning_pattern[ESDHC_TUNING_BLOCK_PATTERN_LEN];
 
 	cmd.opcode = opcode;
 	cmd.arg = 0;
@@ -726,11 +725,9 @@ static int esdhc_send_tuning_cmd(struct sdhci_host *host, u32 opcode)
 	data.blksz = ESDHC_TUNING_BLOCK_PATTERN_LEN;
 	data.blocks = 1;
 	data.flags = MMC_DATA_READ;
-	data.sg = &sg;
+	data.sg = sg;
 	data.sg_len = 1;
 
-	sg_init_one(&sg, tuning_pattern, sizeof(tuning_pattern));
-
 	mrq.cmd = &cmd;
 	mrq.cmd->mrq = &mrq;
 	mrq.data = &data;
@@ -770,13 +767,21 @@ static void esdhc_post_tuning(struct sdhci_host *host)
 
 static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
 {
+	struct scatterlist sg;
+	char *tuning_pattern;
 	int min, max, avg, ret;
 
+	tuning_pattern = kmalloc(ESDHC_TUNING_BLOCK_PATTERN_LEN, GFP_KERNEL);
+	if (!tuning_pattern)
+		return -ENOMEM;
+
+	sg_init_one(&sg, tuning_pattern, ESDHC_TUNING_BLOCK_PATTERN_LEN);
+
 	/* find the mininum delay first which can pass tuning */
 	min = ESDHC_TUNE_CTRL_MIN;
 	while (min < ESDHC_TUNE_CTRL_MAX) {
 		esdhc_prepare_tuning(host, min);
-		if (!esdhc_send_tuning_cmd(host, opcode))
+		if (!esdhc_send_tuning_cmd(host, opcode, &sg))
 			break;
 		min += ESDHC_TUNE_CTRL_STEP;
 	}
@@ -785,7 +790,7 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
 	max = min + ESDHC_TUNE_CTRL_STEP;
 	while (max < ESDHC_TUNE_CTRL_MAX) {
 		esdhc_prepare_tuning(host, max);
-		if (esdhc_send_tuning_cmd(host, opcode)) {
+		if (esdhc_send_tuning_cmd(host, opcode, &sg)) {
 			max -= ESDHC_TUNE_CTRL_STEP;
 			break;
 		}
@@ -795,9 +800,11 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
 	/* use average delay to get the best timing */
 	avg = (min + max) / 2;
 	esdhc_prepare_tuning(host, avg);
-	ret = esdhc_send_tuning_cmd(host, opcode);
+	ret = esdhc_send_tuning_cmd(host, opcode, &sg);
 	esdhc_post_tuning(host);
 
+	kfree(tuning_pattern);
+
 	dev_dbg(mmc_dev(host->mmc), "tunning %s at 0x%x ret %d\n",
 		ret ? "failed" : "passed", avg, ret);
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 203/222] mmc: sdhci-esdhc-imx: comment runtime_pm_get_sync() in esdhc_prepare_tuning()
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (201 preceding siblings ...)
  2014-04-25 11:59 ` [PATCH 202/222] mmc: sdhci-esdhc-imx: avoid DMA to kernel stack Russell King
@ 2014-04-25 11:59 ` Russell King
  2014-04-25 11:59 ` [PATCH 204/222] mmc: sdhci-esdhc-imx: fix lockdep splat upon tuning Russell King
                   ` (19 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:59 UTC (permalink / raw)
  To: linux-arm-kernel

It is far from obvious what this is doing, and it looks like it's an
unbalanced runtime_pm_get() call.  However, the put is inside
sdhci_tasklet_finish(), so it's not unbalanced at all.  This should
be documented so people know what's going on here.  Do so.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci-esdhc-imx.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 5acfe2fc4fe0..eb7a13796bcb 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -695,6 +695,7 @@ static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val)
 	/* FIXME: delay a bit for card to be ready for next tuning due to errors */
 	mdelay(1);
 
+	/* This is balanced by the runtime put in sdhci_tasklet_finish */
 	pm_runtime_get_sync(host->mmc->parent);
 	reg = readl(host->ioaddr + ESDHC_MIX_CTRL);
 	reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL |
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 204/222] mmc: sdhci-esdhc-imx: fix lockdep splat upon tuning
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (202 preceding siblings ...)
  2014-04-25 11:59 ` [PATCH 203/222] mmc: sdhci-esdhc-imx: comment runtime_pm_get_sync() in esdhc_prepare_tuning() Russell King
@ 2014-04-25 11:59 ` Russell King
  2014-04-25 11:59 ` [PATCH 205/222] mmc: sdhci: hack up driver to make it more compliant with UHS-1 Russell King
                   ` (18 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:59 UTC (permalink / raw)
  To: linux-arm-kernel

=================================
[ INFO: inconsistent lock state ]
3.14.0-rc1+ #490 Not tainted
---------------------------------
inconsistent {IN-HARDIRQ-W} -> {HARDIRQ-ON-W} usage.
kworker/u8:0/6 [HC0[0]:SC0[0]:HE1:SE1] takes:
 (&(&host->lock)->rlock#2){?.-...}, at: [<c04b57a4>] esdhc_send_tuning_cmd+0x104/0x14c
{IN-HARDIRQ-W} state was registered at:
  [<c00652fc>] mark_lock+0x15c/0x6f8
  [<c0066354>] __lock_acquire+0xabc/0x1ca0
  [<c0067ad8>] lock_acquire+0xa0/0x130
  [<c0697a44>] _raw_spin_lock+0x34/0x44
  [<c04b0dbc>] sdhci_irq+0x20/0xa40
  [<c0071b1c>] handle_irq_event_percpu+0x74/0x284
  [<c0071d70>] handle_irq_event+0x44/0x64
  [<c0074db8>] handle_fasteoi_irq+0xac/0x140
  [<c007147c>] generic_handle_irq+0x28/0x38
  [<c000efd4>] handle_IRQ+0x40/0x98
  [<c0008584>] gic_handle_irq+0x30/0x64
  [<c0013144>] __irq_svc+0x44/0x58
  [<c0028fc8>] irq_exit+0xc0/0x120
  [<c000efd8>] handle_IRQ+0x44/0x98
  [<c0008584>] gic_handle_irq+0x30/0x64
  [<c0013144>] __irq_svc+0x44/0x58
  [<c068f398>] printk+0x3c/0x44
  [<c03191d0>] _regulator_get+0x1b4/0x1e0
  [<c031924c>] regulator_get+0x18/0x1c
  [<c049fbc4>] mmc_add_host+0x30/0x1c0
  [<c04b2e10>] sdhci_add_host+0x804/0xbbc
  [<c04b5318>] sdhci_esdhc_imx_probe+0x380/0x674
  [<c036d530>] platform_drv_probe+0x20/0x50
  [<c036b948>] driver_probe_device+0x120/0x234
  [<c036baf8>] __driver_attach+0x9c/0xa0
  [<c036a04c>] bus_for_each_dev+0x5c/0x90
  [<c036b418>] driver_attach+0x24/0x28
  [<c036b018>] bus_add_driver+0xe4/0x1d8
  [<c036c1b0>] driver_register+0x80/0xfc
  [<c036ce28>] __platform_driver_register+0x50/0x64
  [<c093706c>] sdhci_esdhc_imx_driver_init+0x18/0x20
  [<c0008834>] do_one_initcall+0x3c/0x164
  [<c0901c94>] kernel_init_freeable+0x104/0x1d0
  [<c068c45c>] kernel_init+0x10/0x118
  [<c000e768>] ret_from_fork+0x14/0x2c
irq event stamp: 5933
hardirqs last  enabled at (5933): [<c069813c>] _raw_spin_unlock_irqrestore+0x38/0x4c
hardirqs last disabled at (5932): [<c0697b04>] _raw_spin_lock_irqsave+0x24/0x60
softirqs last  enabled at (5914): [<c0028ba0>] __do_softirq+0x260/0x360
softirqs last disabled at (5909): [<c0028fc8>] irq_exit+0xc0/0x120

other info that might help us debug this:
 Possible unsafe locking scenario:

       CPU0
       ----
  lock(&(&host->lock)->rlock#2);
  <Interrupt>
    lock(&(&host->lock)->rlock#2);

 *** DEADLOCK ***

2 locks held by kworker/u8:0/6:
 #0:  (kmmcd){.+.+.+}, at: [<c003d890>] process_one_work+0x134/0x4e8
 #1:  ((&(&host->detect)->work)){+.+.+.}, at: [<c003d890>] process_one_work+0x134/0x4e8

stack backtrace:
CPU: 2 PID: 6 Comm: kworker/u8:0 Not tainted 3.14.0-rc1+ #490
Workqueue: kmmcd mmc_rescan
Backtrace:
[<c00124a0>] (dump_backtrace) from [<c0012640>] (show_stack+0x18/0x1c)
[<c0012628>] (show_stack) from [<c069164c>] (dump_stack+0x70/0x8c)
[<c06915dc>] (dump_stack) from [<c068f080>] (print_usage_bug+0x274/0x2e4)
[<c068ee0c>] (print_usage_bug) from [<c0065774>] (mark_lock+0x5d4/0x6f8)
[<c00651a0>] (mark_lock) from [<c0065e6c>] (__lock_acquire+0x5d4/0x1ca0)
[<c0065898>] (__lock_acquire) from [<c0067ad8>] (lock_acquire+0xa0/0x130)
[<c0067a38>] (lock_acquire) from [<c0697a44>] (_raw_spin_lock+0x34/0x44)
[<c0697a10>] (_raw_spin_lock) from [<c04b57a4>] (esdhc_send_tuning_cmd+0x104/0x14c)
[<c04b56a0>] (esdhc_send_tuning_cmd) from [<c04b582c>] (esdhc_executing_tuning+0x40/0x100)
[<c04b57ec>] (esdhc_executing_tuning) from [<c04afa54>] (sdhci_execute_tuning+0xcc/0x754)
[<c04af988>] (sdhci_execute_tuning) from [<c04a4684>] (mmc_sd_init_card+0x65c/0x694)
[<c04a4028>] (mmc_sd_init_card) from [<c04a48f0>] (mmc_attach_sd+0xb0/0x184)
[<c04a4840>] (mmc_attach_sd) from [<c049eb28>] (mmc_rescan+0x26c/0x2e8)
[<c049e8bc>] (mmc_rescan) from [<c003d914>] (process_one_work+0x1b8/0x4e8)
[<c003d75c>] (process_one_work) from [<c003e090>] (worker_thread+0x13c/0x3f8)
[<c003df54>] (worker_thread) from [<c00449bc>] (kthread+0xcc/0xe8)
[<c00448f0>] (kthread) from [<c000e768>] (ret_from_fork+0x14/0x2c)

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci-esdhc-imx.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index eb7a13796bcb..dfed2c37ab3f 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -738,14 +738,12 @@ static int esdhc_send_tuning_cmd(struct sdhci_host *host, u32 opcode,
 	mrq.done = esdhc_request_done;
 	init_completion(&(mrq.completion));
 
-	disable_irq(host->irq);
-	spin_lock(&host->lock);
+	spin_lock_irq(&host->lock);
 	host->mrq = &mrq;
 
 	sdhci_send_command(host, mrq.cmd);
 
-	spin_unlock(&host->lock);
-	enable_irq(host->irq);
+	spin_unlock_irq(&host->lock);
 
 	wait_for_completion(&mrq.completion);
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 205/222] mmc: sdhci: hack up driver to make it more compliant with UHS-1
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (203 preceding siblings ...)
  2014-04-25 11:59 ` [PATCH 204/222] mmc: sdhci-esdhc-imx: fix lockdep splat upon tuning Russell King
@ 2014-04-25 11:59 ` Russell King
  2014-04-25 11:59 ` [PATCH 206/222] mmc: sdhci: set_uhs_signaling() need not return a value Russell King
                   ` (17 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:59 UTC (permalink / raw)
  To: linux-arm-kernel

Patch suggested by Dong Aisheng <dongas86@gmail.com>, this avoids
additional clock start/stop cycles during the transition to 1.8V
signalling mode.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci.c | 12 ------------
 1 file changed, 12 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index bbf8d8bcfde6..3516a1d95116 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1507,12 +1507,6 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 			host->ops->set_clock(host, host->clock);
 		}
 
-
-		/* Reset SD Clock Enable */
-		clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
-		clk &= ~SDHCI_CLOCK_CARD_EN;
-		sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
-
 		if (host->ops->set_uhs_signaling)
 			host->ops->set_uhs_signaling(host, ios->timing);
 		else {
@@ -1546,9 +1540,6 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 			ios->drv_type = (preset & SDHCI_PRESET_DRV_MASK)
 				>> SDHCI_PRESET_DRV_SHIFT;
 		}
-
-		/* Re-enable SD Clock */
-		host->ops->set_clock(host, host->clock);
 	} else
 		sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
 
@@ -1757,9 +1748,6 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		ctrl |= SDHCI_CTRL_VDD_180;
 		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
 
-		/* Wait for 5ms */
-		usleep_range(5000, 5500);
-
 		/* 1.8V regulator output should be stable within 5 ms */
 		ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
 		if (ctrl & SDHCI_CTRL_VDD_180)
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 206/222] mmc: sdhci: set_uhs_signaling() need not return a value
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (204 preceding siblings ...)
  2014-04-25 11:59 ` [PATCH 205/222] mmc: sdhci: hack up driver to make it more compliant with UHS-1 Russell King
@ 2014-04-25 11:59 ` Russell King
  2014-04-25 11:59 ` [PATCH 207/222] mmc: sdhci: convert sdhci_set_uhs_signaling() into a library function Russell King
                   ` (16 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:59 UTC (permalink / raw)
  To: linux-arm-kernel

The set_uhs_signaling() method gives the impression that it can fail,
but anything returned from the method is entirely ignored by the sdhci
driver.  So returning failure has no effect.

So, kill the idea that it's possible for this to return an error by
removing the returned value.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci-esdhc-imx.c | 4 ++--
 drivers/mmc/host/sdhci-pxav3.c     | 4 +---
 drivers/mmc/host/sdhci.h           | 2 +-
 3 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index dfed2c37ab3f..72e0581e564f 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -841,7 +841,7 @@ static int esdhc_change_pinstate(struct sdhci_host *host,
 	return pinctrl_select_state(imx_data->pinctrl, pinctrl);
 }
 
-static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
+static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
 {
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 	struct pltfm_imx_data *imx_data = pltfm_host->priv;
@@ -879,7 +879,7 @@ static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
 		break;
 	}
 
-	return esdhc_change_pinstate(host, uhs);
+	esdhc_change_pinstate(host, uhs);
 }
 
 static void esdhc_reset(struct sdhci_host *host, u8 mask)
diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c
index 8a40e079a57e..05574104a254 100644
--- a/drivers/mmc/host/sdhci-pxav3.c
+++ b/drivers/mmc/host/sdhci-pxav3.c
@@ -186,7 +186,7 @@ static void pxav3_gen_init_74_clocks(struct sdhci_host *host, u8 power_mode)
 	pxa->power_mode = power_mode;
 }
 
-static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
+static void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
 {
 	u16 ctrl_2;
 
@@ -220,8 +220,6 @@ static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
 	dev_dbg(mmc_dev(host->mmc),
 		"%s uhs = %d, ctrl_2 = %04X\n",
 		__func__, uhs, ctrl_2);
-
-	return 0;
 }
 
 static const struct sdhci_ops pxav3_sdhci_ops = {
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index ac20195f667b..3179a8053019 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -287,7 +287,7 @@ struct sdhci_ops {
 	unsigned int    (*get_ro)(struct sdhci_host *host);
 	void		(*reset)(struct sdhci_host *host, u8 mask);
 	int	(*platform_execute_tuning)(struct sdhci_host *host, u32 opcode);
-	int	(*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
+	void	(*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
 	void	(*hw_reset)(struct sdhci_host *host);
 	void	(*platform_suspend)(struct sdhci_host *host);
 	void	(*platform_resume)(struct sdhci_host *host);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 207/222] mmc: sdhci: convert sdhci_set_uhs_signaling() into a library function
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (205 preceding siblings ...)
  2014-04-25 11:59 ` [PATCH 206/222] mmc: sdhci: set_uhs_signaling() need not return a value Russell King
@ 2014-04-25 11:59 ` Russell King
  2014-04-25 11:59 ` [PATCH 208/222] mmc: sdhci: cache timing information locally Russell King
                   ` (15 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:59 UTC (permalink / raw)
  To: linux-arm-kernel

Add sdhci_set_uhs_signaling() and always call the set_uhs_signaling
method.  This avoids quirks being added into sdhci_set_uhs_signaling().

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci-acpi.c      |  2 ++
 drivers/mmc/host/sdhci-bcm-kona.c  |  1 +
 drivers/mmc/host/sdhci-bcm2835.c   |  1 +
 drivers/mmc/host/sdhci-cns3xxx.c   |  1 +
 drivers/mmc/host/sdhci-dove.c      |  1 +
 drivers/mmc/host/sdhci-of-arasan.c |  1 +
 drivers/mmc/host/sdhci-of-esdhc.c  |  1 +
 drivers/mmc/host/sdhci-of-hlwd.c   |  1 +
 drivers/mmc/host/sdhci-pci.c       |  1 +
 drivers/mmc/host/sdhci-pltfm.c     |  1 +
 drivers/mmc/host/sdhci-pxav2.c     |  1 +
 drivers/mmc/host/sdhci-pxav3.c     |  1 +
 drivers/mmc/host/sdhci-s3c.c       |  1 +
 drivers/mmc/host/sdhci-sirf.c      |  1 +
 drivers/mmc/host/sdhci-spear.c     |  1 +
 drivers/mmc/host/sdhci-tegra.c     |  1 +
 drivers/mmc/host/sdhci.c           | 42 +++++++++++++++++++++-----------------
 drivers/mmc/host/sdhci.h           |  1 +
 18 files changed, 41 insertions(+), 19 deletions(-)

diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c
index 323e2a688563..8ce3c28cb76e 100644
--- a/drivers/mmc/host/sdhci-acpi.c
+++ b/drivers/mmc/host/sdhci-acpi.c
@@ -106,6 +106,7 @@ static const struct sdhci_ops sdhci_acpi_ops_dflt = {
 	.enable_dma = sdhci_acpi_enable_dma,
 	.set_bus_width = sdhci_set_bus_width,
 	.reset = sdhci_reset,
+	.set_uhs_signaling = sdhci_set_uhs_signaling,
 };
 
 static const struct sdhci_ops sdhci_acpi_ops_int = {
@@ -113,6 +114,7 @@ static const struct sdhci_ops sdhci_acpi_ops_int = {
 	.enable_dma = sdhci_acpi_enable_dma,
 	.set_bus_width = sdhci_set_bus_width,
 	.reset = sdhci_reset,
+	.set_uhs_signaling = sdhci_set_uhs_signaling,
 	.hw_reset   = sdhci_acpi_int_hw_reset,
 };
 
diff --git a/drivers/mmc/host/sdhci-bcm-kona.c b/drivers/mmc/host/sdhci-bcm-kona.c
index e610811c09b0..dd780c315a63 100644
--- a/drivers/mmc/host/sdhci-bcm-kona.c
+++ b/drivers/mmc/host/sdhci-bcm-kona.c
@@ -212,6 +212,7 @@ static struct sdhci_ops sdhci_bcm_kona_ops = {
 	.platform_send_init_74_clocks = sdhci_bcm_kona_init_74_clocks,
 	.set_bus_width = sdhci_set_bus_width,
 	.reset = sdhci_reset,
+	.set_uhs_signaling = sdhci_set_uhs_signaling,
 	.card_event = sdhci_bcm_kona_card_event,
 };
 
diff --git a/drivers/mmc/host/sdhci-bcm2835.c b/drivers/mmc/host/sdhci-bcm2835.c
index 74906d6008e1..46af9a439d7b 100644
--- a/drivers/mmc/host/sdhci-bcm2835.c
+++ b/drivers/mmc/host/sdhci-bcm2835.c
@@ -136,6 +136,7 @@ static const struct sdhci_ops bcm2835_sdhci_ops = {
 	.get_min_clock = bcm2835_sdhci_get_min_clock,
 	.set_bus_width = sdhci_set_bus_width,
 	.reset = sdhci_reset,
+	.set_uhs_signaling = sdhci_set_uhs_signaling,
 };
 
 static const struct sdhci_pltfm_data bcm2835_sdhci_pdata = {
diff --git a/drivers/mmc/host/sdhci-cns3xxx.c b/drivers/mmc/host/sdhci-cns3xxx.c
index 587d73ef33ff..14b74075589a 100644
--- a/drivers/mmc/host/sdhci-cns3xxx.c
+++ b/drivers/mmc/host/sdhci-cns3xxx.c
@@ -81,6 +81,7 @@ static const struct sdhci_ops sdhci_cns3xxx_ops = {
 	.set_clock	= sdhci_cns3xxx_set_clock,
 	.set_bus_width	= sdhci_set_bus_width,
 	.reset          = sdhci_reset,
+	.set_uhs_signaling = sdhci_set_uhs_signaling,
 };
 
 static const struct sdhci_pltfm_data sdhci_cns3xxx_pdata = {
diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c
index 8ef4ab52f8e0..0d315f4496c8 100644
--- a/drivers/mmc/host/sdhci-dove.c
+++ b/drivers/mmc/host/sdhci-dove.c
@@ -89,6 +89,7 @@ static const struct sdhci_ops sdhci_dove_ops = {
 	.set_clock = sdhci_set_clock,
 	.set_bus_width = sdhci_set_bus_width,
 	.reset = sdhci_reset,
+	.set_uhs_signaling = sdhci_set_uhs_signaling,
 };
 
 static const struct sdhci_pltfm_data sdhci_dove_pdata = {
diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
index f0ee594f25d1..5bd1092310f2 100644
--- a/drivers/mmc/host/sdhci-of-arasan.c
+++ b/drivers/mmc/host/sdhci-of-arasan.c
@@ -57,6 +57,7 @@ static struct sdhci_ops sdhci_arasan_ops = {
 	.get_timeout_clock = sdhci_arasan_get_timeout_clock,
 	.set_bus_width = sdhci_set_bus_width,
 	.reset = sdhci_reset,
+	.set_uhs_signaling = sdhci_set_uhs_signaling,
 };
 
 static struct sdhci_pltfm_data sdhci_arasan_pdata = {
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index c4f8cd3f83c8..fcaeae5f55b8 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -309,6 +309,7 @@ static const struct sdhci_ops sdhci_esdhc_ops = {
 	.adma_workaround = esdhci_of_adma_workaround,
 	.set_bus_width = esdhc_pltfm_set_bus_width,
 	.reset = sdhci_reset,
+	.set_uhs_signaling = sdhci_set_uhs_signaling,
 };
 
 static const struct sdhci_pltfm_data sdhci_esdhc_pdata = {
diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c
index a4a1f0f2c0a0..b341661369a2 100644
--- a/drivers/mmc/host/sdhci-of-hlwd.c
+++ b/drivers/mmc/host/sdhci-of-hlwd.c
@@ -61,6 +61,7 @@ static const struct sdhci_ops sdhci_hlwd_ops = {
 	.set_clock = sdhci_set_clock,
 	.set_bus_width = sdhci_set_bus_width,
 	.reset = sdhci_reset,
+	.set_uhs_signaling = sdhci_set_uhs_signaling,
 };
 
 static const struct sdhci_pltfm_data sdhci_hlwd_pdata = {
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index b3a28f6b170e..52c42fcc284c 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -1082,6 +1082,7 @@ static const struct sdhci_ops sdhci_pci_ops = {
 	.enable_dma	= sdhci_pci_enable_dma,
 	.set_bus_width	= sdhci_pci_set_bus_width,
 	.reset		= sdhci_reset,
+	.set_uhs_signaling = sdhci_set_uhs_signaling,
 	.hw_reset		= sdhci_pci_hw_reset,
 };
 
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
index 1fb89f44bd58..7e834fb78f42 100644
--- a/drivers/mmc/host/sdhci-pltfm.c
+++ b/drivers/mmc/host/sdhci-pltfm.c
@@ -48,6 +48,7 @@ static const struct sdhci_ops sdhci_pltfm_ops = {
 	.set_clock = sdhci_set_clock,
 	.set_bus_width = sdhci_set_bus_width,
 	.reset = sdhci_reset,
+	.set_uhs_signaling = sdhci_set_uhs_signaling,
 };
 
 #ifdef CONFIG_OF
diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c
index db5257bf032e..3c0f3c0a1cc8 100644
--- a/drivers/mmc/host/sdhci-pxav2.c
+++ b/drivers/mmc/host/sdhci-pxav2.c
@@ -116,6 +116,7 @@ static const struct sdhci_ops pxav2_sdhci_ops = {
 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
 	.set_bus_width = pxav2_mmc_set_bus_width,
 	.reset         = pxav2_reset,
+	.set_uhs_signaling = sdhci_set_uhs_signaling,
 };
 
 #ifdef CONFIG_OF
diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c
index 05574104a254..f4f128947561 100644
--- a/drivers/mmc/host/sdhci-pxav3.c
+++ b/drivers/mmc/host/sdhci-pxav3.c
@@ -229,6 +229,7 @@ static const struct sdhci_ops pxav3_sdhci_ops = {
 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
 	.set_bus_width = sdhci_set_bus_width,
 	.reset = pxav3_reset,
+	.set_uhs_signaling = sdhci_set_uhs_signaling,
 };
 
 static struct sdhci_pltfm_data sdhci_pxav3_pdata = {
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
index 0ac075dfd844..76d7c12d8ef9 100644
--- a/drivers/mmc/host/sdhci-s3c.c
+++ b/drivers/mmc/host/sdhci-s3c.c
@@ -374,6 +374,7 @@ static struct sdhci_ops sdhci_s3c_ops = {
 	.get_min_clock		= sdhci_s3c_get_min_clock,
 	.set_bus_width		= sdhci_s3c_set_bus_width,
 	.reset			= sdhci_reset,
+	.set_uhs_signaling	= sdhci_set_uhs_signaling,
 };
 
 static void sdhci_s3c_notify_change(struct platform_device *dev, int state)
diff --git a/drivers/mmc/host/sdhci-sirf.c b/drivers/mmc/host/sdhci-sirf.c
index 3b775348b470..17004531d089 100644
--- a/drivers/mmc/host/sdhci-sirf.c
+++ b/drivers/mmc/host/sdhci-sirf.c
@@ -32,6 +32,7 @@ static struct sdhci_ops sdhci_sirf_ops = {
 	.get_max_clock	= sdhci_sirf_get_max_clk,
 	.set_bus_width = sdhci_set_bus_width,
 	.reset = sdhci_reset,
+	.set_uhs_signaling = sdhci_set_uhs_signaling,
 };
 
 static struct sdhci_pltfm_data sdhci_sirf_pdata = {
diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c
index 8bf64ab36720..9d535c7336ef 100644
--- a/drivers/mmc/host/sdhci-spear.c
+++ b/drivers/mmc/host/sdhci-spear.c
@@ -41,6 +41,7 @@ static const struct sdhci_ops sdhci_pltfm_ops = {
 	.set_clock = sdhci_set_clock,
 	.set_bus_width = sdhci_set_bus_width,
 	.reset = sdhci_reset,
+	.set_uhs_signaling = sdhci_set_uhs_signaling,
 };
 
 #ifdef CONFIG_OF
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index a0a8b5cc3b0c..d06b6ff60432 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -156,6 +156,7 @@ static const struct sdhci_ops tegra_sdhci_ops = {
 	.set_clock  = sdhci_set_clock,
 	.set_bus_width = tegra_sdhci_set_bus_width,
 	.reset      = tegra_sdhci_reset,
+	.set_uhs_signaling = sdhci_set_uhs_signaling,
 };
 
 static const struct sdhci_pltfm_data sdhci_tegra20_pdata = {
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 3516a1d95116..c4075398de0f 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1404,6 +1404,28 @@ void sdhci_set_bus_width(struct sdhci_host *host, int width)
 }
 EXPORT_SYMBOL_GPL(sdhci_set_bus_width);
 
+void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
+{
+	u16 ctrl_2;
+
+	ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+	/* Select Bus Speed Mode for host */
+	ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
+	if ((timing == MMC_TIMING_MMC_HS200) ||
+	    (timing == MMC_TIMING_UHS_SDR104))
+		ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
+	else if (timing == MMC_TIMING_UHS_SDR12)
+		ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
+	else if (timing == MMC_TIMING_UHS_SDR25)
+		ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
+	else if (timing == MMC_TIMING_UHS_SDR50)
+		ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
+	else if (timing == MMC_TIMING_UHS_DDR50)
+		ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
+	sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+}
+EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling);
+
 static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 {
 	unsigned long flags;
@@ -1507,25 +1529,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 			host->ops->set_clock(host, host->clock);
 		}
 
-		if (host->ops->set_uhs_signaling)
-			host->ops->set_uhs_signaling(host, ios->timing);
-		else {
-			ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
-			/* Select Bus Speed Mode for host */
-			ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
-			if ((ios->timing == MMC_TIMING_MMC_HS200) ||
-			    (ios->timing == MMC_TIMING_UHS_SDR104))
-				ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
-			else if (ios->timing == MMC_TIMING_UHS_SDR12)
-				ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
-			else if (ios->timing == MMC_TIMING_UHS_SDR25)
-				ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
-			else if (ios->timing == MMC_TIMING_UHS_SDR50)
-				ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
-			else if (ios->timing == MMC_TIMING_UHS_DDR50)
-				ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
-			sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
-		}
+		host->ops->set_uhs_signaling(host, ios->timing);
 
 		if (!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN) &&
 				((ios->timing == MMC_TIMING_UHS_SDR12) ||
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 3179a8053019..7a35395e5f56 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -403,6 +403,7 @@ static inline bool sdhci_sdio_irq_enabled(struct sdhci_host *host)
 void sdhci_set_clock(struct sdhci_host *host, unsigned int clock);
 void sdhci_set_bus_width(struct sdhci_host *host, int width);
 void sdhci_reset(struct sdhci_host *host, u8 mask);
+void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing);
 
 #ifdef CONFIG_PM
 extern int sdhci_suspend_host(struct sdhci_host *host);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 208/222] mmc: sdhci: cache timing information locally
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (206 preceding siblings ...)
  2014-04-25 11:59 ` [PATCH 207/222] mmc: sdhci: convert sdhci_set_uhs_signaling() into a library function Russell King
@ 2014-04-25 11:59 ` Russell King
  2014-04-25 11:59 ` [PATCH 209/222] mmc: sdhci: clean up sdhci_execute_tuning() decision Russell King
                   ` (14 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:59 UTC (permalink / raw)
  To: linux-arm-kernel

Rather than reading back the timing information from the registers,
cache it locally.  This allows implementations to translate the UHS
timing by overriding the set_uhs_signaling() method as required
without also having to emulate the SDHCI_HOST_CONTROL2 register.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci.c  | 23 ++++++++++++-----------
 include/linux/mmc/sdhci.h |  2 ++
 2 files changed, 14 insertions(+), 11 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index c4075398de0f..f3b9a4386731 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1083,24 +1083,23 @@ static void sdhci_finish_command(struct sdhci_host *host)
 
 static u16 sdhci_get_preset_value(struct sdhci_host *host)
 {
-	u16 ctrl, preset = 0;
+	u16 preset = 0;
 
-	ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
-
-	switch (ctrl & SDHCI_CTRL_UHS_MASK) {
-	case SDHCI_CTRL_UHS_SDR12:
+	switch (host->timing) {
+	case MMC_TIMING_UHS_SDR12:
 		preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR12);
 		break;
-	case SDHCI_CTRL_UHS_SDR25:
+	case MMC_TIMING_UHS_SDR25:
 		preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR25);
 		break;
-	case SDHCI_CTRL_UHS_SDR50:
+	case MMC_TIMING_UHS_SDR50:
 		preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR50);
 		break;
-	case SDHCI_CTRL_UHS_SDR104:
+	case MMC_TIMING_UHS_SDR104:
+	case MMC_TIMING_MMC_HS200:
 		preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR104);
 		break;
-	case SDHCI_CTRL_UHS_DDR50:
+	case MMC_TIMING_UHS_DDR50:
 		preset = sdhci_readw(host, SDHCI_PRESET_FOR_DDR50);
 		break;
 	default:
@@ -1530,6 +1529,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 		}
 
 		host->ops->set_uhs_signaling(host, ios->timing);
+		host->timing = ios->timing;
 
 		if (!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN) &&
 				((ios->timing == MMC_TIMING_UHS_SDR12) ||
@@ -1828,12 +1828,13 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 	 * If the Host Controller supports the HS200 mode then the
 	 * tuning function has to be executed.
 	 */
-	if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR50) &&
+	if (host->timing == MMC_TIMING_UHS_SDR50 &&
 	    (host->flags & SDHCI_SDR50_NEEDS_TUNING ||
 	     host->flags & SDHCI_SDR104_NEEDS_TUNING))
 		requires_tuning_nonuhs = true;
 
-	if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR104) ||
+	if (host->timing == MMC_TIMING_MMC_HS200 ||
+	    host->timing == MMC_TIMING_UHS_SDR104 ||
 	    requires_tuning_nonuhs)
 		ctrl |= SDHCI_CTRL_EXEC_TUNING;
 	else {
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index 72a90baf111f..7f3efbab8732 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -172,6 +172,8 @@ struct sdhci_host {
 	unsigned int            ocr_avail_mmc;
 	u32 ocr_mask;		/* available voltages */
 
+	unsigned		timing;		/* Current timing */
+
 	u32			thread_isr;
 
 	/* cached registers */
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 209/222] mmc: sdhci: clean up sdhci_execute_tuning() decision
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (207 preceding siblings ...)
  2014-04-25 11:59 ` [PATCH 208/222] mmc: sdhci: cache timing information locally Russell King
@ 2014-04-25 11:59 ` Russell King
  2014-04-25 11:59 ` [PATCH 210/222] mmc: sdhci-esdhc-imx: remove emulation of uhs_mode Russell King
                   ` (13 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:59 UTC (permalink / raw)
  To: linux-arm-kernel

Clean up the code in sdhci_execute_tuning() so the decision whether
to execute tuning is clearer - and despite this reflecting what the
original code was doing, it shows that it may not be what the author
actually intended.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci.c | 31 +++++++++++++++----------------
 1 file changed, 15 insertions(+), 16 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index f3b9a4386731..b7e53d43c659 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1806,21 +1806,16 @@ static int sdhci_card_busy(struct mmc_host *mmc)
 
 static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 {
-	struct sdhci_host *host;
+	struct sdhci_host *host = mmc_priv(mmc);
 	u16 ctrl;
 	int tuning_loop_counter = MAX_TUNING_LOOP;
 	unsigned long timeout;
 	int err = 0;
-	bool requires_tuning_nonuhs = false;
 	unsigned long flags;
 
-	host = mmc_priv(mmc);
-
 	sdhci_runtime_pm_get(host);
 	spin_lock_irqsave(&host->lock, flags);
 
-	ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
-
 	/*
 	 * The Host Controller needs tuning only in case of SDR104 mode
 	 * and for SDR50 mode when Use Tuning for SDR50 is set in the
@@ -1828,16 +1823,18 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 	 * If the Host Controller supports the HS200 mode then the
 	 * tuning function has to be executed.
 	 */
-	if (host->timing == MMC_TIMING_UHS_SDR50 &&
-	    (host->flags & SDHCI_SDR50_NEEDS_TUNING ||
-	     host->flags & SDHCI_SDR104_NEEDS_TUNING))
-		requires_tuning_nonuhs = true;
-
-	if (host->timing == MMC_TIMING_MMC_HS200 ||
-	    host->timing == MMC_TIMING_UHS_SDR104 ||
-	    requires_tuning_nonuhs)
-		ctrl |= SDHCI_CTRL_EXEC_TUNING;
-	else {
+	switch (host->timing) {
+	case MMC_TIMING_MMC_HS200:
+	case MMC_TIMING_UHS_SDR104:
+		break;
+
+	case MMC_TIMING_UHS_SDR50:
+		if (host->flags & SDHCI_SDR50_NEEDS_TUNING ||
+		    host->flags & SDHCI_SDR104_NEEDS_TUNING)
+			break;
+		/* FALLTHROUGH */
+
+	default:
 		spin_unlock_irqrestore(&host->lock, flags);
 		sdhci_runtime_pm_put(host);
 		return 0;
@@ -1850,6 +1847,8 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 		return err;
 	}
 
+	ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+	ctrl |= SDHCI_CTRL_EXEC_TUNING;
 	sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
 
 	/*
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 210/222] mmc: sdhci-esdhc-imx: remove emulation of uhs_mode
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (208 preceding siblings ...)
  2014-04-25 11:59 ` [PATCH 209/222] mmc: sdhci: clean up sdhci_execute_tuning() decision Russell King
@ 2014-04-25 11:59 ` Russell King
  2014-04-25 11:59 ` [PATCH 211/222] mmc: sdhci-of-esdhc: remove platform_suspend/platform_resume callbacks Russell King
                   ` (12 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:59 UTC (permalink / raw)
  To: linux-arm-kernel

We no longer need to emulate the uhs_mode field of the host control2
register - the main sdhci driver never reads this back to evaluate
the current mode as it caches the current mode instead.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci-esdhc-imx.c | 17 +++--------------
 1 file changed, 3 insertions(+), 14 deletions(-)

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 72e0581e564f..4866d802f9e2 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -160,7 +160,6 @@ struct pltfm_imx_data {
 		MULTIBLK_IN_PROCESS, /* exact multiblock cmd in process */
 		WAIT_FOR_INT,        /* sent CMD12, waiting for response INT */
 	} multiblock_status;
-	u32 uhs_mode;
 	u32 is_ddr;
 };
 
@@ -382,7 +381,6 @@ static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
 		if (val & ESDHC_MIX_CTRL_SMPCLK_SEL)
 			ret |= SDHCI_CTRL_TUNED_CLK;
 
-		ret |= (imx_data->uhs_mode & SDHCI_CTRL_UHS_MASK);
 		ret &= ~SDHCI_CTRL_PRESET_VAL_ENABLE;
 
 		return ret;
@@ -429,7 +427,6 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
 		else
 			new_val &= ~ESDHC_VENDOR_SPEC_VSELECT;
 		writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC);
-		imx_data->uhs_mode = val & SDHCI_CTRL_UHS_MASK;
 		if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) {
 			new_val = readl(host->ioaddr + ESDHC_MIX_CTRL);
 			if (val & SDHCI_CTRL_TUNED_CLK)
@@ -841,28 +838,20 @@ static int esdhc_change_pinstate(struct sdhci_host *host,
 	return pinctrl_select_state(imx_data->pinctrl, pinctrl);
 }
 
-static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
+static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
 {
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 	struct pltfm_imx_data *imx_data = pltfm_host->priv;
 	struct esdhc_platform_data *boarddata = &imx_data->boarddata;
 
-	switch (uhs) {
+	switch (timing) {
 	case MMC_TIMING_UHS_SDR12:
-		imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR12;
-		break;
 	case MMC_TIMING_UHS_SDR25:
-		imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR25;
-		break;
 	case MMC_TIMING_UHS_SDR50:
-		imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR50;
-		break;
 	case MMC_TIMING_UHS_SDR104:
 	case MMC_TIMING_MMC_HS200:
-		imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR104;
 		break;
 	case MMC_TIMING_UHS_DDR50:
-		imx_data->uhs_mode = SDHCI_CTRL_UHS_DDR50;
 		writel(readl(host->ioaddr + ESDHC_MIX_CTRL) |
 				ESDHC_MIX_CTRL_DDREN,
 				host->ioaddr + ESDHC_MIX_CTRL);
@@ -879,7 +868,7 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
 		break;
 	}
 
-	esdhc_change_pinstate(host, uhs);
+	esdhc_change_pinstate(host, timing);
 }
 
 static void esdhc_reset(struct sdhci_host *host, u8 mask)
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 211/222] mmc: sdhci-of-esdhc: remove platform_suspend/platform_resume callbacks
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (209 preceding siblings ...)
  2014-04-25 11:59 ` [PATCH 210/222] mmc: sdhci-esdhc-imx: remove emulation of uhs_mode Russell King
@ 2014-04-25 11:59 ` Russell King
  2014-04-25 11:59 ` [PATCH 212/222] mmc: sdhci: " Russell King
                   ` (11 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:59 UTC (permalink / raw)
  To: linux-arm-kernel

We don't need these hooks in order to insert code in these paths, we
can just provide our own handlers and call the main sdhci handlers as
appropriate.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci-of-esdhc.c | 55 +++++++++++++++++++++++++--------------
 1 file changed, 36 insertions(+), 19 deletions(-)

diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index fcaeae5f55b8..605815e52f5f 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -241,20 +241,6 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
 	mdelay(1);
 }
 
-#ifdef CONFIG_PM
-static u32 esdhc_proctl;
-static void esdhc_of_suspend(struct sdhci_host *host)
-{
-	esdhc_proctl = sdhci_be32bs_readl(host, SDHCI_HOST_CONTROL);
-}
-
-static void esdhc_of_resume(struct sdhci_host *host)
-{
-	esdhc_of_enable_dma(host);
-	sdhci_be32bs_writel(host, esdhc_proctl, SDHCI_HOST_CONTROL);
-}
-#endif
-
 static void esdhc_of_platform_init(struct sdhci_host *host)
 {
 	u32 vvn;
@@ -302,16 +288,47 @@ static const struct sdhci_ops sdhci_esdhc_ops = {
 	.get_max_clock = esdhc_of_get_max_clock,
 	.get_min_clock = esdhc_of_get_min_clock,
 	.platform_init = esdhc_of_platform_init,
-#ifdef CONFIG_PM
-	.platform_suspend = esdhc_of_suspend,
-	.platform_resume = esdhc_of_resume,
-#endif
 	.adma_workaround = esdhci_of_adma_workaround,
 	.set_bus_width = esdhc_pltfm_set_bus_width,
 	.reset = sdhci_reset,
 	.set_uhs_signaling = sdhci_set_uhs_signaling,
 };
 
+#ifdef CONFIG_PM
+
+static u32 esdhc_proctl;
+static int esdhc_of_suspend(struct device *dev)
+{
+	struct sdhci_host *host = dev_get_drvdata(dev);
+
+	esdhc_proctl = sdhci_be32bs_readl(host, SDHCI_HOST_CONTROL);
+
+	return sdhci_suspend_host(host);
+}
+
+static void esdhc_of_resume(device *dev)
+{
+	struct sdhci_host *host = dev_get_drvdata(dev);
+	int ret = sdhci_resume_host(host);
+
+	if (ret == 0) {
+		/* Isn't this already done by sdhci_resume_host() ? --rmk */
+		esdhc_of_enable_dma(host);
+		sdhci_be32bs_writel(host, esdhc_proctl, SDHCI_HOST_CONTROL);
+	}
+
+	return ret;
+}
+
+static const struct dev_pm_ops esdhc_pmops = {
+	.suspend	= esdhci_of_suspend,
+	.resume		= esdhci_of_resume,
+};
+#define ESDHC_PMOPS (&esdhc_pmops)
+#else
+#define ESDHC_PMOPS NULL
+#endif
+
 static const struct sdhci_pltfm_data sdhci_esdhc_pdata = {
 	/*
 	 * card detection could be handled via GPIO
@@ -373,7 +390,7 @@ static struct platform_driver sdhci_esdhc_driver = {
 		.name = "sdhci-esdhc",
 		.owner = THIS_MODULE,
 		.of_match_table = sdhci_esdhc_of_match,
-		.pm = SDHCI_PLTFM_PMOPS,
+		.pm = ESDHC_PMOPS,
 	},
 	.probe = sdhci_esdhc_probe,
 	.remove = sdhci_esdhc_remove,
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 212/222] mmc: sdhci: remove platform_suspend/platform_resume callbacks
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (210 preceding siblings ...)
  2014-04-25 11:59 ` [PATCH 211/222] mmc: sdhci-of-esdhc: remove platform_suspend/platform_resume callbacks Russell King
@ 2014-04-25 11:59 ` Russell King
  2014-04-25 11:59 ` [PATCH 213/222] mmc: sdhci-tegra: get rid of special PRESENT_STATE register handling Russell King
                   ` (10 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:59 UTC (permalink / raw)
  To: linux-arm-kernel

The only user (sdhci-of-esdhc) no longer uses these callbacks, so lets
remove them to discourage any further use.

Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci.c | 6 ------
 drivers/mmc/host/sdhci.h | 2 --
 2 files changed, 8 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index b7e53d43c659..0d55a5bca2aa 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2530,9 +2530,6 @@ EXPORT_SYMBOL_GPL(sdhci_disable_irq_wakeups);
 
 int sdhci_suspend_host(struct sdhci_host *host)
 {
-	if (host->ops->platform_suspend)
-		host->ops->platform_suspend(host);
-
 	sdhci_disable_card_detection(host);
 
 	/* Disable tuning since we are suspending */
@@ -2589,9 +2586,6 @@ int sdhci_resume_host(struct sdhci_host *host)
 
 	sdhci_enable_card_detection(host);
 
-	if (host->ops->platform_resume)
-		host->ops->platform_resume(host);
-
 	/* Set the re-tuning expiration flag */
 	if (host->flags & SDHCI_USING_RETUNING_TIMER)
 		host->flags |= SDHCI_NEEDS_RETUNING;
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 7a35395e5f56..4a5cd5e3fa3e 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -289,8 +289,6 @@ struct sdhci_ops {
 	int	(*platform_execute_tuning)(struct sdhci_host *host, u32 opcode);
 	void	(*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
 	void	(*hw_reset)(struct sdhci_host *host);
-	void	(*platform_suspend)(struct sdhci_host *host);
-	void	(*platform_resume)(struct sdhci_host *host);
 	void    (*adma_workaround)(struct sdhci_host *host, u32 intmask);
 	void	(*platform_init)(struct sdhci_host *host);
 	void    (*card_event)(struct sdhci_host *host);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 213/222] mmc: sdhci-tegra: get rid of special PRESENT_STATE register handling
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (211 preceding siblings ...)
  2014-04-25 11:59 ` [PATCH 212/222] mmc: sdhci: " Russell King
@ 2014-04-25 11:59 ` Russell King
  2014-04-25 12:00 ` [PATCH 214/222] mmc: sdhci: move regulator handling into sdhci_set_power() Russell King
                   ` (9 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 11:59 UTC (permalink / raw)
  To: linux-arm-kernel

sdhci-tegra provides a get_ro method, which overrides the checking
of the write protect bit in the PRESENT_STATE register in sdhci.c:

        if (host->flags & SDHCI_DEVICE_DEAD)
                is_readonly = 0;
        else if (host->ops->get_ro)
                is_readonly = host->ops->get_ro(host);
        else
                is_readonly = !(sdhci_readl(host, SDHCI_PRESENT_STATE)
                                & SDHCI_WRITE_PROTECT);

This means it's pointless detecting accesses to this register and
manually setting the SDHCI_WRITE_PROTECT as it has no effect.

This means that the whole of tegra_sdhci_readl() can be removed and
we can use the builtin sdhci readl functionality here.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci-tegra.c | 14 --------------
 1 file changed, 14 deletions(-)

diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index d06b6ff60432..985247649f46 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -48,19 +48,6 @@ struct sdhci_tegra {
 	int power_gpio;
 };
 
-static u32 tegra_sdhci_readl(struct sdhci_host *host, int reg)
-{
-	u32 val;
-
-	if (unlikely(reg == SDHCI_PRESENT_STATE)) {
-		/* Use wp_gpio here instead? */
-		val = readl(host->ioaddr + reg);
-		return val | SDHCI_WRITE_PROTECT;
-	}
-
-	return readl(host->ioaddr + reg);
-}
-
 static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg)
 {
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -150,7 +137,6 @@ static void tegra_sdhci_set_bus_width(struct sdhci_host *host, int bus_width)
 
 static const struct sdhci_ops tegra_sdhci_ops = {
 	.get_ro     = tegra_sdhci_get_ro,
-	.read_l     = tegra_sdhci_readl,
 	.read_w     = tegra_sdhci_readw,
 	.write_l    = tegra_sdhci_writel,
 	.set_clock  = sdhci_set_clock,
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 214/222] mmc: sdhci: move regulator handling into sdhci_set_power()
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (212 preceding siblings ...)
  2014-04-25 11:59 ` [PATCH 213/222] mmc: sdhci-tegra: get rid of special PRESENT_STATE register handling Russell King
@ 2014-04-25 12:00 ` Russell King
  2014-04-25 12:00 ` [PATCH 215/222] mmc: sdhci: move remaining power " Russell King
                   ` (8 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 12:00 UTC (permalink / raw)
  To: linux-arm-kernel

Move the regulator handling into sdhci_set_power() rather than being in
sdhci_do_set_ios().  This wraps all power control up into this function.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci.c | 72 +++++++++++++++++++++++-------------------------
 1 file changed, 35 insertions(+), 37 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 0d55a5bca2aa..3ce81577b0c7 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1216,7 +1216,7 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 }
 EXPORT_SYMBOL_GPL(sdhci_set_clock);
 
-static int sdhci_set_power(struct sdhci_host *host, unsigned short power)
+static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
 {
 	u8 pwr = 0;
 
@@ -1239,7 +1239,7 @@ static int sdhci_set_power(struct sdhci_host *host, unsigned short power)
 	}
 
 	if (host->pwr == pwr)
-		return -1;
+		return;
 
 	host->pwr = pwr;
 
@@ -1247,38 +1247,43 @@ static int sdhci_set_power(struct sdhci_host *host, unsigned short power)
 		sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
 		if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
 			sdhci_runtime_pm_bus_off(host);
-		return 0;
-	}
-
-	/*
-	 * Spec says that we should clear the power reg before setting
-	 * a new value. Some controllers don't seem to like this though.
-	 */
-	if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
-		sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
+		power = 0;
+	} else {
+		/*
+		 * Spec says that we should clear the power reg before setting
+		 * a new value. Some controllers don't seem to like this though.
+		 */
+		if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
+			sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
 
-	/*
-	 * At least the Marvell CaFe chip gets confused if we set the voltage
-	 * and set turn on power at the same time, so set the voltage first.
-	 */
-	if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER)
-		sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
+		/*
+		 * At least the Marvell CaFe chip gets confused if we set the
+		 * voltage and set turn on power at the same time, so set the
+		 * voltage first.
+		 */
+		if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER)
+			sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
 
-	pwr |= SDHCI_POWER_ON;
+		pwr |= SDHCI_POWER_ON;
 
-	sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
+		sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
 
-	if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
-		sdhci_runtime_pm_bus_on(host);
+		if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
+			sdhci_runtime_pm_bus_on(host);
 
-	/*
-	 * Some controllers need an extra 10ms delay of 10ms before they
-	 * can apply clock after applying power
-	 */
-	if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER)
-		mdelay(10);
+		/*
+		 * Some controllers need an extra 10ms delay of 10ms before
+		 * they can apply clock after applying power
+		 */
+		if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER)
+			mdelay(10);
+	}
 
-	return power;
+	if (host->vmmc) {
+		spin_unlock_irq(&host->lock);
+		mmc_regulator_set_ocr(host->mmc, host->vmmc, power);
+		spin_lock_irq(&host->lock);
+	}
 }
 
 /*****************************************************************************\
@@ -1428,7 +1433,6 @@ EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling);
 static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 {
 	unsigned long flags;
-	int vdd_bit = -1;
 	u8 ctrl;
 
 	spin_lock_irqsave(&host->lock, flags);
@@ -1460,15 +1464,9 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 	}
 
 	if (ios->power_mode == MMC_POWER_OFF)
-		vdd_bit = sdhci_set_power(host, -1);
+		sdhci_set_power(host, -1);
 	else
-		vdd_bit = sdhci_set_power(host, ios->vdd);
-
-	if (host->vmmc && vdd_bit != -1) {
-		spin_unlock_irqrestore(&host->lock, flags);
-		mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd_bit);
-		spin_lock_irqsave(&host->lock, flags);
-	}
+		sdhci_set_power(host, ios->vdd);
 
 	if (host->ops->platform_send_init_74_clocks)
 		host->ops->platform_send_init_74_clocks(host, ios->power_mode);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 215/222] mmc: sdhci: move remaining power handling into sdhci_set_power()
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (213 preceding siblings ...)
  2014-04-25 12:00 ` [PATCH 214/222] mmc: sdhci: move regulator handling into sdhci_set_power() Russell King
@ 2014-04-25 12:00 ` Russell King
  2014-04-25 12:00 ` [PATCH 216/222] mmc: sdhci: track whether preset mode is currently enabled in hardware Russell King
                   ` (7 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 12:00 UTC (permalink / raw)
  To: linux-arm-kernel

Move the remaining parts of the power handling in sdhci_do_set_ios()
into sdhci_set_power().

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci.c | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 3ce81577b0c7..2bf4908c576e 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1216,12 +1216,13 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 }
 EXPORT_SYMBOL_GPL(sdhci_set_clock);
 
-static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
+static void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
+			    unsigned short vdd)
 {
 	u8 pwr = 0;
 
-	if (power != (unsigned short)-1) {
-		switch (1 << power) {
+	if (mode != MMC_POWER_OFF) {
+		switch (1 << vdd) {
 		case MMC_VDD_165_195:
 			pwr = SDHCI_POWER_180;
 			break;
@@ -1247,7 +1248,7 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
 		sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
 		if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
 			sdhci_runtime_pm_bus_off(host);
-		power = 0;
+		vdd = 0;
 	} else {
 		/*
 		 * Spec says that we should clear the power reg before setting
@@ -1281,7 +1282,7 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
 
 	if (host->vmmc) {
 		spin_unlock_irq(&host->lock);
-		mmc_regulator_set_ocr(host->mmc, host->vmmc, power);
+		mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd);
 		spin_lock_irq(&host->lock);
 	}
 }
@@ -1463,10 +1464,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 		host->clock = ios->clock;
 	}
 
-	if (ios->power_mode == MMC_POWER_OFF)
-		sdhci_set_power(host, -1);
-	else
-		sdhci_set_power(host, ios->vdd);
+	sdhci_set_power(host, ios->power_mode, ios->vdd);
 
 	if (host->ops->platform_send_init_74_clocks)
 		host->ops->platform_send_init_74_clocks(host, ios->power_mode);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 216/222] mmc: sdhci: track whether preset mode is currently enabled in hardware
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (214 preceding siblings ...)
  2014-04-25 12:00 ` [PATCH 215/222] mmc: sdhci: move remaining power " Russell King
@ 2014-04-25 12:00 ` Russell King
  2014-04-25 12:00 ` [PATCH 217/222] mmc: sdhci: fix SDHCI dependencies Russell King
                   ` (6 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 12:00 UTC (permalink / raw)
  To: linux-arm-kernel

Track whether preset mode is currently enabled in hardware, and use that
when making decisions elsewhere in the code rather than reading the
register and checking the bit.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci.c  | 44 ++++++++++++++++++++++++++------------------
 include/linux/mmc/sdhci.h |  1 +
 2 files changed, 27 insertions(+), 18 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 2bf4908c576e..caf712d518a3 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -205,9 +205,14 @@ static void sdhci_do_reset(struct sdhci_host *host, u8 mask)
 
 	host->ops->reset(host, mask);
 
-	if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
-		if ((host->ops->enable_dma) && (mask & SDHCI_RESET_ALL))
-			host->ops->enable_dma(host);
+	if (mask & SDHCI_RESET_ALL) {
+		if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
+			if (host->ops->enable_dma)
+				host->ops->enable_dma(host);
+		}
+
+		/* Resetting the controller clears many */
+		host->preset_enabled = false;
 	}
 }
 
@@ -1126,8 +1131,7 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 		return;
 
 	if (host->version >= SDHCI_SPEC_300) {
-		if (sdhci_readw(host, SDHCI_HOST_CONTROL2) &
-			SDHCI_CTRL_PRESET_VAL_ENABLE) {
+		if (host->preset_enabled) {
 			u16 pre_val;
 
 			clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
@@ -1491,13 +1495,13 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 		    (ios->timing == MMC_TIMING_UHS_SDR25))
 			ctrl |= SDHCI_CTRL_HISPD;
 
-		ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
-		if (!(ctrl_2 & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
+		if (!host->preset_enabled) {
 			sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
 			/*
 			 * We only need to set Driver Strength if the
 			 * preset value enable is not set.
 			 */
+			ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
 			ctrl_2 &= ~SDHCI_CTRL_DRV_TYPE_MASK;
 			if (ios->drv_type == MMC_SET_DRIVER_TYPE_A)
 				ctrl_2 |= SDHCI_CTRL_DRV_TYPE_A;
@@ -2001,26 +2005,30 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 
 static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable)
 {
-	u16 ctrl;
-
 	/* Host Controller v3.00 defines preset value registers */
 	if (host->version < SDHCI_SPEC_300)
 		return;
 
-	ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
-
 	/*
 	 * We only enable or disable Preset Value if they are not already
 	 * enabled or disabled respectively. Otherwise, we bail out.
 	 */
-	if (enable && !(ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
-		ctrl |= SDHCI_CTRL_PRESET_VAL_ENABLE;
-		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
-		host->flags |= SDHCI_PV_ENABLED;
-	} else if (!enable && (ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
-		ctrl &= ~SDHCI_CTRL_PRESET_VAL_ENABLE;
+	if (host->preset_enabled != enable) {
+		u16 ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+
+		if (enable)
+			ctrl |= SDHCI_CTRL_PRESET_VAL_ENABLE;
+		else
+			ctrl &= ~SDHCI_CTRL_PRESET_VAL_ENABLE;
+
 		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
-		host->flags &= ~SDHCI_PV_ENABLED;
+
+		if (enable)
+			host->flags |= SDHCI_PV_ENABLED;
+		else
+			host->flags &= ~SDHCI_PV_ENABLED;
+
+		host->preset_enabled = enable;
 	}
 }
 
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index 7f3efbab8732..08abe9941884 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -143,6 +143,7 @@ struct sdhci_host {
 
 	bool runtime_suspended;	/* Host is runtime suspended */
 	bool bus_on;		/* Bus power prevents runtime suspend */
+	bool preset_enabled;	/* Preset is enabled */
 
 	struct mmc_request *mrq;	/* Current request */
 	struct mmc_command *cmd;	/* Current command */
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 217/222] mmc: sdhci: fix SDHCI dependencies
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (215 preceding siblings ...)
  2014-04-25 12:00 ` [PATCH 216/222] mmc: sdhci: track whether preset mode is currently enabled in hardware Russell King
@ 2014-04-25 12:00 ` Russell King
  2014-04-25 12:00 ` [PATCH 218/222] mmc: add support for power-on sequencing through DT Russell King
                   ` (5 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 12:00 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/Kconfig | 63 ++++++++++++++++++++++++------------------------
 1 file changed, 32 insertions(+), 31 deletions(-)

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 8aaf8c1f3f63..d8c1f31ab37f 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -25,8 +25,7 @@ config MMC_PXA
 	  If unsure, say N.
 
 config MMC_SDHCI
-	tristate "Secure Digital Host Controller Interface support"
-	depends on HAS_DMA
+	tristate
 	help
 	  This selects the generic Secure Digital Host Controller Interface.
 	  It is used by manufacturers such as Texas Instruments(R), Ricoh(R)
@@ -59,7 +58,8 @@ config MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
 
 config MMC_SDHCI_PCI
 	tristate "SDHCI support on PCI bus"
-	depends on MMC_SDHCI && PCI
+	depends on PCI && HAS_DMA
+	select MMC_SDHCI
 	help
 	  This selects the PCI Secure Digital Host Controller Interface.
 	  Most controllers found today are PCI devices.
@@ -83,7 +83,8 @@ config MMC_RICOH_MMC
 
 config MMC_SDHCI_ACPI
 	tristate "SDHCI support for ACPI enumerated SDHCI controllers"
-	depends on MMC_SDHCI && ACPI
+	depends on ACPI && HAS_DMA
+	select MMC_SDHCI
 	help
 	  This selects support for ACPI enumerated SDHCI controllers,
 	  identified by ACPI Compatibility ID PNP0D40 or specific
@@ -94,8 +95,8 @@ config MMC_SDHCI_ACPI
 	  If unsure, say N.
 
 config MMC_SDHCI_PLTFM
-	tristate "SDHCI platform and OF driver helper"
-	depends on MMC_SDHCI
+	tristate
+	select MMC_SDHCI
 	help
 	  This selects the common helper functions support for Secure Digital
 	  Host Controller Interface based platform and OF drivers.
@@ -106,8 +107,8 @@ config MMC_SDHCI_PLTFM
 
 config MMC_SDHCI_OF_ARASAN
 	tristate "SDHCI OF support for the Arasan SDHCI controllers"
-	depends on MMC_SDHCI_PLTFM
-	depends on OF
+	depends on OF && HAS_DMA
+	select MMC_SDHCI_PLTFM
 	help
 	  This selects the Arasan Secure Digital Host Controller Interface
 	  (SDHCI). This hardware is found e.g. in Xilinx' Zynq SoC.
@@ -118,9 +119,9 @@ config MMC_SDHCI_OF_ARASAN
 
 config MMC_SDHCI_OF_ESDHC
 	tristate "SDHCI OF support for the Freescale eSDHC controller"
-	depends on MMC_SDHCI_PLTFM
-	depends on PPC_OF
+	depends on PPC_OF && HAS_DMA
 	select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
+	select MMC_SDHCI_PLTFM
 	help
 	  This selects the Freescale eSDHC controller support.
 
@@ -130,9 +131,9 @@ config MMC_SDHCI_OF_ESDHC
 
 config MMC_SDHCI_OF_HLWD
 	tristate "SDHCI OF support for the Nintendo Wii SDHCI controllers"
-	depends on MMC_SDHCI_PLTFM
-	depends on PPC_OF
+	depends on PPC_OF && HAS_DMA
 	select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
+	select MMC_SDHCI_PLTFM
 	help
 	  This selects the Secure Digital Host Controller Interface (SDHCI)
 	  found in the "Hollywood" chipset of the Nintendo Wii video game
@@ -144,8 +145,8 @@ config MMC_SDHCI_OF_HLWD
 
 config MMC_SDHCI_CNS3XXX
 	tristate "SDHCI support on the Cavium Networks CNS3xxx SoC"
-	depends on ARCH_CNS3XXX
-	depends on MMC_SDHCI_PLTFM
+	depends on ARCH_CNS3XXX && HAS_DMA
+	select MMC_SDHCI_PLTFM
 	help
 	  This selects the SDHCI support for CNS3xxx System-on-Chip devices.
 
@@ -155,9 +156,9 @@ config MMC_SDHCI_CNS3XXX
 
 config MMC_SDHCI_ESDHC_IMX
 	tristate "SDHCI support for the Freescale eSDHC/uSDHC i.MX controller"
-	depends on ARCH_MXC
-	depends on MMC_SDHCI_PLTFM
+	depends on ARCH_MXC && HAS_DMA
 	select MMC_SDHCI_IO_ACCESSORS
+	select MMC_SDHCI_PLTFM
 	help
 	  This selects the Freescale eSDHC/uSDHC controller support
 	  found on i.MX25, i.MX35 i.MX5x and i.MX6x.
@@ -168,9 +169,9 @@ config MMC_SDHCI_ESDHC_IMX
 
 config MMC_SDHCI_DOVE
 	tristate "SDHCI support on Marvell's Dove SoC"
-	depends on ARCH_DOVE
-	depends on MMC_SDHCI_PLTFM
+	depends on ARCH_DOVE && HAS_DMA
 	select MMC_SDHCI_IO_ACCESSORS
+	select MMC_SDHCI_PLTFM
 	help
 	  This selects the Secure Digital Host Controller Interface in
 	  Marvell's Dove SoC.
@@ -181,9 +182,9 @@ config MMC_SDHCI_DOVE
 
 config MMC_SDHCI_TEGRA
 	tristate "SDHCI platform support for the Tegra SD/MMC Controller"
-	depends on ARCH_TEGRA
-	depends on MMC_SDHCI_PLTFM
+	depends on ARCH_TEGRA && HAS_DMA
 	select MMC_SDHCI_IO_ACCESSORS
+	select MMC_SDHCI_PLTFM
 	help
 	  This selects the Tegra SD/MMC controller. If you have a Tegra
 	  platform with SD or MMC devices, say Y or M here.
@@ -192,7 +193,8 @@ config MMC_SDHCI_TEGRA
 
 config MMC_SDHCI_S3C
 	tristate "SDHCI support on Samsung S3C SoC"
-	depends on MMC_SDHCI && PLAT_SAMSUNG
+	depends on PLAT_SAMSUNG && HAS_DMA
+	select MMC_SDHCI
 	help
 	  This selects the Secure Digital Host Controller Interface (SDHCI)
 	  often referrered to as the HSMMC block in some of the Samsung S3C
@@ -204,8 +206,8 @@ config MMC_SDHCI_S3C
 
 config MMC_SDHCI_SIRF
 	tristate "SDHCI support on CSR SiRFprimaII and SiRFmarco SoCs"
-	depends on ARCH_SIRF
-	depends on MMC_SDHCI_PLTFM
+	depends on ARCH_SIRF && HAS_DMA
+	select MMC_SDHCI_PLTFM
 	help
 	  This selects the SDHCI support for SiRF System-on-Chip devices.
 
@@ -215,8 +217,7 @@ config MMC_SDHCI_SIRF
 
 config MMC_SDHCI_PXAV3
 	tristate "Marvell MMP2 SD Host Controller support (PXAV3)"
-	depends on CLKDEV_LOOKUP
-	select MMC_SDHCI
+	depends on CLKDEV_LOOKUP && HAS_DMA
 	select MMC_SDHCI_PLTFM
 	default CPU_MMP2
 	help
@@ -228,8 +229,7 @@ config MMC_SDHCI_PXAV3
 
 config MMC_SDHCI_PXAV2
 	tristate "Marvell PXA9XX SD Host Controller support (PXAV2)"
-	depends on CLKDEV_LOOKUP
-	select MMC_SDHCI
+	depends on CLKDEV_LOOKUP && HAS_DMA
 	select MMC_SDHCI_PLTFM
 	default CPU_PXA910
 	help
@@ -241,7 +241,8 @@ config MMC_SDHCI_PXAV2
 
 config MMC_SDHCI_SPEAR
 	tristate "SDHCI support on ST SPEAr platform"
-	depends on MMC_SDHCI && PLAT_SPEAR
+	depends on PLAT_SPEAR && HAS_DMA
+	select MMC_SDHCI
 	help
 	  This selects the Secure Digital Host Controller Interface (SDHCI)
 	  often referrered to as the HSMMC block in some of the ST SPEAR range
@@ -263,7 +264,7 @@ config MMC_SDHCI_S3C_DMA
 
 config MMC_SDHCI_BCM_KONA
 	tristate "SDHCI support on Broadcom KONA platform"
-	depends on ARCH_BCM_MOBILE
+	depends on ARCH_BCM_MOBILE && HAS_DMA
 	select MMC_SDHCI_PLTFM
 	help
 	  This selects the Broadcom Kona Secure Digital Host Controller
@@ -274,9 +275,9 @@ config MMC_SDHCI_BCM_KONA
 
 config MMC_SDHCI_BCM2835
 	tristate "SDHCI platform support for the BCM2835 SD/MMC Controller"
-	depends on ARCH_BCM2835
-	depends on MMC_SDHCI_PLTFM
+	depends on ARCH_BCM2835 && HAS_DMA
 	select MMC_SDHCI_IO_ACCESSORS
+	select MMC_SDHCI_PLTFM
 	help
 	  This selects the BCM2835 SD/MMC controller. If you have a BCM2835
 	  platform with SD or MMC devices, say Y or M here.
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 218/222] mmc: add support for power-on sequencing through DT
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (216 preceding siblings ...)
  2014-04-25 12:00 ` [PATCH 217/222] mmc: sdhci: fix SDHCI dependencies Russell King
@ 2014-04-25 12:00 ` Russell King
  2014-04-25 12:00 ` [PATCH 219/222] mmc: dw_mmc: call mmc_of_parse to fill in common options Russell King
                   ` (4 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 12:00 UTC (permalink / raw)
  To: linux-arm-kernel

From: Olof Johansson <olof@lixom.net>
To: linux-arm-kernel at lists.infradead.org

This patch enables support for power-on sequencing of SDIO peripherals through DT.

In general, it's quite common that wifi modules and other similar
peripherals have several signals in addition to the SDIO interface that
needs wiggling before the module will power on. It's common to have a
reference clock, one or several power rails and one or several lines
for reset/enable type functions.

The binding as written today introduces a number of reset gpios,
a regulator and a clock specifier. The code will handle up to 2 gpio
reset lines, but it's trivial to increase to more than that if needed
at some point.

Implementation-wise, the MMC core has been changed to handle this during
host power up, before the host interface is powered on. I have not yet
implemented the power-down side, I wanted people to have a chance for
reporting back w.r.t. issues (or comments on the bindings) first.

I have not tested the regulator portion, since the system and module
I'm working on doesn't need one (Samsung Chromebook with Marvell
8797-based wifi). Testing of those portions (and reporting back) would
be appreciated.

Signed-off-by: Olof Johansson <olof@lixom.net>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 Documentation/devicetree/bindings/mmc/mmc.txt | 11 +++++++
 drivers/mmc/core/core.c                       | 42 +++++++++++++++++++++++++++
 drivers/mmc/core/host.c                       | 30 ++++++++++++++++++-
 include/linux/mmc/host.h                      |  5 ++++
 4 files changed, 87 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt
index 9dce540771fb..b9b534ebc0c5 100644
--- a/Documentation/devicetree/bindings/mmc/mmc.txt
+++ b/Documentation/devicetree/bindings/mmc/mmc.txt
@@ -5,6 +5,8 @@ these definitions.
 Interpreted by the OF core:
 - reg: Registers location and length.
 - interrupts: Interrupts used by the MMC controller.
+- clocks: Clocks needed for the host controller, if any.
+- clock-names: Goes with clocks above.
 
 Card detection:
 If no property below is supplied, host native card detect is used.
@@ -39,6 +41,15 @@ If no property below is supplied, host native card detect is used.
 - mmc-hs200-1_8v: eMMC HS200 mode(1.8V I/O) is supported
 - mmc-hs200-1_2v: eMMC HS200 mode(1.2V I/O) is supported
 
+Card power and reset control:
+The following properties can be specified for cases where the MMC
+peripheral needs additional reset, regulator and clock lines. It is for
+example common for WiFi/BT adapters to have these separate from the main
+MMC bus:
+  - card-reset-gpios: Specify GPIOs for card reset (reset active low)
+  - card-external-vcc-supply: Regulator to drive (independent) card VCC
+  - clock with name "card_ext_clock": External clock provided to the card
+
 *NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line
 polarity properties, we have to fix the meaning of the "normal" and "inverted"
 line levels. We choose to follow the SDHCI standard, which specifies both those
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index acbc3f2aaaf9..41c4033ec765 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -13,11 +13,13 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/clk.h>
 #include <linux/completion.h>
 #include <linux/device.h>
 #include <linux/delay.h>
 #include <linux/pagemap.h>
 #include <linux/err.h>
+#include <linux/gpio.h>
 #include <linux/leds.h>
 #include <linux/scatterlist.h>
 #include <linux/log2.h>
@@ -1504,6 +1506,43 @@ void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type)
 	mmc_host_clk_release(host);
 }
 
+static void mmc_card_power_up(struct mmc_host *host)
+{
+	int i;
+	struct gpio_desc **gds = host->card_reset_gpios;
+
+	for (i = 0; i < ARRAY_SIZE(host->card_reset_gpios); i++) {
+		if (gds[i]) {
+			dev_dbg(host->parent, "Asserting reset line %d", i);
+			gpiod_set_value(gds[i], 1);
+		}
+	}
+
+	if (host->card_regulator) {
+		dev_dbg(host->parent, "Enabling external regulator");
+		if (regulator_enable(host->card_regulator))
+			dev_err(host->parent, "Failed to enable external regulator");
+	}
+
+	if (host->card_clk) {
+		dev_dbg(host->parent, "Enabling external clock");
+		clk_prepare_enable(host->card_clk);
+	}
+
+	/* 2ms delay to let clocks and power settle */
+	mmc_delay(20);
+
+	for (i = 0; i < ARRAY_SIZE(host->card_reset_gpios); i++) {
+		if (gds[i]) {
+			dev_dbg(host->parent, "Deasserting reset line %d", i);
+			gpiod_set_value(gds[i], 0);
+		}
+	}
+
+	/* 2ms delay to after reset release */
+	mmc_delay(20);
+}
+
 /*
  * Apply power to the MMC stack.  This is a two-stage process.
  * First, we enable power to the card without the clock running.
@@ -1520,6 +1559,9 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
 	if (host->ios.power_mode == MMC_POWER_ON)
 		return;
 
+	/* Power up the card/module first, if needed */
+	mmc_card_power_up(host);
+
 	mmc_host_clk_hold(host);
 
 	host->ios.vdd = fls(ocr) - 1;
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index fdea825dbb24..abc60f39aa7e 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -12,14 +12,18 @@
  *  MMC host class device management
  */
 
+#include <linux/kernel.h>
+#include <linux/clk.h>
 #include <linux/device.h>
 #include <linux/err.h>
+#include <linux/gpio/consumer.h>
 #include <linux/idr.h>
 #include <linux/of.h>
 #include <linux/of_gpio.h>
 #include <linux/pagemap.h>
 #include <linux/export.h>
 #include <linux/leds.h>
+#include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <linux/suspend.h>
 
@@ -312,7 +316,7 @@ int mmc_of_parse(struct mmc_host *host)
 	u32 bus_width;
 	bool explicit_inv_wp, gpio_inv_wp = false;
 	enum of_gpio_flags flags;
-	int len, ret, gpio;
+	int i, len, ret, gpio;
 
 	if (!host->parent || !host->parent->of_node)
 		return 0;
@@ -415,6 +419,30 @@ int mmc_of_parse(struct mmc_host *host)
 	if (explicit_inv_wp ^ gpio_inv_wp)
 		host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
 
+	/* Parse card power/reset/clock control */
+	if (of_find_property(np, "card-reset-gpios", NULL)) {
+		struct gpio_desc *gpd;
+		for (i = 0; i < ARRAY_SIZE(host->card_reset_gpios); i++) {
+			gpd = devm_gpiod_get_index(host->parent, "card-reset", i);
+			if (IS_ERR(gpd))
+				break;
+			gpiod_direction_output(gpd, 0);
+			host->card_reset_gpios[i] = gpd;
+		}
+
+		gpd = devm_gpiod_get_index(host->parent, "card-reset", ARRAY_SIZE(host->card_reset_gpios));
+		if (!IS_ERR(gpd)) {
+			dev_warn(host->parent, "More reset gpios than we can handle");
+			gpiod_put(gpd);
+		}
+	}
+
+	host->card_clk = of_clk_get_by_name(np, "card_ext_clock");
+	if (IS_ERR(host->card_clk))
+		host->card_clk = NULL;
+
+	host->card_regulator = regulator_get(host->parent, "card-external-vcc");
+
 	if (of_find_property(np, "cap-sd-highspeed", &len))
 		host->caps |= MMC_CAP_SD_HIGHSPEED;
 	if (of_find_property(np, "cap-mmc-highspeed", &len))
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 4c0f94679898..2fdfe30295d5 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -294,6 +294,11 @@ struct mmc_host {
 	unsigned long           clkgate_delay;
 #endif
 
+	/* card specific properties to deal with power and reset */
+	struct regulator	*card_regulator; /* External VCC needed by the card */
+	struct gpio_desc	*card_reset_gpios[2]; /* External resets, active low */
+	struct clk		*card_clk;	/* External clock needed by the card */
+
 	/* host specific block data */
 	unsigned int		max_seg_size;	/* see blk_queue_max_segment_size */
 	unsigned short		max_segs;	/* see blk_queue_max_segments */
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 219/222] mmc: dw_mmc: call mmc_of_parse to fill in common options
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (217 preceding siblings ...)
  2014-04-25 12:00 ` [PATCH 218/222] mmc: add support for power-on sequencing through DT Russell King
@ 2014-04-25 12:00 ` Russell King
  2014-04-25 12:00 ` [PATCH 220/222] mmc: fix power-on sequencing for esdhc-imx driver Russell King
                   ` (3 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 12:00 UTC (permalink / raw)
  To: linux-arm-kernel

From: Olof Johansson <olof@lixom.net>
To: linux-arm-kernel at lists.infradead.org

The shared of parse function fills in common options for capabilities,
etc, but it needs to be called from each driver that wants to make use
of it. dw_mmc was missing the call.

Signed-off-by: Olof Johansson <olof@lixom.net>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/host/dw_mmc.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index cced599d5aeb..a2c12ebb376e 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -2140,6 +2140,8 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 	if (!mmc)
 		return -ENOMEM;
 
+	mmc_of_parse(mmc);
+
 	slot = mmc_priv(mmc);
 	slot->id = id;
 	slot->mmc = mmc;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 220/222] mmc: fix power-on sequencing for esdhc-imx driver
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (218 preceding siblings ...)
  2014-04-25 12:00 ` [PATCH 219/222] mmc: dw_mmc: call mmc_of_parse to fill in common options Russell King
@ 2014-04-25 12:00 ` Russell King
  2014-04-25 12:00 ` [PATCH 221/222] ARM: cubox-i: add support for SD UHS-1 cards Russell King
                   ` (2 subsequent siblings)
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 12:00 UTC (permalink / raw)
  To: linux-arm-kernel

There's no reason that this can't be applied to all MMC interfaces as
it's all core code, so tie this into the core rather than it being
optional for each host.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/mmc/core/host.c | 90 +++++++++++++++++++++++++++++++++++--------------
 1 file changed, 65 insertions(+), 25 deletions(-)

diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index abc60f39aa7e..c523f55b317c 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -316,7 +316,7 @@ int mmc_of_parse(struct mmc_host *host)
 	u32 bus_width;
 	bool explicit_inv_wp, gpio_inv_wp = false;
 	enum of_gpio_flags flags;
-	int i, len, ret, gpio;
+	int len, ret, gpio;
 
 	if (!host->parent || !host->parent->of_node)
 		return 0;
@@ -419,30 +419,6 @@ int mmc_of_parse(struct mmc_host *host)
 	if (explicit_inv_wp ^ gpio_inv_wp)
 		host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
 
-	/* Parse card power/reset/clock control */
-	if (of_find_property(np, "card-reset-gpios", NULL)) {
-		struct gpio_desc *gpd;
-		for (i = 0; i < ARRAY_SIZE(host->card_reset_gpios); i++) {
-			gpd = devm_gpiod_get_index(host->parent, "card-reset", i);
-			if (IS_ERR(gpd))
-				break;
-			gpiod_direction_output(gpd, 0);
-			host->card_reset_gpios[i] = gpd;
-		}
-
-		gpd = devm_gpiod_get_index(host->parent, "card-reset", ARRAY_SIZE(host->card_reset_gpios));
-		if (!IS_ERR(gpd)) {
-			dev_warn(host->parent, "More reset gpios than we can handle");
-			gpiod_put(gpd);
-		}
-	}
-
-	host->card_clk = of_clk_get_by_name(np, "card_ext_clock");
-	if (IS_ERR(host->card_clk))
-		host->card_clk = NULL;
-
-	host->card_regulator = regulator_get(host->parent, "card-external-vcc");
-
 	if (of_find_property(np, "cap-sd-highspeed", &len))
 		host->caps |= MMC_CAP_SD_HIGHSPEED;
 	if (of_find_property(np, "cap-mmc-highspeed", &len))
@@ -485,6 +461,66 @@ int mmc_of_parse(struct mmc_host *host)
 
 EXPORT_SYMBOL(mmc_of_parse);
 
+static int mmc_of_parse_child(struct mmc_host *host)
+{
+	struct device_node *np;
+	struct clk *clk;
+	int i;
+
+	if (!host->parent || !host->parent->of_node)
+		return 0;
+
+	np = host->parent->of_node;
+
+	host->card_regulator = regulator_get(host->parent, "card-external-vcc");
+	if (IS_ERR(host->card_regulator)) {
+		if (PTR_ERR(host->card_regulator) == -EPROBE_DEFER)
+			return PTR_ERR(host->card_regulator);
+		host->card_regulator = NULL;
+	}
+
+	/* Parse card power/reset/clock control */
+	if (of_find_property(np, "card-reset-gpios", NULL)) {
+		struct gpio_desc *gpd;
+		int level = 0;
+
+		/*
+		 * If the regulator is enabled, then we can hold the
+		 * card in reset with an active high resets.  Otherwise,
+		 * hold the resets low.
+		 */
+		if (host->card_regulator && regulator_is_enabled(host->card_regulator))
+			level = 1;
+
+		for (i = 0; i < ARRAY_SIZE(host->card_reset_gpios); i++) {
+			gpd = devm_gpiod_get_index(host->parent, "card-reset", i);
+			if (IS_ERR(gpd)) {
+				if (PTR_ERR(gpd) == -EPROBE_DEFER)
+					return PTR_ERR(gpd);
+				break;
+			}
+			gpiod_direction_output(gpd, gpiod_is_active_low(gpd) | level);
+			host->card_reset_gpios[i] = gpd;
+		}
+
+		gpd = devm_gpiod_get_index(host->parent, "card-reset", ARRAY_SIZE(host->card_reset_gpios));
+		if (!IS_ERR(gpd)) {
+			dev_warn(host->parent, "More reset gpios than we can handle");
+			gpiod_put(gpd);
+		}
+	}
+
+	clk = of_clk_get_by_name(np, "card_ext_clock");
+	if (IS_ERR(clk)) {
+		if (PTR_ERR(clk) == -EPROBE_DEFER)
+			return PTR_ERR(clk);
+		clk = NULL;
+	}
+	host->card_clk = clk;
+
+	return 0;
+}
+
 /**
  *	mmc_alloc_host - initialise the per-host structure.
  *	@extra: sizeof private data structure
@@ -564,6 +600,10 @@ int mmc_add_host(struct mmc_host *host)
 {
 	int err;
 
+	err = mmc_of_parse_child(host);
+	if (err)
+		return err;
+
 	WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&
 		!host->ops->enable_sdio_irq);
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 221/222] ARM: cubox-i: add support for SD UHS-1 cards
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (219 preceding siblings ...)
  2014-04-25 12:00 ` [PATCH 220/222] mmc: fix power-on sequencing for esdhc-imx driver Russell King
@ 2014-04-25 12:00 ` Russell King
  2014-04-25 12:00 ` [PATCH 222/222] ARM: cubox-i: add support for Wifi/BT Russell King
  2014-04-25 13:50 ` [PATCH 000/222] The *Full* Cubox-i series Thierry Reding
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 12:00 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/boot/dts/imx6qdl-cubox-i.dtsi | 26 +++++++++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi b/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
index c2a24888a276..c928c0a5e3cc 100644
--- a/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
@@ -111,6 +111,28 @@
 				MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x13059
 			>;
 		};
+
+		pinctrl_cubox_i_usdhc2_100mhz: cubox-i-usdhc2-100mhz {
+			fsl,pins = <
+				MX6QDL_PAD_SD2_CMD__SD2_CMD    0x170b9
+				MX6QDL_PAD_SD2_CLK__SD2_CLK    0x100b9
+				MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x170b9
+				MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170b9
+				MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170b9
+				MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x130b9
+			>;
+		};
+
+		pinctrl_cubox_i_usdhc2_200mhz: cubox-i-usdhc2-200mhz {
+			fsl,pins = <
+				MX6QDL_PAD_SD2_CMD__SD2_CMD    0x170f9
+				MX6QDL_PAD_SD2_CLK__SD2_CLK    0x100f9
+				MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x170f9
+				MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170f9
+				MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170f9
+				MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x130f9
+			>;
+		};
 	};
 };
 
@@ -131,8 +153,10 @@
 };
 
 &usdhc2 {
-	pinctrl-names = "default";
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
 	pinctrl-0 = <&pinctrl_cubox_i_usdhc2_aux &pinctrl_cubox_i_usdhc2>;
+	pinctrl-1 = <&pinctrl_cubox_i_usdhc2_aux &pinctrl_cubox_i_usdhc2_100mhz>;
+	pinctrl-2 = <&pinctrl_cubox_i_usdhc2_aux &pinctrl_cubox_i_usdhc2_200mhz>;
 	vmmc-supply = <&reg_3p3v>;
 	cd-gpios = <&gpio1 4 0>;
 	status = "okay";
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 222/222] ARM: cubox-i: add support for Wifi/BT
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (220 preceding siblings ...)
  2014-04-25 12:00 ` [PATCH 221/222] ARM: cubox-i: add support for SD UHS-1 cards Russell King
@ 2014-04-25 12:00 ` Russell King
  2014-04-25 13:50 ` [PATCH 000/222] The *Full* Cubox-i series Thierry Reding
  222 siblings, 0 replies; 232+ messages in thread
From: Russell King @ 2014-04-25 12:00 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/boot/dts/imx6qdl-cubox-i.dtsi  |  8 +++
 arch/arm/boot/dts/imx6qdl-microsom.dtsi | 98 +++++++++++++++++++++++++++++++++
 2 files changed, 106 insertions(+)

diff --git a/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi b/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
index c928c0a5e3cc..67fe5585f6dd 100644
--- a/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
@@ -152,6 +152,14 @@
 	status = "okay";
 };
 
+&uart4 {
+	status = "okay";
+};
+
+&usdhc1 {
+	status = "okay";
+};
+
 &usdhc2 {
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
 	pinctrl-0 = <&pinctrl_cubox_i_usdhc2_aux &pinctrl_cubox_i_usdhc2>;
diff --git a/arch/arm/boot/dts/imx6qdl-microsom.dtsi b/arch/arm/boot/dts/imx6qdl-microsom.dtsi
index d729d0b15f25..a5d72895d9ce 100644
--- a/arch/arm/boot/dts/imx6qdl-microsom.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-microsom.dtsi
@@ -1,9 +1,69 @@
 /*
  * Copyright (C) 2013,2014 Russell King
  */
+#include <dt-bindings/gpio/gpio.h>
+/ {
+	regulators {
+		compatible = "simple-bus";
+
+		reg_brcm_osc: brcm-osc-reg {
+			compatible = "regulator-fixed";
+			enable-active-high;
+			gpio = <&gpio5 5 0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_microsom_brcm_osc_reg>;
+			regulator-name = "brcm_osc_reg";
+			regulator-min-microvolt = <3300000>;
+			regulator-max-microvolt = <3300000>;
+			regulator-always-on;
+			regulator-boot-on;
+		};
+
+		reg_brcm: brcm-reg {
+			compatible = "regulator-fixed";
+			enable-active-high;
+			gpio = <&gpio3 19 0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_microsom_brcm_reg>;
+			regulator-name = "brcm_reg";
+			regulator-min-microvolt = <3300000>;
+			regulator-max-microvolt = <3300000>;
+			startup-delay-us = <200000>;
+		};
+	};
+};
 
 &iomuxc {
 	microsom {
+		pinctrl_microsom_brcm_osc_reg: microsom-brcm-osc-reg {
+			fsl,pins = <
+				MX6QDL_PAD_DISP0_DAT11__GPIO5_IO05 0x40013070
+			>;
+		};
+
+		pinctrl_microsom_brcm_reg: microsom-brcm-reg {
+			fsl,pins = <
+				MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x40013070
+			>;
+		};
+
+		pinctrl_microsom_brcm_wifi: microsom-brcm-wifi {
+			fsl,pins = <
+				MX6QDL_PAD_GPIO_8__XTALOSC_REF_CLK_32K	0x1b0b0
+				MX6QDL_PAD_CSI0_DATA_EN__GPIO5_IO20	0x40013070
+				MX6QDL_PAD_CSI0_DAT8__GPIO5_IO26	0x40013070
+				MX6QDL_PAD_CSI0_DAT9__GPIO5_IO27	0x40013070
+			>;
+		};
+
+		pinctrl_microsom_brcm_bt: microsom-brcm-bt {
+			fsl,pins = <
+				MX6QDL_PAD_CSI0_DAT14__GPIO6_IO00	0x40013070
+				MX6QDL_PAD_CSI0_DAT15__GPIO6_IO01	0x40013070
+				MX6QDL_PAD_CSI0_DAT18__GPIO6_IO04	0x40013070
+			>;
+		};
+
 		pinctrl_microsom_uart1: microsom-uart1 {
 			fsl,pins = <
 				MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA	0x1b0b1
@@ -11,6 +71,15 @@
 			>;
 		};
 
+		pinctrl_microsom_uart4_1: microsom-uart4 {
+			fsl,pins = <
+				MX6QDL_PAD_CSI0_DAT12__UART4_TX_DATA 0x1b0b1
+				MX6QDL_PAD_CSI0_DAT13__UART4_RX_DATA 0x1b0b1
+				MX6QDL_PAD_CSI0_DAT16__UART4_RTS_B 0x1b0b1
+				MX6QDL_PAD_CSI0_DAT17__UART4_CTS_B 0x1b0b1
+			>;
+		};
+
 		pinctrl_microsom_usbotg: microsom-usbotg {
 			/*
 			 * Similar to pinctrl_usbotg_2, but we want it
@@ -18,6 +87,17 @@
 			 */
 			fsl,pins = <MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x13059>;
 		};
+
+		pinctrl_microsom_usdhc1: microsom-usdhc1 {
+			fsl,pins = <
+				MX6QDL_PAD_SD1_CMD__SD1_CMD    0x17059
+				MX6QDL_PAD_SD1_CLK__SD1_CLK    0x10059
+				MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17059
+				MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17059
+				MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17059
+				MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059
+			>;
+		};
 	};
 };
 
@@ -27,7 +107,25 @@
 	status = "okay";
 };
 
+/* UART4 - Connected to optional BRCM Wifi/BT/FM */
+&uart4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_microsom_brcm_bt &pinctrl_microsom_uart4_1>;
+	fsl,uart-has-rtscts;
+};
+
 &usbotg {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_microsom_usbotg>;
 };
+
+/* USDHC1 - Connected to optional BRCM Wifi/BT/FM */
+&usdhc1 {
+	card-external-vcc-supply = <&reg_brcm>;
+	card-reset-gpios = <&gpio5 26 GPIO_ACTIVE_LOW>, <&gpio6 0 GPIO_ACTIVE_LOW>;
+	keep-power-in-suspend;
+	non-removable;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_microsom_brcm_wifi &pinctrl_microsom_usdhc1>;
+	vmmc-supply = <&reg_brcm>;
+};
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 232+ messages in thread

* [PATCH 000/222] The *Full* Cubox-i series
  2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
                   ` (221 preceding siblings ...)
  2014-04-25 12:00 ` [PATCH 222/222] ARM: cubox-i: add support for Wifi/BT Russell King
@ 2014-04-25 13:50 ` Thierry Reding
  2014-04-25 14:15   ` Russell King - ARM Linux
  222 siblings, 1 reply; 232+ messages in thread
From: Thierry Reding @ 2014-04-25 13:50 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Apr 25, 2014 at 12:29:51PM +0100, Russell King - ARM Linux wrote:
> So that people can see what kind of a patch nightmare I'm in, and
> hopefully start being more co-operative towards getting patches into
> mainline, here is the *full* patch set for CuBox-i support that I'm
> presently sitting on.
> 
> Anything that can be done to make this easier would be very helpful,
> so I'm not spending lots of time tweaking some random patch and then
> having to remerge all these different sub-series.

Do you happen to have a branch that I can pull to test this on Tegra? Is
there anything that I should be paying special attention to when
testing?

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140425/1a66ff1c/attachment.sig>

^ permalink raw reply	[flat|nested] 232+ messages in thread

* [PATCH 000/222] The *Full* Cubox-i series
  2014-04-25 13:50 ` [PATCH 000/222] The *Full* Cubox-i series Thierry Reding
@ 2014-04-25 14:15   ` Russell King - ARM Linux
  2014-04-25 14:22     ` Thierry Reding
  2014-04-25 19:50     ` Kevin Hilman
  0 siblings, 2 replies; 232+ messages in thread
From: Russell King - ARM Linux @ 2014-04-25 14:15 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Apr 25, 2014 at 03:50:49PM +0200, Thierry Reding wrote:
> On Fri, Apr 25, 2014 at 12:29:51PM +0100, Russell King - ARM Linux wrote:
> > So that people can see what kind of a patch nightmare I'm in, and
> > hopefully start being more co-operative towards getting patches into
> > mainline, here is the *full* patch set for CuBox-i support that I'm
> > presently sitting on.
> > 
> > Anything that can be done to make this easier would be very helpful,
> > so I'm not spending lots of time tweaking some random patch and then
> > having to remerge all these different sub-series.
> 
> Do you happen to have a branch that I can pull to test this on Tegra? Is
> there anything that I should be paying special attention to when
> testing?

One of the issues I'm _most_ concerned about is the L2C code.  I only
have a very limited number of platforms I can test that stuff out on.

The L2C code that I've now dumped into linux-next is there in an attempt
to get more testing coverage, and it has resulted in that - Kevin's
boot test revealed that it breaks on a Broadcom platform.  I'm hoping
Kevin will investigate further as per my emails, but I've no idea at the
moment whether that's going to happen or not.  I can't do it because I
don't have access to any Broadcom hardware, neither do I have much idea
as to its cause.

This is one of the big problems of the arm-soc automatic testing.  It's
all very well setting up some automatic testing facility, but it's
utterly useless if you can't get at information needed to debug issues
that it reports.

I know that various patches in there need squashing together or deleting
(eg, whether we enable the power management via DT, or whether we always
enable it) depending on the results of testing...

I'm at the end of knowing what to do with any of that stuff right now.
The way I'm currently feeling, I might just as well delete the entire
L2 cache changes branch because I'm *not* getting the support needed to
make progress with it.

The same is true of the mmc stuff.  It's a big patch set, and it's
conflicting with other people's changes.  That patch set is over two
months old now, and it's received very little in the way of testing so
far...

And as you can see from this patch set, I also have a whole load of
changes to the Freescale FEC driver which haven't yet been properly
posted (and as I found out yesterday from one of DaveM's review comments
for a different driver, it already requires some changes.)

What I would like to do is to get some of these patches into a "finished"
state (iow, reviewed and tested) and properly queued up for the next merge
window so I don't have to mess around with soo many in-flux patches, as
I have been for the last two to three months.

At the moment, the rate at which I seem to be able to get patches into
the mainline kernel is down around 40 per cycle (basically the imx-drm
debacle), which is piss poor when dealing with such a big backlog - a
backlog which has taken just four months to build up.

-- 
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.

^ permalink raw reply	[flat|nested] 232+ messages in thread

* [PATCH 000/222] The *Full* Cubox-i series
  2014-04-25 14:15   ` Russell King - ARM Linux
@ 2014-04-25 14:22     ` Thierry Reding
  2014-04-25 14:26       ` Russell King - ARM Linux
  2014-04-25 19:50     ` Kevin Hilman
  1 sibling, 1 reply; 232+ messages in thread
From: Thierry Reding @ 2014-04-25 14:22 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Apr 25, 2014 at 03:15:50PM +0100, Russell King - ARM Linux wrote:
> On Fri, Apr 25, 2014 at 03:50:49PM +0200, Thierry Reding wrote:
> > On Fri, Apr 25, 2014 at 12:29:51PM +0100, Russell King - ARM Linux wrote:
> > > So that people can see what kind of a patch nightmare I'm in, and
> > > hopefully start being more co-operative towards getting patches into
> > > mainline, here is the *full* patch set for CuBox-i support that I'm
> > > presently sitting on.
> > > 
> > > Anything that can be done to make this easier would be very helpful,
> > > so I'm not spending lots of time tweaking some random patch and then
> > > having to remerge all these different sub-series.
> > 
> > Do you happen to have a branch that I can pull to test this on Tegra? Is
> > there anything that I should be paying special attention to when
> > testing?
[...]
> What I would like to do is to get some of these patches into a "finished"
> state (iow, reviewed and tested) and properly queued up for the next merge
> window so I don't have to mess around with soo many in-flux patches, as
> I have been for the last two to three months.

Okay. I don't have access to a whole lot of hardware myself. It's really
just a couple of Tegra boards, but I can still at least run the patches
and report back if (or not) there's any breakage and help debug from
there.

But I'm somewhat reluctant to go pick up 222 patches from my inbox
manually if there's a branch available somewhere that I can pick up more
easily.

> At the moment, the rate at which I seem to be able to get patches into
> the mainline kernel is down around 40 per cycle (basically the imx-drm
> debacle), which is piss poor when dealing with such a big backlog - a
> backlog which has taken just four months to build up.

I've been through some of that same myself. Hence my offer to help.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140425/aadfc6da/attachment.sig>

^ permalink raw reply	[flat|nested] 232+ messages in thread

* [PATCH 000/222] The *Full* Cubox-i series
  2014-04-25 14:22     ` Thierry Reding
@ 2014-04-25 14:26       ` Russell King - ARM Linux
  0 siblings, 0 replies; 232+ messages in thread
From: Russell King - ARM Linux @ 2014-04-25 14:26 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Apr 25, 2014 at 04:22:51PM +0200, Thierry Reding wrote:
> Okay. I don't have access to a whole lot of hardware myself. It's really
> just a couple of Tegra boards, but I can still at least run the patches
> and report back if (or not) there's any breakage and help debug from
> there.
> 
> But I'm somewhat reluctant to go pick up 222 patches from my inbox
> manually if there's a branch available somewhere that I can pick up more
> easily.

Let me re-merge for the changes which just happened to the MMC branch
and I'll push this stuff out.

Thanks for the offer to help, much appreciated.

-- 
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.

^ permalink raw reply	[flat|nested] 232+ messages in thread

* [PATCH 000/222] The *Full* Cubox-i series
  2014-04-25 14:15   ` Russell King - ARM Linux
  2014-04-25 14:22     ` Thierry Reding
@ 2014-04-25 19:50     ` Kevin Hilman
  1 sibling, 0 replies; 232+ messages in thread
From: Kevin Hilman @ 2014-04-25 19:50 UTC (permalink / raw)
  To: linux-arm-kernel

Russell King - ARM Linux <linux@arm.linux.org.uk> writes:

> On Fri, Apr 25, 2014 at 03:50:49PM +0200, Thierry Reding wrote:
>> On Fri, Apr 25, 2014 at 12:29:51PM +0100, Russell King - ARM Linux wrote:
>> > So that people can see what kind of a patch nightmare I'm in, and
>> > hopefully start being more co-operative towards getting patches into
>> > mainline, here is the *full* patch set for CuBox-i support that I'm
>> > presently sitting on.
>> > 
>> > Anything that can be done to make this easier would be very helpful,
>> > so I'm not spending lots of time tweaking some random patch and then
>> > having to remerge all these different sub-series.
>> 
>> Do you happen to have a branch that I can pull to test this on Tegra? Is
>> there anything that I should be paying special attention to when
>> testing?
>
> One of the issues I'm _most_ concerned about is the L2C code.  I only
> have a very limited number of platforms I can test that stuff out on.
>
> The L2C code that I've now dumped into linux-next is there in an attempt
> to get more testing coverage, and it has resulted in that - Kevin's
> boot test revealed that it breaks on a Broadcom platform.  I'm hoping
> Kevin will investigate further as per my emails, but I've no idea at the
> moment whether that's going to happen or not.  

Yes, it is happening.  Actually Matt Porter (co-maintainer of BCM SoC
support) has reproduced it and is looking into it since he has access to
HW details/docs that I do not.  However, both of us will be at ELC next
week, so there might not be much progress immediately.

Kevin

^ permalink raw reply	[flat|nested] 232+ messages in thread

* [PATCH 071/222] net:fec: remove unnecessary ip stack includes
  2014-04-25 11:36 ` [PATCH 071/222] net:fec: remove unnecessary ip stack includes Russell King
@ 2014-04-28 18:36   ` Frank Li
  2014-04-28 18:39     ` Russell King - ARM Linux
  0 siblings, 1 reply; 232+ messages in thread
From: Frank Li @ 2014-04-28 18:36 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Apr 25, 2014 at 6:36 AM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:
> Commit 4c09eed9dc42 (net: fec: Enable imx6 enet checksum acceleration.)
> added support for hardware checksum support, adding six new includes
> for things like tcp, udp, ip, icmp, but never made use of anything
> provided by those header files.  Let's remove this bloat.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Russell

       I see patches from 71 to 126 are related with fec driver.
       But maintainer David S. Miller is not in to list.

       Do you need someone follow up this patches and resent to David
S Miller till accepted by david? Or you will do it by yourself?

Best regards
Frank Li

> ---
>  drivers/net/ethernet/freescale/fec_main.c | 6 ------
>  1 file changed, 6 deletions(-)
>
> diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
> index 8d69e439f0c5..b151eaf3b500 100644
> --- a/drivers/net/ethernet/freescale/fec_main.c
> +++ b/drivers/net/ethernet/freescale/fec_main.c
> @@ -33,12 +33,6 @@
>  #include <linux/netdevice.h>
>  #include <linux/etherdevice.h>
>  #include <linux/skbuff.h>
> -#include <linux/in.h>
> -#include <linux/ip.h>
> -#include <net/ip.h>
> -#include <linux/tcp.h>
> -#include <linux/udp.h>
> -#include <linux/icmp.h>
>  #include <linux/spinlock.h>
>  #include <linux/workqueue.h>
>  #include <linux/bitops.h>
> --
> 1.8.3.1
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 232+ messages in thread

* [PATCH 071/222] net:fec: remove unnecessary ip stack includes
  2014-04-28 18:36   ` Frank Li
@ 2014-04-28 18:39     ` Russell King - ARM Linux
  0 siblings, 0 replies; 232+ messages in thread
From: Russell King - ARM Linux @ 2014-04-28 18:39 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Apr 28, 2014 at 01:36:44PM -0500, Frank Li wrote:
> On Fri, Apr 25, 2014 at 6:36 AM, Russell King
> <rmk+kernel@arm.linux.org.uk> wrote:
> > Commit 4c09eed9dc42 (net: fec: Enable imx6 enet checksum acceleration.)
> > added support for hardware checksum support, adding six new includes
> > for things like tcp, udp, ip, icmp, but never made use of anything
> > provided by those header files.  Let's remove this bloat.
> >
> > Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
> 
> Russell
> 
>        I see patches from 71 to 126 are related with fec driver.
>        But maintainer David S. Miller is not in to list.
> 
>        Do you need someone follow up this patches and resent to David
> S Miller till accepted by david? Or you will do it by yourself?

I know they need to re-worked to convert unsigned -> unsigned int before
David sees them, otherwise it'd be an instant review failure.  Doing the
conversion is the easy bit, doing it without hitting the 80 column limit
is much harder...

-- 
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.

^ permalink raw reply	[flat|nested] 232+ messages in thread

* [PATCH 134/222] ARM: imx: keep PLLs in bypass while they're locking
  2014-04-25 11:42 ` [PATCH 134/222] ARM: imx: keep PLLs in bypass while they're locking Russell King
@ 2014-04-30 10:52   ` Dirk Behme
  2014-05-08  8:59     ` Dirk Behme
  0 siblings, 1 reply; 232+ messages in thread
From: Dirk Behme @ 2014-04-30 10:52 UTC (permalink / raw)
  To: linux-arm-kernel

On 25.04.2014 13:42, Russell King wrote:
> Keep the PLL bypassed while we prepare a clock by powering up the PLL,
> otherwise we can end up with improper output/gitches which prevents
> further operation.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
> ---
>   arch/arm/mach-imx/clk-pllv3.c | 27 +++++++++++++++++++++------
>   1 file changed, 21 insertions(+), 6 deletions(-)
>
> diff --git a/arch/arm/mach-imx/clk-pllv3.c b/arch/arm/mach-imx/clk-pllv3.c
> index 61364050fccd..3776f974d1dc 100644
> --- a/arch/arm/mach-imx/clk-pllv3.c
> +++ b/arch/arm/mach-imx/clk-pllv3.c
> @@ -273,9 +273,10 @@ static int clk_pllv3_av_set_rate(struct clk_hw *hw, unsigned long rate,
>   	struct clk_pllv3 *pll = to_clk_pllv3(hw);
>   	unsigned long min_rate = parent_rate * 27;
>   	unsigned long max_rate = parent_rate * 54;
> -	u32 val, div;
> +	u32 val, newval, div;
>   	u32 mfn, mfd = 1000000;
>   	s64 temp64;
> +	int ret;
>
>   	if (rate < min_rate || rate > max_rate)
>   		return -EINVAL;
> @@ -287,13 +288,27 @@ static int clk_pllv3_av_set_rate(struct clk_hw *hw, unsigned long rate,
>   	mfn = temp64;
>
>   	val = readl_relaxed(pll->base);
> -	val &= ~pll->div_mask;
> -	val |= div;
> -	writel_relaxed(val, pll->base);
> +
> +	/* set the PLL into bypass mode */
> +	newval = val | BM_PLL_BYPASS;
> +	writel_relaxed(newval, pll->base);
> +
> +	/* configure the new frequency */
> +	newval &= ~pll->div_mask;
> +	newval |= div;
> +	writel_relaxed(newval, pll->base);
>   	writel_relaxed(mfn, pll->base + PLL_NUM_OFFSET);
> -	writel_relaxed(mfd, pll->base + PLL_DENOM_OFFSET);
> +	writel(mfd, pll->base + PLL_DENOM_OFFSET);
>
> -	return clk_pllv3_wait_lock(pll);
> +	ret = clk_pllv3_wait_lock(pll);
> +	if (ret == 0 && val & BM_PLL_POWER) {

I'm no expert on this, so sorry if I'm wrong ;)

But regarding the check 'val & BM_PLL_POWER' here:

Reading the manual, it seems that both PLL4_AUDIO & PLL5_VIDEO don't 
have a POWER bit, instead they have a POWERDOWN at bit 12. So for 
PLL4_AUDIO & PLL5_VIDEO 'val & BM_PLL_POWER' would mean not powered up?

Maybe the check should be done anywhere else, e.g. in clk_pllv3_set_rate()?

Best regards

Dirk

^ permalink raw reply	[flat|nested] 232+ messages in thread

* [PATCH 134/222] ARM: imx: keep PLLs in bypass while they're locking
  2014-04-30 10:52   ` Dirk Behme
@ 2014-05-08  8:59     ` Dirk Behme
  0 siblings, 0 replies; 232+ messages in thread
From: Dirk Behme @ 2014-05-08  8:59 UTC (permalink / raw)
  To: linux-arm-kernel


Besides the question below regarding 'val & BM_PLL_POWER', three 
additional questions:

On 30.04.2014 12:52, Dirk Behme wrote:
> On 25.04.2014 13:42, Russell King wrote:
>> Keep the PLL bypassed while we prepare a clock by powering up the PLL,
>> otherwise we can end up with improper output/gitches which prevents
>> further operation.

Have you seen a real world case to show this patch fixes an issue in 
real? Have you been seeing anything like "improper output/gitches"?

>> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
>> ---
>>   arch/arm/mach-imx/clk-pllv3.c | 27 +++++++++++++++++++++------
>>   1 file changed, 21 insertions(+), 6 deletions(-)
>>
>> diff --git a/arch/arm/mach-imx/clk-pllv3.c
>> b/arch/arm/mach-imx/clk-pllv3.c
>> index 61364050fccd..3776f974d1dc 100644
>> --- a/arch/arm/mach-imx/clk-pllv3.c
>> +++ b/arch/arm/mach-imx/clk-pllv3.c
>> @@ -273,9 +273,10 @@ static int clk_pllv3_av_set_rate(struct clk_hw

We touch here pllv3/av only, while the commit message generically says 
"keep PLLs in bypass while they're locking" nothing specific to 
audio/video PLL clock. So isn't similar modification needed for the 
other set_rate() functions as well?

>> *hw, unsigned long rate,
>>       struct clk_pllv3 *pll = to_clk_pllv3(hw);
>>       unsigned long min_rate = parent_rate * 27;
>>       unsigned long max_rate = parent_rate * 54;
>> -    u32 val, div;
>> +    u32 val, newval, div;
>>       u32 mfn, mfd = 1000000;
>>       s64 temp64;
>> +    int ret;
>>
>>       if (rate < min_rate || rate > max_rate)
>>           return -EINVAL;
>> @@ -287,13 +288,27 @@ static int clk_pllv3_av_set_rate(struct clk_hw
>> *hw, unsigned long rate,
>>       mfn = temp64;
>>
>>       val = readl_relaxed(pll->base);
>> -    val &= ~pll->div_mask;
>> -    val |= div;
>> -    writel_relaxed(val, pll->base);
>> +
>> +    /* set the PLL into bypass mode */
>> +    newval = val | BM_PLL_BYPASS;
>> +    writel_relaxed(newval, pll->base);
>> +
>> +    /* configure the new frequency */

Reading the i.MX6 reference manual section '18.5.1.5.3 PLL clock 
change': 'Before changing the PLL setting, power it down. Power up the 
PLL after the change.' So we need to power down/up the PLL rather than 
just bypass for a rate change?

>> +    newval &= ~pll->div_mask;
>> +    newval |= div;
>> +    writel_relaxed(newval, pll->base);
>>       writel_relaxed(mfn, pll->base + PLL_NUM_OFFSET);
>> -    writel_relaxed(mfd, pll->base + PLL_DENOM_OFFSET);
>> +    writel(mfd, pll->base + PLL_DENOM_OFFSET);
>>
>> -    return clk_pllv3_wait_lock(pll);
>> +    ret = clk_pllv3_wait_lock(pll);
>> +    if (ret == 0 && val & BM_PLL_POWER) {
>
> I'm no expert on this, so sorry if I'm wrong ;)
>
> But regarding the check 'val & BM_PLL_POWER' here:
>
> Reading the manual, it seems that both PLL4_AUDIO & PLL5_VIDEO don't
> have a POWER bit, instead they have a POWERDOWN at bit 12. So for
> PLL4_AUDIO & PLL5_VIDEO 'val & BM_PLL_POWER' would mean not powered up?
>
> Maybe the check should be done anywhere else, e.g. in clk_pllv3_set_rate()?

Best regards

Dirk

^ permalink raw reply	[flat|nested] 232+ messages in thread

end of thread, other threads:[~2014-05-08  8:59 UTC | newest]

Thread overview: 232+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-04-25 11:29 [PATCH 000/222] The *Full* Cubox-i series Russell King - ARM Linux
2014-04-25 11:31 ` [PATCH 001/222] ARM: l2c: remove outer_inv_all() method Russell King
2014-04-25 11:31 ` [PATCH 002/222] ARM: l2c: remove unnecessary call to outer_flush_all() Russell King
2014-04-25 11:31 ` [PATCH 003/222] ARM: l2c: avoid calling outer_flush_all() unnecessarily (Spear) Russell King
2014-04-25 11:31 ` [PATCH 004/222] ARM: l2c: omap2: remove ES1.0 support Russell King
2014-04-25 11:31 ` [PATCH 005/222] ARM: l2c: remove unnecessary UL-suffix to mask values Russell King
2014-04-25 11:31 ` [PATCH 006/222] ARM: outer cache: add documentation of outer cache functions Russell King
2014-04-25 11:31 ` [PATCH 007/222] ARM: outer cache: add WARN_ON() to outer_disable() Russell King
2014-04-25 11:31 ` [PATCH 008/222] ARM: l2c: add helper for L2 cache controller DT IDs Russell King
2014-04-25 11:31 ` [PATCH 009/222] ARM: l2c: tidy up l2x0_of_data declarations Russell King
2014-04-25 11:31 ` [PATCH 010/222] ARM: l2c: rename OF specific things, making l2x0_of_data available to all Russell King
2014-04-25 11:31 ` [PATCH 011/222] ARM: l2c: provide generic function for calling set_debug method Russell King
2014-04-25 11:31 ` [PATCH 012/222] ARM: l2c: split out cache unlock code Russell King
2014-04-25 11:32 ` [PATCH 013/222] ARM: l2c: provide generic helper for way-based operations Russell King
2014-04-25 11:32 ` [PATCH 014/222] ARM: l2c: rename cache_wait_way() Russell King
2014-04-25 11:32 ` [PATCH 015/222] ARM: l2c: add and use L2C revision constants Russell King
2014-04-25 11:32 ` [PATCH 016/222] ARM: l2c: clean up OF initialisation a bit Russell King
2014-04-25 11:32 ` [PATCH 017/222] ARM: l2c: pass iomem address into data->save function Russell King
2014-04-25 11:32 ` [PATCH 018/222] ARM: l2c: move l2c save function to __l2c_init() Russell King
2014-04-25 11:32 ` [PATCH 019/222] ARM: l2c: group implementation specific code together Russell King
2014-04-25 11:32 ` [PATCH 020/222] ARM: l2c: provide enable method Russell King
2014-04-25 11:32 ` [PATCH 021/222] ARM: l2c: write auxctrl register before unlocking Russell King
2014-04-25 11:32 ` [PATCH 022/222] ARM: l2c: only write the auxiliary control register if required Russell King
2014-04-25 11:32 ` [PATCH 023/222] ARM: l2c: move aurora broadcast setup to enable function Russell King
2014-04-25 11:32 ` [PATCH 024/222] ARM: l2c: implement fixups for L2 cache controller quirks/errata Russell King
2014-04-25 11:33 ` [PATCH 025/222] ARM: l2c: clean up L2 cache initialisation messages Russell King
2014-04-25 11:33 ` [PATCH 026/222] ARM: l2c: move and add ARM L2C-2x0/L2C-310 save/resume code to non-OF Russell King
2014-04-25 11:33 ` [PATCH 027/222] ARM: l2c: clean up save/resume functions Russell King
2014-04-25 11:33 ` [PATCH 028/222] ARM: l2c: simplify l2x0 unlocking code Russell King
2014-04-25 11:33 ` [PATCH 029/222] ARM: l2c: move pl310_set_debug() into l2c-310 code Russell King
2014-04-25 11:33 ` [PATCH 030/222] ARM: l2c: add L2C-210 specific handlers Russell King
2014-04-25 11:33 ` [PATCH 031/222] ARM: l2c: implement L2C-310 erratum 727915 as a method override Russell King
2014-04-25 11:33 ` [PATCH 032/222] ARM: l2c: implement L2C-310 erratum 588369 " Russell King
2014-04-25 11:33 ` [PATCH 033/222] ARM: l2c: use L2C-210 handlers for L2C-310 errata-less implementations Russell King
2014-04-25 11:33 ` [PATCH 034/222] ARM: l2c: add L2C-220 specific handlers Russell King
2014-04-25 11:33 ` [PATCH 035/222] ARM: l2c: convert Broadcom L2C-310 to new code Russell King
2014-04-25 11:34 ` [PATCH 036/222] ARM: l2c: remove obsolete l2x0 ops for non-OF init Russell King
2014-04-25 11:34 ` [PATCH 037/222] ARM: l2c: move type string into l2c_init_data structure Russell King
2014-04-25 11:34 ` [PATCH 038/222] ARM: l2c: add decode for L2C-220 cache ways Russell King
2014-04-25 11:34 ` [PATCH 039/222] ARM: l2c: move way size calculation data into l2c_init_data Russell King
2014-04-25 11:34 ` [PATCH 040/222] ARM: l2c: move errata configuration options to arch/arm/mm/Kconfig Russell King
2014-04-25 11:34 ` [PATCH 041/222] ARM: l2c: provide generic hook to intercept writes to secure registers Russell King
2014-04-25 11:34 ` [PATCH 042/222] ARM: l2c: omap2: implement new write_sec method Russell King
2014-04-25 11:34 ` [PATCH 043/222] ARM: l2c: omap2: remove explicit SMI calls to enable L2 cache Russell King
2014-04-25 11:34 ` [PATCH 044/222] ARM: l2c: highbank: implement new write_sec method Russell King
2014-04-25 11:34 ` [PATCH 045/222] ARM: l2c: highbank: remove explicit SMI call in L2 cache initialisation Russell King
2014-04-25 11:34 ` [PATCH 046/222] ARM: l2c: ux500: implement dummy write_sec method Russell King
2014-04-25 11:34 ` [PATCH 047/222] ARM: l2c: remove old .set_debug method Russell King
2014-04-25 11:35 ` [PATCH 048/222] ARM: l2c: implement L2C-310 erratum 752271 in core L2C code Russell King
2014-04-25 11:35 ` [PATCH 049/222] ARM: l2c: fix register naming Russell King
2014-04-25 11:35 ` [PATCH 050/222] ARM: l2c: add automatic enable of early BRESP Russell King
2014-04-25 11:35 ` [PATCH 051/222] ARM: l2c: remove platforms/SoCs setting " Russell King
2014-04-25 11:35 ` [PATCH 052/222] ARM: l2c: tegra: remove associativity and way size from aux_ctrl Russell King
2014-04-25 11:35 ` [PATCH 053/222] ARM: l2c: ux500: " Russell King
2014-04-25 11:35 ` [PATCH 054/222] ARM: l2c: ux500: don't try to change the L2 cache auxiliary control register Russell King
2014-04-25 11:35 ` [PATCH 055/222] ARM: l2c: cns3xxx: remove cache size override Russell King
2014-04-25 11:35 ` [PATCH 056/222] ARM: l2c: exynos: " Russell King
2014-04-25 11:35 ` [PATCH 057/222] ARM: l2c: nomadik: " Russell King
2014-04-25 11:35 ` [PATCH 058/222] ARM: l2c: omap2: " Russell King
2014-04-25 11:35 ` [PATCH 059/222] ARM: l2c: prima2: " Russell King
2014-04-25 11:36 ` [PATCH 060/222] ARM: l2c: shmobile: " Russell King
2014-04-25 11:36 ` [PATCH 061/222] ARM: l2c: spear13xx: " Russell King
2014-04-25 11:36 ` [PATCH 062/222] ARM: l2c: sti: " Russell King
2014-04-25 11:36 ` [PATCH 063/222] ARM: l2c: zynq: " Russell King
2014-04-25 11:36 ` [PATCH 064/222] ARM: l2c: realview: improve commentry about the L2 cache requirements Russell King
2014-04-25 11:36 ` [PATCH 065/222] ARM: l2c: kill L2X0_AUX_CTRL_MASK before anyone else makes use of this Russell King
2014-04-25 11:36 ` [PATCH 066/222] ARM: l2c: print a warning with L2C-310 caches if the cache size is modified Russell King
2014-04-25 11:36 ` [PATCH 067/222] ARM: l2c: vexpress ca9x4: move L2 cache initialisation earlier Russell King
2014-04-25 11:36 ` [PATCH 068/222] ARM: l2c: add L2C-310 power control DT properties Russell King
2014-04-25 11:36 ` [PATCH 069/222] ARM: l2c: check that DT files specify the required "cache-unified" property Russell King
2014-04-25 11:36 ` [PATCH 070/222] ARM: l2c: add warnings for stuff modifying aux_ctrl register values Russell King
2014-04-25 11:36 ` [PATCH 071/222] net:fec: remove unnecessary ip stack includes Russell King
2014-04-28 18:36   ` Frank Li
2014-04-28 18:39     ` Russell King - ARM Linux
2014-04-25 11:37 ` [PATCH 072/222] net:fec: reorder ethtool ops to match order in struct declaration Russell King
2014-04-25 11:37 ` [PATCH 073/222] net:fec: remove checking for NULL phy_dev in fec_enet_close() Russell King
2014-04-25 11:37 ` [PATCH 074/222] net:fec: ensure that a disconnected phy isn't configured Russell King
2014-04-25 11:37 ` [PATCH 075/222] net:fec: add support for dumping transmit ring on timeout Russell King
2014-04-25 11:37 ` [PATCH 076/222] net:fec: use netif_tx_disable() rather than netif_stop_queue() Russell King
2014-04-25 11:37 ` [PATCH 077/222] net:fec: iMX6 FEC does not support half-duplex gigabit Russell King
2014-04-25 11:37 ` [PATCH 078/222] net:fec: clean up transmit descriptor setup Russell King
2014-04-25 11:37 ` [PATCH 079/222] net:fec: make rx skb allocation/map more robust Russell King
2014-04-25 11:37 ` [PATCH 080/222] net:fec: ensure fec_enet_free_buffers() properly cleans the rings Russell King
2014-04-25 11:37 ` [PATCH 081/222] net:fec: fix missing kmalloc() failure check in fec_enet_alloc_buffers() Russell King
2014-04-25 11:37 ` [PATCH 082/222] net:fec: ensure that we dma unmap the transmit descriptors Russell King
2014-04-25 11:38 ` [PATCH 083/222] net:fec: remove useless fep->opened Russell King
2014-04-25 11:38 ` [PATCH 084/222] net:fec: stop the phy before shutting down the MAC Russell King
2014-04-25 11:38 ` [PATCH 085/222] net:fec: improve safety of suspend/resume/transmit timeout paths Russell King
2014-04-25 11:38 ` [PATCH 086/222] net:fec: ensure fec_enet_close() copes with resume failure Russell King
2014-04-25 11:38 ` [PATCH 087/222] net:fec: only run a restart or stop if the device is present and running Russell King
2014-04-25 11:38 ` [PATCH 088/222] net:fec: move calls to quiesce/resume packet processing out of fec_restart() Russell King
2014-04-25 11:38 ` [PATCH 089/222] net:fec: remove inappropriate calls around fec_restart() Russell King
2014-04-25 11:38 ` [PATCH 090/222] net:fec: quiesce packet processing before stopping device in fec_suspend() Russell King
2014-04-25 11:38 ` [PATCH 091/222] net:fec: quiesce packet processing before stopping device in fec_set_features() Russell King
2014-04-25 11:38 ` [PATCH 092/222] net:fec: quiesce packet processing before changing features Russell King
2014-04-25 11:38 ` [PATCH 093/222] net:fec: quiesce packet processing when taking link down in fec_enet_adjust_link() Russell King
2014-04-25 11:38 ` [PATCH 094/222] net:fec: fix ethtool set_pauseparam duplex bug Russell King
2014-04-25 11:39 ` [PATCH 095/222] net:fec: clean up duplex mode handling Russell King
2014-04-25 11:39 ` [PATCH 096/222] net:fec: add barrier to transmit path to ensure proper ordering Russell King
2014-04-25 11:39 ` [PATCH 097/222] net:fec: add barrier to receive " Russell King
2014-04-25 11:39 ` [PATCH 098/222] net:fec: better implementation of iMX6 ERR006358 quirk Russell King
2014-04-25 11:39 ` [PATCH 099/222] net:fec: avoid hitting transmitter if it is still running Russell King
2014-04-25 11:39 ` [PATCH 100/222] net:fec: remove delayed work Russell King
2014-04-25 11:39 ` [PATCH 101/222] net:fec: fix interrupt handling races Russell King
2014-04-25 11:39 ` [PATCH 102/222] net:fec: clear receive interrupts before processing a packet Russell King
2014-04-25 11:39 ` [PATCH 103/222] net:fec: remove useless status check in tx reap path Russell King
2014-04-25 11:39 ` [PATCH 104/222] net:fec: use a union for the buffer descriptors Russell King
2014-04-25 11:39 ` [PATCH 105/222] net:fec: consolidate hwtstamp implementation Russell King
2014-04-25 11:39 ` [PATCH 106/222] net:fec: better indexing for transmit descriptor ring Russell King
2014-04-25 11:40 ` [PATCH 107/222] net:fec: better indexing for receive " Russell King
2014-04-25 11:40 ` [PATCH 108/222] net:fec: calculate ring space rather than relying on comparing indices Russell King
2014-04-25 11:40 ` [PATCH 109/222] net:fec: increase transmit ring size Russell King
2014-04-25 11:40 ` [PATCH 110/222] net:fec: increase receive " Russell King
2014-04-25 11:40 ` [PATCH 111/222] net:fec: add scatter-gather support Russell King
2014-04-25 11:40 ` [PATCH 112/222] net:fec: add byte queue limits support Russell King
2014-04-25 11:41 ` [PATCH 113/222] net:fec: add better flow control support Russell King
2014-04-25 11:41 ` [PATCH 114/222] net:fec: move transmit dma ring address calculation to fec_enet_init() Russell King
2014-04-25 11:41 ` [PATCH 115/222] net:fec: allocate descriptor rings at device open, and free on device close Russell King
2014-04-25 11:41 ` [PATCH 116/222] net:fec: remove unnecessary code Russell King
2014-04-25 11:41 ` [PATCH 117/222] net:fec: consolidate common parts of mdio read/write Russell King
2014-04-25 11:41 ` [PATCH 118/222] net:fec: add locking for MDIO bus access Russell King
2014-04-25 11:41 ` [PATCH 119/222] net:fec: move bufdesc_ex flag into flags Russell King
2014-04-25 11:41 ` [PATCH 120/222] net:fec: move receive checksum flags into new flags member Russell King
2014-04-25 11:41 ` [PATCH 121/222] net:fec: only enable CTAG_RX and IP checksumming if we have enhanced buffer descriptors Russell King
2014-04-25 11:41 ` [PATCH 122/222] net:fec: avoid checking more flags than necessary in rx path Russell King
2014-04-25 11:41 ` [PATCH 123/222] net:fec: move vlan receive flag into our private flags Russell King
2014-04-25 11:42 ` [PATCH 124/222] net:fec: add ethtool support for tx/rx ring sizes Russell King
2014-04-25 11:42 ` [PATCH 125/222] net:fec: even larger rings Russell King
2014-04-25 11:42 ` [PATCH 126/222] net:fec: unsorted hacks Russell King
2014-04-25 11:42 ` [PATCH 127/222] leds: leds-pwm: provide a common function to setup a single led-pwm device Russell King
2014-04-25 11:42 ` [PATCH 128/222] leds: leds-pwm: convert OF parsing code to use led_pwm_add() Russell King
2014-04-25 11:42 ` [PATCH 129/222] leds: leds-pwm: implement PWM inversion Russell King
2014-04-25 11:42 ` [PATCH 130/222] leds: leds-pwm: add DT support for LEDs wired to supply Russell King
2014-04-25 11:42 ` [PATCH 131/222] ARM: add support for Cubox-i PWM-driven front panel LED Russell King
2014-04-25 11:42 ` [PATCH 132/222] ASoC: work around block transfer issues with imx-pcm-dma Russell King
2014-04-25 11:42 ` [PATCH 133/222] ata: ahci_imx: warn when disabling ahci link Russell King
2014-04-25 11:42 ` [PATCH 134/222] ARM: imx: keep PLLs in bypass while they're locking Russell King
2014-04-30 10:52   ` Dirk Behme
2014-05-08  8:59     ` Dirk Behme
2014-04-25 11:42 ` [PATCH 135/222] ARM: imx: set IPU to be derived from the 540MHz PLL3 PFD1 clock Russell King
2014-04-25 11:43 ` [PATCH 136/222] regulator: allow GPIO 0 to be used for an enable signal Russell King
2014-04-25 11:43 ` [PATCH 137/222] ARM: dt: microsom: don't set bit 7 for ethernet mux settings Russell King
2014-04-25 11:43 ` [PATCH 138/222] ARM: imx6q: clk: Parent DI clocks to video PLL via di_pre_sel Russell King
2014-04-25 11:43 ` [PATCH 139/222] ARM: i.MX6: ipu_di_sel clocks can set parent rates Russell King
2014-04-25 11:43 ` [PATCH 140/222] ata: ahci_imx: allow hardware parameters to be specified in DT Russell King
2014-04-25 11:43 ` [PATCH 141/222] ARM: cubox-i: add eSATA DT configuration Russell King
2014-04-25 11:43 ` [PATCH 142/222] ahci_imx: add disable for spread-spectrum Russell King
2014-04-25 11:43 ` [PATCH 143/222] imx-drm: imx-drm-core: fix imx_drm_encoder_get_mux_id Russell King
2014-04-25 11:43 ` [PATCH 144/222] imx-drm: imx-drm-core: skip components whose parent device is disabled Russell King
2014-04-25 11:43 ` [PATCH 145/222] imx-drm: imx-ldb: add drm_panel support Russell King
2014-04-25 11:43 ` [PATCH 146/222] imx-drm: match ipu_di_signal_cfg's clk_pol with its description Russell King
2014-04-25 11:43 ` [PATCH 147/222] v4l2: add new V4L2_PIX_FMT_RGB666 pixel format Russell King
2014-04-25 11:44 ` [PATCH 148/222] imx-drm: add RGB666 support for parallel display Russell King
2014-04-25 11:44 ` [PATCH 149/222] imx-drm: ipu-common: add ipu_map_irq to request non-IDMAC interrupts Russell King
2014-04-25 11:44 ` [PATCH 150/222] imx-drm: ipu-common: add helpers to check for a busy IDMAC channel and to busywait for an interrupt Russell King
2014-04-25 11:44 ` [PATCH 151/222] imx-drm: ipu-dmfc: wait for FIFOs to run empty before disabling Russell King
2014-04-25 11:44 ` [PATCH 152/222] imx-drm: ipu-dc: wait for DC_FC_1 / DP_SF_END interrupt Russell King
2014-04-25 11:44 ` [PATCH 153/222] imx-drm: ipu-dp: split disabling the DP foreground channel from disabling the DP module Russell King
2014-04-25 11:44 ` [PATCH 154/222] imx-drm: imx-dp: when disabling the DP foreground channel, wait until the DP background channel is finished before disabling the IDMAC channel Russell King
2014-04-25 11:44 ` [PATCH 155/222] imx-drm: ipuv3-crtc: change display enable/disable order Russell King
2014-04-25 11:44 ` [PATCH 156/222] imx-drm: ipu-dc: disable DC module when not in use Russell King
2014-04-25 11:45 ` [PATCH 157/222] imx-drm: imx-hdmi: fix hdmi hotplug detection initial state Russell King
2014-04-25 11:46 ` [PATCH 158/222] dw-hdmi-audio: add audio driver Russell King
2014-04-25 11:46 ` [PATCH 159/222] dw-hdmi-audio: better hardware position tracking Russell King
2014-04-25 11:46 ` [PATCH 160/222] dw-hdmi-audio: parse ELD from HDMI driver Russell King
2014-04-25 11:48 ` [PATCH 161/222] dw-hdmi-audio: try to fix burbling audio Russell King
2014-04-25 11:48 ` [PATCH 162/222] dw-hdmi-audio: try implementing ERR005174 " Russell King
2014-04-25 11:48 ` [PATCH 163/222] dw-hdmi-audio: another attempt at fixing burbling Russell King
2014-04-25 11:48 ` [PATCH 164/222] dw-hdmi-audio: basic suspend/resume support Russell King
2014-04-25 11:48 ` [PATCH 165/222] cec: add generic HDMI CEC driver Russell King
2014-04-25 11:48 ` [PATCH 166/222] imx-drm: dw-hdmi-cec: add " Russell King
2014-04-25 11:48 ` [PATCH 167/222] ARM: imx: add HDMI support for SolidRun HummingBoard and Cubox-i Russell King
2014-04-25 11:48 ` [PATCH 168/222] ARM: imx: enable HDMI DRM support for imx_v6_v7_defconfig Russell King
2014-04-25 11:49 ` [PATCH 169/222] drm/i915: don't disable disconnected outputs Russell King
2014-04-25 11:49 ` [PATCH 170/222] drm: add generic ddc connector Russell King
2014-04-25 11:49 ` [PATCH 171/222] ARM: l2c: trial at enabling some Cortex-A9 optimisations Russell King
2014-04-25 11:49 ` [PATCH 172/222] ARM: l2c: move L2 cache register saving to a more sensible location Russell King
2014-04-25 11:50 ` [PATCH 173/222] ARM: l2c: always enable low power modes Russell King
2014-04-25 11:50 ` [PATCH 174/222] ARM: l2c: imx: remove direct write to power control register Russell King
2014-04-25 11:50 ` [PATCH 175/222] ARM: l2c: omap2: avoid reading directly from the L2 registers in platform code Russell King
2014-04-25 11:50 ` [PATCH 176/222] ARM: l2c: provide common PL310 early resume code Russell King
2014-04-25 11:50 ` [PATCH 177/222] ARM: l2c: exynos: convert to common l2c310 early resume functionality Russell King
2014-04-25 11:50 ` [PATCH 178/222] ARM: l2c: tegra: " Russell King
2014-04-25 11:50 ` [PATCH 179/222] ARM: l2c: imx: " Russell King
2014-04-25 11:50 ` [PATCH 180/222] ARM: l2c: always enable non-secure access to lockdown registers Russell King
2014-04-25 11:55 ` [PATCH 181/222] ARM: l2c: omap2+: get rid of redundant cache replacement policy setting Russell King
2014-04-25 11:55 ` [PATCH 182/222] ARM: l2c: omap2+: get rid of init call Russell King
2014-04-25 11:55 ` [PATCH 183/222] ARM: l2c: AM43x: add L2 cache support Russell King
2014-04-25 11:55 ` [PATCH 184/222] ARM: l2c: permit flush_all() on large flush_range() XXX Needs more thought XXX Russell King
2014-04-25 11:55 ` [PATCH 185/222] mmc: sdio_irq: rework sdio irq handling Russell King
2014-04-25 11:55 ` [PATCH 186/222] mmc: sdhci: clean up interrupt handling Russell King
2014-04-25 11:55 ` [PATCH 187/222] mmc: sdhci: clean up sdio interrupt enable handling Russell King
2014-04-25 11:55 ` [PATCH 188/222] mmc: sdhci: convert to new SDIO IRQ handling Russell King
2014-04-25 11:55 ` [PATCH 189/222] mmc: sdhci: push card_tasklet into threaded irq handler Russell King
2014-04-25 11:55 ` [PATCH 190/222] mmc: sdhci: allow sdio interrupts while sdhci runtime suspended Russell King
2014-04-25 11:56 ` [PATCH 191/222] mmc: sdhci: more efficient interrupt enable register handling Russell King
2014-04-25 11:57 ` [PATCH 192/222] mmc: sdhci: plug hole in disabling card detection interrupts Russell King
2014-04-25 11:57 ` [PATCH 193/222] mmc: sdhci: convert generic bus width setup to library function Russell King
2014-04-25 11:57 ` [PATCH 194/222] mmc: sdhci: convert reset into a " Russell King
2014-04-25 11:57 ` [PATCH 195/222] mmc: sdhci: move FSL ESDHC reset handling quirk into esdhc code Russell King
2014-04-25 11:58 ` [PATCH 196/222] mmc: sdhci: avoid sync'ing the SG if there's no misalignment Russell King
2014-04-25 11:58 ` [PATCH 197/222] mmc: sdhci: convert ADMA descriptors to a coherent allocation Russell King
2014-04-25 11:58 ` [PATCH 198/222] mmc: sdhci: clean up sdhci_update_clock()/sdhci_set_clock() Russell King
2014-04-25 11:58 ` [PATCH 199/222] mmc: sdhci: move setting host->clock into sdhci_do_set_ios() Russell King
2014-04-25 11:58 ` [PATCH 200/222] mmc: sdhci: move setting mmc->actual_clock into set_clock handlers Russell King
2014-04-25 11:58 ` [PATCH 201/222] mmc: sdhci: convert sdhci_set_clock() into a library function Russell King
2014-04-25 11:59 ` [PATCH 202/222] mmc: sdhci-esdhc-imx: avoid DMA to kernel stack Russell King
2014-04-25 11:59 ` [PATCH 203/222] mmc: sdhci-esdhc-imx: comment runtime_pm_get_sync() in esdhc_prepare_tuning() Russell King
2014-04-25 11:59 ` [PATCH 204/222] mmc: sdhci-esdhc-imx: fix lockdep splat upon tuning Russell King
2014-04-25 11:59 ` [PATCH 205/222] mmc: sdhci: hack up driver to make it more compliant with UHS-1 Russell King
2014-04-25 11:59 ` [PATCH 206/222] mmc: sdhci: set_uhs_signaling() need not return a value Russell King
2014-04-25 11:59 ` [PATCH 207/222] mmc: sdhci: convert sdhci_set_uhs_signaling() into a library function Russell King
2014-04-25 11:59 ` [PATCH 208/222] mmc: sdhci: cache timing information locally Russell King
2014-04-25 11:59 ` [PATCH 209/222] mmc: sdhci: clean up sdhci_execute_tuning() decision Russell King
2014-04-25 11:59 ` [PATCH 210/222] mmc: sdhci-esdhc-imx: remove emulation of uhs_mode Russell King
2014-04-25 11:59 ` [PATCH 211/222] mmc: sdhci-of-esdhc: remove platform_suspend/platform_resume callbacks Russell King
2014-04-25 11:59 ` [PATCH 212/222] mmc: sdhci: " Russell King
2014-04-25 11:59 ` [PATCH 213/222] mmc: sdhci-tegra: get rid of special PRESENT_STATE register handling Russell King
2014-04-25 12:00 ` [PATCH 214/222] mmc: sdhci: move regulator handling into sdhci_set_power() Russell King
2014-04-25 12:00 ` [PATCH 215/222] mmc: sdhci: move remaining power " Russell King
2014-04-25 12:00 ` [PATCH 216/222] mmc: sdhci: track whether preset mode is currently enabled in hardware Russell King
2014-04-25 12:00 ` [PATCH 217/222] mmc: sdhci: fix SDHCI dependencies Russell King
2014-04-25 12:00 ` [PATCH 218/222] mmc: add support for power-on sequencing through DT Russell King
2014-04-25 12:00 ` [PATCH 219/222] mmc: dw_mmc: call mmc_of_parse to fill in common options Russell King
2014-04-25 12:00 ` [PATCH 220/222] mmc: fix power-on sequencing for esdhc-imx driver Russell King
2014-04-25 12:00 ` [PATCH 221/222] ARM: cubox-i: add support for SD UHS-1 cards Russell King
2014-04-25 12:00 ` [PATCH 222/222] ARM: cubox-i: add support for Wifi/BT Russell King
2014-04-25 13:50 ` [PATCH 000/222] The *Full* Cubox-i series Thierry Reding
2014-04-25 14:15   ` Russell King - ARM Linux
2014-04-25 14:22     ` Thierry Reding
2014-04-25 14:26       ` Russell King - ARM Linux
2014-04-25 19:50     ` Kevin Hilman

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).