Hi all, I was writing a simple driver to test IRQ handling on the AMCC Yosemite board. The board has an 8x2 header with several GPIO pins, a number of which can be configured as IRQ inputs.
I plan to setup GPIO46 as output, and GPIO47 as input, and select IRQ8 on that pin. The GPIO46 and GPIO47 are configured via the GPIO1 registers at 0xEF600C00. U-Boot can be used to read the register values: => md ef600c00 b ef600c00: 00000000 c2000000 50080000 00000000 ........P....... ef600c10: 00000000 00000000 00000000 3ffcfffd ............?... ef600c20: 00000000 00000000 00000000 ............ => md ef600c30 6 ef600c30: 00000400 00000000 00010000 00000000 ................ ef600c40: 00000000 00000000 ........ => So ef600c00 GPIO1_OR = 00000000 ef600c04 GPIO1_TCR = c2000000 ef600c30 GPIO1_ISR1L = 00000400 However, if I read those same registers back under Linux, using the driver code pasted at the end of this message I get: # insmod yosemite_gpio.ko - remap the GPIO registers - remapped to address 0xD1008C00 - Read some GPIO1 registers using readl() - GPIO1_OR = 0x00000000 - GPIO1_TCR = 0x000000C2 - GPIO1_ISR1L = 0x00040000 - Read some GPIO1 registers using ioread32() - GPIO1_OR = 0x00000000 - GPIO1_TCR = 0x000000C2 - GPIO1_ISR1L = 0x00040000 - Read some GPIO1 registers using an integer pointer - GPIO1_OR = 0x00000000 - GPIO1_TCR = 0xC2000000 - GPIO1_ISR1L = 0x00000400 readl() and ioread32() read the registers in little-endian format! Looking at asm-ppc/io.h - ioread32() is just a readl() - line 180 (2.6.13) has readl() as in_le32() (the code is the same in the 2.6.15-denx kernel too) So, this explains why the data is read in little-endian format, but not why this was done. If the processor was reading from the PCI bus, then sure, I could understand why this might be used, but even then, that should be up to the user, eg. by using cpu_to_le32 etc. Should I just be using pointers for remapped processor registers, and only use readl(), ioread32(), etc, on external memory? I know this is just a big-endian/little-endian issue, I'm really just asking for the driver writing 'best practices' in this regard. Looking forward to enlightenment :) Cheers Dave --------------------------driver code---------------------------- /* yosemite_gpio.c */ #include <linux/module.h> /* kernel modules */ #include <asm/io.h> /* ioremap64(), iounmap(), readl() */ static unsigned long long base = 0x0EF600C00; // 36-bit address static unsigned int size = 0x44; static char *kernel; static int __init simple_init(void) { int *p; /* Get the GPIO control registers */ printk(" - remap the GPIO registers\n"); kernel = ioremap64(base, size); printk(" - remapped to address 0x%.8X\n", (int)kernel); printk(" - Read some GPIO1 registers using readl()\n"); printk(" - GPIO1_OR = 0x%.8X\n", readl(kernel)); printk(" - GPIO1_TCR = 0x%.8X\n", readl(kernel+0x04)); printk(" - GPIO1_ISR1L = 0x%.8X\n", readl(kernel+0x30)); printk(" - Read some GPIO1 registers using ioread32()\n"); printk(" - GPIO1_OR = 0x%.8X\n", ioread32(kernel)); printk(" - GPIO1_TCR = 0x%.8X\n", ioread32(kernel+0x04)); printk(" - GPIO1_ISR1L = 0x%.8X\n", ioread32(kernel+0x30)); p = (int *)kernel; printk(" - Read some GPIO1 registers using an integer pointer\n"); printk(" - GPIO1_OR = 0x%.8X\n", p[0]); printk(" - GPIO1_TCR = 0x%.8X\n", p[1]); printk(" - GPIO1_ISR1L = 0x%.8X\n", p[12]); /* Don't load */ iounmap(kernel); return -EINVAL; } module_init(simple_init); MODULE_LICENSE("GPL");