RFC: Linux BCM2708 peripheral drivers w/pinctrl


24 posts
by M33P » Tue Jan 01, 2013 6:32 pm
Hello

Most (if not all) Raspi peripheral drivers using a broad subset of the GPIO pins should be implemented using the Pinctrl framework within Linux.

As an example, currently every single GPIO0-53 is exportable via the sysfs interface
Code: Select all
pi@raspberrypi /sys/class/gpio $ sudo -s
root@raspberrypi:/sys/class/gpio# echo 54 > export
bash: echo: write error: No such device
root@raspberrypi:/sys/class/gpio# echo 53 > export
root@raspberrypi:/sys/class/gpio# echo 52 > export
root@raspberrypi:/sys/class/gpio# echo 51 > export
root@raspberrypi:/sys/class/gpio# echo 50 > export
root@raspberrypi:/sys/class/gpio# echo 49 > export
root@raspberrypi:/sys/class/gpio# ls gp
gpio49/    gpio50/    gpio51/    gpio52/    gpio53/    gpiochip0/
root@raspberrypi:/sys/class/gpio# cd gpio49
root@raspberrypi:/sys/class/gpio/gpio49# ls
active_low  direction  edge  power  subsystem  uevent  value
root@raspberrypi:/sys/class/gpio/gpio49# cat direction
in
root@raspberrypi:/sys/class/gpio/gpio49# cat edge
none
root@raspberrypi:/sys/class/gpio/gpio49# cat active_low
0
root@raspberrypi:/sys/class/gpio/gpio49# echo out > direction
root@raspberrypi:/sys/class/gpio/gpio49# echo 1 > value
root@raspberrypi:/sys/class/gpio/gpio49# sync
bash: sync: command not found
root@raspberrypi:/sys/class/gpio/gpio49# dmesg
bash: dmesg: command not found

What I did there was to completely break the SD controller by robbing it of one of its data pins. These pins are exposed as GPIO and as such the GPIO driver will happily stomp all over them if commanded to do so.

Currently, there are #define macro hacks within the various drivers to "hard code" gluing GPIO pins to various functions - SPI and I2C are the most pertinent examples in addition to the one given above.

Further to this, there are 2 (and shortly 3) versions of the R-pi "in the wild" - with several important changes to GPIO between B1.0 and B2.0.

With a properly implemented pinctrl-aware device structure, it would be possible to
a) deny exporting to userspace a GPIO already used by (important) hardware functions, either because another device has claimed them already or because they are connected to e.g. chip enable of the LAN device (if fitted)
b) correctly order the i2c-0 and i2c-1 devices based upon the revision of model B the kernel is running on
c) additionally prevent use of GPIOs that are permanently attached to the "hw version" resistors on the B1.0 pi, but are available as P5 on the B2.0 pi (which essentially means that a future I2S sound driver will have to know what revision Pi it is running on)
d) remove the need for rather hacky macros in the other device drivers.

An implementation of pinctrl can be made board revision-aware to be more transparent and add an additional barrier of safety between the various essential guts of the Pi and userland.

FYI: RFC means "request for comments" - I know that this will require a rewrite of several of the peripheral drivers of the Pi
Posts: 199
Joined: Sun Sep 02, 2012 1:14 pm
by M33P » Fri Jan 04, 2013 12:37 am
I have started writing a pinctrl driver/controller/whatever for the pi - but is somewhat complicated by the fact that the pinctrl/pinmux/pinconf subsystem is still in a state of flux. Which means the documentation is not entirely congruent with the code it is attached to.

For a quick and easy hack, I have kludged together some gpio_lib calls that prevent the use of reserved GPIOs on the pi.

Code: Select all
diff --git a/arch/arm/mach-bcm2708/bcm2708_gpio.c b/arch/arm/mach-bcm2708/bcm2708_gpio.c
index c8161e1..a31c984 100644
--- a/arch/arm/mach-bcm2708/bcm2708_gpio.c
+++ b/arch/arm/mach-bcm2708/bcm2708_gpio.c
@@ -129,10 +129,32 @@ static void bcm2708_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
                writel(1 << gpio_field_offset, gpio->base + GPIOCLR(gpio_bank));
 }

