* RE: [PATCH 01/12] Blackfin arch: add peripheral resource allocation support
@ 2007-08-17 20:02 Hennerich, Michael
2007-08-17 21:10 ` David Brownell
0 siblings, 1 reply; 8+ messages in thread
From: Hennerich, Michael @ 2007-08-17 20:02 UTC (permalink / raw)
To: David Brownell, Bryan Wu; +Cc: torvalds, linux-kernel, akpm, Michael Hennerich
Hi Dave,
>-----Original Message-----
>From: David Brownell [mailto:david-b@pacbell.net]
>Sent: Freitag, 17. August 2007 20:12
>To: Bryan Wu
>Cc: torvalds@linux-foundation.org; linux-kernel@vger.kernel.org;
>akpm@linux-foundation.org; Michael Hennerich
>Subject: Re: [PATCH 01/12] Blackfin arch: add peripheral resource
>allocation support
>
>On Tuesday 07 August 2007, Bryan Wu wrote:
>> From: Michael Hennerich <michael.hennerich@analog.com>
>
>The patch description here is IMO misleading, and is clearly
>weak-to-nonexistent ... what this patch does is
>
> * Start tracking the label strings provided by gpio_request()
> * Provide a new portmux mechanisms
> * Start using those in the serial support code
>
Right - our patch descriptions needs to be worked on.
>When I read "resource allocation" I think of "struct resource"
>from <linux/ioport.h>, allocate_resource(), and so on. So while
>it's true there are other kinds of driver resource, it's rather
>unnatural for me to think about pin mux and gpio issues in any
>terms other than chip and board setup.
Let me explain a bit. On some Blackfin derivatives almost all PINs can
be GPIOs besides up to 4 alternative functions. For a well experienced
systems engineer being the same time the same guy who does the Hardware
and the Software this is not an issue.
We provide all kind of drivers utilizing almost any peripheral on
Blackfin.
While potentially causing conflicting usage, for someone without
detailed hardware knowledge. The platform device board file is a good
thing to track conflicting memory or IO space resources as well as IRQs.
We also utilize platform device files for exactly these purposes.
The dynamic resource allocation for pinmux and gpio seems to us the best
way to handle things. The "resource allocation" mechanism will spill an
error and dump in case conflicting usage is detected. It'll also tell
you who is causing the conflicting usage.
>
>
>> +static int cmp_label(unsigned short ident, const char *label)
>> +{
>> + if (label && str_ident)
>> + return strncmp(str_ident + ident * RESOURCE_LABEL_SIZE,
>> + label, strlen(label));
>> + else
>> + return -EINVAL;
>> +}
>
>GRPIO labels are purely for diagnostics. There's no reason to
>compare one to another. You seem to be using these for purposes
>in addition to GPIOs though ... probably worth commenting on that
>unusual scheme.
You are right - diagnostics:
Telling who claimed my resource.
In addition getting a signature, allowing double allocation.
Some drives provide the option for a simple callback function exported
though the platform device file, in order to toggle a GPIO powering up
some external device. Without some additional global external flag it's
pretty had to maintain whether this gpio was allocated before.
In this case I prefer to allow double allocation, for the same purpose.
>
>
>> +int peripheral_request(unsigned short per, const char *label)
>> +{
>> + ...
>> +
>> + if (unlikely(reserved_peri_map[gpio_bank(ident)] &
gpio_bit(ident)))
>{
>> +
>> + /*
>> + * Pin functions like AMC address strobes my
>> + * be requested and used by several drivers
>> + */
>> +
>> + if (!(per & P_MAYSHARE)) {
>
>Goofy indentation. And as a rule, drivers have been kept out of
>the business of configuring pin usage. It's simpler that way;
>they don't need to try coping with configuration errors like two
>drivers wanting conflicting usage ... or as you say above, needing
>some explicit sharing mechanism ...
We define some PINs or better single PIN functions to be may shared.
This is only for PINs where the sharing of the function is in nature.
Think about an address strobe or a bus (Busy/Wait) signal, used by
several
drivers/devices sharing the same bus.
>
>
>> +
>> + /*
>> + * Allow that the identical pin function can
>> + * be requested from the same driver twice
>> + */
>
>... or as you say here, needing to structure themselves so they
>don't configure the same usage more than once ...
Same as explained above - this is only for these spots where the
request/free scheme doesn't work.
>
>
>That said, how you handle pinmux on Blackfin is your business.
>
>But you should know that this approach seems idiosyncratic and
>more complex than needed: when pin config is done early and as
>part of board setup, drivers don't need to care about it or to
>handle any pinmux errors. And heck, products can sometimes be
>shipped with the bootloader having done all pinmux setup, so
>Linux won't need to worry about it at all. That can help ship
>multiple board revisions using the same kernel.
This works for fixed function boards. But not for development boards
where we provide lego like add on cards, and allow people to connect
their homebrewn hardware.
Most people/customers I cope with, use the boot loader to only boot the
Linux kernel. The hardware setup we default the processor in the boot
loader might not fit their applications needs.
-Michael
>
>- Dave
>
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH 01/12] Blackfin arch: add peripheral resource allocation support
2007-08-17 20:02 [PATCH 01/12] Blackfin arch: add peripheral resource allocation support Hennerich, Michael
@ 2007-08-17 21:10 ` David Brownell
2007-08-17 22:15 ` Robin Getz
0 siblings, 1 reply; 8+ messages in thread
From: David Brownell @ 2007-08-17 21:10 UTC (permalink / raw)
To: Hennerich, Michael; +Cc: Bryan Wu, torvalds, linux-kernel, akpm
On Friday 17 August 2007, Hennerich, Michael wrote:
> Hi Dave,
>
> Right - our patch descriptions needs to be worked on.
Yes, please ... that makes reviewing easier!
> For a well experienced
> systems engineer being the same time the same guy who does the Hardware
> and the Software this is not an issue.
I guess I've rarely come across job descriptions like that.
Lowlevel software folk need to be able to use schematics and
often test equipment, but not design product circuits ... and
circuit designers rarely have responsibility to ship software.
On the other hand, maybe you want your "typical" customer to
be more of a systems integrator than anything else.
> We provide all kind of drivers utilizing almost any peripheral on
> Blackfin.
Chip vendors supporting Linux drivers for all their hardware.
What a pleasant change! :)
> While potentially causing conflicting usage, for someone without
> detailed hardware knowledge. The platform device board file is a good
> thing to track conflicting memory or IO space resources as well as IRQs.
> We also utilize platform device files for exactly these purposes.
>
> The dynamic resource allocation for pinmux and gpio seems to us the best
> way to handle things. The "resource allocation" mechanism will spill an
> error and dump in case conflicting usage is detected. It'll also tell
> you who is causing the conflicting usage.
That's your call, of course. I was pointing out why the "early"
binding of pin resources is the more usual strategy with Linux.
A "late" strategy is a bit surprising, and has its own issues.
> >That said, how you handle pinmux on Blackfin is your business.
> >
> >But you should know that this approach seems idiosyncratic and
> >more complex than needed: when pin config is done early and as
> >part of board setup, drivers don't need to care about it or to
> >handle any pinmux errors. And heck, products can sometimes be
> >shipped with the bootloader having done all pinmux setup, so
> >Linux won't need to worry about it at all. That can help ship
> >multiple board revisions using the same kernel.
>
> This works for fixed function boards.
That is, for typical products embedding Linux...
> But not for development boards
> where we provide lego like add on cards, and allow people to connect
> their homebrewn hardware.
Development boards are usually run differently than product
boards. All that flexibility in the development boards is
not necessarily a feature in the product version; it costs
space and time, which the application may need. Being able
to shift costs *early* and then drop them at runtime is a
useful strategy to apply in most places.
And heck -- most development setups get used only with one
card stack at a time, and it's easy to install new kernels
for new stacks.
- Dave
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 01/12] Blackfin arch: add peripheral resource allocation support
2007-08-17 21:10 ` David Brownell
@ 2007-08-17 22:15 ` Robin Getz
2007-08-17 22:46 ` David Brownell
0 siblings, 1 reply; 8+ messages in thread
From: Robin Getz @ 2007-08-17 22:15 UTC (permalink / raw)
To: David Brownell; +Cc: Hennerich, Michael, Bryan Wu, torvalds, linux-kernel, akpm
On Fri 17 Aug 2007 17:10, David Brownell pondered:
> On the other hand, maybe you want your "typical" customer to
> be more of a systems integrator than anything else.
We are getting yelled at by our customers (I was on the phone yesterday),
because the kernel build environment we distribute (the default) was not
inside Eclipse, and someone couldn't push a button on a GUI rather than
typing "make".
While Linux and other open source software is free, for some taking advantage
of its benefits can require a significant investment in time. Linux is
powerful, rich, and flexible. It is these very characteristics that make
Linux so appealing that also create a significant level of complexity.
We are seeing more and more "first time buyers" jumping from bare metal - no
OS, to Linux. For them - the ease of not having to write configuration files
gives them a warm fuzzy feeling when they boot their board, and it
just "works".
> > While potentially causing conflicting usage, for someone without
> > detailed hardware knowledge. The platform device board file is a good
> > thing to track conflicting memory or IO space resources as well as
> > IRQs. We also utilize platform device files for exactly these purposes.
> >
> > The dynamic resource allocation for pinmux and gpio seems to us the
> > best way to handle things. The "resource allocation" mechanism will
> > spill an error and dump in case conflicting usage is detected. It'll
> > also tell you who is causing the conflicting usage.
>
> That's your call, of course. I was pointing out why the "early"
> binding of pin resources is the more usual strategy with Linux.
> A "late" strategy is a bit surprising, and has its own issues.
Agreed - Every implementation has its own issues, but based on what we were
being asked to do - it was the best way we could accommodate everyone.
> > >That said, how you handle pinmux on Blackfin is your business.
> > >
> > >But you should know that this approach seems idiosyncratic and
> > >more complex than needed: when pin config is done early and as
> > >part of board setup, drivers don't need to care about it or to
> > >handle any pinmux errors. And heck, products can sometimes be
> > >shipped with the bootloader having done all pinmux setup, so
> > >Linux won't need to worry about it at all. That can help ship
> > >multiple board revisions using the same kernel.
> >
> > This works for fixed function boards.
>
> That is, for typical products embedding Linux...
We have multiple customers shipping the same bootloader/kernel binary on
different products, and the only difference is the /etc/rc file - which
drivers they install, and a few things in userspace.
Could this be smaller - sure - but NAND is cheap (according to them) compared
to the effort and cost of maintaining and testing multiple kernel versions
for every product.
Could this be faster - sure - but it is done at init - and then never again.
We have a ~2-3 second boot time - maybe we shave off a few ms - things go
pretty fast at 600MHz.
-Robin
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 01/12] Blackfin arch: add peripheral resource allocation support
2007-08-17 22:15 ` Robin Getz
@ 2007-08-17 22:46 ` David Brownell
0 siblings, 0 replies; 8+ messages in thread
From: David Brownell @ 2007-08-17 22:46 UTC (permalink / raw)
To: Robin Getz; +Cc: Hennerich, Michael, Bryan Wu, torvalds, linux-kernel, akpm
On Friday 17 August 2007, Robin Getz wrote:
> On Fri 17 Aug 2007 17:10, David Brownell pondered:
> > On the other hand, maybe you want your "typical" customer to
> > be more of a systems integrator than anything else.
>
> We are getting yelled at by our customers (I was on the phone yesterday),
> because the kernel build environment we distribute (the default) was not
> inside Eclipse, and someone couldn't push a button on a GUI rather than
> typing "make".
Press the "enter" button after typing "make". ;)
> While Linux and other open source software is free, for some taking advantage
> of its benefits can require a significant investment in time. Linux is
> powerful, rich, and flexible. It is these very characteristics that make
> Linux so appealing that also create a significant level of complexity.
Yes.
> We are seeing more and more "first time buyers" jumping from bare metal - no
> OS, to Linux. For them - the ease of not having to write configuration files
> gives them a warm fuzzy feeling when they boot their board, and it
> just "works".
There's certainly a lot to be said for having things
just work the first time when you're making such a big
transition in tools. On the other hand, at some point
the training wheels need to come off!
> > > >That said, how you handle pinmux on Blackfin is your business.
> > > >
> > > >But you should know that this approach seems idiosyncratic and
> > > >more complex than needed: when pin config is done early and as
> > > >part of board setup, drivers don't need to care about it or to
> > > >handle any pinmux errors. And heck, products can sometimes be
> > > >shipped with the bootloader having done all pinmux setup, so
> > > >Linux won't need to worry about it at all. That can help ship
> > > >multiple board revisions using the same kernel.
> > >
> > > This works for fixed function boards.
> >
> > That is, for typical products embedding Linux...
>
> We have multiple customers shipping the same bootloader/kernel binary on
> different products, and the only difference is the /etc/rc file - which
> drivers they install, and a few things in userspace.
Be careful there. Remember that the driver model is predicated
on knowing the devices first, and *then* matching drivers. I
expect you *will* see problems if you get people thinking system
config comes from a "which driver" selection rather than "here's
the exact hardware that's available". Maybe configfs should be
used for device config.
> Could this be smaller - sure - but NAND is cheap (according to them) compared
> to the effort and cost of maintaining and testing multiple kernel versions
> for every product.
>
> Could this be faster - sure - but it is done at init - and then never again.
> We have a ~2-3 second boot time - maybe we shave off a few ms - things go
> pretty fast at 600MHz.
I'm more used to clock rates less than 1/3 that much. :)
- Dave
^ permalink raw reply [flat|nested] 8+ messages in thread
* RE: [PATCH 01/12] Blackfin arch: add peripheral resource allocation support
@ 2007-08-08 7:18 Hennerich, Michael
2007-08-08 7:49 ` Bryan Wu
0 siblings, 1 reply; 8+ messages in thread
From: Hennerich, Michael @ 2007-08-08 7:18 UTC (permalink / raw)
To: Bryan Wu, torvalds, linux-kernel, akpm; +Cc: dbrownell, Michael Hennerich
Bryan,
This patch doesn't seem to be up to date.
It doesn't include the changes made based on feedback from Joe Perches.
Please see our SVN:
Modified: trunk/arch/blackfin/kernel/bfin_gpio.c (3489 => 3490)
-Michael
>-----Original Message-----
>From: Bryan Wu [mailto:bryan.wu@analog.com]
>Sent: Mittwoch, 8. August 2007 05:35
>To: torvalds@linux-foundation.org; linux-kernel@vger.kernel.org;
>akpm@linux-foundation.org
>Cc: dbrownell@users.sourceforge.net; Michael Hennerich; Bryan Wu
>Subject: [PATCH 01/12] Blackfin arch: add peripheral resource
allocation
>support
>
>From: Michael Hennerich <michael.hennerich@analog.com>
>
>Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
>Signed-off-by: Bryan Wu <bryan.wu@analog.com>
>---
> arch/blackfin/kernel/bfin_gpio.c | 272
>++++++++++++++++++---
> include/asm-blackfin/mach-bf533/bfin_serial_5xx.h | 11 +-
> include/asm-blackfin/mach-bf537/bfin_serial_5xx.h | 23 +-
> include/asm-blackfin/mach-bf537/portmux.h | 2 +-
> include/asm-blackfin/mach-bf561/bfin_serial_5xx.h | 11 +-
> 5 files changed, 274 insertions(+), 45 deletions(-)
>
>diff --git a/arch/blackfin/kernel/bfin_gpio.c
>b/arch/blackfin/kernel/bfin_gpio.c
>index bafcfa5..9f30948 100644
>--- a/arch/blackfin/kernel/bfin_gpio.c
>+++ b/arch/blackfin/kernel/bfin_gpio.c
>@@ -84,6 +84,7 @@
> #include <linux/err.h>
> #include <asm/blackfin.h>
> #include <asm/gpio.h>
>+#include <asm/portmux.h>
> #include <linux/irq.h>
>
> #ifdef BF533_FAMILY
>@@ -115,7 +116,11 @@ static struct gpio_port_t
>*gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
> };
> #endif
>
>-static unsigned short reserved_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
>+static unsigned short
reserved_gpio_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
>+static unsigned short reserved_peri_map[gpio_bank(MAX_BLACKFIN_GPIOS +
>16)];
>+char *str_ident = NULL;
>+
>+#define RESOURCE_LABEL_SIZE 16
>
> #ifdef CONFIG_PM
> static unsigned short wakeup_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
>@@ -143,13 +148,39 @@ inline int check_gpio(unsigned short gpio)
> return 0;
> }
>
>+static void set_label(unsigned short ident, const char *label)
>+{
>+
>+ if (label && str_ident) {
>+ strncpy(str_ident + ident * RESOURCE_LABEL_SIZE, label,
>+ RESOURCE_LABEL_SIZE);
>+ str_ident[ident * RESOURCE_LABEL_SIZE +
>+ RESOURCE_LABEL_SIZE - 1] = 0;
>+ }
>+}
>+
>+static char *get_label(unsigned short ident)
>+{
>+ if (!str_ident)
>+ return "UNKNOWN";
>+
>+ return (str_ident[ident * RESOURCE_LABEL_SIZE] ?
>+ (str_ident + ident * RESOURCE_LABEL_SIZE) : "UNKNOWN");
>+}
>+
>+static int cmp_label(unsigned short ident, const char *label)
>+{
>+ if (label && str_ident)
>+ return strncmp(str_ident + ident * RESOURCE_LABEL_SIZE,
>+ label, strlen(label));
>+ else
>+ return -EINVAL;
>+}
>+
> #ifdef BF537_FAMILY
> static void port_setup(unsigned short gpio, unsigned short usage)
> {
> if (usage == GPIO_USAGE) {
>- if (*port_fer[gpio_bank(gpio)] & gpio_bit(gpio))
>- printk(KERN_WARNING "bfin-gpio: Possible
Conflict with
>Peripheral "
>- "usage and GPIO %d detected!\n", gpio);
> *port_fer[gpio_bank(gpio)] &= ~gpio_bit(gpio);
> } else
> *port_fer[gpio_bank(gpio)] |= gpio_bit(gpio);
>@@ -159,6 +190,56 @@ static void port_setup(unsigned short gpio,
unsigned
>short usage)
> # define port_setup(...) do { } while (0)
> #endif
>
>+#ifdef BF537_FAMILY
>+
>+#define PMUX_LUT_RES 0
>+#define PMUX_LUT_OFFSET 1
>+#define PMUX_LUT_ENTRIES 41
>+#define PMUX_LUT_SIZE 2
>+
>+static unsigned short port_mux_lut[PMUX_LUT_ENTRIES][PMUX_LUT_SIZE] =
{
>+ {P_PPI0_D13, 11}, {P_PPI0_D14, 11}, {P_PPI0_D15, 11},
>+ {P_SPORT1_TFS, 11}, {P_SPORT1_TSCLK, 11}, {P_SPORT1_DTPRI, 11},
>+ {P_PPI0_D10, 10}, {P_PPI0_D11, 10}, {P_PPI0_D12, 10},
>+ {P_SPORT1_RSCLK, 10}, {P_SPORT1_RFS, 10}, {P_SPORT1_DRPRI, 10},
>+ {P_PPI0_D8, 9}, {P_PPI0_D9, 9}, {P_SPORT1_DRSEC, 9},
>+ {P_SPORT1_DTSEC, 9}, {P_TMR2, 8}, {P_PPI0_FS3, 8}, {P_TMR3, 7},
>+ {P_SPI0_SSEL4, 7}, {P_TMR4, 6}, {P_SPI0_SSEL5, 6}, {P_TMR5, 5},
>+ {P_SPI0_SSEL6, 5}, {P_UART1_RX, 4}, {P_UART1_TX, 4}, {P_TMR6,
4},
>+ {P_TMR7, 4}, {P_UART0_RX, 3}, {P_UART0_TX, 3}, {P_DMAR0, 3},
>+ {P_DMAR1, 3}, {P_SPORT0_DTSEC, 1}, {P_SPORT0_DRSEC, 1},
>+ {P_CAN0_RX, 1}, {P_CAN0_TX, 1}, {P_SPI0_SSEL7, 1},
>+ {P_SPORT0_TFS, 0}, {P_SPORT0_DTPRI, 0}, {P_SPI0_SSEL2, 0},
>+ {P_SPI0_SSEL3, 0}
>+};
>+
>+static void portmux_setup(unsigned short per, unsigned short function)
>+{
>+ u16 y, muxreg, offset;
>+
>+ for (y = 0; y < PMUX_LUT_ENTRIES; y++) {
>+ if (port_mux_lut[y][PMUX_LUT_RES] == per) {
>+
>+ /* SET PORTMUX REG */
>+
>+ offset = port_mux_lut[y][PMUX_LUT_OFFSET];
>+ muxreg = bfin_read_PORT_MUX();
>+
>+ if (offset != 1) {
>+ muxreg &= ~(1 << offset);
>+ } else {
>+ muxreg &= ~(3 << 1);
>+ }
>+
>+ muxreg |= (function << offset);
>+ bfin_write_PORT_MUX(muxreg);
>+ }
>+ }
>+}
>+
>+#else
>+# define portmux_setup(...) do { } while (0)
>+#endif
>
> static void default_gpio(unsigned short gpio)
> {
>@@ -179,22 +260,15 @@ static void default_gpio(unsigned short gpio)
>
> static int __init bfin_gpio_init(void)
> {
>- int i;
>-
>- printk(KERN_INFO "Blackfin GPIO Controller\n");
>
>- for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE)
>- reserved_map[gpio_bank(i)] = 0;
>+ str_ident = kzalloc(RESOURCE_LABEL_SIZE * 256, GFP_KERNEL);
>+ if (!str_ident)
>+ return -ENOMEM;
>
>-#if defined(BF537_FAMILY) && (defined(CONFIG_BFIN_MAC) ||
>defined(CONFIG_BFIN_MAC_MODULE))
>-# if defined(CONFIG_BFIN_MAC_RMII)
>- reserved_map[gpio_bank(PORT_H)] = 0xC373;
>-# else
>- reserved_map[gpio_bank(PORT_H)] = 0xFFFF;
>-# endif
>-#endif
>+ printk(KERN_INFO "Blackfin GPIO Controller\n");
>
> return 0;
>+
> }
>
> arch_initcall(bfin_gpio_init);
>@@ -223,7 +297,7 @@ arch_initcall(bfin_gpio_init);
> void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \
> { \
> unsigned long flags; \
>- BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
>+ BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
\
> local_irq_save(flags); \
> if (arg) \
> gpio_bankb[gpio_bank(gpio)]->name |= gpio_bit(gpio); \
>@@ -243,7 +317,7 @@ SET_GPIO(both)
> #define SET_GPIO_SC(name) \
> void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \
> { \
>- BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
>+ BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
\
> if (arg) \
> gpio_bankb[gpio_bank(gpio)]->name ## _set =
gpio_bit(gpio); \
> else \
>@@ -258,7 +332,7 @@ SET_GPIO_SC(maskb)
> void set_gpio_data(unsigned short gpio, unsigned short arg)
> {
> unsigned long flags;
>- BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
>+ BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
> local_irq_save(flags);
> if (arg)
> gpio_bankb[gpio_bank(gpio)]->data_set = gpio_bit(gpio);
>@@ -277,7 +351,7 @@ SET_GPIO_SC(data)
> void set_gpio_toggle(unsigned short gpio)
> {
> unsigned long flags;
>- BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
>+ BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
> local_irq_save(flags);
> gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio);
> bfin_read_CHIPID();
>@@ -286,7 +360,7 @@ void set_gpio_toggle(unsigned short gpio)
> #else
> void set_gpio_toggle(unsigned short gpio)
> {
>- BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
>+ BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
> gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio);
> }
> #endif
>@@ -350,7 +424,7 @@ unsigned short get_gpio_data(unsigned short gpio)
> {
> unsigned long flags;
> unsigned short ret;
>- BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
>+ BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
> local_irq_save(flags);
> ret = 0x01 & (gpio_bankb[gpio_bank(gpio)]->data >>
gpio_sub_n(gpio));
> bfin_read_CHIPID();
>@@ -494,13 +568,14 @@ u32 gpio_pm_setup(void)
> gpio_bank_saved[bank].dir =
gpio_bankb[bank]->dir;
> gpio_bank_saved[bank].edge =
gpio_bankb[bank]->edge;
> gpio_bank_saved[bank].both =
gpio_bankb[bank]->both;
>- gpio_bank_saved[bank].reserved =
reserved_map[bank];
>+ gpio_bank_saved[bank].reserved =
>+ reserved_gpio_map[bank];
>
> gpio = i;
>
> while (mask) {
> if (mask & 1) {
>- reserved_map[gpio_bank(gpio)] |=
>+
reserved_gpio_map[gpio_bank(gpio)] |=
> gpio_bit(gpio);
> bfin_gpio_wakeup_type(gpio,
> wakeup_flags_map[gpio]);
>@@ -540,7 +615,8 @@ void gpio_pm_restore(void)
> gpio_bankb[bank]->edge =
gpio_bank_saved[bank].edge;
> gpio_bankb[bank]->both =
gpio_bank_saved[bank].both;
>
>- reserved_map[bank] =
gpio_bank_saved[bank].reserved;
>+ reserved_gpio_map[bank] =
>+ gpio_bank_saved[bank].reserved;
>
> }
>
>@@ -550,6 +626,140 @@ void gpio_pm_restore(void)
>
> #endif
>
>+
>+
>+
>+int peripheral_request(unsigned short per, const char *label)
>+{
>+ unsigned long flags;
>+ unsigned short ident = P_IDENT(per);
>+
>+ /*
>+ * Don't cares are pins with only one dedicated function
>+ */
>+
>+ if (per & P_DONTCARE)
>+ return 0;
>+
>+ if (!(per & P_DEFINED))
>+ return -ENODEV;
>+
>+ if (check_gpio(ident) < 0)
>+ return -EINVAL;
>+
>+ local_irq_save(flags);
>+
>+ if (unlikely(reserved_gpio_map[gpio_bank(ident)] &
gpio_bit(ident)))
>{
>+ printk(KERN_ERR
>+ "%s: Peripheral %d is already reserved as GPIO by
%s
>!\n",
>+ __FUNCTION__, ident, get_label(ident));
>+ dump_stack();
>+ local_irq_restore(flags);
>+ return -EBUSY;
>+ }
>+
>+ if (unlikely(reserved_peri_map[gpio_bank(ident)] &
gpio_bit(ident)))
>{
>+
>+ /*
>+ * Pin functions like AMC address strobes my
>+ * be requested and used by several drivers
>+ */
>+
>+ if (!(per & P_MAYSHARE)) {
>+
>+ /*
>+ * Allow that the identical pin function can
>+ * be requested from the same driver twice
>+ */
>+
>+ if (cmp_label(ident, label) == 0)
>+ goto anyway;
>+
>+ printk(KERN_ERR
>+ "%s: Peripheral %d function %d is
already"
>+ "reserved by %s !\n",
>+ __FUNCTION__, ident, P_FUNCT2MUX(per),
>+ get_label(ident));
>+ dump_stack();
>+ local_irq_restore(flags);
>+ return -EBUSY;
>+ }
>+
>+ }
>+
>+anyway:
>+
>+
>+ portmux_setup(per, P_FUNCT2MUX(per));
>+
>+ port_setup(ident, PERIPHERAL_USAGE);
>+
>+ reserved_peri_map[gpio_bank(ident)] |= gpio_bit(ident);
>+ local_irq_restore(flags);
>+ set_label(ident, label);
>+
>+ return 0;
>+}
>+EXPORT_SYMBOL(peripheral_request);
>+
>+int peripheral_request_list(unsigned short per[], const char *label)
>+{
>+ u16 cnt;
>+ int ret;
>+
>+ for (cnt = 0; per[cnt] != 0; cnt++) {
>+ ret = peripheral_request(per[cnt], label);
>+ if (ret < 0)
>+ return ret;
>+ }
>+
>+ return 0;
>+}
>+EXPORT_SYMBOL(peripheral_request_list);
>+
>+void peripheral_free(unsigned short per)
>+{
>+ unsigned long flags;
>+ unsigned short ident = P_IDENT(per);
>+
>+ if (per & P_DONTCARE)
>+ return;
>+
>+ if (!(per & P_DEFINED))
>+ return;
>+
>+ if (check_gpio(ident) < 0)
>+ return;
>+
>+ local_irq_save(flags);
>+
>+ if (unlikely(!(reserved_peri_map[gpio_bank(ident)]
>+ & gpio_bit(ident)))) {
>+ local_irq_restore(flags);
>+ return;
>+ }
>+
>+ if (!(per & P_MAYSHARE)) {
>+ port_setup(ident, GPIO_USAGE);
>+ }
>+
>+ reserved_peri_map[gpio_bank(ident)] &= ~gpio_bit(ident);
>+
>+ local_irq_restore(flags);
>+}
>+EXPORT_SYMBOL(peripheral_free);
>+
>+void peripheral_free_list(unsigned short per[])
>+{
>+ u16 cnt;
>+
>+ for (cnt = 0; per[cnt] != 0; cnt++) {
>+ peripheral_free(per[cnt]);
>+ }
>+
>+}
>+EXPORT_SYMBOL(peripheral_free_list);
>+
> /***********************************************************
> *
> * FUNCTIONS: Blackfin GPIO Driver
>@@ -574,13 +784,13 @@ int gpio_request(unsigned short gpio, const char
>*label)
>
> local_irq_save(flags);
>
>- if (unlikely(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
>+ if (unlikely(reserved_gpio_map[gpio_bank(gpio)] &
gpio_bit(gpio))) {
> printk(KERN_ERR "bfin-gpio: GPIO %d is already
reserved!\n",
>gpio);
> dump_stack();
> local_irq_restore(flags);
> return -EBUSY;
> }
>- reserved_map[gpio_bank(gpio)] |= gpio_bit(gpio);
>+ reserved_gpio_map[gpio_bank(gpio)] |= gpio_bit(gpio);
>
> local_irq_restore(flags);
>
>@@ -599,7 +809,7 @@ void gpio_free(unsigned short gpio)
>
> local_irq_save(flags);
>
>- if (unlikely(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))))
{
>+ if (unlikely(!(reserved_gpio_map[gpio_bank(gpio)] &
gpio_bit(gpio))))
>{
> printk(KERN_ERR "bfin-gpio: GPIO %d wasn't reserved!\n",
gpio);
> dump_stack();
> local_irq_restore(flags);
>@@ -608,7 +818,7 @@ void gpio_free(unsigned short gpio)
>
> default_gpio(gpio);
>
>- reserved_map[gpio_bank(gpio)] &= ~gpio_bit(gpio);
>+ reserved_gpio_map[gpio_bank(gpio)] &= ~gpio_bit(gpio);
>
> local_irq_restore(flags);
> }
>@@ -618,7 +828,7 @@ void gpio_direction_input(unsigned short gpio)
> {
> unsigned long flags;
>
>- BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
>+ BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
>
> local_irq_save(flags);
> gpio_bankb[gpio_bank(gpio)]->dir &= ~gpio_bit(gpio);
>@@ -631,7 +841,7 @@ void gpio_direction_output(unsigned short gpio)
> {
> unsigned long flags;
>
>- BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
>+ BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
>
> local_irq_save(flags);
> gpio_bankb[gpio_bank(gpio)]->inen &= ~gpio_bit(gpio);
>diff --git a/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
>b/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
>index e043caf..69b9f8e 100644
>--- a/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
>+++ b/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
>@@ -1,5 +1,6 @@
> #include <linux/serial.h>
> #include <asm/dma.h>
>+#include <asm/portmux.h>
>
> #define NR_PORTS 1
>
>@@ -92,18 +93,24 @@ struct bfin_serial_res bfin_serial_resource[] = {
> }
> };
>
>+#define DRIVER_NAME "bfin-uart"
>
> int nr_ports = NR_PORTS;
> static void bfin_serial_hw_init(struct bfin_serial_port *uart)
> {
>
>+#ifdef CONFIG_SERIAL_BFIN_UART0
>+ peripheral_request(P_UART0_TX, DRIVER_NAME);
>+ peripheral_request(P_UART0_RX, DRIVER_NAME);
>+#endif
>+
> #ifdef CONFIG_SERIAL_BFIN_CTSRTS
> if (uart->cts_pin >= 0) {
>- gpio_request(uart->cts_pin, NULL);
>+ gpio_request(uart->cts_pin, DRIVER_NAME);
> gpio_direction_input(uart->cts_pin);
> }
> if (uart->rts_pin >= 0) {
>- gpio_request(uart->rts_pin, NULL);
>+ gpio_request(uart->rts_pin, DRIVER_NAME);
> gpio_direction_input(uart->rts_pin);
> }
> #endif
>diff --git a/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
>b/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
>index 8f5d9c4..6fb328f 100644
>--- a/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
>+++ b/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
>@@ -1,5 +1,6 @@
> #include <linux/serial.h>
> #include <asm/dma.h>
>+#include <asm/portmux.h>
>
> #define NR_PORTS 2
>
>@@ -122,25 +123,29 @@ struct bfin_serial_res bfin_serial_resource[] = {
>
> int nr_ports = ARRAY_SIZE(bfin_serial_resource);
>
>+#define DRIVER_NAME "bfin-uart"
>+
> static void bfin_serial_hw_init(struct bfin_serial_port *uart)
> {
>- unsigned short val;
>- val = bfin_read16(BFIN_PORT_MUX);
>- val &= ~(PFDE | PFTE);
>- bfin_write16(BFIN_PORT_MUX, val);
>
>- val = bfin_read16(PORTF_FER);
>- val |= 0xF;
>- bfin_write16(PORTF_FER, val);
>+#ifdef CONFIG_SERIAL_BFIN_UART0
>+ peripheral_request(P_UART0_TX, DRIVER_NAME);
>+ peripheral_request(P_UART0_RX, DRIVER_NAME);
>+#endif
>+
>+#ifdef CONFIG_SERIAL_BFIN_UART1
>+ peripheral_request(P_UART1_TX, DRIVER_NAME);
>+ peripheral_request(P_UART1_RX, DRIVER_NAME);
>+#endif
>
> #ifdef CONFIG_SERIAL_BFIN_CTSRTS
> if (uart->cts_pin >= 0) {
>- gpio_request(uart->cts_pin, NULL);
>+ gpio_request(uart->cts_pin, DRIVER_NAME);
> gpio_direction_input(uart->cts_pin);
> }
>
> if (uart->rts_pin >= 0) {
>- gpio_request(uart->rts_pin, NULL);
>+ gpio_request(uart->rts_pin, DRIVER_NAME);
> gpio_direction_output(uart->rts_pin);
> }
> #endif
>diff --git a/include/asm-blackfin/mach-bf537/portmux.h b/include/asm-
>blackfin/mach-bf537/portmux.h
>index 23e13c5..7daa247 100644
>--- a/include/asm-blackfin/mach-bf537/portmux.h
>+++ b/include/asm-blackfin/mach-bf537/portmux.h
>@@ -106,4 +106,4 @@
> #define P_SPI0_SSEL2 (P_DEFINED | P_IDENT(PORT_PJ11) | P_FUNCT(1))
> #define P_SPI0_SSEL7 (P_DEFINED | P_IDENT(PORT_PJ5) | P_FUNCT(2))
>
>-#endif /* _MACH_PORTMUX_H_ */
>+#endif /* _MACH_PORTMUX_H_ */
>diff --git a/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
>b/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
>index e043caf..69b9f8e 100644
>--- a/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
>+++ b/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
>@@ -1,5 +1,6 @@
> #include <linux/serial.h>
> #include <asm/dma.h>
>+#include <asm/portmux.h>
>
> #define NR_PORTS 1
>
>@@ -92,18 +93,24 @@ struct bfin_serial_res bfin_serial_resource[] = {
> }
> };
>
>+#define DRIVER_NAME "bfin-uart"
>
> int nr_ports = NR_PORTS;
> static void bfin_serial_hw_init(struct bfin_serial_port *uart)
> {
>
>+#ifdef CONFIG_SERIAL_BFIN_UART0
>+ peripheral_request(P_UART0_TX, DRIVER_NAME);
>+ peripheral_request(P_UART0_RX, DRIVER_NAME);
>+#endif
>+
> #ifdef CONFIG_SERIAL_BFIN_CTSRTS
> if (uart->cts_pin >= 0) {
>- gpio_request(uart->cts_pin, NULL);
>+ gpio_request(uart->cts_pin, DRIVER_NAME);
> gpio_direction_input(uart->cts_pin);
> }
> if (uart->rts_pin >= 0) {
>- gpio_request(uart->rts_pin, NULL);
>+ gpio_request(uart->rts_pin, DRIVER_NAME);
> gpio_direction_input(uart->rts_pin);
> }
> #endif
>--
>1.5.2
^ permalink raw reply [flat|nested] 8+ messages in thread* RE: [PATCH 01/12] Blackfin arch: add peripheral resource allocation support
2007-08-08 7:18 Hennerich, Michael
@ 2007-08-08 7:49 ` Bryan Wu
0 siblings, 0 replies; 8+ messages in thread
From: Bryan Wu @ 2007-08-08 7:49 UTC (permalink / raw)
To: Hennerich, Michael
Cc: Bryan Wu, torvalds, linux-kernel, akpm, dbrownell,
Michael Hennerich
On Wed, 2007-08-08 at 08:18 +0100, Hennerich, Michael wrote:
> Bryan,
>
> This patch doesn't seem to be up to date.
> It doesn't include the changes made based on feedback from Joe Perches.
>
> Please see our SVN:
> Modified: trunk/arch/blackfin/kernel/bfin_gpio.c (3489 => 3490)
>
Yes, I got all changes in my local git-tree.
Actually I send out the patches ordered by time, next time I will send
out patch based on Joe's idea.
Please don't worry about this, I'll try my best to make sure never
missing the changes.
Thanks
- Bryan Wu
> -Michael
>
> >-----Original Message-----
> >From: Bryan Wu [mailto:bryan.wu@analog.com]
> >Sent: Mittwoch, 8. August 2007 05:35
> >To: torvalds@linux-foundation.org; linux-kernel@vger.kernel.org;
> >akpm@linux-foundation.org
> >Cc: dbrownell@users.sourceforge.net; Michael Hennerich; Bryan Wu
> >Subject: [PATCH 01/12] Blackfin arch: add peripheral resource allocation
> >support
> >
> >From: Michael Hennerich <michael.hennerich@analog.com>
> >
> >Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
> >Signed-off-by: Bryan Wu <bryan.wu@analog.com>
> >---
> > arch/blackfin/kernel/bfin_gpio.c | 272
> >++++++++++++++++++---
> > include/asm-blackfin/mach-bf533/bfin_serial_5xx.h | 11 +-
> > include/asm-blackfin/mach-bf537/bfin_serial_5xx.h | 23 +-
> > include/asm-blackfin/mach-bf537/portmux.h | 2 +-
> > include/asm-blackfin/mach-bf561/bfin_serial_5xx.h | 11 +-
> > 5 files changed, 274 insertions(+), 45 deletions(-)
> >
> >diff --git a/arch/blackfin/kernel/bfin_gpio.c
> >b/arch/blackfin/kernel/bfin_gpio.c
> >index bafcfa5..9f30948 100644
> >--- a/arch/blackfin/kernel/bfin_gpio.c
> >+++ b/arch/blackfin/kernel/bfin_gpio.c
> >@@ -84,6 +84,7 @@
> > #include <linux/err.h>
> > #include <asm/blackfin.h>
> > #include <asm/gpio.h>
> >+#include <asm/portmux.h>
> > #include <linux/irq.h>
> >
> > #ifdef BF533_FAMILY
> >@@ -115,7 +116,11 @@ static struct gpio_port_t
> >*gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
> > };
> > #endif
> >
> >-static unsigned short reserved_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
> >+static unsigned short reserved_gpio_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
> >+static unsigned short reserved_peri_map[gpio_bank(MAX_BLACKFIN_GPIOS +
> >16)];
> >+char *str_ident = NULL;
> >+
> >+#define RESOURCE_LABEL_SIZE 16
> >
> > #ifdef CONFIG_PM
> > static unsigned short wakeup_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
> >@@ -143,13 +148,39 @@ inline int check_gpio(unsigned short gpio)
> > return 0;
> > }
> >
> >+static void set_label(unsigned short ident, const char *label)
> >+{
> >+
> >+ if (label && str_ident) {
> >+ strncpy(str_ident + ident * RESOURCE_LABEL_SIZE, label,
> >+ RESOURCE_LABEL_SIZE);
> >+ str_ident[ident * RESOURCE_LABEL_SIZE +
> >+ RESOURCE_LABEL_SIZE - 1] = 0;
> >+ }
> >+}
> >+
> >+static char *get_label(unsigned short ident)
> >+{
> >+ if (!str_ident)
> >+ return "UNKNOWN";
> >+
> >+ return (str_ident[ident * RESOURCE_LABEL_SIZE] ?
> >+ (str_ident + ident * RESOURCE_LABEL_SIZE) : "UNKNOWN");
> >+}
> >+
> >+static int cmp_label(unsigned short ident, const char *label)
> >+{
> >+ if (label && str_ident)
> >+ return strncmp(str_ident + ident * RESOURCE_LABEL_SIZE,
> >+ label, strlen(label));
> >+ else
> >+ return -EINVAL;
> >+}
> >+
> > #ifdef BF537_FAMILY
> > static void port_setup(unsigned short gpio, unsigned short usage)
> > {
> > if (usage == GPIO_USAGE) {
> >- if (*port_fer[gpio_bank(gpio)] & gpio_bit(gpio))
> >- printk(KERN_WARNING "bfin-gpio: Possible Conflict with
> >Peripheral "
> >- "usage and GPIO %d detected!\n", gpio);
> > *port_fer[gpio_bank(gpio)] &= ~gpio_bit(gpio);
> > } else
> > *port_fer[gpio_bank(gpio)] |= gpio_bit(gpio);
> >@@ -159,6 +190,56 @@ static void port_setup(unsigned short gpio, unsigned
> >short usage)
> > # define port_setup(...) do { } while (0)
> > #endif
> >
> >+#ifdef BF537_FAMILY
> >+
> >+#define PMUX_LUT_RES 0
> >+#define PMUX_LUT_OFFSET 1
> >+#define PMUX_LUT_ENTRIES 41
> >+#define PMUX_LUT_SIZE 2
> >+
> >+static unsigned short port_mux_lut[PMUX_LUT_ENTRIES][PMUX_LUT_SIZE] = {
> >+ {P_PPI0_D13, 11}, {P_PPI0_D14, 11}, {P_PPI0_D15, 11},
> >+ {P_SPORT1_TFS, 11}, {P_SPORT1_TSCLK, 11}, {P_SPORT1_DTPRI, 11},
> >+ {P_PPI0_D10, 10}, {P_PPI0_D11, 10}, {P_PPI0_D12, 10},
> >+ {P_SPORT1_RSCLK, 10}, {P_SPORT1_RFS, 10}, {P_SPORT1_DRPRI, 10},
> >+ {P_PPI0_D8, 9}, {P_PPI0_D9, 9}, {P_SPORT1_DRSEC, 9},
> >+ {P_SPORT1_DTSEC, 9}, {P_TMR2, 8}, {P_PPI0_FS3, 8}, {P_TMR3, 7},
> >+ {P_SPI0_SSEL4, 7}, {P_TMR4, 6}, {P_SPI0_SSEL5, 6}, {P_TMR5, 5},
> >+ {P_SPI0_SSEL6, 5}, {P_UART1_RX, 4}, {P_UART1_TX, 4}, {P_TMR6, 4},
> >+ {P_TMR7, 4}, {P_UART0_RX, 3}, {P_UART0_TX, 3}, {P_DMAR0, 3},
> >+ {P_DMAR1, 3}, {P_SPORT0_DTSEC, 1}, {P_SPORT0_DRSEC, 1},
> >+ {P_CAN0_RX, 1}, {P_CAN0_TX, 1}, {P_SPI0_SSEL7, 1},
> >+ {P_SPORT0_TFS, 0}, {P_SPORT0_DTPRI, 0}, {P_SPI0_SSEL2, 0},
> >+ {P_SPI0_SSEL3, 0}
> >+};
> >+
> >+static void portmux_setup(unsigned short per, unsigned short function)
> >+{
> >+ u16 y, muxreg, offset;
> >+
> >+ for (y = 0; y < PMUX_LUT_ENTRIES; y++) {
> >+ if (port_mux_lut[y][PMUX_LUT_RES] == per) {
> >+
> >+ /* SET PORTMUX REG */
> >+
> >+ offset = port_mux_lut[y][PMUX_LUT_OFFSET];
> >+ muxreg = bfin_read_PORT_MUX();
> >+
> >+ if (offset != 1) {
> >+ muxreg &= ~(1 << offset);
> >+ } else {
> >+ muxreg &= ~(3 << 1);
> >+ }
> >+
> >+ muxreg |= (function << offset);
> >+ bfin_write_PORT_MUX(muxreg);
> >+ }
> >+ }
> >+}
> >+
> >+#else
> >+# define portmux_setup(...) do { } while (0)
> >+#endif
> >
> > static void default_gpio(unsigned short gpio)
> > {
> >@@ -179,22 +260,15 @@ static void default_gpio(unsigned short gpio)
> >
> > static int __init bfin_gpio_init(void)
> > {
> >- int i;
> >-
> >- printk(KERN_INFO "Blackfin GPIO Controller\n");
> >
> >- for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE)
> >- reserved_map[gpio_bank(i)] = 0;
> >+ str_ident = kzalloc(RESOURCE_LABEL_SIZE * 256, GFP_KERNEL);
> >+ if (!str_ident)
> >+ return -ENOMEM;
> >
> >-#if defined(BF537_FAMILY) && (defined(CONFIG_BFIN_MAC) ||
> >defined(CONFIG_BFIN_MAC_MODULE))
> >-# if defined(CONFIG_BFIN_MAC_RMII)
> >- reserved_map[gpio_bank(PORT_H)] = 0xC373;
> >-# else
> >- reserved_map[gpio_bank(PORT_H)] = 0xFFFF;
> >-# endif
> >-#endif
> >+ printk(KERN_INFO "Blackfin GPIO Controller\n");
> >
> > return 0;
> >+
> > }
> >
> > arch_initcall(bfin_gpio_init);
> >@@ -223,7 +297,7 @@ arch_initcall(bfin_gpio_init);
> > void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \
> > { \
> > unsigned long flags; \
> >- BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
> >+ BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
> > local_irq_save(flags); \
> > if (arg) \
> > gpio_bankb[gpio_bank(gpio)]->name |= gpio_bit(gpio); \
> >@@ -243,7 +317,7 @@ SET_GPIO(both)
> > #define SET_GPIO_SC(name) \
> > void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \
> > { \
> >- BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
> >+ BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
> > if (arg) \
> > gpio_bankb[gpio_bank(gpio)]->name ## _set = gpio_bit(gpio); \
> > else \
> >@@ -258,7 +332,7 @@ SET_GPIO_SC(maskb)
> > void set_gpio_data(unsigned short gpio, unsigned short arg)
> > {
> > unsigned long flags;
> >- BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
> >+ BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
> > local_irq_save(flags);
> > if (arg)
> > gpio_bankb[gpio_bank(gpio)]->data_set = gpio_bit(gpio);
> >@@ -277,7 +351,7 @@ SET_GPIO_SC(data)
> > void set_gpio_toggle(unsigned short gpio)
> > {
> > unsigned long flags;
> >- BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
> >+ BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
> > local_irq_save(flags);
> > gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio);
> > bfin_read_CHIPID();
> >@@ -286,7 +360,7 @@ void set_gpio_toggle(unsigned short gpio)
> > #else
> > void set_gpio_toggle(unsigned short gpio)
> > {
> >- BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
> >+ BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
> > gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio);
> > }
> > #endif
> >@@ -350,7 +424,7 @@ unsigned short get_gpio_data(unsigned short gpio)
> > {
> > unsigned long flags;
> > unsigned short ret;
> >- BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
> >+ BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
> > local_irq_save(flags);
> > ret = 0x01 & (gpio_bankb[gpio_bank(gpio)]->data >> gpio_sub_n(gpio));
> > bfin_read_CHIPID();
> >@@ -494,13 +568,14 @@ u32 gpio_pm_setup(void)
> > gpio_bank_saved[bank].dir = gpio_bankb[bank]->dir;
> > gpio_bank_saved[bank].edge = gpio_bankb[bank]->edge;
> > gpio_bank_saved[bank].both = gpio_bankb[bank]->both;
> >- gpio_bank_saved[bank].reserved = reserved_map[bank];
> >+ gpio_bank_saved[bank].reserved =
> >+ reserved_gpio_map[bank];
> >
> > gpio = i;
> >
> > while (mask) {
> > if (mask & 1) {
> >- reserved_map[gpio_bank(gpio)] |=
> >+ reserved_gpio_map[gpio_bank(gpio)] |=
> > gpio_bit(gpio);
> > bfin_gpio_wakeup_type(gpio,
> > wakeup_flags_map[gpio]);
> >@@ -540,7 +615,8 @@ void gpio_pm_restore(void)
> > gpio_bankb[bank]->edge = gpio_bank_saved[bank].edge;
> > gpio_bankb[bank]->both = gpio_bank_saved[bank].both;
> >
> >- reserved_map[bank] = gpio_bank_saved[bank].reserved;
> >+ reserved_gpio_map[bank] =
> >+ gpio_bank_saved[bank].reserved;
> >
> > }
> >
> >@@ -550,6 +626,140 @@ void gpio_pm_restore(void)
> >
> > #endif
> >
> >+
> >+
> >+
> >+int peripheral_request(unsigned short per, const char *label)
> >+{
> >+ unsigned long flags;
> >+ unsigned short ident = P_IDENT(per);
> >+
> >+ /*
> >+ * Don't cares are pins with only one dedicated function
> >+ */
> >+
> >+ if (per & P_DONTCARE)
> >+ return 0;
> >+
> >+ if (!(per & P_DEFINED))
> >+ return -ENODEV;
> >+
> >+ if (check_gpio(ident) < 0)
> >+ return -EINVAL;
> >+
> >+ local_irq_save(flags);
> >+
> >+ if (unlikely(reserved_gpio_map[gpio_bank(ident)] & gpio_bit(ident)))
> >{
> >+ printk(KERN_ERR
> >+ "%s: Peripheral %d is already reserved as GPIO by %s
> >!\n",
> >+ __FUNCTION__, ident, get_label(ident));
> >+ dump_stack();
> >+ local_irq_restore(flags);
> >+ return -EBUSY;
> >+ }
> >+
> >+ if (unlikely(reserved_peri_map[gpio_bank(ident)] & gpio_bit(ident)))
> >{
> >+
> >+ /*
> >+ * Pin functions like AMC address strobes my
> >+ * be requested and used by several drivers
> >+ */
> >+
> >+ if (!(per & P_MAYSHARE)) {
> >+
> >+ /*
> >+ * Allow that the identical pin function can
> >+ * be requested from the same driver twice
> >+ */
> >+
> >+ if (cmp_label(ident, label) == 0)
> >+ goto anyway;
> >+
> >+ printk(KERN_ERR
> >+ "%s: Peripheral %d function %d is already"
> >+ "reserved by %s !\n",
> >+ __FUNCTION__, ident, P_FUNCT2MUX(per),
> >+ get_label(ident));
> >+ dump_stack();
> >+ local_irq_restore(flags);
> >+ return -EBUSY;
> >+ }
> >+
> >+ }
> >+
> >+anyway:
> >+
> >+
> >+ portmux_setup(per, P_FUNCT2MUX(per));
> >+
> >+ port_setup(ident, PERIPHERAL_USAGE);
> >+
> >+ reserved_peri_map[gpio_bank(ident)] |= gpio_bit(ident);
> >+ local_irq_restore(flags);
> >+ set_label(ident, label);
> >+
> >+ return 0;
> >+}
> >+EXPORT_SYMBOL(peripheral_request);
> >+
> >+int peripheral_request_list(unsigned short per[], const char *label)
> >+{
> >+ u16 cnt;
> >+ int ret;
> >+
> >+ for (cnt = 0; per[cnt] != 0; cnt++) {
> >+ ret = peripheral_request(per[cnt], label);
> >+ if (ret < 0)
> >+ return ret;
> >+ }
> >+
> >+ return 0;
> >+}
> >+EXPORT_SYMBOL(peripheral_request_list);
> >+
> >+void peripheral_free(unsigned short per)
> >+{
> >+ unsigned long flags;
> >+ unsigned short ident = P_IDENT(per);
> >+
> >+ if (per & P_DONTCARE)
> >+ return;
> >+
> >+ if (!(per & P_DEFINED))
> >+ return;
> >+
> >+ if (check_gpio(ident) < 0)
> >+ return;
> >+
> >+ local_irq_save(flags);
> >+
> >+ if (unlikely(!(reserved_peri_map[gpio_bank(ident)]
> >+ & gpio_bit(ident)))) {
> >+ local_irq_restore(flags);
> >+ return;
> >+ }
> >+
> >+ if (!(per & P_MAYSHARE)) {
> >+ port_setup(ident, GPIO_USAGE);
> >+ }
> >+
> >+ reserved_peri_map[gpio_bank(ident)] &= ~gpio_bit(ident);
> >+
> >+ local_irq_restore(flags);
> >+}
> >+EXPORT_SYMBOL(peripheral_free);
> >+
> >+void peripheral_free_list(unsigned short per[])
> >+{
> >+ u16 cnt;
> >+
> >+ for (cnt = 0; per[cnt] != 0; cnt++) {
> >+ peripheral_free(per[cnt]);
> >+ }
> >+
> >+}
> >+EXPORT_SYMBOL(peripheral_free_list);
> >+
> > /***********************************************************
> > *
> > * FUNCTIONS: Blackfin GPIO Driver
> >@@ -574,13 +784,13 @@ int gpio_request(unsigned short gpio, const char
> >*label)
> >
> > local_irq_save(flags);
> >
> >- if (unlikely(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
> >+ if (unlikely(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
> > printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved!\n",
> >gpio);
> > dump_stack();
> > local_irq_restore(flags);
> > return -EBUSY;
> > }
> >- reserved_map[gpio_bank(gpio)] |= gpio_bit(gpio);
> >+ reserved_gpio_map[gpio_bank(gpio)] |= gpio_bit(gpio);
> >
> > local_irq_restore(flags);
> >
> >@@ -599,7 +809,7 @@ void gpio_free(unsigned short gpio)
> >
> > local_irq_save(flags);
> >
> >- if (unlikely(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)))) {
> >+ if (unlikely(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))))
> >{
> > printk(KERN_ERR "bfin-gpio: GPIO %d wasn't reserved!\n", gpio);
> > dump_stack();
> > local_irq_restore(flags);
> >@@ -608,7 +818,7 @@ void gpio_free(unsigned short gpio)
> >
> > default_gpio(gpio);
> >
> >- reserved_map[gpio_bank(gpio)] &= ~gpio_bit(gpio);
> >+ reserved_gpio_map[gpio_bank(gpio)] &= ~gpio_bit(gpio);
> >
> > local_irq_restore(flags);
> > }
> >@@ -618,7 +828,7 @@ void gpio_direction_input(unsigned short gpio)
> > {
> > unsigned long flags;
> >
> >- BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
> >+ BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
> >
> > local_irq_save(flags);
> > gpio_bankb[gpio_bank(gpio)]->dir &= ~gpio_bit(gpio);
> >@@ -631,7 +841,7 @@ void gpio_direction_output(unsigned short gpio)
> > {
> > unsigned long flags;
> >
> >- BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
> >+ BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
> >
> > local_irq_save(flags);
> > gpio_bankb[gpio_bank(gpio)]->inen &= ~gpio_bit(gpio);
> >diff --git a/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
> >b/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
> >index e043caf..69b9f8e 100644
> >--- a/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
> >+++ b/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
> >@@ -1,5 +1,6 @@
> > #include <linux/serial.h>
> > #include <asm/dma.h>
> >+#include <asm/portmux.h>
> >
> > #define NR_PORTS 1
> >
> >@@ -92,18 +93,24 @@ struct bfin_serial_res bfin_serial_resource[] = {
> > }
> > };
> >
> >+#define DRIVER_NAME "bfin-uart"
> >
> > int nr_ports = NR_PORTS;
> > static void bfin_serial_hw_init(struct bfin_serial_port *uart)
> > {
> >
> >+#ifdef CONFIG_SERIAL_BFIN_UART0
> >+ peripheral_request(P_UART0_TX, DRIVER_NAME);
> >+ peripheral_request(P_UART0_RX, DRIVER_NAME);
> >+#endif
> >+
> > #ifdef CONFIG_SERIAL_BFIN_CTSRTS
> > if (uart->cts_pin >= 0) {
> >- gpio_request(uart->cts_pin, NULL);
> >+ gpio_request(uart->cts_pin, DRIVER_NAME);
> > gpio_direction_input(uart->cts_pin);
> > }
> > if (uart->rts_pin >= 0) {
> >- gpio_request(uart->rts_pin, NULL);
> >+ gpio_request(uart->rts_pin, DRIVER_NAME);
> > gpio_direction_input(uart->rts_pin);
> > }
> > #endif
> >diff --git a/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
> >b/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
> >index 8f5d9c4..6fb328f 100644
> >--- a/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
> >+++ b/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
> >@@ -1,5 +1,6 @@
> > #include <linux/serial.h>
> > #include <asm/dma.h>
> >+#include <asm/portmux.h>
> >
> > #define NR_PORTS 2
> >
> >@@ -122,25 +123,29 @@ struct bfin_serial_res bfin_serial_resource[] = {
> >
> > int nr_ports = ARRAY_SIZE(bfin_serial_resource);
> >
> >+#define DRIVER_NAME "bfin-uart"
> >+
> > static void bfin_serial_hw_init(struct bfin_serial_port *uart)
> > {
> >- unsigned short val;
> >- val = bfin_read16(BFIN_PORT_MUX);
> >- val &= ~(PFDE | PFTE);
> >- bfin_write16(BFIN_PORT_MUX, val);
> >
> >- val = bfin_read16(PORTF_FER);
> >- val |= 0xF;
> >- bfin_write16(PORTF_FER, val);
> >+#ifdef CONFIG_SERIAL_BFIN_UART0
> >+ peripheral_request(P_UART0_TX, DRIVER_NAME);
> >+ peripheral_request(P_UART0_RX, DRIVER_NAME);
> >+#endif
> >+
> >+#ifdef CONFIG_SERIAL_BFIN_UART1
> >+ peripheral_request(P_UART1_TX, DRIVER_NAME);
> >+ peripheral_request(P_UART1_RX, DRIVER_NAME);
> >+#endif
> >
> > #ifdef CONFIG_SERIAL_BFIN_CTSRTS
> > if (uart->cts_pin >= 0) {
> >- gpio_request(uart->cts_pin, NULL);
> >+ gpio_request(uart->cts_pin, DRIVER_NAME);
> > gpio_direction_input(uart->cts_pin);
> > }
> >
> > if (uart->rts_pin >= 0) {
> >- gpio_request(uart->rts_pin, NULL);
> >+ gpio_request(uart->rts_pin, DRIVER_NAME);
> > gpio_direction_output(uart->rts_pin);
> > }
> > #endif
> >diff --git a/include/asm-blackfin/mach-bf537/portmux.h b/include/asm-
> >blackfin/mach-bf537/portmux.h
> >index 23e13c5..7daa247 100644
> >--- a/include/asm-blackfin/mach-bf537/portmux.h
> >+++ b/include/asm-blackfin/mach-bf537/portmux.h
> >@@ -106,4 +106,4 @@
> > #define P_SPI0_SSEL2 (P_DEFINED | P_IDENT(PORT_PJ11) | P_FUNCT(1))
> > #define P_SPI0_SSEL7 (P_DEFINED | P_IDENT(PORT_PJ5) | P_FUNCT(2))
> >
> >-#endif /* _MACH_PORTMUX_H_ */
> >+#endif /* _MACH_PORTMUX_H_ */
> >diff --git a/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
> >b/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
> >index e043caf..69b9f8e 100644
> >--- a/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
> >+++ b/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
> >@@ -1,5 +1,6 @@
> > #include <linux/serial.h>
> > #include <asm/dma.h>
> >+#include <asm/portmux.h>
> >
> > #define NR_PORTS 1
> >
> >@@ -92,18 +93,24 @@ struct bfin_serial_res bfin_serial_resource[] = {
> > }
> > };
> >
> >+#define DRIVER_NAME "bfin-uart"
> >
> > int nr_ports = NR_PORTS;
> > static void bfin_serial_hw_init(struct bfin_serial_port *uart)
> > {
> >
> >+#ifdef CONFIG_SERIAL_BFIN_UART0
> >+ peripheral_request(P_UART0_TX, DRIVER_NAME);
> >+ peripheral_request(P_UART0_RX, DRIVER_NAME);
> >+#endif
> >+
> > #ifdef CONFIG_SERIAL_BFIN_CTSRTS
> > if (uart->cts_pin >= 0) {
> >- gpio_request(uart->cts_pin, NULL);
> >+ gpio_request(uart->cts_pin, DRIVER_NAME);
> > gpio_direction_input(uart->cts_pin);
> > }
> > if (uart->rts_pin >= 0) {
> >- gpio_request(uart->rts_pin, NULL);
> >+ gpio_request(uart->rts_pin, DRIVER_NAME);
> > gpio_direction_input(uart->rts_pin);
> > }
> > #endif
> >--
> >1.5.2
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 00/12] Blackfin arch GPIO updating
@ 2007-08-08 3:35 Bryan Wu
2007-08-08 3:35 ` [PATCH 01/12] Blackfin arch: add peripheral resource allocation support Bryan Wu
0 siblings, 1 reply; 8+ messages in thread
From: Bryan Wu @ 2007-08-08 3:35 UTC (permalink / raw)
To: torvalds, linux-kernel, akpm; +Cc: dbrownell
As David mentioned, I send out these series patch to LKML for review.
These patches are related Blackfin arch GPIO updating, not big change at all.
I think it is OK for git-pull in -RC2 or later.
Thanks
- Bryan Wu
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 01/12] Blackfin arch: add peripheral resource allocation support
2007-08-08 3:35 [PATCH 00/12] Blackfin arch GPIO updating Bryan Wu
@ 2007-08-08 3:35 ` Bryan Wu
2007-08-17 18:12 ` David Brownell
0 siblings, 1 reply; 8+ messages in thread
From: Bryan Wu @ 2007-08-08 3:35 UTC (permalink / raw)
To: torvalds, linux-kernel, akpm; +Cc: dbrownell, Michael Hennerich, Bryan Wu
From: Michael Hennerich <michael.hennerich@analog.com>
Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
Signed-off-by: Bryan Wu <bryan.wu@analog.com>
---
arch/blackfin/kernel/bfin_gpio.c | 272 ++++++++++++++++++---
include/asm-blackfin/mach-bf533/bfin_serial_5xx.h | 11 +-
include/asm-blackfin/mach-bf537/bfin_serial_5xx.h | 23 +-
include/asm-blackfin/mach-bf537/portmux.h | 2 +-
include/asm-blackfin/mach-bf561/bfin_serial_5xx.h | 11 +-
5 files changed, 274 insertions(+), 45 deletions(-)
diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c
index bafcfa5..9f30948 100644
--- a/arch/blackfin/kernel/bfin_gpio.c
+++ b/arch/blackfin/kernel/bfin_gpio.c
@@ -84,6 +84,7 @@
#include <linux/err.h>
#include <asm/blackfin.h>
#include <asm/gpio.h>
+#include <asm/portmux.h>
#include <linux/irq.h>
#ifdef BF533_FAMILY
@@ -115,7 +116,11 @@ static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
};
#endif
-static unsigned short reserved_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
+static unsigned short reserved_gpio_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
+static unsigned short reserved_peri_map[gpio_bank(MAX_BLACKFIN_GPIOS + 16)];
+char *str_ident = NULL;
+
+#define RESOURCE_LABEL_SIZE 16
#ifdef CONFIG_PM
static unsigned short wakeup_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
@@ -143,13 +148,39 @@ inline int check_gpio(unsigned short gpio)
return 0;
}
+static void set_label(unsigned short ident, const char *label)
+{
+
+ if (label && str_ident) {
+ strncpy(str_ident + ident * RESOURCE_LABEL_SIZE, label,
+ RESOURCE_LABEL_SIZE);
+ str_ident[ident * RESOURCE_LABEL_SIZE +
+ RESOURCE_LABEL_SIZE - 1] = 0;
+ }
+}
+
+static char *get_label(unsigned short ident)
+{
+ if (!str_ident)
+ return "UNKNOWN";
+
+ return (str_ident[ident * RESOURCE_LABEL_SIZE] ?
+ (str_ident + ident * RESOURCE_LABEL_SIZE) : "UNKNOWN");
+}
+
+static int cmp_label(unsigned short ident, const char *label)
+{
+ if (label && str_ident)
+ return strncmp(str_ident + ident * RESOURCE_LABEL_SIZE,
+ label, strlen(label));
+ else
+ return -EINVAL;
+}
+
#ifdef BF537_FAMILY
static void port_setup(unsigned short gpio, unsigned short usage)
{
if (usage == GPIO_USAGE) {
- if (*port_fer[gpio_bank(gpio)] & gpio_bit(gpio))
- printk(KERN_WARNING "bfin-gpio: Possible Conflict with Peripheral "
- "usage and GPIO %d detected!\n", gpio);
*port_fer[gpio_bank(gpio)] &= ~gpio_bit(gpio);
} else
*port_fer[gpio_bank(gpio)] |= gpio_bit(gpio);
@@ -159,6 +190,56 @@ static void port_setup(unsigned short gpio, unsigned short usage)
# define port_setup(...) do { } while (0)
#endif
+#ifdef BF537_FAMILY
+
+#define PMUX_LUT_RES 0
+#define PMUX_LUT_OFFSET 1
+#define PMUX_LUT_ENTRIES 41
+#define PMUX_LUT_SIZE 2
+
+static unsigned short port_mux_lut[PMUX_LUT_ENTRIES][PMUX_LUT_SIZE] = {
+ {P_PPI0_D13, 11}, {P_PPI0_D14, 11}, {P_PPI0_D15, 11},
+ {P_SPORT1_TFS, 11}, {P_SPORT1_TSCLK, 11}, {P_SPORT1_DTPRI, 11},
+ {P_PPI0_D10, 10}, {P_PPI0_D11, 10}, {P_PPI0_D12, 10},
+ {P_SPORT1_RSCLK, 10}, {P_SPORT1_RFS, 10}, {P_SPORT1_DRPRI, 10},
+ {P_PPI0_D8, 9}, {P_PPI0_D9, 9}, {P_SPORT1_DRSEC, 9},
+ {P_SPORT1_DTSEC, 9}, {P_TMR2, 8}, {P_PPI0_FS3, 8}, {P_TMR3, 7},
+ {P_SPI0_SSEL4, 7}, {P_TMR4, 6}, {P_SPI0_SSEL5, 6}, {P_TMR5, 5},
+ {P_SPI0_SSEL6, 5}, {P_UART1_RX, 4}, {P_UART1_TX, 4}, {P_TMR6, 4},
+ {P_TMR7, 4}, {P_UART0_RX, 3}, {P_UART0_TX, 3}, {P_DMAR0, 3},
+ {P_DMAR1, 3}, {P_SPORT0_DTSEC, 1}, {P_SPORT0_DRSEC, 1},
+ {P_CAN0_RX, 1}, {P_CAN0_TX, 1}, {P_SPI0_SSEL7, 1},
+ {P_SPORT0_TFS, 0}, {P_SPORT0_DTPRI, 0}, {P_SPI0_SSEL2, 0},
+ {P_SPI0_SSEL3, 0}
+};
+
+static void portmux_setup(unsigned short per, unsigned short function)
+{
+ u16 y, muxreg, offset;
+
+ for (y = 0; y < PMUX_LUT_ENTRIES; y++) {
+ if (port_mux_lut[y][PMUX_LUT_RES] == per) {
+
+ /* SET PORTMUX REG */
+
+ offset = port_mux_lut[y][PMUX_LUT_OFFSET];
+ muxreg = bfin_read_PORT_MUX();
+
+ if (offset != 1) {
+ muxreg &= ~(1 << offset);
+ } else {
+ muxreg &= ~(3 << 1);
+ }
+
+ muxreg |= (function << offset);
+ bfin_write_PORT_MUX(muxreg);
+ }
+ }
+}
+
+#else
+# define portmux_setup(...) do { } while (0)
+#endif
static void default_gpio(unsigned short gpio)
{
@@ -179,22 +260,15 @@ static void default_gpio(unsigned short gpio)
static int __init bfin_gpio_init(void)
{
- int i;
-
- printk(KERN_INFO "Blackfin GPIO Controller\n");
- for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE)
- reserved_map[gpio_bank(i)] = 0;
+ str_ident = kzalloc(RESOURCE_LABEL_SIZE * 256, GFP_KERNEL);
+ if (!str_ident)
+ return -ENOMEM;
-#if defined(BF537_FAMILY) && (defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
-# if defined(CONFIG_BFIN_MAC_RMII)
- reserved_map[gpio_bank(PORT_H)] = 0xC373;
-# else
- reserved_map[gpio_bank(PORT_H)] = 0xFFFF;
-# endif
-#endif
+ printk(KERN_INFO "Blackfin GPIO Controller\n");
return 0;
+
}
arch_initcall(bfin_gpio_init);
@@ -223,7 +297,7 @@ arch_initcall(bfin_gpio_init);
void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \
{ \
unsigned long flags; \
- BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
+ BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
local_irq_save(flags); \
if (arg) \
gpio_bankb[gpio_bank(gpio)]->name |= gpio_bit(gpio); \
@@ -243,7 +317,7 @@ SET_GPIO(both)
#define SET_GPIO_SC(name) \
void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \
{ \
- BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
+ BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
if (arg) \
gpio_bankb[gpio_bank(gpio)]->name ## _set = gpio_bit(gpio); \
else \
@@ -258,7 +332,7 @@ SET_GPIO_SC(maskb)
void set_gpio_data(unsigned short gpio, unsigned short arg)
{
unsigned long flags;
- BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+ BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
local_irq_save(flags);
if (arg)
gpio_bankb[gpio_bank(gpio)]->data_set = gpio_bit(gpio);
@@ -277,7 +351,7 @@ SET_GPIO_SC(data)
void set_gpio_toggle(unsigned short gpio)
{
unsigned long flags;
- BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+ BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
local_irq_save(flags);
gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio);
bfin_read_CHIPID();
@@ -286,7 +360,7 @@ void set_gpio_toggle(unsigned short gpio)
#else
void set_gpio_toggle(unsigned short gpio)
{
- BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+ BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio);
}
#endif
@@ -350,7 +424,7 @@ unsigned short get_gpio_data(unsigned short gpio)
{
unsigned long flags;
unsigned short ret;
- BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+ BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
local_irq_save(flags);
ret = 0x01 & (gpio_bankb[gpio_bank(gpio)]->data >> gpio_sub_n(gpio));
bfin_read_CHIPID();
@@ -494,13 +568,14 @@ u32 gpio_pm_setup(void)
gpio_bank_saved[bank].dir = gpio_bankb[bank]->dir;
gpio_bank_saved[bank].edge = gpio_bankb[bank]->edge;
gpio_bank_saved[bank].both = gpio_bankb[bank]->both;
- gpio_bank_saved[bank].reserved = reserved_map[bank];
+ gpio_bank_saved[bank].reserved =
+ reserved_gpio_map[bank];
gpio = i;
while (mask) {
if (mask & 1) {
- reserved_map[gpio_bank(gpio)] |=
+ reserved_gpio_map[gpio_bank(gpio)] |=
gpio_bit(gpio);
bfin_gpio_wakeup_type(gpio,
wakeup_flags_map[gpio]);
@@ -540,7 +615,8 @@ void gpio_pm_restore(void)
gpio_bankb[bank]->edge = gpio_bank_saved[bank].edge;
gpio_bankb[bank]->both = gpio_bank_saved[bank].both;
- reserved_map[bank] = gpio_bank_saved[bank].reserved;
+ reserved_gpio_map[bank] =
+ gpio_bank_saved[bank].reserved;
}
@@ -550,6 +626,140 @@ void gpio_pm_restore(void)
#endif
+
+
+
+int peripheral_request(unsigned short per, const char *label)
+{
+ unsigned long flags;
+ unsigned short ident = P_IDENT(per);
+
+ /*
+ * Don't cares are pins with only one dedicated function
+ */
+
+ if (per & P_DONTCARE)
+ return 0;
+
+ if (!(per & P_DEFINED))
+ return -ENODEV;
+
+ if (check_gpio(ident) < 0)
+ return -EINVAL;
+
+ local_irq_save(flags);
+
+ if (unlikely(reserved_gpio_map[gpio_bank(ident)] & gpio_bit(ident))) {
+ printk(KERN_ERR
+ "%s: Peripheral %d is already reserved as GPIO by %s !\n",
+ __FUNCTION__, ident, get_label(ident));
+ dump_stack();
+ local_irq_restore(flags);
+ return -EBUSY;
+ }
+
+ if (unlikely(reserved_peri_map[gpio_bank(ident)] & gpio_bit(ident))) {
+
+ /*
+ * Pin functions like AMC address strobes my
+ * be requested and used by several drivers
+ */
+
+ if (!(per & P_MAYSHARE)) {
+
+ /*
+ * Allow that the identical pin function can
+ * be requested from the same driver twice
+ */
+
+ if (cmp_label(ident, label) == 0)
+ goto anyway;
+
+ printk(KERN_ERR
+ "%s: Peripheral %d function %d is already"
+ "reserved by %s !\n",
+ __FUNCTION__, ident, P_FUNCT2MUX(per),
+ get_label(ident));
+ dump_stack();
+ local_irq_restore(flags);
+ return -EBUSY;
+ }
+
+ }
+
+anyway:
+
+
+ portmux_setup(per, P_FUNCT2MUX(per));
+
+ port_setup(ident, PERIPHERAL_USAGE);
+
+ reserved_peri_map[gpio_bank(ident)] |= gpio_bit(ident);
+ local_irq_restore(flags);
+ set_label(ident, label);
+
+ return 0;
+}
+EXPORT_SYMBOL(peripheral_request);
+
+int peripheral_request_list(unsigned short per[], const char *label)
+{
+ u16 cnt;
+ int ret;
+
+ for (cnt = 0; per[cnt] != 0; cnt++) {
+ ret = peripheral_request(per[cnt], label);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(peripheral_request_list);
+
+void peripheral_free(unsigned short per)
+{
+ unsigned long flags;
+ unsigned short ident = P_IDENT(per);
+
+ if (per & P_DONTCARE)
+ return;
+
+ if (!(per & P_DEFINED))
+ return;
+
+ if (check_gpio(ident) < 0)
+ return;
+
+ local_irq_save(flags);
+
+ if (unlikely(!(reserved_peri_map[gpio_bank(ident)]
+ & gpio_bit(ident)))) {
+ local_irq_restore(flags);
+ return;
+ }
+
+ if (!(per & P_MAYSHARE)) {
+ port_setup(ident, GPIO_USAGE);
+ }
+
+ reserved_peri_map[gpio_bank(ident)] &= ~gpio_bit(ident);
+
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL(peripheral_free);
+
+void peripheral_free_list(unsigned short per[])
+{
+ u16 cnt;
+
+ for (cnt = 0; per[cnt] != 0; cnt++) {
+ peripheral_free(per[cnt]);
+ }
+
+}
+EXPORT_SYMBOL(peripheral_free_list);
+
/***********************************************************
*
* FUNCTIONS: Blackfin GPIO Driver
@@ -574,13 +784,13 @@ int gpio_request(unsigned short gpio, const char *label)
local_irq_save(flags);
- if (unlikely(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
+ if (unlikely(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved!\n", gpio);
dump_stack();
local_irq_restore(flags);
return -EBUSY;
}
- reserved_map[gpio_bank(gpio)] |= gpio_bit(gpio);
+ reserved_gpio_map[gpio_bank(gpio)] |= gpio_bit(gpio);
local_irq_restore(flags);
@@ -599,7 +809,7 @@ void gpio_free(unsigned short gpio)
local_irq_save(flags);
- if (unlikely(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)))) {
+ if (unlikely(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)))) {
printk(KERN_ERR "bfin-gpio: GPIO %d wasn't reserved!\n", gpio);
dump_stack();
local_irq_restore(flags);
@@ -608,7 +818,7 @@ void gpio_free(unsigned short gpio)
default_gpio(gpio);
- reserved_map[gpio_bank(gpio)] &= ~gpio_bit(gpio);
+ reserved_gpio_map[gpio_bank(gpio)] &= ~gpio_bit(gpio);
local_irq_restore(flags);
}
@@ -618,7 +828,7 @@ void gpio_direction_input(unsigned short gpio)
{
unsigned long flags;
- BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+ BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
local_irq_save(flags);
gpio_bankb[gpio_bank(gpio)]->dir &= ~gpio_bit(gpio);
@@ -631,7 +841,7 @@ void gpio_direction_output(unsigned short gpio)
{
unsigned long flags;
- BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+ BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
local_irq_save(flags);
gpio_bankb[gpio_bank(gpio)]->inen &= ~gpio_bit(gpio);
diff --git a/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
index e043caf..69b9f8e 100644
--- a/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
+++ b/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
@@ -1,5 +1,6 @@
#include <linux/serial.h>
#include <asm/dma.h>
+#include <asm/portmux.h>
#define NR_PORTS 1
@@ -92,18 +93,24 @@ struct bfin_serial_res bfin_serial_resource[] = {
}
};
+#define DRIVER_NAME "bfin-uart"
int nr_ports = NR_PORTS;
static void bfin_serial_hw_init(struct bfin_serial_port *uart)
{
+#ifdef CONFIG_SERIAL_BFIN_UART0
+ peripheral_request(P_UART0_TX, DRIVER_NAME);
+ peripheral_request(P_UART0_RX, DRIVER_NAME);
+#endif
+
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
if (uart->cts_pin >= 0) {
- gpio_request(uart->cts_pin, NULL);
+ gpio_request(uart->cts_pin, DRIVER_NAME);
gpio_direction_input(uart->cts_pin);
}
if (uart->rts_pin >= 0) {
- gpio_request(uart->rts_pin, NULL);
+ gpio_request(uart->rts_pin, DRIVER_NAME);
gpio_direction_input(uart->rts_pin);
}
#endif
diff --git a/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
index 8f5d9c4..6fb328f 100644
--- a/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
+++ b/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
@@ -1,5 +1,6 @@
#include <linux/serial.h>
#include <asm/dma.h>
+#include <asm/portmux.h>
#define NR_PORTS 2
@@ -122,25 +123,29 @@ struct bfin_serial_res bfin_serial_resource[] = {
int nr_ports = ARRAY_SIZE(bfin_serial_resource);
+#define DRIVER_NAME "bfin-uart"
+
static void bfin_serial_hw_init(struct bfin_serial_port *uart)
{
- unsigned short val;
- val = bfin_read16(BFIN_PORT_MUX);
- val &= ~(PFDE | PFTE);
- bfin_write16(BFIN_PORT_MUX, val);
- val = bfin_read16(PORTF_FER);
- val |= 0xF;
- bfin_write16(PORTF_FER, val);
+#ifdef CONFIG_SERIAL_BFIN_UART0
+ peripheral_request(P_UART0_TX, DRIVER_NAME);
+ peripheral_request(P_UART0_RX, DRIVER_NAME);
+#endif
+
+#ifdef CONFIG_SERIAL_BFIN_UART1
+ peripheral_request(P_UART1_TX, DRIVER_NAME);
+ peripheral_request(P_UART1_RX, DRIVER_NAME);
+#endif
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
if (uart->cts_pin >= 0) {
- gpio_request(uart->cts_pin, NULL);
+ gpio_request(uart->cts_pin, DRIVER_NAME);
gpio_direction_input(uart->cts_pin);
}
if (uart->rts_pin >= 0) {
- gpio_request(uart->rts_pin, NULL);
+ gpio_request(uart->rts_pin, DRIVER_NAME);
gpio_direction_output(uart->rts_pin);
}
#endif
diff --git a/include/asm-blackfin/mach-bf537/portmux.h b/include/asm-blackfin/mach-bf537/portmux.h
index 23e13c5..7daa247 100644
--- a/include/asm-blackfin/mach-bf537/portmux.h
+++ b/include/asm-blackfin/mach-bf537/portmux.h
@@ -106,4 +106,4 @@
#define P_SPI0_SSEL2 (P_DEFINED | P_IDENT(PORT_PJ11) | P_FUNCT(1))
#define P_SPI0_SSEL7 (P_DEFINED | P_IDENT(PORT_PJ5) | P_FUNCT(2))
-#endif /* _MACH_PORTMUX_H_ */
+#endif /* _MACH_PORTMUX_H_ */
diff --git a/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
index e043caf..69b9f8e 100644
--- a/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
+++ b/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
@@ -1,5 +1,6 @@
#include <linux/serial.h>
#include <asm/dma.h>
+#include <asm/portmux.h>
#define NR_PORTS 1
@@ -92,18 +93,24 @@ struct bfin_serial_res bfin_serial_resource[] = {
}
};
+#define DRIVER_NAME "bfin-uart"
int nr_ports = NR_PORTS;
static void bfin_serial_hw_init(struct bfin_serial_port *uart)
{
+#ifdef CONFIG_SERIAL_BFIN_UART0
+ peripheral_request(P_UART0_TX, DRIVER_NAME);
+ peripheral_request(P_UART0_RX, DRIVER_NAME);
+#endif
+
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
if (uart->cts_pin >= 0) {
- gpio_request(uart->cts_pin, NULL);
+ gpio_request(uart->cts_pin, DRIVER_NAME);
gpio_direction_input(uart->cts_pin);
}
if (uart->rts_pin >= 0) {
- gpio_request(uart->rts_pin, NULL);
+ gpio_request(uart->rts_pin, DRIVER_NAME);
gpio_direction_input(uart->rts_pin);
}
#endif
--
1.5.2
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCH 01/12] Blackfin arch: add peripheral resource allocation support
2007-08-08 3:35 ` [PATCH 01/12] Blackfin arch: add peripheral resource allocation support Bryan Wu
@ 2007-08-17 18:12 ` David Brownell
0 siblings, 0 replies; 8+ messages in thread
From: David Brownell @ 2007-08-17 18:12 UTC (permalink / raw)
To: Bryan Wu; +Cc: torvalds, linux-kernel, akpm, Michael Hennerich
On Tuesday 07 August 2007, Bryan Wu wrote:
> From: Michael Hennerich <michael.hennerich@analog.com>
The patch description here is IMO misleading, and is clearly
weak-to-nonexistent ... what this patch does is
* Start tracking the label strings provided by gpio_request()
* Provide a new portmux mechanisms
* Start using those in the serial support code
When I read "resource allocation" I think of "struct resource"
from <linux/ioport.h>, allocate_resource(), and so on. So while
it's true there are other kinds of driver resource, it's rather
unnatural for me to think about pin mux and gpio issues in any
terms other than chip and board setup.
> +static int cmp_label(unsigned short ident, const char *label)
> +{
> + if (label && str_ident)
> + return strncmp(str_ident + ident * RESOURCE_LABEL_SIZE,
> + label, strlen(label));
> + else
> + return -EINVAL;
> +}
GRPIO labels are purely for diagnostics. There's no reason to
compare one to another. You seem to be using these for purposes
in addition to GPIOs though ... probably worth commenting on that
unusual scheme.
> +int peripheral_request(unsigned short per, const char *label)
> +{
> + ...
> +
> + if (unlikely(reserved_peri_map[gpio_bank(ident)] & gpio_bit(ident))) {
> +
> + /*
> + * Pin functions like AMC address strobes my
> + * be requested and used by several drivers
> + */
> +
> + if (!(per & P_MAYSHARE)) {
Goofy indentation. And as a rule, drivers have been kept out of
the business of configuring pin usage. It's simpler that way;
they don't need to try coping with configuration errors like two
drivers wanting conflicting usage ... or as you say above, needing
some explicit sharing mechanism ...
> +
> + /*
> + * Allow that the identical pin function can
> + * be requested from the same driver twice
> + */
... or as you say here, needing to structure themselves so they
don't configure the same usage more than once ...
That said, how you handle pinmux on Blackfin is your business.
But you should know that this approach seems idiosyncratic and
more complex than needed: when pin config is done early and as
part of board setup, drivers don't need to care about it or to
handle any pinmux errors. And heck, products can sometimes be
shipped with the bootloader having done all pinmux setup, so
Linux won't need to worry about it at all. That can help ship
multiple board revisions using the same kernel.
- Dave
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2007-08-17 22:46 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-08-17 20:02 [PATCH 01/12] Blackfin arch: add peripheral resource allocation support Hennerich, Michael
2007-08-17 21:10 ` David Brownell
2007-08-17 22:15 ` Robin Getz
2007-08-17 22:46 ` David Brownell
-- strict thread matches above, loose matches on Subject: below --
2007-08-08 7:18 Hennerich, Michael
2007-08-08 7:49 ` Bryan Wu
2007-08-08 3:35 [PATCH 00/12] Blackfin arch GPIO updating Bryan Wu
2007-08-08 3:35 ` [PATCH 01/12] Blackfin arch: add peripheral resource allocation support Bryan Wu
2007-08-17 18:12 ` David Brownell
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox