* Endian problem when accessing internel regs on 8347 @ 2008-01-17 6:26 Bruce_Leonard 2008-01-17 15:01 ` Ben Warren 2008-01-17 17:39 ` Scott Wood 0 siblings, 2 replies; 11+ messages in thread From: Bruce_Leonard @ 2008-01-17 6:26 UTC (permalink / raw) To: linuxppc-embedded Hi, I've got an MPC8347 running the 2.6.24-rc5 kernel and I'm trying to access the GPIO registers. I already have a driver that's doing related work (tho across PCI) and I just want to remap the internal CPU address to a kernal address and be able to read/write the register using an IOCTL call from user space. My problem is, every accessor I try does an endian conversion before giving me my data. So here's some code snipits of what I'm doing: request_mem_region(0xe0000c00, 24, "my driver"); // 0xe0000c00 is the memory mapped location of the GPIO regs data_ptr2 = ioremap(0xe0000c00, 24); Then in the IOCTL function I try to read from the register. First I tried: ioread32(data_ptr2); I know that the mapping is working okay because I got the data from the GPIO direction register, but it's been byte swapped. The contents of the register are 0xFFFFFFE7, but what my user space app gets back is 0xE7FFFFFF. I've tried all the varients I can find, readl(), inl(), in_be32(), in_le32(), even __raw_readl(). They all give me back byte swapped data. I'm very confused. Especially since I've looked at in_be32() and in_le32(), they're both inline assembly, and they use different instructions. They can't be giving me the same results. I'm sure I'm not the first person to want to access PowerPC internal registers through a driver. Can anyone give me a hint what I'm doing wrong? As an additional question related to PowerPC inline assembly, can anyone tell me what "%U1%X1" means in the following: __asm__ __volatile__("lwz%U1%X1 %0,%1; twi 0,%0,0; isync" : "=r" (ret) : "m" (*addr)); Thanks. See 'ya! Bruce ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Endian problem when accessing internel regs on 8347 2008-01-17 6:26 Endian problem when accessing internel regs on 8347 Bruce_Leonard @ 2008-01-17 15:01 ` Ben Warren 2008-01-17 18:01 ` Bruce_Leonard 2008-01-17 17:39 ` Scott Wood 1 sibling, 1 reply; 11+ messages in thread From: Ben Warren @ 2008-01-17 15:01 UTC (permalink / raw) To: Bruce_Leonard; +Cc: linuxppc-embedded [-- Attachment #1: Type: text/plain, Size: 2065 bytes --] Hi Bruce, Bruce_Leonard@selinc.com wrote: > Hi, > > I've got an MPC8347 running the 2.6.24-rc5 kernel and I'm trying to access > the GPIO registers. I already have a driver that's doing related work > (tho across PCI) and I just want to remap the internal CPU address to a > kernal address and be able to read/write the register using an IOCTL call > from user space. My problem is, every accessor I try does an endian > conversion before giving me my data. So here's some code snipits of what > I'm doing: > > request_mem_region(0xe0000c00, 24, "my driver"); // 0xe0000c00 is the > memory mapped location of the GPIO regs > data_ptr2 = ioremap(0xe0000c00, 24); > > Then in the IOCTL function I try to read from the register. First I > tried: > > ioread32(data_ptr2); > > I know that the mapping is working okay because I got the data from the > GPIO direction register, but it's been byte swapped. The contents of the > register are 0xFFFFFFE7, but what my user space app gets back is > 0xE7FFFFFF. I've tried all the varients I can find, readl(), inl(), > in_be32(), in_le32(), even __raw_readl(). They all give me back byte > swapped data. I'm very confused. Especially since I've looked at > in_be32() and in_le32(), they're both inline assembly, and they use > different instructions. They can't be giving me the same results. I'm > sure I'm not the first person to want to access PowerPC internal registers > through a driver. Can anyone give me a hint what I'm doing wrong? > > As an additional question related to PowerPC inline assembly, can anyone > tell me what "%U1%X1" means in the following: > > __asm__ __volatile__("lwz%U1%X1 %0,%1; twi 0,%0,0; isync" : "=r" (ret) : > "m" (*addr)); > > Thanks. > > See 'ya! > > Bruce > _______________________________________________ > I've attached a poorly-written-yet-functional GPIO driver that I wrote a while ago for the MPC8349 (same as what you have for all intents and purposes). It uses in_be32() and out_be32(). Let me know if you have any questions. regards, Ben [-- Attachment #2: mpc83xx_gpio.c --] [-- Type: text/x-csrc, Size: 6289 bytes --] /****************************************************************************** * * gpio_driver.c * Copyright Qstreams Networks 2006 * * This file contains a simple Linux device driver for accessing GPIO ports * It is originally targeted for the MPC8349 PowerQUICC II Pro processor, * although with simple modifications it should work with lots of CPUs. Note * that all CPU accesses are big-endian. * * History: * 04/11/2006 BAW Initial Creation * *****************************************************************************/ #include <linux/init.h> #include <linux/module.h> #include <linux/ioport.h> #include <linux/fs.h> #include <linux/cdev.h> #include <asm/io.h> #include <asm/uaccess.h> #include "gpio.h" struct gpio_dev { struct gpio_reg *regs; struct cdev cdev; }; MODULE_AUTHOR("Ben Warren"); MODULE_LICENSE("GPL"); static int gpio_major_num; static struct gpio_dev *gpio_devices; static spinlock_t gpioLock[GPIO_NUM_BANKS]; extern phys_addr_t get_immrbase(void); static u32 readGpioReg(u8 bank, u32 * addr) { u32 value; spin_lock(&gpioLock[bank]); value = in_be32(addr); spin_unlock(&gpioLock[bank]); return value; } static void writeGpioReg(u8 bank, u32 * addr, u32 val, u32 mask) { spin_lock(&gpioLock[bank]); out_be32(addr, (in_be32(addr) & ~mask) | val); spin_unlock(&gpioLock[bank]); } /***** * Kernel-mode GPIO access functions. * DO NOT CALL FROM USERSPACE *****/ int kgpio_set_dir(u8 bank, u8 bit, u8 isOutput) { u32 value = GPIO_BIT(bit); if ((bank >= GPIO_NUM_BANKS) || !gpio_devices) { return -ENODEV; } writeGpioReg(bank, &gpio_devices[bank].regs->gpxdir, isOutput ? value : 0, value); return 0; } EXPORT_SYMBOL(kgpio_set_dir); int kgpio_get_dir(u8 bank, u8 bit) { u32 value; if ((bank >= GPIO_NUM_BANKS) || !gpio_devices) { return -ENODEV; } value = readGpioReg(bank, &gpio_devices[bank].regs->gpxdir); return (value & GPIO_BIT(bit) ? 1 : 0); } EXPORT_SYMBOL(kgpio_get_dir); int kgpio_set_data(u8 bank, u8 bit, u8 isHigh) { u32 value = GPIO_BIT(bit); if ((bank >= GPIO_NUM_BANKS) || !gpio_devices) { return -ENODEV; } writeGpioReg(bank, &gpio_devices[bank].regs->gpxdat, isHigh ? value : 0, value); return 0; } EXPORT_SYMBOL(kgpio_set_data); int kgpio_get_data(u8 bank, u8 bit) { u32 value; if ((bank >= GPIO_NUM_BANKS) || !gpio_devices) { return -ENODEV; } value = readGpioReg(bank, &gpio_devices[bank].regs->gpxdat); return (value & GPIO_BIT(bit) ? 1 : 0); } EXPORT_SYMBOL(kgpio_get_data); int gpio_open(struct inode *inode, struct file *filp) { struct gpio_dev *dev; /* Set things up so other methods can access private data */ dev = container_of(inode->i_cdev, struct gpio_dev, cdev); filp->private_data = dev; return 0; } int gpio_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { int rc = 0; gpioDataAccess gpioData = { 0, 0 }; struct gpio_dev *dev; u8 bank; /* Check that the caller really wanted GPIO */ if (_IOC_TYPE(cmd) != GPIO_IOC_MAGIC) return -ENOTTY; if (_IOC_NR(cmd) > GPIO_IOC_MAXNR) return -ENOTTY; /* Check access controls */ if (_IOC_DIR(cmd) & _IOC_READ) rc = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); else if (_IOC_DIR(cmd) & _IOC_WRITE) rc = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); if (rc) return -EFAULT; bank = (u8) iminor(inode); dev = filp->private_data; switch (cmd) { /* Direction Register access */ case GPIO_IOC_GET_DIR: return readGpioReg(bank, &dev->regs->gpxdir); case GPIO_IOC_SET_DIR: if (copy_from_user(&gpioData, (const void __user *)arg, sizeof(gpioDataAccess))) { printk(KERN_ERR "copy_from_user failed\n"); return -EFAULT; } writeGpioReg(bank, &dev->regs->gpxdir, gpioData.value, gpioData.mask); break; /* Data Register access */ case GPIO_IOC_GET_DATA: return readGpioReg(bank, &dev->regs->gpxdat); case GPIO_IOC_SET_DATA: if (copy_from_user(&gpioData, (const void __user *)arg, sizeof(gpioDataAccess))) { printk(KERN_ERR "copy_from_user failed\n"); return -EFAULT; } writeGpioReg(bank, &dev->regs->gpxdat, gpioData.value, gpioData.mask); break; default: return -ENOTTY; } return rc; } /* File operations structure. Pretty limited on this device */ struct file_operations gpio_fops = { .owner = THIS_MODULE, .open = gpio_open, .ioctl = gpio_ioctl, }; static void gpio_cleanup(void) { int i; u32 addr; dev_t devno = MKDEV(gpio_major_num, 0); if (gpio_devices) { for (i = 0; i < GPIO_NUM_BANKS; i++) { cdev_del(&gpio_devices[i].cdev); } iounmap(gpio_devices); } addr = get_immrbase() + GPIO1_IO_OFFSET; release_mem_region(addr, sizeof(struct gpio_reg)); addr = get_immrbase() + GPIO2_IO_OFFSET; release_mem_region(addr, sizeof(struct gpio_reg)); unregister_chrdev_region(devno, GPIO_NUM_BANKS); } static void gpio_setup_cdev(struct gpio_dev *dev, int index) { int rc, devno = MKDEV(gpio_major_num, index); cdev_init(&dev->cdev, &gpio_fops); dev->cdev.owner = THIS_MODULE; dev->cdev.ops = &gpio_fops; if ((rc = cdev_add(&dev->cdev, devno, 1))) printk(KERN_CRIT "Error %d adding gpio%d", rc, index); } static int gpio_init(void) { int i, rc; dev_t dev = 0; u32 addr; /* Grab a dynamic major number and GPIO_NUM_BANKS minors */ rc = alloc_chrdev_region(&dev, 0, GPIO_NUM_BANKS, "gpio"); gpio_major_num = MAJOR(dev); if (rc < 0) { printk(KERN_CRIT "GPIO: couldn't get major number\n"); return rc; } if (!(gpio_devices = kmalloc(GPIO_NUM_BANKS * sizeof(struct gpio_dev), GFP_KERNEL))) { gpio_cleanup(); return -ENOMEM; } for (i = 0; i < GPIO_NUM_BANKS; i++) { spin_lock_init(&gpioLock[i]); gpio_setup_cdev(&gpio_devices[i], i); addr = get_immrbase() + (i == 0 ? GPIO1_IO_OFFSET : GPIO2_IO_OFFSET); if (!request_mem_region(addr, sizeof(struct gpio_reg), "gpio")) { printk(KERN_CRIT "gpio: I/O memory request failed\n"); return -ENODEV; } gpio_devices[i].regs = (struct gpio_reg *)ioremap_nocache(addr, sizeof (struct gpio_reg)); if (!gpio_devices[i].regs) { printk(KERN_CRIT "gpio: can't remap I/O memory\n"); return -ENODEV; } } return 0; } module_init(gpio_init); module_exit(gpio_cleanup); [-- Attachment #3: gpio.h --] [-- Type: text/x-chdr, Size: 829 bytes --] #ifndef GPIO_INCLUDE_H #define GPIO_INCLUDE_H #include <asm/ioctl.h> #define GPIO1_IO_OFFSET 0x00000c00 #define GPIO2_IO_OFFSET 0x00000d00 typedef struct _gpioDatAccess { unsigned int value; unsigned int mask; } gpioDataAccess; #define GPIO_IOC_MAGIC 0xaa #define GPIO_IOC_GET_DIR _IO(GPIO_IOC_MAGIC, 1) #define GPIO_IOC_SET_DIR _IOW(GPIO_IOC_MAGIC, 2, gpioDataAccess) #define GPIO_IOC_GET_DATA _IO(GPIO_IOC_MAGIC, 3) #define GPIO_IOC_SET_DATA _IOW(GPIO_IOC_MAGIC, 4, gpioDataAccess) #define GPIO_IOC_MAXNR 5 #define GPIO_NUM_BANKS 2 struct gpio_reg { unsigned int gpxdir; unsigned int gpxdr; unsigned int gpxdat; unsigned int gpxier; unsigned int gpximr; unsigned int gpxicr; }; /* On our CPU, bit 0 is the MS bit, so go from the left */ #define GPIO_BIT(x) (0x80000000 >> (x)) #endif /* GPIO_INCLUDE_H */ ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Endian problem when accessing internel regs on 8347 2008-01-17 15:01 ` Ben Warren @ 2008-01-17 18:01 ` Bruce_Leonard 2008-01-17 18:25 ` Ben Warren 0 siblings, 1 reply; 11+ messages in thread From: Bruce_Leonard @ 2008-01-17 18:01 UTC (permalink / raw) To: Ben Warren; +Cc: linuxppc-embedded Ben Warren <biggerbadderben@gmail.com> wrote on 01/17/2008 07:01:10 AM: > > > I've attached a poorly-written-yet-functional GPIO driver that I wrote a > while ago for the MPC8349 (same as what you have for all intents and > purposes). It uses in_be32() and out_be32(). > Ben, Thanks for the answer. Hummmm, at first glance it looks like you're doing the same thing I am. Only difference I can see is you use get_immrbase() to figure out the address to ask for and I've got it hardcoded. Other than that we're both using request_mem_region() in in/out_be32(). Yet your's works for you and mine doesn't. Well, I'll take a closer look tonight and see if there's something you're doing that I missed. Unfortunately, I've gotten a higher level interrupt this morning and it may ba a day or so before I get back to this and can give you any feedback. Thanks again. See 'ya! Bruce ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Endian problem when accessing internel regs on 8347 2008-01-17 18:01 ` Bruce_Leonard @ 2008-01-17 18:25 ` Ben Warren 0 siblings, 0 replies; 11+ messages in thread From: Ben Warren @ 2008-01-17 18:25 UTC (permalink / raw) To: Bruce_Leonard; +Cc: linuxppc-embedded Bruce_Leonard@selinc.com wrote: > Ben Warren <biggerbadderben@gmail.com> wrote on 01/17/2008 07:01:10 AM: > > >> I've attached a poorly-written-yet-functional GPIO driver that I wrote a >> > > >> while ago for the MPC8349 (same as what you have for all intents and >> purposes). It uses in_be32() and out_be32(). >> >> > Ben, > > Thanks for the answer. Hummmm, at first glance it looks like you're doing > the same thing I am. Only difference I can see is you use get_immrbase() > to figure out the address to ask for and I've got it hardcoded. Other > than that we're both using request_mem_region() in in/out_be32(). Yet > your's works for you and mine doesn't. Well, I'll take a closer look > tonight and see if there's something you're doing that I missed. > Unfortunately, I've gotten a higher level interrupt this morning and it > may ba a day or so before I get back to this and can give you any > feedback. Thanks again. > > See 'ya! > > Bruce > > Something else to consider is that I've never tried this beyond 2.6.19. Maybe things have changed since then. Anyway, glad to help if I can. cheers, Ben ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Endian problem when accessing internel regs on 8347 2008-01-17 6:26 Endian problem when accessing internel regs on 8347 Bruce_Leonard 2008-01-17 15:01 ` Ben Warren @ 2008-01-17 17:39 ` Scott Wood 2008-01-17 18:38 ` Bruce_Leonard 1 sibling, 1 reply; 11+ messages in thread From: Scott Wood @ 2008-01-17 17:39 UTC (permalink / raw) To: Bruce_Leonard; +Cc: linuxppc-embedded Bruce_Leonard@selinc.com wrote: > As an additional question related to PowerPC inline assembly, can anyone > tell me what "%U1%X1" means in the following: > > __asm__ __volatile__("lwz%U1%X1 %0,%1; twi 0,%0,0; isync" : "=r" (ret) : > "m" (*addr)); They allow the compiler to use update and/or index mode for the memory operand. -Scott ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Endian problem when accessing internel regs on 8347 2008-01-17 17:39 ` Scott Wood @ 2008-01-17 18:38 ` Bruce_Leonard 2008-01-17 22:18 ` Scott Wood 0 siblings, 1 reply; 11+ messages in thread From: Bruce_Leonard @ 2008-01-17 18:38 UTC (permalink / raw) To: Scott Wood; +Cc: linuxppc-embedded > > __asm__ __volatile__("lwz%U1%X1 %0,%1; twi 0,%0,0; isync" : "=r" (ret) : > > "m" (*addr)); > > They allow the compiler to use update and/or index mode for the memory > operand. Well that makes sense, U for update and X for index, but I'm not sure they're applicable to this particular instruction and I'm not sure that the memory operand makes sense for PowerPC. However, before I post anything that makes me look like I've got hoof-n-mouth disease I'm going to do some more digging. Is the GCC manual the only "official" documentation on this (I've found a couple of web sites but none of them gun.org) or is there another manual I should be looking for? Thanks for the pointers. Bruce ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Endian problem when accessing internel regs on 8347 2008-01-17 18:38 ` Bruce_Leonard @ 2008-01-17 22:18 ` Scott Wood 2008-01-21 7:21 ` Bruce_Leonard 0 siblings, 1 reply; 11+ messages in thread From: Scott Wood @ 2008-01-17 22:18 UTC (permalink / raw) To: Bruce_Leonard; +Cc: linuxppc-embedded Bruce_Leonard@selinc.com wrote: >>> __asm__ __volatile__("lwz%U1%X1 %0,%1; twi 0,%0,0; isync" : "=r" (ret) > : >>> "m" (*addr)); >> They allow the compiler to use update and/or index mode for the memory >> operand. > > Well that makes sense, U for update and X for index, but I'm not sure > they're applicable to this particular instruction and I'm not sure that > the memory operand makes sense for PowerPC. Why not? > However, before I post > anything that makes me look like I've got hoof-n-mouth disease I'm going > to do some more digging. Is the GCC manual the only "official" > documentation on this (I've found a couple of web sites but none of them > gun.org) I believe so... other than the sources, of course. :-) -Scott ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Endian problem when accessing internel regs on 8347 2008-01-17 22:18 ` Scott Wood @ 2008-01-21 7:21 ` Bruce_Leonard 2008-01-21 15:16 ` Ben Warren 2008-01-21 16:40 ` Scott Wood 0 siblings, 2 replies; 11+ messages in thread From: Bruce_Leonard @ 2008-01-21 7:21 UTC (permalink / raw) To: Scott Wood; +Cc: linuxppc-embedded > >>> __asm__ __volatile__("lwz%U1%X1 %0,%1; twi 0,%0,0; isync" : "=r" (ret) > > : > >>> "m" (*addr)); > >> They allow the compiler to use update and/or index mode for the memory > >> operand. > > > > Well that makes sense, U for update and X for index, but I'm not sure > > they're applicable to this particular instruction and I'm not sure that > > the memory operand makes sense for PowerPC. > > Why not? Okay, after much digging and experimenting, I'll agree that the memory operand makes sense. When I first said that I was thinking of direct manipulation of memory, which the PPC doesn't support. (Don't ask, my brain sometimes goes off into la-la land without me :-> ) Also, update mode is applicable and makes sense. But I do still have a problem with the index mode, though it could be compiler magic. Here's why: the index mode of the 'lwz' instruction requires three operands, i.e., 'lwzx rD,rA,rB', and there's only place holders for two operands. Is the compiler smart enough to add the third operand for the index mode? If so, what does it put for the third operand? Another question is how does the compiler know which mode to pick? And what is the significance of the trailing number? Some places in the code have %U1%X1 and others have %U2%X2? I've found documentation for the # and ## tokens, but I can't find anything for the %U or %X tokens. Now this has all been very interesting to learn but doesn't solve my underlying problem which I've finally drilled down to. At first I thought in_be32() might be broken because I wasn't getting back the value I knew to be in the internal register. I knew I had the address and the mapping to kernel space correct because I could use in_le32 and get the right value though it was byte swapped. The value in the register was 0xFFFFFFE7 but what I was getting from in_be32 was 0xFFFFFFFF. Then I started playing and here's what I found: Register value in_be32 value 0x12345678 0x1234567 0xff345678 0xff345678 0xffff5678 0xffff5678 0xfffff678 0xfffff678 0xfffffe78 0xffffffff 0xffffff78 0xffffffff This isn't an exhastive list but I tried about twenty values and pretty much what I found was that if bits 0 through 22 are set to 1 then in_be32 reads 0xffffffff. I've also tried it at a variety of addresses and the behaviour is the same. in_le32 works fine as does in_be16. I've got no ideas as to what may be wrong. I don't want to just arbitrarily point to that %U1%X1 parameter list, but I get compiler errors if I try to remove them so I can't prove or disprove it and I can't find any documentation on it I can't even form a theroy. Has anyone ever seen anything like this? Can't anyone suggest anything I can try? ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Endian problem when accessing internel regs on 8347 2008-01-21 7:21 ` Bruce_Leonard @ 2008-01-21 15:16 ` Ben Warren 2008-01-21 16:40 ` Scott Wood 1 sibling, 0 replies; 11+ messages in thread From: Ben Warren @ 2008-01-21 15:16 UTC (permalink / raw) To: Bruce_Leonard; +Cc: Scott Wood, linuxppc-embedded Hey Bruce, Bruce_Leonard@selinc.com wrote: >>>>> __asm__ __volatile__("lwz%U1%X1 %0,%1; twi 0,%0,0; isync" : "=r" >>>>> > (ret) > >>> : >>> >>>>> "m" (*addr)); >>>>> >>>> They allow the compiler to use update and/or index mode for the >>>> > memory > >>>> operand. >>>> >>> Well that makes sense, U for update and X for index, but I'm not sure >>> they're applicable to this particular instruction and I'm not sure >>> > that > >>> the memory operand makes sense for PowerPC. >>> >> Why not? >> > > Okay, after much digging and experimenting, I'll agree that the memory > operand makes sense. When I first said that I was thinking of direct > manipulation of memory, which the PPC doesn't support. (Don't ask, my > brain sometimes goes off into la-la land without me :-> ) Also, update > mode is applicable and makes sense. But I do still have a problem with > the index mode, though it could be compiler magic. Here's why: the index > mode of the 'lwz' instruction requires three operands, i.e., 'lwzx > rD,rA,rB', and there's only place holders for two operands. Is the > compiler smart enough to add the third operand for the index mode? If so, > what does it put for the third operand? > > Another question is how does the compiler know which mode to pick? And > what is the significance of the trailing number? Some places in the code > have %U1%X1 and others have %U2%X2? I've found documentation for the # > and ## tokens, but I can't find anything for the %U or %X tokens. > > Now this has all been very interesting to learn but doesn't solve my > underlying problem which I've finally drilled down to. At first I thought > in_be32() might be broken because I wasn't getting back the value I knew > to be in the internal register. I knew I had the address and the mapping > to kernel space correct because I could use in_le32 and get the right > value though it was byte swapped. The value in the register was > 0xFFFFFFE7 but what I was getting from in_be32 was 0xFFFFFFFF. Then I > started playing and here's what I found: > > Register value in_be32 value > 0x12345678 0x1234567 > 0xff345678 0xff345678 > 0xffff5678 0xffff5678 > 0xfffff678 0xfffff678 > 0xfffffe78 0xffffffff > 0xffffff78 0xffffffff > > This isn't an exhastive list but I tried about twenty values and pretty > much what I found was that if bits 0 through 22 are set to 1 then in_be32 > reads 0xffffffff. I've also tried it at a variety of addresses and the > behaviour is the same. in_le32 works fine as does in_be16. I've got no > ideas as to what may be wrong. I don't want to just arbitrarily point to > that %U1%X1 parameter list, but I get compiler errors if I try to remove > them so I can't prove or disprove it and I can't find any documentation on > it I can't even form a theroy. Has anyone ever seen anything like this? > Can't anyone suggest anything I can try? > Are you sure that all the bits are configured as GPIO? Almost every peripheral pin on these chips is muxed at least two ways. Maybe some of the bits that you think are GPIO are configured as some other bus, possibly explaining goofy behavior and perceived volatility of data. This is pretty well-vetted code on a reasonably mature product, and in my experience it's very rarely the tools ... Just a thought. regards, Ben ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Endian problem when accessing internel regs on 8347 2008-01-21 7:21 ` Bruce_Leonard 2008-01-21 15:16 ` Ben Warren @ 2008-01-21 16:40 ` Scott Wood 2008-01-22 5:33 ` Bruce_Leonard 1 sibling, 1 reply; 11+ messages in thread From: Scott Wood @ 2008-01-21 16:40 UTC (permalink / raw) To: Bruce_Leonard; +Cc: linuxppc-embedded On Sun, Jan 20, 2008 at 11:21:48PM -0800, Bruce_Leonard@selinc.com wrote: > Okay, after much digging and experimenting, I'll agree that the memory > operand makes sense. When I first said that I was thinking of direct > manipulation of memory, which the PPC doesn't support. (Don't ask, my > brain sometimes goes off into la-la land without me :-> ) Also, update > mode is applicable and makes sense. But I do still have a problem with > the index mode, though it could be compiler magic. Here's why: the index > mode of the 'lwz' instruction requires three operands, i.e., 'lwzx > rD,rA,rB', and there's only place holders for two operands. Is the > compiler smart enough to add the third operand for the index mode? If so, > what does it put for the third operand? When the compiler decides to use index mode, the second "operand" is a string containing "rX, rY", just as when it decides not to, the second operand is a string containing "offset(rX)". > Another question is how does the compiler know which mode to pick? The same way it decides which mode to use for internally generated loads and stores. Compiler optimization implementation is beyond the scope of this list. :-) > And what is the significance of the trailing number? Some places in > the code have %U1%X1 and others have %U2%X2? I've found documentation > for the # and ## tokens, but I can't find anything for the %U or %X > tokens. The number is an index into the operand list at the end of the asm statement. > Now this has all been very interesting to learn but doesn't solve my > underlying problem which I've finally drilled down to. At first I thought > in_be32() might be broken because I wasn't getting back the value I knew > to be in the internal register. I knew I had the address and the mapping > to kernel space correct because I could use in_le32 and get the right > value though it was byte swapped. Are you absolutely sure that in_le32 to in_be32 is the only thing that changed? If you change it back now, does it resume returning a byte-swap of the correct value? If that is indeed what is making the difference, then perhaps it's some subtle timing (or memory corruption) difference caused by different code generation because the compiler is forced to use index mode for in_le32 (though it appears that the same operand list is given to GCC in either case -- is GCC smart enough to optimize away preperation of inputs that aren't actually referenced in the asm statement?). Is there any difference in the generated assembly besides the specific load instruction used? Alternatively, maybe your chip is just fried. :-) > I don't want to just arbitrarily point to that %U1%X1 parameter list, So please don't. > but I get compiler errors if I try to remove them That's why it's there. :-) > Can't anyone suggest anything I can try? Beer. -Scott ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Endian problem when accessing internel regs on 8347 2008-01-21 16:40 ` Scott Wood @ 2008-01-22 5:33 ` Bruce_Leonard 0 siblings, 0 replies; 11+ messages in thread From: Bruce_Leonard @ 2008-01-22 5:33 UTC (permalink / raw) To: Scott Wood; +Cc: linuxppc-embedded > > Can't anyone suggest anything I can try? > > Beer. > > -Scott Right there with you Scott! I have to apologize for the noise on the list. Turns out my problem doesn't have anything to do with in_be32. I didn't have print statements in enough places. I was only printing out what was returned from the ioctl call in user space and assumed (we know what that means ;) ) that what was coming back from the ioctl call was what was coming back from io_read32. With better instrumenting I find that io_read32 is just fine. Apparently my return value from the ioctl function in my driver is getting corrupted by the time it gets to my user space app. I don't have an answer for that one yet, but now that I'm turned in the correct direction hopefully it'll fall out pretty quickly. Thanks for the patience. See 'ya! Bruce ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2008-01-22 5:34 UTC | newest] Thread overview: 11+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2008-01-17 6:26 Endian problem when accessing internel regs on 8347 Bruce_Leonard 2008-01-17 15:01 ` Ben Warren 2008-01-17 18:01 ` Bruce_Leonard 2008-01-17 18:25 ` Ben Warren 2008-01-17 17:39 ` Scott Wood 2008-01-17 18:38 ` Bruce_Leonard 2008-01-17 22:18 ` Scott Wood 2008-01-21 7:21 ` Bruce_Leonard 2008-01-21 15:16 ` Ben Warren 2008-01-21 16:40 ` Scott Wood 2008-01-22 5:33 ` Bruce_Leonard
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).