+static int bcm2708_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+       /* temporary fix until the pinmux interface is implemented
+        * hard-code the (very) unusable gpios on r-pi */
+       //return pinctrl_request_gpio(offset);
+       if(offset > BCM_NR_GPIOS || offset < 0 ||
+               offset == 6 || offset == 12 ||
+               offset == 13 || offset == 19 ||
+               offset == 20 || offset == 26 ||
+               (offset >= 32 && offset <= 39) ||
+               (offset >= 41 && offset <= 44) ||
+               (offset >= 47 && offset <= 53)) {
+               return -EINVAL;
+       } else {
+               return 0;
+       }
+}
+
+void  bcm2708_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+       //pinctrl_free_gpio(offset);
+       return;
+}
 /***************************************************************************************************
  * bcm2708 GPIO IRQ
- */
-
+ */
 #if BCM_GPIO_USE_IRQ

 #define IRQ_TO_GPIO(x) irq_to_gpio(x)
@@ -255,6 +277,7 @@ static void bcm2708_gpio_irq_init(struct bcm2708_gpio *ucb)
 {
 }

+
 #endif /* #if BCM_GPIO_USE_IRQ *********************************************************************

 static int bcm2708_gpio_probe(struct platform_device *dev)
@@ -283,6 +306,8 @@ static int bcm2708_gpio_probe(struct platform_device *dev)
        ucb->gc.ngpio = BCM_NR_GPIOS;
        ucb->gc.owner = THIS_MODULE;

+       ucb->gc.request = bcm2708_gpio_request;
+       ucb->gc.free = bcm2708_gpio_free;
        ucb->gc.direction_input = bcm2708_gpio_dir_in;
        ucb->gc.direction_output = bcm2708_gpio_dir_out;
        ucb->gc.get = bcm2708_gpio_get;


Testing the result:

Code: Select all
pi@raspberrypi /sys/class/gpio $ sudo -s
root@raspberrypi:/sys/class/gpio# echo 53 > export
bash: echo: write error: Invalid argument


Success, apparently!

