AnsweredAssumed Answered

IMX53: Floating GPIO Pins due to MUX_PAD_CTRL(NO_PAD_CTRL) bug.

Question asked by TomE on Jan 24, 2016
Latest reply on Jan 27, 2016 by TomE

Has this problem been found and fixed already? It is so serious it might be causing all sorts of problems to a lot of products.


Scroll down to "RESULT" if you want to see what this does.


This applies to the 2.6.35 Linux that is the last one Freescale released for the i.MX53.


(Edit) This also affects Android distributions "imx_2.6.38_11.09.01", but was fixed in "11.11.01" and "12.01.01"


This most likely doesn't affect i.MX6, but I don't have a build to test this with.


I was verifying the levels and timing of the PWRDWN and RESET GPIO pins we have driving an ADV7180 on an i.MX53-based product.


The board stopped working when I put an oscilloscope probe on those signals!


The reason turned out to be that the PWRDN pin was floating, and the 10M probe pulled it to ground. The CPU's default configuration is to have a 100k pullup on the pin, but that had been turned off by something!


The "something" turned out to be a serious, widespread bug in the arch/arm/plat-mxc/include/mach/iomux-mx53.h file, and in other ones. One way to describe the bug is to say that there are 986 buggy lines in that file, like this one:


#define MX53_PAD_SD2_CLK__GPIO1_10      (_MX53_PAD_SD2_CLK__GPIO1_10 | MUX_PAD_CTRL(NO_PAD_CTRL))


The other way to put it is that the definition of "NO_PAD_CTRL" is wrong.


"NO_PAD_CTRL" means to leave the control bits for the port (that control hysteresis, drive strength and the pullup or pulldown value) alone at their Reset Default condition.


The problem is pretty obvious looking at the definitions of the above macros in this file:



#define MUX_PAD_CTRL_MASK  ((iomux_v3_cfg_t)0x1ffff << MUX_PAD_CTRL_SHIFT)
#define NO_PAD_CTRL        ((iomux_v3_cfg_t)1 << (MUX_PAD_CTRL_SHIFT + 16))
#define MUX_PAD_CTRL(x)    ((iomux_v3_cfg_t)(x) << MUX_PAD_CTRL_SHIFT)


Allowing the compiler to expand some definitions in the board file for me:


arch/arm/mach-mx5/mx53_evk.c or mx53_loco.c:

#include <mach/iomux-mx53.h>


static iomux_v3_cfg_t tx53_pads[] = {




#include <mach/iomux-v3.h>




The above results (using "gcc -E" and using exactly the same command as the normal build uses):


static iomux_v3_cfg_t tx53_fec_gpio_pads[] __attribute__ ((__section__(""))
) = {
((((iomux_v3_cfg_t)(0x30) << 0) | ((iomux_v3_cfg_t)(1) << 36) |
((iomux_v3_cfg_t)(0x358) << 12) | ((iomux_v3_cfg_t)(0) << 41) |
((iomux_v3_cfg_t)(0x0) << 24) | ((iomux_v3_cfg_t)(0) << 58)) |
((iomux_v3_cfg_t)(((iomux_v3_cfg_t)1 << (41 + 16))) << 41)),
((((iomux_v3_cfg_t)(0x328) << 0) | ((iomux_v3_cfg_t)(1) << 36) |
((iomux_v3_cfg_t)(0x6B8) << 12) | ((iomux_v3_cfg_t)(0) << 41) |
((iomux_v3_cfg_t)(0x0) << 24) | ((iomux_v3_cfg_t)(0) << 58)) |
((iomux_v3_cfg_t)(((iomux_v3_cfg_t)1 << (41 + 16))) << 41)),};


The red bit results in 1 being left-shifted 98 bit positions and then being stored in a 64-bit word.


EITHER "NO_PAD_CTRL" shouldn't be shifted, or it shouldn't be inside MUX_PAD_CTRL(). One or the other.


There's another bug that prevents this from working. The following code is meant to check to see if "NO_PAD_CTRL" is set, and if it is, to NOT write to the control register:


int mxc_iomux_v3_setup_multiple_pads(...)
        u32 pad_ctrl_ofs = (pad & MUX_PAD_CTRL_OFS_MASK) >> MUX_PAD_CTRL_OFS_SHIFT;
        u32 pad_ctrl = (pad & MUX_PAD_CTRL_MASK) >> MUX_PAD_CTRL_SHIFT;


        if (!(pad_ctrl & NO_PAD_CTRL) && pad_ctrl_ofs)
            __raw_writel(pad_ctrl, base + pad_ctrl_ofs);


The test in the second last line comes down to:


((pad & (0x1ffff << 41)) >> 41) & (1 << (41 + 16))


It is comparing the right-shifted pad value with the left-shifted mask. That's never true either.




The result of all of the above is that all pads "mentioned" anywhere in the Board file will be corrupted by having the IOMUXC_SW_PAD_CTL_PAD register written to ZERO. This means:


  • The Hysteresis is turned off,
  • The Pullup or Pulldown is disabled,
  • The Drive Strength will be changed from the default "High" to "Low",
  • The Slew Rate (if the pin has that configured) will be set to "Low".


The board file listing GPIOs that will be affected may be one of:






So if you have any problems with floating pins that you thought were safely pulled high or low, or the drive strength of an GPIO pin is a lot lower than you expect (and your hardware requires), then this might be the cause. If you have any EM or ESD susceptibility problems then it may be due to this.


Has this been fixed anywhere?


(Edit) The bug was released as a patch into a Pengutronix tree where it was fixed 7 months later. The buggy patch was included in Freescale's tree, but the fix never was.


It would be worth checking the i.MX6 files to see if they have the same problem (unlikely, i.MX6 changes fixed this bug as a side effect).




You can see if this affects you from the Console by reading the IOMUXC_SW_PAD_CTL_PAD registers for the GPIOs you're using:


# devmem 0x53fa8688   # IOMUXC_SW_PAD_CTL_PAD_SD2_CLK  
# devmem 0x53fa868c   # IOMUXC_SW_PAD_CTL_PAD_SD2_CMD  
# devmem 0x53fa8690   # IOMUXC_SW_PAD_CTL_PAD_SD2_DATA3 : GPIO1_12 VID_IN_PWRDWN
# devmem 0x53fa8694   # IOMUXC_SW_PAD_CTL_PAD_SD2_DATA2
# devmem 0x53fa8698   # IOMUXC_SW_PAD_CTL_PAD_SD2_DATA1
# devmem 0x53fa869c   # IOMUXC_SW_PAD_CTL_PAD_SD2_DATA0 : GPIO1_15 uP_WD_SET1


The Green ones are unaffected as they aren't listed in my board file.




Message was edited by: Tom Evans. Problem may affect i.MX25 and i.MX50 as well. From the code it also looks to affect 'iomux-mx35.h", but there's no "Category" for that chip.