From 42e54c508f2c57cbd85a5a76bf17a621de7c1642 Mon Sep 17 00:00:00 2001 From: Amaury Pouly Date: Mon, 12 Dec 2016 11:31:31 +0100 Subject: imx233: workaround hardware dma bug This bug mostly affects the ZEN and ZEN X-Fi and hangs the lcdif dma randomly on boot. Change-Id: I4255db90d87737b7a70d1d53e3ef84e4e14c8c13 --- firmware/target/arm/imx233/dma-imx233.c | 34 +++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/firmware/target/arm/imx233/dma-imx233.c b/firmware/target/arm/imx233/dma-imx233.c index 390add481b..fa8ee074bb 100644 --- a/firmware/target/arm/imx233/dma-imx233.c +++ b/firmware/target/arm/imx233/dma-imx233.c @@ -32,8 +32,42 @@ // statistics about unaligned transfers static int apb_nr_unaligned[32]; +static void safe_reset_channel(int chan) +{ + bool apbx_running = !BF_RD(APBX_CTRL0, SFTRST) && !BF_RD(APBX_CTRL0, CLKGATE); + bool apbh_running = !BF_RD(APBH_CTRL0, SFTRST) && !BF_RD(APBH_CTRL0, CLKGATE); + if(APB_IS_APBX_CHANNEL(chan)) + { + if(!apbx_running) + return; /* don't reset if block is not running */ + } + else + { + if(!apbh_running) + return; /* don't reset if block is not running */ + if(BF_RD(APBH_CTRL0, CLKGATE_CHANNEL) & (1 << chan)) + return; /* don't reset a gated channel */ + } + imx233_dma_reset_channel(chan); +} + void imx233_dma_init(void) { + /* BUG The stmp3700 (and probably stmp3780) have a hardware bug related to + * resetting the block when channel is running. It appears that at least + * for the LCDIF channel, resetting the block while the channel is running + * will make the channel hang. Once the channel hang, it cannot be recovered + * except by a chip reset. On most devices this situation will never arise + * but on the Creative ZEN (X-Fi), the OF bootloader leaves the channel + * running (to display the logo) when booting. It is unclear if this bug only + * affects the APBH or also the APBX. I believe it is related to the errata about + * channels not clearing the fifo on abrupt termination which affects both + * dma engines. Also note that we can't safely reset 'all' the channels by + * setting the reset mask to 0xffff since non-implemented channels don't clear + * their reset bit... Also reset won't work on gated channels and won't work if + * block is in reset or gated, in which case this situation is assumed not + * to exists */ + safe_reset_channel(APB_LCDIF); /* Enable APHB and APBX */ imx233_reset_block(&HW_APBH_CTRL0); imx233_reset_block(&HW_APBX_CTRL0); -- cgit v1.2.3