* UIO not working on ppc405 onchip registers
@ 2008-07-21 19:52 Markus Brunner
2008-07-22 6:17 ` Uwe Kleine-König
0 siblings, 1 reply; 8+ messages in thread
From: Markus Brunner @ 2008-07-21 19:52 UTC (permalink / raw)
To: linuxppc-dev; +Cc: linux-embedded
Hi,
I'm unable to get UIO working on the ppc405ep onchip registers (e.g. gpio/iic)
however it's working fine on peripherals.
It seems to me to be a problem with UIO on powerpc, because if I change the
address (and nothing more) to point to a external FPGA it's working fine.
I also tried the generic uio_pdrv which had the same problems.
Sometimes I get a "bus error" sometimes it only produces wrong results.
The "bus error" occurred when not a full 32 bit register was read (e.g. only a
byte of it), but I'm not sure if it doesn't occur for other reasons as well.
Here is a simple example against 2.6.26. It should toggle the GPIO pin 0 on
ppc405ep, but can be changed easily to work on other ppc variants.
Can anyone reproduce this problem, did anyone already succeed in writing a UIO
driver for the onchip registers? How can I fix this?
Might this be something like commit c9698d6b1a90929e427a165bd8283f803f57d9bd which
added pgprot_noncached() to UIO mmap code to get it work on ppc?
Regards
Markus
diff -upNr linux-2.6.26/drivers/uio-orig/Kconfig linux-2.6.26/drivers/uio/Kconfig
--- linux-2.6.26/drivers/uio-orig/Kconfig 2008-07-18 09:15:51.000000000 +0200
+++ linux-2.6.26/drivers/uio/Kconfig 2008-07-18 09:16:18.000000000 +0200
@@ -39,4 +39,12 @@ config UIO_SMX
If you compile this as a module, it will be called uio_smx.
+config UIO_GPIO
+ tristate "Driver for PPC_4xx GPIO"
+ depends on UIO
+ default n
+ help
+ Driver for PPC_4xx GPIO Registers
+
endif
+
diff -upNr linux-2.6.26/drivers/uio-orig/Makefile linux-2.6.26/drivers/uio/Makefile
--- linux-2.6.26/drivers/uio-orig/Makefile 2008-07-18 09:27:18.000000000 +0200
+++ linux-2.6.26/drivers/uio/Makefile 2008-07-18 09:16:50.000000000 +0200
@@ -1,3 +1,4 @@
obj-$(CONFIG_UIO) += uio.o
obj-$(CONFIG_UIO_CIF) += uio_cif.o
obj-$(CONFIG_UIO_SMX) += uio_smx.o
+obj-$(CONFIG_UIO_GPIO) += uio_ppc_4xx-gpio.o
diff -upNr linux-2.6.26/drivers/uio-orig/uio-gpio.c linux-2.6.26/drivers/uio/uio-gpio.c
--- linux-2.6.26/drivers/uio-orig/uio-gpio.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.26/drivers/uio/uio-gpio.c 2008-07-18 09:18:56.000000000 +0200
@@ -0,0 +1,59 @@
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+const unsigned long pin_mask( unsigned int pin) { return (0x80000000 >> (pin));}
+
+const char UIO_DEV[] = "/dev/uio0";
+const unsigned int UIO_SIZE = 0x1000;
+const unsigned int UIO_ADDR = 0xef600700;
+
+const int or = 0;
+const int tcr = 1;
+
+const unsigned int gpio_pin = 0; /* What gpio pin do you want to toggle? */
+
+volatile unsigned long *gpio_regs;
+
+int main(int argc, char *argv[])
+{
+ int uiofd = open(UIO_DEV,O_RDWR);
+ if (uiofd < 0)
+ return uiofd;
+
+ unsigned long* map_addr = mmap(NULL,
+ UIO_SIZE,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ uiofd,
+ 0);
+ if (map_addr == ((unsigned long*) -1))
+ return -1;
+ gpio_regs = (volatile unsigned long*) map_addr;
+ printf("Mapped %0lx bytes from %08lx to %08lx\n", UIO_SIZE, UIO_ADDR, (unsigned long)map_addr);
+
+ printf("TCR = %08lx\n", gpio_regs[tcr]);
+ printf("TCR = %08lx\n", gpio_regs[tcr]);
+ printf("setting TCR\n");
+ gpio_regs[tcr] = gpio_regs[tcr] | pin_mask( gpio_pin ); // set tcr for pin to 1
+ printf("TCR = %08lx\n", gpio_regs[tcr]);
+ printf("TCR = %08lx\n", gpio_regs[tcr]);
+
+ printf("OR = %08lx\n", gpio_regs[or]);
+ printf("OR = %08lx\n", gpio_regs[or]);
+ printf("setting OR\n");
+ gpio_regs[or] = gpio_regs[or] | pin_mask( gpio_pin ); // set tcr for pin to 1
+ printf("OR = %08lx\n", gpio_regs[or]);
+ printf("OR = %08lx\n", gpio_regs[or]);
+ sleep( 3 );
+ printf("setting OR\n");
+ gpio_regs[or] = gpio_regs[or] & ~pin_mask( gpio_pin ); // set tcr for pin to 0
+ printf("OR = %08lx\n", gpio_regs[or]);
+ printf("OR = %08lx\n", gpio_regs[or]);
+
+}
diff -upNr linux-2.6.26/drivers/uio-orig/uio_ppc_4xx-gpio.c linux-2.6.26/drivers/uio/uio_ppc_4xx-gpio.c
--- linux-2.6.26/drivers/uio-orig/uio_ppc_4xx-gpio.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.26/drivers/uio/uio_ppc_4xx-gpio.c 2008-07-18 09:23:32.000000000 +0200
@@ -0,0 +1,74 @@
+/*
+ * simple UIO GPIO driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/uio_driver.h>
+
+#include <asm/io.h>
+
+static struct uio_info info = {
+ .name = "uio_gpio",
+ .version = "0.0.0",
+ .irq = UIO_IRQ_NONE,
+ .irq_flags = 0,
+ .mem[0].addr = 0xef600700,
+ .mem[0].size = 0x1000,
+ .mem[0].memtype = UIO_MEM_PHYS,
+};
+
+static int __devinit uio_gpio_probe(struct device *dev)
+{
+ if (uio_register_device(dev, &info)){
+ printk(KERN_ERR "uio_gpio: uio_register_device failed\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static int uio_gpio_remove(struct device *dev)
+{
+ uio_unregister_device(&info);
+ info.mem[0].addr = 0;
+ info.mem[0].size = 0;
+ return 0;
+}
+
+static struct platform_device *uio_gpio_device;
+
+static struct device_driver uio_gpio_driver = {
+ .name = "uio_gpio",
+ .bus = &platform_bus_type,
+ .probe = uio_gpio_probe,
+ .remove = uio_gpio_remove,
+};
+
+
+static int __init uio_gpio_init(void)
+{
+ uio_gpio_device = platform_device_register_simple("uio_gpio", -1,
+ NULL, 0);
+ if (IS_ERR(uio_gpio_device))
+ return PTR_ERR(uio_gpio_device);
+
+ return driver_register(&uio_gpio_driver);
+}
+
+static void __exit uio_gpio_exit(void)
+{
+ platform_device_unregister(uio_gpio_device);
+ driver_unregister(&uio_gpio_driver);
+}
+
+module_init(uio_gpio_init);
+module_exit(uio_gpio_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Markus Brunner");
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: UIO not working on ppc405 onchip registers
2008-07-21 19:52 UIO not working on ppc405 onchip registers Markus Brunner
@ 2008-07-22 6:17 ` Uwe Kleine-König
2008-07-22 6:42 ` Ben Nizette
2008-07-22 7:47 ` super.firetwister
0 siblings, 2 replies; 8+ messages in thread
From: Uwe Kleine-König @ 2008-07-22 6:17 UTC (permalink / raw)
To: Markus Brunner; +Cc: linuxppc-dev@ozlabs.org, linux-embedded@vger.kernel.org
Hello Markus,
Markus Brunner wrote:
> I'm unable to get UIO working on the ppc405ep onchip registers (e.g. gpio/iic)
> however it's working fine on peripherals.
I don't know powerpc in general nor ppc405ep in detail but IIRC arm has
problems if some memory is mapped twice. Might this be the problem
here?
> It seems to me to be a problem with UIO on powerpc, because if I change the
> address (and nothing more) to point to a external FPGA it's working fine.
> I also tried the generic uio_pdrv which had the same problems.
> Sometimes I get a "bus error" sometimes it only produces wrong results.
> The "bus error" occurred when not a full 32 bit register was read (e.g. only a
> byte of it), but I'm not sure if it doesn't occur for other reasons as well.
Well, if this is a 32bit memory mapped device and you do a non-32 bit
access strage things can happen.
>
> diff -upNr linux-2.6.26/drivers/uio-orig/Kconfig linux-2.6.26/drivers/uio/Kconfig
> --- linux-2.6.26/drivers/uio-orig/Kconfig 2008-07-18 09:15:51.000000000 +0200
> +++ linux-2.6.26/drivers/uio/Kconfig 2008-07-18 09:16:18.000000000 +0200
> @@ -39,4 +39,12 @@ config UIO_SMX
>
> If you compile this as a module, it will be called uio_smx.
>
> +config UIO_GPIO
> + tristate "Driver for PPC_4xx GPIO"
> + depends on UIO
> + default n
> + help
> + Driver for PPC_4xx GPIO Registers
> +
> endif
This endif matches an "if UIO", so there is no need to depend on UIO
explicitly.
> diff -upNr linux-2.6.26/drivers/uio-orig/Makefile linux-2.6.26/drivers/uio/Makefile
> --- linux-2.6.26/drivers/uio-orig/Makefile 2008-07-18 09:27:18.000000000 +0200
> +++ linux-2.6.26/drivers/uio/Makefile 2008-07-18 09:16:50.000000000 +0200
> @@ -1,3 +1,4 @@
> obj-$(CONFIG_UIO) += uio.o
> obj-$(CONFIG_UIO_CIF) += uio_cif.o
> obj-$(CONFIG_UIO_SMX) += uio_smx.o
> +obj-$(CONFIG_UIO_GPIO) += uio_ppc_4xx-gpio.o
> diff -upNr linux-2.6.26/drivers/uio-orig/uio-gpio.c linux-2.6.26/drivers/uio/uio-gpio.c
> --- linux-2.6.26/drivers/uio-orig/uio-gpio.c 1970-01-01 01:00:00.000000000 +0100
> +++ linux-2.6.26/drivers/uio/uio-gpio.c 2008-07-18 09:18:56.000000000 +0200
> @@ -0,0 +1,59 @@
> +#include <sys/types.h>
> +#include <sys/time.h>
> +#include <sys/stat.h>
> +#include <sys/mman.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +
> +const unsigned long pin_mask( unsigned int pin) { return (0x80000000 >> (pin));}
> +
> +const char UIO_DEV[] = "/dev/uio0";
> +const unsigned int UIO_SIZE = 0x1000;
> +const unsigned int UIO_ADDR = 0xef600700;
> +
> +const int or = 0;
> +const int tcr = 1;
> +
> +const unsigned int gpio_pin = 0; /* What gpio pin do you want to toggle? */
> +
> +volatile unsigned long *gpio_regs;
> +
> +int main(int argc, char *argv[])
> +{
> + int uiofd = open(UIO_DEV,O_RDWR);
For debugging this is OK, in the final application you should add some
tests. Check the UIO documentation for the details.
> + if (uiofd < 0)
> + return uiofd;
> +
> + unsigned long* map_addr = mmap(NULL,
> + UIO_SIZE,
> + PROT_READ | PROT_WRITE,
> + MAP_SHARED,
> + uiofd,
> + 0);
> + if (map_addr == ((unsigned long*) -1))
> + return -1;
> [...]
> diff -upNr linux-2.6.26/drivers/uio-orig/uio_ppc_4xx-gpio.c linux-2.6.26/drivers/uio/uio_ppc_4xx-gpio.c
> --- linux-2.6.26/drivers/uio-orig/uio_ppc_4xx-gpio.c 1970-01-01 01:00:00.000000000 +0100
> +++ linux-2.6.26/drivers/uio/uio_ppc_4xx-gpio.c 2008-07-18 09:23:32.000000000 +0200
> @@ -0,0 +1,74 @@
> +/*
> + * simple UIO GPIO driver.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#include <linux/device.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/uio_driver.h>
> +
> +#include <asm/io.h>
> +
> +static struct uio_info info = {
> + .name = "uio_gpio",
> + .version = "0.0.0",
> + .irq = UIO_IRQ_NONE,
> + .irq_flags = 0,
> + .mem[0].addr = 0xef600700,
> + .mem[0].size = 0x1000,
> + .mem[0].memtype = UIO_MEM_PHYS,
> +};
IIRC you should initialise the other mem members.
> +static int __devinit uio_gpio_probe(struct device *dev)
> +{
> + if (uio_register_device(dev, &info)){
> + printk(KERN_ERR "uio_gpio: uio_register_device failed\n");
> + return -ENODEV;
> + }
> + return 0;
> +}
> +
> +static int uio_gpio_remove(struct device *dev)
> +{
> + uio_unregister_device(&info);
> + info.mem[0].addr = 0;
> + info.mem[0].size = 0;
> + return 0;
> +}
Are you sure that overwriting info.mem[0].addr is a good idea? Then
unbinding the platform device and rebinding it fails to do the right
thing for sure.
> +static struct platform_device *uio_gpio_device;
> +
> +static struct device_driver uio_gpio_driver = {
> + .name = "uio_gpio",
> + .bus = &platform_bus_type,
> + .probe = uio_gpio_probe,
> + .remove = uio_gpio_remove,
> +};
> +
> +
> +static int __init uio_gpio_init(void)
> +{
> + uio_gpio_device = platform_device_register_simple("uio_gpio", -1,
> + NULL, 0);
> + if (IS_ERR(uio_gpio_device))
> + return PTR_ERR(uio_gpio_device);
> +
> + return driver_register(&uio_gpio_driver);
> +}
> +
> +static void __exit uio_gpio_exit(void)
> +{
> + platform_device_unregister(uio_gpio_device);
> + driver_unregister(&uio_gpio_driver);
> +}
> +
> +module_init(uio_gpio_init);
> +module_exit(uio_gpio_exit);
> +
> +MODULE_LICENSE("GPL");
The header says this is GPL v2. So you should use "GPL v2" here, too.
Best regards
Uwe
--
Uwe Kleine-König, Software Engineer
Digi International GmbH Branch Breisach, Küferstrasse 8, 79206 Breisach, Germany
Tax: 315/5781/0242 / VAT: DE153662976 / Reg. Amtsgericht Dortmund HRB 13962
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: UIO not working on ppc405 onchip registers
2008-07-22 6:17 ` Uwe Kleine-König
@ 2008-07-22 6:42 ` Ben Nizette
2008-07-22 7:48 ` super.firetwister
2008-07-22 7:47 ` super.firetwister
1 sibling, 1 reply; 8+ messages in thread
From: Ben Nizette @ 2008-07-22 6:42 UTC (permalink / raw)
To: Markus Brunner; +Cc: linuxppc-dev@ozlabs.org, linux-embedded@vger.kernel.org
Hey Markus,
> >
> > +config UIO_GPIO
> > + tristate "Driver for PPC_4xx GPIO"
As an aside, you sure you want to do this anyway? I'd suggest that you
just do a gpio chip driver for this, tie it in to gpiolib and use the
gpiolib user interface (which IIRC has only made it as far as -mm but is
on the way up). This gives kernel internals nice access to the pins as
well through the standard gpio framework.
Thanks :-)
--Ben.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: UIO not working on ppc405 onchip registers
2008-07-22 6:17 ` Uwe Kleine-König
2008-07-22 6:42 ` Ben Nizette
@ 2008-07-22 7:47 ` super.firetwister
2008-07-22 16:20 ` super.firetwister
1 sibling, 1 reply; 8+ messages in thread
From: super.firetwister @ 2008-07-22 7:47 UTC (permalink / raw)
To: Uwe Kleine-König
Cc: linuxppc-dev@ozlabs.org, linux-embedded@vger.kernel.org
Hello Uwe,
On Tuesday 22 July 2008, Uwe Kleine-K=F6nig wrote:
> I don't know powerpc in general nor ppc405ep in detail but IIRC arm has
> problems if some memory is mapped twice. Might this be the problem
> here?
Maybee, the emac0 (0xef600800) and emac1 (0xef600900) get mapped as well,=20
because AFAIK I have to map a whole pagesize (0x1000).
> > + int uiofd =3D open(UIO_DEV,O_RDWR);
>
> For debugging this is OK, in the final application you should add some
> tests. Check the UIO documentation for the details.
The whole example was meant to be short.
> > +static int uio_gpio_remove(struct device *dev)
> > +{
> > + uio_unregister_device(&info);
> > + info.mem[0].addr =3D 0;
> > + info.mem[0].size =3D 0;
> > + return 0;
> > +}
>
> Are you sure that overwriting info.mem[0].addr is a good idea? Then
> unbinding the platform device and rebinding it fails to do the right
> thing for sure.
This was stolen from uio_dummy. So this might become a common error :(
Thanks a lot for your comments, I will try to get an exclusive memory regio=
n=20
mapped.
Markus
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: UIO not working on ppc405 onchip registers
2008-07-22 6:42 ` Ben Nizette
@ 2008-07-22 7:48 ` super.firetwister
2008-07-22 7:52 ` Ben Nizette
0 siblings, 1 reply; 8+ messages in thread
From: super.firetwister @ 2008-07-22 7:48 UTC (permalink / raw)
To: Ben Nizette; +Cc: linuxppc-dev@ozlabs.org, linux-embedded@vger.kernel.org
On Tuesday 22 July 2008, Ben Nizette wrote:
> As an aside, you sure you want to do this anyway?
No ;)
> I'd suggest that you
> just do a gpio chip driver for this, tie it in to gpiolib and use the
> gpiolib user interface (which IIRC has only made it as far as -mm but is
> on the way up). This gives kernel internals nice access to the pins as
> well through the standard gpio framework.
This was just an example to make it others easier to reproduce my problem. My
goal is to have a soft spi driver in userspace, which would probably be
slower if it uses gpiolib. This driver is integrated in the application I
want to port to Linux.
Thanks
Markus
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: UIO not working on ppc405 onchip registers
2008-07-22 7:48 ` super.firetwister
@ 2008-07-22 7:52 ` Ben Nizette
2008-09-05 6:18 ` Markus Brunner
0 siblings, 1 reply; 8+ messages in thread
From: Ben Nizette @ 2008-07-22 7:52 UTC (permalink / raw)
To: super.firetwister; +Cc: linuxppc-dev@ozlabs.org, linux-embedded@vger.kernel.org
On Tue, 2008-07-22 at 09:48 +0200, super.firetwister@googlemail.com
wrote:
> On Tuesday 22 July 2008, Ben Nizette wrote:
>
> > As an aside, you sure you want to do this anyway?
>
> No ;)
>
>
> > I'd suggest that you
> > just do a gpio chip driver for this, tie it in to gpiolib and use the
> > gpiolib user interface (which IIRC has only made it as far as -mm but is
> > on the way up). This gives kernel internals nice access to the pins as
> > well through the standard gpio framework.
>
> This was just an example to make it others easier to reproduce my problem. My
> goal is to have a soft spi driver in userspace, which would probably be
> slower if it uses gpiolib. This driver is integrated in the application I
> want to port to Linux.
Ah right, cool. I donno what the speed would be like, but both David
Brownell and Michael Buesch both have spi-over-gpio patches floating
around (eg [1]). That, plus the spidev interface, might at least be
worth a try..?
But I'll let you get back to solving the UIO problem at hand :-D
--Ben.
[1] http://lwn.net/Articles/290066/
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: UIO not working on ppc405 onchip registers
2008-07-22 7:47 ` super.firetwister
@ 2008-07-22 16:20 ` super.firetwister
0 siblings, 0 replies; 8+ messages in thread
From: super.firetwister @ 2008-07-22 16:20 UTC (permalink / raw)
To: Uwe Kleine-König
Cc: linuxppc-dev@ozlabs.org, linux-embedded@vger.kernel.org
On Tuesday 22 July 2008, super.firetwister@gmail.com wrote:
> Hello Uwe,
>
> On Tuesday 22 July 2008, Uwe Kleine-K=F6nig wrote:
> > I don't know powerpc in general nor ppc405ep in detail but IIRC arm has
> > problems if some memory is mapped twice. Might this be the problem
> > here?
>
> Maybee, the emac0 (0xef600800) and emac1 (0xef600900) get mapped as well,
> because AFAIK I have to map a whole pagesize (0x1000).
Same problem without emac module loaded.
Did anybody tried to reproduce the problem?
Regards
Markus
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: UIO not working on ppc405 onchip registers
2008-07-22 7:52 ` Ben Nizette
@ 2008-09-05 6:18 ` Markus Brunner
0 siblings, 0 replies; 8+ messages in thread
From: Markus Brunner @ 2008-09-05 6:18 UTC (permalink / raw)
To: Ben Nizette; +Cc: linuxppc-dev@ozlabs.org, linux-embedded@vger.kernel.org
On Tuesday 22 July 2008, Ben Nizette wrote:
> But I'll let you get back to solving the UIO problem at hand :-D
I already surrendered and created (hacked) a read/write driver, which let me
use the old userspace drivers I'm trying to port (with some changes of
course). This was way faster than understanding all the involved APIs and
creating glue code between them. And the amount of time it needs was easy to
estimate.
However accidently I ran over the "old school" userland mmap code
with /dev/mem. I already knew mapping with /dev/mem is possible but I haven't
thought this could make a difference.
http://ozlabs.org/pipermail/linuxppc-embedded/2006-August/023811.html
Also I was wrong with my assumption that uio worked well on the peripherals.
It worked (very) well on the leds, just to fool me!!! But it returned crap on
some version registers.
With a working and a non working version of mmap it should be rather easy to
trace this bug. Unfortunately I was already short of time before running into
this (and other) problems and it didn't get any better.
So I would need some help from someone with more experience to fix this.
Any instructions?
Markus
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2008-09-05 6:09 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-07-21 19:52 UIO not working on ppc405 onchip registers Markus Brunner
2008-07-22 6:17 ` Uwe Kleine-König
2008-07-22 6:42 ` Ben Nizette
2008-07-22 7:48 ` super.firetwister
2008-07-22 7:52 ` Ben Nizette
2008-09-05 6:18 ` Markus Brunner
2008-07-22 7:47 ` super.firetwister
2008-07-22 16:20 ` super.firetwister
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).