I think I will submit as a pull request on github, unless someone disagrees.
Posts: 199
Joined: Sun Sep 02, 2012 1:14 pm
by jojopi » Fri Jan 04, 2013 8:57 am
M33P wrote:+ if(offset > BCM_NR_GPIOS || offset < 0 ||
+ offset == 6 || offset == 12 ||
+ offset == 13 || offset == 19 ||
+ offset == 20 || offset == 26 ||
+ (offset >= 32 && offset <= 39) ||
+ (offset >= 41 && offset <= 44) ||
+ (offset >= 47 && offset <= 53)) {
+ return -EINVAL;
Almost all of the pins you are "protecting" are unconnected anyway. The users should be allowed to play with those, if only to convince themselves that nothing happens.

On a Model A I should certainly be able to use GPIO6 for my own purposes.

That leaves only the SD card pins. Why can I not at least read GPIO47? What if my rootfs is on USB or NFS?

Refusing an explicit user request because you assume they are an idiot is not the right philosophy for the kernel at all.
User avatar
Posts: 2036
Joined: Tue Oct 11, 2011 8:38 pm
by jamesh » Fri Jan 04, 2013 9:55 am
M33P wrote:Further to this, there are 2 (and shortly 3) versions of the R-pi "in the wild" - with several important changes to GPIO between B1.0 and B2.0.


Colour me intrigued. Shortly 3? Wassat then?
Soon to be unemployed software engineer currently specialising in camera drivers and frameworks, but can put mind to most embedded tasks. Got a job in N.Cambridge or surroundings? I'm interested!
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 11651
Joined: Sat Jul 30, 2011 7:41 pm
by Stephen99 » Fri Jan 04, 2013 9:58 am
I am guessing the Model A?
Posts: 12
Joined: Fri Oct 05, 2012 6:18 pm
by jamesh » Fri Jan 04, 2013 10:01 am
Stephen99 wrote:I am guessing the Model A?


But that's just a B with bits taken off. No changes to the GPIO's AFAIK.
Soon to be unemployed software engineer currently specialising in camera drivers and frameworks, but can put mind to most embedded tasks. Got a job in N.Cambridge or surroundings? I'm interested!
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 11651
Joined: Sat Jul 30, 2011 7:41 pm
by Stephen99 » Fri Jan 04, 2013 11:25 am
(I agree)

I guess the important bit for his post relates to the fact that the removed bits no longer need the GPIO pins to drive them any more so could be used for other things.

That said. I agree with the other point that protection like this doesn't sound like something that should be 'hard enforced' by the kernel module.
Posts: 12
Joined: Fri Oct 05, 2012 6:18 pm
by M33P » Fri Jan 04, 2013 3:57 pm
jojopi wrote:Almost all of the pins you are "protecting" are unconnected anyway. The users should be allowed to play with those, if only to convince themselves that nothing happens.

On a Model A I should certainly be able to use GPIO6 for my own purposes.

That leaves only the SD card pins. Why can I not at least read GPIO47? What if my rootfs is on USB or NFS?

Refusing an explicit user request because you assume they are an idiot is not the right philosophy for the kernel at all.


The basic idea was to (simply) get some degree of protection for the SD card into the GPIO driver. It could be toggled with a module parameter. The SD card driver does not do anything to configure (or request) GPIOs - not necessary as it gets the hardware "first" given that on boot of the kernel the SD controller is already plumbed into the pins.

Read/write behaviour for sysfs exports would have to be managed by udev - reading/writing permission granularity is not presented at the gpiolib sysfs interface.

Udev is meant to be for naming and user permissions on device nodes, not controlling actions on the underlying hardware. The readonly behaviour would have to come from lower down in the gpio driver.

The gpio_request() only allows access/no access through the use of a success/fail return value, which means that the eventual readonly behaviour would have to come from bcm2708_gpio_set(), bcm2708_gpio_dir_in() and _out() - again by returning an error when called for certain gpio numbers.

I have looked at several other gpio drivers employing request and free calls - for the ones that do implement them, invalid argument is used as the return value for "reserved" GPIOs.

Also note that with the current GPIO driver, you cannot change a pin back to an ALT-x function once changed to input/output. This would make the GPIO driver unnecessarily messy. It would then have to consider alternate functions of pins and then mutate into, basically, pinctrl.

My idea behind using pinctrl on the pi was to allow peaceful coexistence of the default set of functions (which are available/not available depending on revision of Pi) plus any more that people may use (as custom bitbanged interfaces in kernel mode, userspace programs), as well as allow control of the specific features of the hardware (hysteresis inputs, slew rate limiting, drive strength).
Posts: 199
Joined: Sun Sep 02, 2012 1:14 pm
by jojopi » Fri Jan 04, 2013 5:05 pm
M33P wrote:My idea behind using pinctrl on the pi was to allow peaceful coexistence of the default set of functions
Peaceful coexistence is what we already have! At boot the UART takes GPIO14/15, but I can steal them back if I need them. I do not need to unload the driver first, which is good because it is compiled in and the console is connected to it. I can even steal GPIO15 only and have the kernel logs continue to go out of the other half of the UART on GPIO14.

In short, the situation is not broken. Nobody is complaining that stealing GPIO49 while the SD card is mounted crashes the system. But if you make the /sys interface too safe and inflexible, people will complain and then they will be told to use the more dangerous direct register access instead.

Since the superuser can access any GPIO anyway, surely CAP_SYS_RAWIO should allow export of any GPIO in /sys?
User avatar
Posts: 2036
Joined: Tue Oct 11, 2011 8:38 pm
by M33P » Sun Jan 06, 2013 1:26 am
jojopi wrote:Peaceful coexistence is what we already have! At boot the UART takes GPIO14/15, but I can steal them back if I need them. I do not need to unload the driver first, which is good because it is compiled in and the console is connected to it. I can even steal GPIO15 only and have the kernel logs continue to go out of the other half of the UART on GPIO14.

In short, the situation is not broken. Nobody is complaining that stealing GPIO49 while the SD card is mounted crashes the system. But if you make the /sys interface too safe and inflexible, people will complain and then they will be told to use the more dangerous direct register access instead.

Since the superuser can access any GPIO anyway, surely CAP_SYS_RAWIO should allow export of any GPIO in /sys?


That's not coexistence, at least as far as the PL011 UART driver is concerned.
How do you return the GPIO to the state it was before it was stolen by the GPIO driver? I.E. return it to UART use? For most users that will involve a reboot (trivially easy on a Pi, for given values of easy) unless you are handy with /dev/mem and know which register to poke.

Nobody is complaining about system brokenness now but this is before we see other random uses of the Pi work their way into the world with accompanying blog posts etc. detailing "hey look I made a thing, try this!". I count 7 arbitrary (based on SoC device availability plus connected pins) peripherals that may or may not be used depending on what these miniature computers end up soldered/glued/expertly wired within.

I note that the existing RPi.gpio python libraries have version1 and version2-specific code. The Python GPIO libs access /dev/mem directly for GPIO setting and retrieving the Pi board revision. Wouldn't it be far more correct if the kernel handled this?
Posts: 199
Joined: Sun Sep 02, 2012 1:14 pm
by M33P » Sun Jan 06, 2013 9:50 pm
As it turns out - thread is moot.

Linux 3.8-rc2 incorporates support for the BCM2835 - with pinctrl/GPIO drivers (and device trees!) already implemented.

Reading the mailing lists, other drivers are being churned out and through into upstream at a fair rate of knots. I'm going to go play with 3.8 and see what works.
Posts: 199
Joined: Sun Sep 02, 2012 1:14 pm
by petiepooo » Wed Feb 20, 2013 8:59 pm
Where did you see the info about 3.8 rc2 support?

BTW, https://www.kernel.org/doc/Documentation/gpio.txt talks about non-contiguous blocks of GPIOs under the "Identifying GPIOs" section. Perhaps, if you don't want certain ranges to be available, it's as simple as leaving them out of that list. That may, however, prevent the normal use of those pins from using them if their drivers use gpiolib to configure then.

I'm wondering if a similar mechanism exists for other BCM peripherals. For instance, I'd like to use the PWM peripheral, but don't want to step on any other process that's using it. Do you know of a way to "export" or mark as unavailable peripherals similar to how GPIOs are exported via sysfs?
Posts: 10
Joined: Wed Feb 20, 2013 8:50 pm
by gordon@drogon.net » Thu Feb 21, 2013 11:12 am
When I was writing wiringPi, I did consider masking out the pins that you shouldn't be touching, but I decided that I'd let the user shoot themselves in the foot if that's what they really wanted to do....

Also at the time, I didn't want to detract from any performance issues - although now, knowing that the GPIO is limited to ~20MHz accesses it really doesn't make any difference - there is plenty of 700MHz ARM time avalable between accesses to make little difference.

If I'd gone in on day 1 with that, then the little "hack" to control the OK led wouldn't have been possible as it would have been reserved - unless I did another release of wiringPi (not that it hasn't been regualarly updated and released anyway!) And who knows what other little tricks and hacks people might find or want to play with - e.g. configuring the GPIO clock to output on a pin, digging out the 2nd PWM pin, I2C pins, and so on.

So who knows. Right now I know that wiringPi has been downloaded and used by 1000's of people worldwide and I really do not want anything kernel-wise to change that would break it.

With power comes responsibiltiy, etc.

What I did consider way back was writing a /dev/ access driver for it - still wish I'd made the effort, but I also got some negative feedback when I suggested it (however I see that somone has now gone and done it - and recieved no feedback to his postings )-:

From my experiences with wiringPi so-far, there is a lot of people coming to the Pi from the microcontroller land, or coming in new from environments where they sort of expect to be able to poke the hardware directly - I know that some of these folks are finding it a little frustrating too - especially after the hand-holding you get in Arduino land, etc.

-Gordon
--
Gordons projects: https://projects.drogon.net/
User avatar
Posts: 1514
Joined: Tue Feb 07, 2012 2:14 pm
Location: Devon, UK
by petiepooo » Fri Feb 22, 2013 1:14 am
If you're talking about servo-blaster and pi-blaster, I've been discussing the use of a FIFO in /dev vs something in sysfs on the blog where pi-blaster was announced. The linuxy way is a driver that uses sysfs, but there is much to be said for being able to just compile a userspace app and just run with it. It doesn't play well with the driver tho, as you can't export pins via sysfs after running.
Posts: 10
Joined: Wed Feb 20, 2013 8:50 pm
by gordon@drogon.net » Fri Feb 22, 2013 10:45 am
petiepooo wrote:If you're talking about servo-blaster and pi-blaster, I've been discussing the use of a FIFO in /dev vs something in sysfs on the blog where pi-blaster was announced. The linuxy way is a driver that uses sysfs, but there is much to be said for being able to just compile a userspace app and just run with it. It doesn't play well with the driver tho, as you can't export pins via sysfs after running.


I'm not talking about servoblaster...

But FWIW: I've tried to do servo control in userspace with wiringPi and ... it works, but there is too much jitter and the servos hunt and eventually overheat.

SoftwarePWM and generic multiplexing does work very well in userland though - at the cost of about 0.5% cpu per pin.

What I was refering to was: ... Hm and I can't find the thread, but it was about providing a /dev/ driver for the Pi's GPIO to use an ioctl to read/write GPIO pins as an alternative to the sysfs or mmap methods we're currently using.

-Gordon
--
Gordons projects: https://projects.drogon.net/
User avatar
Posts: 1514
Joined: Tue Feb 07, 2012 2:14 pm
Location: Devon, UK
by petiepooo » Fri Feb 22, 2013 12:42 pm
Oh, ok.

FWIW, the two I mentioned do user land control of a DMA channel to control the GPIOs. There is no jitter when they're under DMA control.
Posts: 10
Joined: Wed Feb 20, 2013 8:50 pm
by gordon@drogon.net » Fri Feb 22, 2013 12:59 pm
petiepooo wrote:Oh, ok.

FWIW, the two I mentioned do user land control of a DMA channel to control the GPIOs. There is no jitter when they're under DMA control.


I thought servoblaster was a kernel module? You can do anything in the kernel...

I've tried to stick to keeping things as standard as possible - when you start to introduce kernel modules it makes it really hard for your average user to get going with them unless you build them on the same version of the kernel they're running under - that is until it's integrated with the stock kernels that the foundation support!

-Gordon
--
Gordons projects: https://projects.drogon.net/
User avatar
Posts: 1514
Joined: Tue Feb 07, 2012 2:14 pm
Location: Devon, UK
by joan » Fri Feb 22, 2013 1:05 pm
There are several userland programs using DMA to provide jitter free servo pulses and general PWM etc.

My own pigpio library for one.

servoblaster has a userland variant.
User avatar
Posts: 5419
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK
by gordon@drogon.net » Fri Feb 22, 2013 1:10 pm
joan wrote:There are several userland programs using DMA to provide jitter free servo pulses and general PWM etc.

My own pigpio library for one.

servoblaster has a userland variant.


Ah. Intersting. If only I had more time...

-Gordon
--
Gordons projects: https://projects.drogon.net/
User avatar
Posts: 1514
Joined: Tue Feb 07, 2012 2:14 pm
Location: Devon, UK
by joan » Fri Feb 22, 2013 1:16 pm
Linux userland servo/PWM etc. https://www.youtube.com/watch?v=2vq0Q4dD6KE
Last edited by joan on Fri Dec 20, 2013 9:38 am, edited 1 time in total.
User avatar
Posts: 5419
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK
by petiepooo » Fri Feb 22, 2013 2:55 pm
joan wrote:There are several userland programs using DMA to provide jitter free servo pulses and general PWM etc.

My own pigpio library for one.

servoblaster has a userland variant.


Yes, I was revering to the servod.c, which is the userland implementation of servo-blaster on which pi-blaster was based.

Joan, I was interested in pigpio... right up until I saw you encrypt the source and don't allow it to be published. Have you changed that policy yet?
Posts: 10
Joined: Wed Feb 20, 2013 8:50 pm
by joan » Fri Feb 22, 2013 3:07 pm
petiepooo wrote:
joan wrote:There are several userland programs using DMA to provide jitter free servo pulses and general PWM etc.

My own pigpio library for one.

servoblaster has a userland variant.


Yes, I was revering to the servod.c, which is the userland implementation of servo-blaster on which pi-blaster was based.

Joan, I was interested in pigpio... right up until I saw you encrypt the source and don't allow it to be published. Have you changed that policy yet?

No. I won't change that policy until the library does everything I want of it. In particular I million samples per second, variable PWM frequency, user cyclic buffers for data samples.
User avatar
Posts: 5419
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK
by petiepooo » Fri Feb 22, 2013 3:47 pm
jojopi wrote:Refusing an explicit user request because you assume they are an idiot is not the right philosophy for the kernel at all.


I respectfully disagree. One of the kernel's main functions is management of shared resources. System RAM is the most obvious example.

With GPIOs, it's not as critical to manage in the kernel, since you likely have hardware attached and can control what software might be accessing it manually, but there are still cases where kernel arbitration of pin "ownership" could be desirable.

Arbitration of peripherals would be even more useful. For example, let's say I have a collection of devices connected to the SPI bus, but they're not all controlled by the same user process. Each process would need the ability to check out the SPI peripheral (only if it's available), perform its action, and release it for the next process to use.

User processes could always agree to use a system-wide semaphore to coordinate access, but simple failure on attempting to claim a busy resource is a pretty common design paradigm too.
Posts: 10
Joined: Wed Feb 20, 2013 8:50 pm
by petiepooo » Fri Feb 22, 2013 4:05 pm
joan wrote:No. I won't change that policy until the library does everything I want of it. In particular I million samples per second, variable PWM frequency, user cyclic buffers for data samples.


Those sound like great goals. If it were open and available for code commits, I might be able to help. But like many users of open source software, I only submit patches to open source projects...

Your policy ensures that you're on your own, which might be exactly what you want. Good luck. I look forward to seeing the finished product.
Posts: 10
Joined: Wed Feb 20, 2013 8:50 pm