Re: [RFC 2.6.27 1/1] gpiolib: add support for batch set of pins

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Nov 25, 2008 at 11:15 PM, David Brownell <david-b@xxxxxxxxxxx> wrote:
> On Tuesday 25 November 2008, Eric Miao wrote:
>> Using a bit mask will be more generic if the GPIOs are not contiguous.
>> Yet I still doubt this will be generic enough to be added to gpiolib.
>
> My expectation for this kind of mechanism was that systems who need
> to craft another parallel bus out of GPIO pins would be doing this
> with some system-specific utility functions.
>
> So my "is it generic enough" question is more at the level of "Are
> there enough Linux systems that need this sort of thing to justify
> generic support?".  I happen not to have come across the need for
> such ganged access from Linux (yet).  Whereas I've yet to use non-x86
> Linux systems that don't need to manipulate individual GPIO pins...

I have come across the following scenarios where a bus set of gpio is useful:
- Broadsheet E-Ink controller (uses 16-bit data bus over GPIO)
framebuffer device (this patch is for this)
- Apollo/Hecuba E-Ink controller (uses 8-bit data bus over GPIO)
framebuffer device
- 8-bit parallel IO matrix LCD controllers, such as the Samsung KS108,
also Hitachi, etc

In the area of framebuffers for lower end display devices, I find this
to be quite common.

I have also seen this in systems such as 8-bit A2D devices, also with
various coprocessor solutions where a smaller CPU like a msp430 or
HC05 would clock data to the host using 8-bit gpio data.

>
>
>> The user of this gpio_set_value_bus() may assume too much about
>> the internal, e.g. how many GPIOs on the chip and whether these GPIOs
>> are contiguous or not, and whether this GPIO chip support bitwise
>> operations.
>
> Actually I would expect that to be addressed by the hardware designer.

I agree that the gpio's are always contiguous. It would be very
unusual (I've never seen it yet) where a hardware designer picked
non-consecutive pins to be used for a bus. In the case of AM300, the
board designer picked the xscale's 58 - 73 gpio pins.

>
> As in, if you're bitbanging a 16-bit parallel bus (plus several
> control signals -- chip select lines, address latch, r/w, etc) the
> board would be designed for efficient bitbanging, by taking care
> that the software bus ops aren't stupidly complex.  So I guess I'm
> agreeing with Eric there:  wanting this kind of stuff at all seems
> to imply being fairly low-down'n'dirty.

Yes, agreed, handling the contiguous bus case turned out to be quite
straightforward and the core is just about 30 lines of code.

+       do {
+               chip = gpio_to_chip(gpio + i);
+               WARN_ON(extra_checks && chip->can_sleep);
+
+               if (!chip->set_bus) {
+                       while (((gpio + i) < (chip->base + chip->ngpio))
+                               && bitwidth) {
+                               value = values & (1 << i);
+                               chip->set(chip, gpio + i - chip->base, value);
+                               i++;
+                               bitwidth--;
+                       }
+               } else {
+                       value = values >> i; /* shift off the used stuff */
+                       remwidth = ((chip->base + (int) chip->ngpio) -
+                                       ((int) gpio + i));
+                       width = min(bitwidth, remwidth);
+
+                       chip->set_bus(chip, gpio + i - chip->base, value,
+                                       width);
+                       i += width;
+                       bitwidth -= width;
+               }
+       } while (bitwidth);


>
>
> Example, assuming a 32 bit GPIO bank, the data lines would probably
> be all adjacent and politely ordered by the board designer so that

A typical board designer will ensure that the selected pins are
consecutive. But I think given today's rapid development time, I'd be
hard pressed to ensure that they're also register consecutive. In the
case of AM300, the designer picked a pin sequence that spans 2 32-bit
registers since it starts at 58 and ends at 73. So it spans the 32-63
and 64-95 registers. The code handles that case fine.

>
>        /* write a 16 bit value on the specfied data lines,
>         * assuming the intermediate state doesn't matter...
>         */
>        writew(0xffff << N, &bank->clear_bits);
>        writew(value << N, &bank->set_bits);
>
> instead of needing to compute some complex permutation of those
> bits ... and similarly
>
>        /* read a 16 bit value from the specified data lines */
>        value = 0xffff & (readw(&bank->read_bits) >> N);
>
> possibly after handshaking with the device on the other side
> about changing signal direction, again without permutation.
>
> But heck, maybe there just aren't that many adjacent GPIOs free,
> because of alternate functions that are used... ugh.
>
>
> Note also that this proposal only includes
>
>> > +       void                    (*set_bus)(struct gpio_chip *chip,
>> > +                                          unsigned offset, int values,
>> > +                                          int bitwidth);
>
> not its sibling read operation.
>

Yes, I figured I'd start with the most basic approach. Also, the
costliest operation in am300epd is the the actual framebuffer transfer
to the device which is just a lot of writes. If people want me to do
it, I can also implement get_bus.

>
>> Let's have a concrete example: what if the user gives a bunch of GPIOs
>> that crosses the chip boundary, say, GPIO29 - GPIO35 (with each chip
>> covering 32 GPIOs).
>
> I'd care more about the upper level operation being performed ... like the
> control protocol for passing the address of a word being read or written
> and then switching the bus from address to data read (or write) mode to
> get the word, then yielding the bus access.

The upper level protocol in this case is from broadsheetfb (also
posted). Here's the relevant code:

+static void broadsheet_issue_data(struct broadsheetfb_par *par, u16 data)
+{
+       par->board->set_ctl(par, BS_WR, 0);
+       par->board->set_hdb(par, data);
+       par->board->set_ctl(par, BS_WR, 1);
+}
...
which is called to transfer the fb via:
+static void broadsheet_burst_write(struct broadsheetfb_par *par, int size,
+                                       u16 *data)
+{
...
+       for (i = 0; i < size; i++) {
...
+               par->board->set_hdb(par, tmp);

Thanks,
jaya
--
To unsubscribe from this list: send the line "unsubscribe linux-embedded" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Gstreamer Embedded]     [Linux MMC Devel]     [U-Boot V2]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux ARM Kernel]     [Linux OMAP]     [Linux SCSI]

  Powered by Linux