From 92ece1cdd27eee32c53630dc6af6d031b55be199 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 9 Nov 2012 16:29:17 +0100 Subject: [PATCH 1/8] arm: mvebu: fix compatible string in armada-370-xp.dtsi All the Device Tree files for Armada 370 and XP SoCs and boards use the "armada-370-xp" common compatible string, except armada-370-xp.dtsi which was specifying "armada_370_xp". Fix this inconsistency by making armada-370-xp.dtsi declare a compatible string of "armada-370-xp" like everyone else. Signed-off-by: Thomas Petazzoni Acked-by: Gregory CLEMENT Tested-by: Gregory CLEMENT --- arch/arm/boot/dts/armada-370-xp.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/armada-370-xp.dtsi b/arch/arm/boot/dts/armada-370-xp.dtsi index 16cc82cdaa81..b113e0b87783 100644 --- a/arch/arm/boot/dts/armada-370-xp.dtsi +++ b/arch/arm/boot/dts/armada-370-xp.dtsi @@ -20,7 +20,7 @@ / { model = "Marvell Armada 370 and XP SoC"; - compatible = "marvell,armada_370_xp"; + compatible = "marvell,armada-370-xp"; cpus { cpu@0 { From 61505e117bb5d626ed7db2e9daa791e184d81bd3 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 9 Nov 2012 16:26:26 +0100 Subject: [PATCH 2/8] arm: mvebu: don't list all boards in dt compat field for Armada 370/XP Instead of listing explicitly all boards in the .dt_compat field of the DT_MACHINE_START structure for Armada 370/XP, use instead a compatible string that is common to all boards using the Armada 370/XP. This allows to add new boards by just using a different Device Tree, without having to modify the source code of the kernel. Note that the name of the array containing the compatible string is also renamed, to reflect the fact that it no longer contains the list of all boards. Signed-off-by: Thomas Petazzoni Acked-by: Gregory CLEMENT Tested-by: Gregory CLEMENT --- arch/arm/mach-mvebu/armada-370-xp.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-mvebu/armada-370-xp.c b/arch/arm/mach-mvebu/armada-370-xp.c index 49d791548ad6..29c27cd71018 100644 --- a/arch/arm/mach-mvebu/armada-370-xp.c +++ b/arch/arm/mach-mvebu/armada-370-xp.c @@ -46,9 +46,8 @@ static void __init armada_370_xp_dt_init(void) of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } -static const char * const armada_370_xp_dt_board_dt_compat[] = { - "marvell,a370-db", - "marvell,axp-db", +static const char * const armada_370_xp_dt_compat[] = { + "marvell,armada-370-xp", NULL, }; @@ -59,5 +58,5 @@ DT_MACHINE_START(ARMADA_XP_DT, "Marvell Aramada 370/XP (Device Tree)") .handle_irq = armada_370_xp_handle_irq, .timer = &armada_370_xp_timer, .restart = mvebu_restart, - .dt_compat = armada_370_xp_dt_board_dt_compat, + .dt_compat = armada_370_xp_dt_compat, MACHINE_END From 8c4340fcfb3e40372101a608ccd906e456ed3fcd Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Mon, 12 Nov 2012 12:03:38 +0100 Subject: [PATCH 3/8] arm: mvebu: fix typo in machine name for Armada 370/XP Signed-off-by: Thomas Petazzoni Acked-by: Gregory CLEMENT Tested-by: Gregory CLEMENT --- arch/arm/mach-mvebu/armada-370-xp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-mvebu/armada-370-xp.c b/arch/arm/mach-mvebu/armada-370-xp.c index 29c27cd71018..a2f5bbc0d2e5 100644 --- a/arch/arm/mach-mvebu/armada-370-xp.c +++ b/arch/arm/mach-mvebu/armada-370-xp.c @@ -51,7 +51,7 @@ static const char * const armada_370_xp_dt_compat[] = { NULL, }; -DT_MACHINE_START(ARMADA_XP_DT, "Marvell Aramada 370/XP (Device Tree)") +DT_MACHINE_START(ARMADA_XP_DT, "Marvell Armada 370/XP (Device Tree)") .init_machine = armada_370_xp_dt_init, .map_io = armada_370_xp_map_io, .init_irq = armada_370_xp_init_irq, From 9f3410ff217f55c2a30bd1b2eb1032806d17c80e Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 22 Nov 2012 18:09:53 +0100 Subject: [PATCH 4/8] arm: mvebu: fix address decoding armada_cfg_base() function The armada_cfg_base() function returns the base address of the registers that allow to configure the decoding for a particular address window. On Armada 370/XP, the lower windows have more configuration registers (4 registers) than the higher windows (2 registers). This armada_cfg_base() takes this into account by doing a different offset calculation depending on the window number, but this offset calculation was wrong for the higher windows. Even though we were not using high window numbers until now (only window 0 is used to map the BootROM, needed for SMP), we use this function at boot time to disable all windows to ensure that nothing remains intialized from what the bootloader has done. Unfortunately, the U-Boot on the OpenBlocks AX3-4 uses a window with a high number (above 8) to remap the BootROM. And then when the kernel boots, it remaps the BootROM in window 0. Normally, this is not a problem, because all windows have previously been disabled. Except that due to our wrong offset calculation, the windows with high numbers were not properly disabled, leading to the BootROM being mapped twice. The visible result of this bug was that the kernel was unable to get the second CPU started on the OpenBlocks AX3-4 platform. With this fix, all windows are properly cleared at boot time, the BootROM is remapped only once in window 0, and the second CPU boots fine. Thanks a lot to Lior Amsamlen for his help in debugging this problem. Signed-off-by: Thomas Petazzoni --- Strictly speaking, this bug was introduced in 3.7, but since the only platforms supported in 3.7 were Armada 370 and Armada XP, and there was anyway no SMP support at this time, it isn't really worth the effort to push this patch in 3.7. --- arch/arm/mach-mvebu/addr-map.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-mvebu/addr-map.c b/arch/arm/mach-mvebu/addr-map.c index fe454a4430be..b20fc751b1e5 100644 --- a/arch/arm/mach-mvebu/addr-map.c +++ b/arch/arm/mach-mvebu/addr-map.c @@ -78,7 +78,7 @@ armada_cfg_base(const struct orion_addr_map_cfg *cfg, int win) if (win < 8) offset = (win << 4); else - offset = ARMADA_WINDOW_8_PLUS_OFFSET + (win << 3); + offset = ARMADA_WINDOW_8_PLUS_OFFSET + ((win - 8) << 3); return cfg->bridge_virt_base + offset; } From c4b4b732b2e99e6e302d90d57f2a4f5c9516d9a3 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 22 Nov 2012 18:16:37 +0100 Subject: [PATCH 5/8] dma: mv_xor: clear the window override control registers The XOR channels on Marvell SoCs have a Window Override Control register that allow to do some fancy things with addresses. Those features are not used by the driver, but some U-Boot versions anyway modify those registers. For some reason, the U-Boot on OpenBlocks AX3-4 was setting an invalid value in those registers when the addition 2 GB DRAM chip was plugged into the board, causing the XOR driver to fail in using the XOR engines. By setting those registers to 0 during the driver initialization, we ensure that the registers are configured according with the driver operation model. Thanks to Lior Amsalem for his help in debugging this problem. Signed-off-by: Thomas Petazzoni --- drivers/dma/mv_xor.c | 2 ++ drivers/dma/mv_xor.h | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index f450fe8cbd61..2c69b89eac4f 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -1240,6 +1240,8 @@ mv_xor_conf_mbus_windows(struct mv_xor_device *xordev, writel(win_enable, base + WINDOW_BAR_ENABLE(0)); writel(win_enable, base + WINDOW_BAR_ENABLE(1)); + writel(0, base + WINDOW_OVERRIDE_CTRL(0)); + writel(0, base + WINDOW_OVERRIDE_CTRL(1)); } static int __devinit mv_xor_probe(struct platform_device *pdev) diff --git a/drivers/dma/mv_xor.h b/drivers/dma/mv_xor.h index 17043287b71a..c632a4761fcf 100644 --- a/drivers/dma/mv_xor.h +++ b/drivers/dma/mv_xor.h @@ -53,6 +53,7 @@ #define WINDOW_SIZE(w) (0x270 + ((w) << 2)) #define WINDOW_REMAP_HIGH(w) (0x290 + ((w) << 2)) #define WINDOW_BAR_ENABLE(chan) (0x240 + ((chan) << 2)) +#define WINDOW_OVERRIDE_CTRL(chan) (0x2A0 + ((chan) << 2)) struct mv_xor_device { void __iomem *xor_base; From 2d0a074517da34a6386bdd9a22bc006c8fa21044 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 22 Nov 2012 18:19:09 +0100 Subject: [PATCH 6/8] dma: mv_xor: use request_irq() instead of devm_request_irq() Even through the usage of devm_*() functions is generally recommended over their classic variants, in the case of devm_request_irq() combined with irq_of_parse_and_map(), it doesn't work nicely. We have the following scenario: irq_of_parse_and_map(...) devm_request_irq(...) For some reason, the driver initialization fails at a later point. Since irq_of_parse_and_map() is no device-managed, we do a: irq_dispose_mapping(...) Unfortunately, this doesn't work, because the free_irq() must be done prior to calling irq_dispose_mapping(). But with the devm mechanism, the automatic free_irq() would happen only after we get out of the ->probe() function. So basically, we revert to using request_irq() with traditional error handling, so that in case of error, free_irq() gets called before irq_dispose_mapping(). Signed-off-by: Thomas Petazzoni --- drivers/dma/mv_xor.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index 2c69b89eac4f..0d4c24e529f7 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -1162,9 +1162,8 @@ mv_xor_channel_add(struct mv_xor_device *xordev, /* clear errors before enabling interrupts */ mv_xor_device_clear_err_status(mv_chan); - ret = devm_request_irq(&pdev->dev, mv_chan->irq, - mv_xor_interrupt_handler, - 0, dev_name(&pdev->dev), mv_chan); + ret = request_irq(mv_chan->irq, mv_xor_interrupt_handler, + 0, dev_name(&pdev->dev), mv_chan); if (ret) goto err_free_dma; @@ -1185,14 +1184,14 @@ mv_xor_channel_add(struct mv_xor_device *xordev, ret = mv_xor_memcpy_self_test(mv_chan); dev_dbg(&pdev->dev, "memcpy self test returned %d\n", ret); if (ret) - goto err_free_dma; + goto err_free_irq; } if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) { ret = mv_xor_xor_self_test(mv_chan); dev_dbg(&pdev->dev, "xor self test returned %d\n", ret); if (ret) - goto err_free_dma; + goto err_free_irq; } dev_info(&pdev->dev, "Marvell XOR: " @@ -1205,6 +1204,8 @@ mv_xor_channel_add(struct mv_xor_device *xordev, dma_async_device_register(dma_dev); return mv_chan; +err_free_irq: + free_irq(mv_chan->irq, mv_chan); err_free_dma: dma_free_coherent(&pdev->dev, MV_XOR_POOL_SIZE, mv_chan->dma_desc_pool_virt, mv_chan->dma_desc_pool); From f8eb9e7d2a198fe3a0f76d9e5b374160c26e4621 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 22 Nov 2012 18:22:12 +0100 Subject: [PATCH 7/8] dma: mv_xor: fix error checking of irq_of_parse_and_map() The irq_of_parse_and_map() function returns 0 on failure, and does not return an error code, so we fix the calling site of irq_of_parse_and_map() in the mv_xor driver. Signed-off-by: Thomas Petazzoni --- drivers/dma/mv_xor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index 0d4c24e529f7..f2edd6a5536e 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -1312,8 +1312,8 @@ static int __devinit mv_xor_probe(struct platform_device *pdev) dma_cap_set(DMA_INTERRUPT, cap_mask); irq = irq_of_parse_and_map(np, 0); - if (irq < 0) { - ret = irq; + if (!irq) { + ret = -ENODEV; goto err_channel_add; } From 73d9cdca1ced6ab32be363b58699039bd82b062a Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 22 Nov 2012 18:22:59 +0100 Subject: [PATCH 8/8] dma: mv_xor: fix error handling path The ->probe() function of the mv_xor function contains in its error handling code a loop to cleanup the XOR channels that had been successfully initialized if some other XOR channel fails to be initialized. It does that by traveling the list of XOR channels, and cleanup those for which the pointer is not NULL. However, since the mv_xor_channel_add() function return a PTR_ERR style value, the pointer is not NULL on error. So, when handling the error of a given channel initialization, we cleanup this channel initialization and mark this channel entry as NULL in the array. This allows the remaining of the cleanup (for other channels) to work properly. Signed-off-by: Thomas Petazzoni --- drivers/dma/mv_xor.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index f2edd6a5536e..9659e58fc8b2 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -1322,6 +1322,7 @@ static int __devinit mv_xor_probe(struct platform_device *pdev) cap_mask, irq); if (IS_ERR(xordev->channels[i])) { ret = PTR_ERR(xordev->channels[i]); + xordev->channels[i] = NULL; irq_dispose_mapping(irq); goto err_channel_add; }