* Re: Patches added to powerpc.git master and powerpc-next branches
From: Kumar Gala @ 2008-04-18 13:20 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev
In-Reply-To: <18440.34891.440661.248400@cargo.ozlabs.ibm.com>
On Apr 18, 2008, at 6:38 AM, Paul Mackerras wrote:
> I have pushed out the following commits to the master and powerpc-next
> branches of the powerpc.git tree. This includes commits from Kumar's
> and Jeremy's trees.
>
> I am intending to ask Linus to pull the powerpc-next branch once we
> have the breakage from the OF helpers for i2c patch sorted out.
>
> Paul.
What are we doing with these two patches:
[POWERPC] 85xx: Add support for relocatble kernel (and booting at non-
zero)
[POWERPC] Port fixmap from x86 and use for kmap_atomic
I know the second was late, but I'd like us to think about putting it
in for v2.6.26. It gives us a good basis for the PCIe 44x and 83xx
config cycle work and kexec/kdump work for v2.6.27.
thanks.
- k
^ permalink raw reply
* Infra red keyboard driver
From: BAK @ 2008-04-18 13:55 UTC (permalink / raw)
To: linuxppc-embedded
Hi every body.
Can any one help me to know the coding method of an infrared keyboard. its
reference is Sagem SWK-8695wt.
thanks khaled
--
View this message in context: http://www.nabble.com/Infra-red-keyboard-driver-tp16763434p16763434.html
Sent from the linuxppc-embedded mailing list archive at Nabble.com.
^ permalink raw reply
* [PATCH] [POWERPC] i2c: fix build breakage introduced by OF helpers
From: Jochen Friedrich @ 2008-04-18 14:23 UTC (permalink / raw)
To: Kumar Gala
Cc: Stephen Rothwell, linuxppc-dev list, Kernel, Linux, Scott Wood,
Paul Mackerras, Jean Delvare, David Miller, Linux I2C
Fix build breakage introduced in commit
"[POWERPC] i2c: OF helpers for the i2c API".
If i2c-core is compiled as module, the helper needs to be
compiled as module, as well. Rename i2c.c to of_i2c.c to
avoid name space conflict.
Signed-off-by: Jochen Friedrich <jochen@scram.de>
---
drivers/of/Kconfig | 2 +-
drivers/of/Makefile | 2 +-
drivers/of/{i2c.c => of_i2c.c} | 0
3 files changed, 2 insertions(+), 2 deletions(-)
rename drivers/of/{i2c.c => of_i2c.c} (100%)
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index 7c30531..0e39f00 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -9,7 +9,7 @@ config OF_GPIO
OpenFirmware GPIO accessors
config OF_I2C
- def_bool y
+ def_tristate I2C
depends on OF && I2C
help
OpenFirmware I2C accessors
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index a07b953..548772e 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -1,4 +1,4 @@
obj-y = base.o
obj-$(CONFIG_OF_DEVICE) += device.o platform.o
obj-$(CONFIG_OF_GPIO) += gpio.o
-obj-$(CONFIG_OF_I2C) += i2c.o
+obj-$(CONFIG_OF_I2C) += of_i2c.o
diff --git a/drivers/of/i2c.c b/drivers/of/of_i2c.c
similarity index 100%
rename from drivers/of/i2c.c
rename to drivers/of/of_i2c.c
--
1.5.5
^ permalink raw reply related
* Re: [PATCH] PowerPC 44x: Add NOR flash entry to Canyonlands DTS.
From: Stefan Roese @ 2008-04-18 14:26 UTC (permalink / raw)
To: Valentine Barshak; +Cc: linuxppc-dev
In-Reply-To: <20080417193744.GA17524@ru.mvista.com>
On Thursday 17 April 2008, Valentine Barshak wrote:
> This patch adds NOR flash entry to the PowerPC 460EX Canyonlands DTS.
Right, I forgot to add this. But the partition names and sizes are a little
different from those we used before (e.g. kilauea). I'll send a patch to
update the Canyonlands & Glacier dts files in a short while.
Thanks.
Best regards,
Stefan
^ permalink raw reply
* Re: Xilinx network trouble (mostly solved)
From: Guillaume Dargaud @ 2008-04-18 14:40 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <20080417155609.9061E1D000B0@mail147-sin.bigfish.com>
Hello Rick,
> Which version of xps_ll_temac are you using, and which version of EDK?
Using xps 9.2.02i, build EDK_lm_SP2.3+0
IP version for the TriMode_MAC_GMII (xps_ll_temac) is 1.00.b. EmacLite is
1.00.a
> Also, do both designs meet timing?
As the software guy here, I have no idea. I've passed the question onto the
electronics guys...
BUT, you put me on the right tracks: looking at the driver versions I
started playing with the options you get in the [Configure IP] of the
Ethernet Mac drivers. I couldn't get any improvement with the LLTEMAC, but
after I added the buffers to the EmacLite: IT WORKED !
I'm still having trouble mounting an NFS root and ssh'ing into the target,
but I guess that's another issue...
--
Guillaume Dargaud
http://www.gdargaud.net/
^ permalink raw reply
* Re: pci issue - wrong detection of pci ressources
From: Johan Borkhuis @ 2008-04-18 14:23 UTC (permalink / raw)
To: Christian Ehrhardt; +Cc: linuxppc-dev, Detlev Zundel, Hollis Blanchard
In-Reply-To: <48088F02.2060806@linux.vnet.ibm.com>
Hello Christian,
Christian Ehrhardt wrote:
> Hi,
> I tried to use a radeon r200 based graphic card on a sequoia ppc
> (440epx) board. I wondered about the initialization of radeonfb that
> failed with
> __ioremap(): phys addr 0x0 is RAM lr c029cf80
> radeonfb (0000:00:0a.0): cannot map MMIO
> radeonfb: probe of 0000:00:0a.0 failed with error -5
>
> I trigger a check in ioremap, because the address it wants to remap is
> 0x0 which can never work. The reason of that is that the pci ressource
> of that graphic card is not properly detected.
>
> With some help I found two kernels - one that work and one that has
> this issue.
> Unfortunately they are very different:
> good => 2.6.24.2 from the linux-2.6-denx - built for arch=ppc
> bad => we have 2.6.25-rc9 (used in our kvm ppc project atm) - build
> for arch=powerpc
> I tried building the 2.6.25-rc9 with arch=ppc, but that one does not
> boot so far. Because of that I can't surely tell you if it is only
> that difference that breaks the pci detection.
> We need arch=powerpc for our kvm code anyway, so I hope there is
> another solution than to switch to arch=ppc ;-)
I came across a similar problem, which (ultimately) was caused by a lack
of memory reserved for PCI. I moved from 2.6.14(ppc) to 2.6.20(powerpc),
and suddenly some cards stopped working: the BAR registers were not
initialized, so it was not possible to access the cards.
Have a look at the boot-time messages, especially the early messages, as
the PCI subsystem is started very early in the boot process. You could
also try switching on PCI-debugging, and have a look at the debug
messages, or add some extra debugging info to the pci-initialization code.
Kind regards,
Johan
^ permalink raw reply
* Re: [EFIKA] Really, don't pretend to be CHRP
From: Matt Sealey @ 2008-04-18 15:21 UTC (permalink / raw)
To: benh; +Cc: linuxppc-dev, David Woodhouse, paulus
In-Reply-To: <1208507048.6958.407.camel@pasglop>
Benjamin Herrenschmidt wrote:
>>> can't set environment variables from within Linux (and yes, we can
>>> probably improve on that too, but we let them setenv for themselves,
>> for
>>> now).
>> You really won't be improving on it because there's no reliable way to
>> pass setenv back to the firmware from userland :D
>
> They aren't in nvram ? If they are and using the standard OF CHRP
> format, then we can.
They aren't (especially on Pegasos) and they aren't, so you can't.
--
Matt Sealey <matt@genesi-usa.com>
Genesi, Manager, Developer Relations
^ permalink raw reply
* Re: [PATCH] PowerPC 44x: Add NOR flash entry to Canyonlands DTS.
From: Valentine Barshak @ 2008-04-18 15:20 UTC (permalink / raw)
To: Stefan Roese; +Cc: linuxppc-dev
In-Reply-To: <200804181626.09585.sr@denx.de>
Stefan Roese wrote:
> On Thursday 17 April 2008, Valentine Barshak wrote:
>> This patch adds NOR flash entry to the PowerPC 460EX Canyonlands DTS.
>
> Right, I forgot to add this. But the partition names and sizes are a little
> different from those we used before (e.g. kilauea). I'll send a patch to
> update the Canyonlands & Glacier dts files in a short while.
>
I've got these partition names and sizes form amcc site.
They seem to correspond to u-boot environment my board has.
Are these incorrect?
Thanks,
Valentine.
> Thanks.
>
> Best regards,
> Stefan
^ permalink raw reply
* Re: [EFIKA] Really, don't pretend to be CHRP
From: Matt Sealey @ 2008-04-18 15:33 UTC (permalink / raw)
To: David Woodhouse; +Cc: linuxppc-dev, paulus
In-Reply-To: <1208450247.9212.275.camel@pmac.infradead.org>
David Woodhouse wrote:
> OTOH, it probably wouldn't be _so_ hard to port Mitch's OpenFirmware to
> mpc5200...
Go for it.
I also give you permission to detail how our firmware is a bit crap in
the Fedora release notes. You will have to do that anyway to evangelize
the weird setenv hack you just proposed, so it will kill two birds with
one stone.
Also regarding your original patch; why not just fix the cpuinfo printout
so that it doesn't print the machine/vendor properties from firmware.
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=arch/powerpc/platforms/52xx/efika.c;h=a2068faef6ea9c7b5b4fb2db804a32f33e1598b1;hb=HEAD#l155
It's right there. I'd rather they were taken out than putting MORE
property changes into fixups.
--
Matt Sealey <matt@genesi-usa.com>
Genesi, Manager, Developer Relations
^ permalink raw reply
* Re: RFC: MPC5200 PSC AC97 driver
From: Peter Czanik @ 2008-04-18 15:43 UTC (permalink / raw)
To: Juergen Beisert; +Cc: linuxppc-dev
In-Reply-To: <200804171619.56615.jbe@pengutronix.de>
Hello,
Juergen Beisert írta:
> Hi,
>
> if someone is interested: Here the full patch to get sound support for
> MPC5200b and a current 2.6.25 kernel.
>
First of all, thanks for fixing the driver. I just tested it on the
EFIKA, it (almost) works. In its current state loading the kernel module
results in a segfault and oops. The fix is to add a missing line to the
device-tree. The forth version of the EFIKA fix works fine (taken from
http://www.powerdeveloper.org/platforms/efika/devicetree ):
efika:~ # cat /mnt/sound.forth
\ FORTH
s" /builtin/sound" find-device
\ Audio is on PSC2, just for informational purposes
1 encode-int s" cell-index" property
device-end
efika:~ #
But trying to fix it up from prom_init.c does not seem to work, the
missing 'cell-index' property does not show up. Please let me know, how
to add it properly. Here is what I tried:
factory:/usr/src/linux-2.6.25 # diff -u
arch/powerpc/kernel/prom_init.c.orig arch/powerpc/kernel/prom_init.c
--- arch/powerpc/kernel/prom_init.c.orig 2008-04-18
13:55:07.000000000 +0200
+++ arch/powerpc/kernel/prom_init.c 2008-04-18 16:26:51.000000000 +0200
@@ -2212,6 +2212,7 @@
static void __init fixup_device_tree_efika(void)
{
+ int sound_ci = 1;
int sound_irq[3] = { 2, 2, 0 };
int bcomm_irq[3*16] = { 3,0,0, 3,1,0, 3,2,0, 3,3,0,
3,4,0, 3,5,0, 3,6,0, 3,7,0,
@@ -2257,6 +2258,8 @@
rv = prom_getprop(node, "interrupts", prop, sizeof(prop));
if (rv == PROM_ERROR) {
prom_printf("Adding sound interrupts property\n");
+ prom_setprop(node, "/builtin/sound", "cell-index",
+ &sound_ci, sizeof(int));
prom_setprop(node, "/builtin/sound", "interrupts",
sound_irq, sizeof(sound_irq));
}
factory:/usr/src/linux-2.6.25 #
Bye,
CzP
^ permalink raw reply
* Re: RFC: MPC5200 PSC AC97 driver
From: Juergen Beisert @ 2008-04-18 16:02 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <4808C1BE.1050607@fang.fa.gau.hu>
On Friday 18 April 2008 17:43, Peter Czanik wrote:
> Hello,
>
> Juergen Beisert =EDrta:
> > Hi,
> >
> > if someone is interested: Here the full patch to get sound support for
> > MPC5200b and a current 2.6.25 kernel.
>
> First of all, thanks for fixing the driver. I just tested it on the
> EFIKA, it (almost) works. In its current state loading the kernel module
> results in a segfault and oops. The fix is to add a missing line to the
> device-tree. The forth version of the EFIKA fix works fine (taken from
> http://www.powerdeveloper.org/platforms/efika/devicetree ):
>
> efika:~ # cat /mnt/sound.forth
> \ FORTH
>
> s" /builtin/sound" find-device
> \ Audio is on PSC2, just for informational purposes
> 1 encode-int s" cell-index" property
> device-end
> efika:~ #
>
> But trying to fix it up from prom_init.c does not seem to work, the
> missing 'cell-index' property does not show up. Please let me know, how
> to add it properly. Here is what I tried:
>
> factory:/usr/src/linux-2.6.25 # diff -u
> arch/powerpc/kernel/prom_init.c.orig arch/powerpc/kernel/prom_init.c
> --- arch/powerpc/kernel/prom_init.c.orig 2008-04-18
> 13:55:07.000000000 +0200
> +++ arch/powerpc/kernel/prom_init.c 2008-04-18 16:26:51.000000000 +02=
00
> @@ -2212,6 +2212,7 @@
>
> static void __init fixup_device_tree_efika(void)
> {
> + int sound_ci =3D 1;
> int sound_irq[3] =3D { 2, 2, 0 };
> int bcomm_irq[3*16] =3D { 3,0,0, 3,1,0, 3,2,0, 3,3,0,
> 3,4,0, 3,5,0, 3,6,0, 3,7,0,
> @@ -2257,6 +2258,8 @@
> rv =3D prom_getprop(node, "interrupts", prop, sizeof(prop=
));
> if (rv =3D=3D PROM_ERROR) {
> prom_printf("Adding sound interrupts property\n");
> + prom_setprop(node, "/builtin/sound", "cell-index=
",
> + &sound_ci, sizeof(int));
> prom_setprop(node, "/builtin/sound", "interrupts",
> sound_irq, sizeof(sound_irq));
> }
> factory:/usr/src/linux-2.6.25 #
>
> Bye,
> CzP
I'm not sure if "cell-index" is a correct property. I copied it from the ua=
rt=20
driver, because this driver needs something to distinguish between PSC1 and=
=20
PSC2. Maybe there is a better and correct oftree solution? Any oftree exper=
t=20
here?
Juergen
=2D-=20
Dipl.-Ing. Juergen Beisert | http://www.pengutronix.de
=A0Pengutronix - Linux Solutions for Science and Industry
=A0 Handelsregister: Amtsgericht Hildesheim, HRA 2686
=A0 =A0 =A0 Vertretung Sued/Muenchen, Germany
Phone: +49-8766-939 228 | Fax: +49-5121-206917-9
^ permalink raw reply
* RE: Xilinx network trouble (mostly solved)
From: Rick Moleres @ 2008-04-18 16:14 UTC (permalink / raw)
To: Guillaume Dargaud, linuxppc-dev
In-Reply-To: <04c001c8a162$242e7330$ad289e86@LPSC0173W>
Guillaume,
You might try v1.00a of the xps_ll_temac core. There are a couple of
issues with v1.00b (posted previously on this list) that may (or may
not) be causing the problem you see.
-Rick
-----Original Message-----
From: linuxppc-dev-bounces+moleres=3Dxilinx.com@ozlabs.org
[mailto:linuxppc-dev-bounces+moleres=3Dxilinx.com@ozlabs.org] On Behalf =
Of
Guillaume Dargaud
Sent: Friday, April 18, 2008 8:40 AM
To: linuxppc-dev@ozlabs.org
Subject: Re: Xilinx network trouble (mostly solved)
Hello Rick,
> Which version of xps_ll_temac are you using, and which version of EDK?
Using xps 9.2.02i, build EDK_lm_SP2.3+0
IP version for the TriMode_MAC_GMII (xps_ll_temac) is 1.00.b. EmacLite
is=20
1.00.a
> Also, do both designs meet timing?
As the software guy here, I have no idea. I've passed the question onto
the=20
electronics guys...
BUT, you put me on the right tracks: looking at the driver versions I=20
started playing with the options you get in the [Configure IP] of the=20
Ethernet Mac drivers. I couldn't get any improvement with the LLTEMAC,
but=20
after I added the buffers to the EmacLite: IT WORKED !
I'm still having trouble mounting an NFS root and ssh'ing into the
target,=20
but I guess that's another issue...
--=20
Guillaume Dargaud
http://www.gdargaud.net/
_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev
^ permalink raw reply
* Re: pci issue - wrong detection of pci ressources
From: Sergei Shtylyov @ 2008-04-18 16:29 UTC (permalink / raw)
To: Christian Ehrhardt; +Cc: linuxppc-dev, Detlev Zundel, Hollis Blanchard
In-Reply-To: <48088F02.2060806@linux.vnet.ibm.com>
Christian Ehrhardt wrote:
> I tried to use a radeon r200 based graphic card on a sequoia ppc
> (440epx) board. I wondered about the initialization of radeonfb that
> failed with
> __ioremap(): phys addr 0x0 is RAM lr c029cf80
> radeonfb (0000:00:0a.0): cannot map MMIO
> radeonfb: probe of 0000:00:0a.0 failed with error -5
> I trigger a check in ioremap, because the address it wants to remap is
> 0x0 which can never work. The reason of that is that the pci ressource
> of that graphic card is not properly detected.
There might be another reason. This driver seems to be another subject to
the 440-specific PCI memory space issue beacuse it uses 'unsigned long' to
store the PCI memory physical addresses and those are 64-bit in the 440
arch/powerpc/ kernels.
> With some help I found two kernels - one that work and one that has this
> issue.
> Unfortunately they are very different:
> good => 2.6.24.2 from the linux-2.6-denx - built for arch=ppc
> bad => we have 2.6.25-rc9 (used in our kvm ppc project atm) - build
> for arch=powerpc
> I tried building the 2.6.25-rc9 with arch=ppc, but that one does not
> boot so far. Because of that I can't surely tell you if it is only that
> difference that breaks the pci detection.
> We need arch=powerpc for our kvm code anyway, so I hope there is another
> solution than to switch to arch=ppc ;-)
Yes, the driver needs fixing -- at least that.
> I just started to debug into that, but I wanted to ask here if there
> might be some known issues causing that and/or to get some hints where
> to look at.
Now you know of at least one.
> The issue is much better visible when I boot with these two kernels and
> use "lspci -vvv"
> Good kernel:
> 00:0a.0 VGA compatible controller: ATI Technologies Inc RV280 [Radeon
> 9200 PRO] (rev 01) (prog-if 00 [VGA])
> Subsystem: PC Partner Limited Unknown device 0250
> Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop-
> ParErr- Stepping- SERR- FastB2B-
> Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
> <TAbort- <MAbort- >SERR- <PERR-
> Latency: 128 (2000ns min)
> Interrupt: pin A routed to IRQ 67
> Region 0: Memory at 88000000 (32-bit, prefetchable) [size=128M]
> Region 1: I/O ports at ff00 [size=256]
> Region 2: Memory at 87ff0000 (32-bit, non-prefetchable) [size=64K]
> Expansion ROM at 80020000 [disabled] [size=128K]
Here, the PCI resources have been re-assigned by arch/ppc/ kernel, and are
confined to 4 GB due to fixup_bigphys_addr() trick used for 440...
> Capabilities: [50] Power Management version 2
> Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=0mA
> PME(D0-,D1-,D2-,D3hot-,D3cold-)
> Status: D0 PME-Enable- DSel=0 DScale=0 PME-
> Bad kernel:
> 00:0a.0 VGA compatible controller: ATI Technologies Inc RV280 [Radeon
> 9200 PRO] (rev 01) (prog-if 00 [VGA])
> Subsystem: PC Partner Limited Unknown device 0250
> Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop-
> ParErr- Stepping- SERR- FastB2B-
> Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
> <TAbort- <MAbort- >SERR- <PERR-
> Latency: 128 (2000ns min)
> Interrupt: pin A routed to IRQ 16
> Region 0: Memory at 180000000 (32-bit, prefetchable) [size=128M]
That's beyond 4 GB, seems correct. That should be the address assigned by
bootloader? BTW, what's your bootloader, U-Boot?
> Region 1: I/O ports at 1000 [size=256]
> Region 2: Memory at <ignored> (32-bit, non-prefetchable)
Hm... what could this mean? Could you post the result of 'lspci -x'?
> Capabilities: [50] Power Management version 2
> Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=0mA
> PME(D0-,D1-,D2-,D3hot-,D3cold-)
> Status: D0 PME-Enable- DSel=0 DScale=0 PME-
> => Region 2 is not detected with our kernel, this later break things
> like radeonfb initialization.
Well, not only this...
WBR, Sergei
^ permalink raw reply
* Re: [PATCH] PowerPC 44x: Add NOR flash entry to Canyonlands DTS.
From: Stefan Roese @ 2008-04-18 16:38 UTC (permalink / raw)
To: Valentine Barshak; +Cc: linuxppc-dev
In-Reply-To: <4808BC33.7070109@ru.mvista.com>
On Friday 18 April 2008, Valentine Barshak wrote:
> > Right, I forgot to add this. But the partition names and sizes are a
> > little different from those we used before (e.g. kilauea). I'll send a
> > patch to update the Canyonlands & Glacier dts files in a short while.
>
> I've got these partition names and sizes form amcc site.
> They seem to correspond to u-boot environment my board has.
I see. I'll check with AMCC on what really to use here.
> Are these incorrect?
Yes, these values are incorrect because of some problems with NOR FLASH on the
first preliminary board ports. This is fixed now.
I'll come up with some new patches shortly.
Best regards,
Stefan
=====================================================================
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80 Email: office@denx.de
=====================================================================
^ permalink raw reply
* Re: [PATCH] PowerPC 44x: Add NOR flash entry to Canyonlands DTS.
From: Valentine Barshak @ 2008-04-18 16:50 UTC (permalink / raw)
To: Stefan Roese; +Cc: linuxppc-dev
In-Reply-To: <200804181838.54673.sr@denx.de>
Stefan Roese wrote:
> On Friday 18 April 2008, Valentine Barshak wrote:
>>> Right, I forgot to add this. But the partition names and sizes are a
>>> little different from those we used before (e.g. kilauea). I'll send a
>>> patch to update the Canyonlands & Glacier dts files in a short while.
>> I've got these partition names and sizes form amcc site.
>> They seem to correspond to u-boot environment my board has.
>
> I see. I'll check with AMCC on what really to use here.
>
>> Are these incorrect?
>
> Yes, these values are incorrect because of some problems with NOR FLASH on the
> first preliminary board ports. This is fixed now.
>
> I'll come up with some new patches shortly.
>
OK thanks a lot,
Valentine.
> Best regards,
> Stefan
>
> =====================================================================
> DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: +49-8142-66989-0 Fax: +49-8142-66989-80 Email: office@denx.de
> =====================================================================
^ permalink raw reply
* [PATCH1/2] [POWERPC] CPM2: Implement GPIO LIB API on CPM2 Freescale SoC.
From: Jochen Friedrich @ 2008-04-18 17:07 UTC (permalink / raw)
To: kumar Gala; +Cc: linuxppc-dev list, Scott Wood
Based on earlier work by Laurent Pinchart.
This patch implement GPIO LIB support for the CPM2 GPIOs.
Signed-off-by: Jochen Friedrich <jochen@scram.de>
Cc: Laurent Pinchart <laurentp@cse-semaphore.com>
---
arch/powerpc/platforms/Kconfig | 2 +
arch/powerpc/sysdev/cpm2.c | 11 ++++
arch/powerpc/sysdev/cpm_common.c | 120 ++++++++++++++++++++++++++++++++++++++
include/asm-powerpc/cpm.h | 3 +
4 files changed, 136 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index f6eecd1..78911f6 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -283,6 +283,8 @@ config CPM2
depends on MPC85xx || 8260
select CPM
select PPC_LIB_RHEAP
+ select GENERIC_GPIO
+ select HAVE_GPIO_LIB
help
The CPM2 (Communications Processor Module) is a coprocessor on
embedded CPUs made by Freescale. Selecting this option means that
diff --git a/arch/powerpc/sysdev/cpm2.c b/arch/powerpc/sysdev/cpm2.c
index 5a6c5df..9311778 100644
--- a/arch/powerpc/sysdev/cpm2.c
+++ b/arch/powerpc/sysdev/cpm2.c
@@ -377,3 +377,14 @@ void cpm2_set_pin(int port, int pin, int flags)
else
clrbits32(&iop[port].odr, pin);
}
+
+static int cpm_init_par_io(void)
+{
+ struct device_node *np;
+
+ for_each_compatible_node(np, NULL, "fsl,cpm2-pario-bank")
+ cpm2_gpiochip_add32(np);
+ return 0;
+}
+arch_initcall(cpm_init_par_io);
+
diff --git a/arch/powerpc/sysdev/cpm_common.c b/arch/powerpc/sysdev/cpm_common.c
index cb7df2d..07d694c 100644
--- a/arch/powerpc/sysdev/cpm_common.c
+++ b/arch/powerpc/sysdev/cpm_common.c
@@ -19,6 +19,9 @@
#include <linux/init.h>
#include <linux/of_device.h>
+#include <linux/spinlock.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
#include <asm/udbg.h>
#include <asm/io.h>
@@ -198,3 +201,120 @@ dma_addr_t cpm_muram_dma(void __iomem *addr)
return muram_pbase + ((u8 __iomem *)addr - muram_vbase);
}
EXPORT_SYMBOL(cpm_muram_dma);
+
+#if defined(CONFIG_CPM2) || defined(CONFIG_8xx_GPIO)
+
+struct cpm2_ioports {
+ u32 dir, par, sor, odr, dat;
+ u32 res[3];
+};
+
+struct cpm2_gpio32_chip {
+ struct of_mm_gpio_chip mm_gc;
+ spinlock_t lock;
+
+ /* shadowed data register to clear/set bits safely */
+ u32 cpdata;
+};
+
+static inline struct cpm2_gpio32_chip *
+to_cpm2_gpio32_chip(struct of_mm_gpio_chip *mm_gc)
+{
+ return container_of(mm_gc, struct cpm2_gpio32_chip, mm_gc);
+}
+
+static void cpm2_gpio32_save_regs(struct of_mm_gpio_chip *mm_gc)
+{
+ struct cpm2_gpio32_chip *cpm2_gc = to_cpm2_gpio32_chip(mm_gc);
+ struct cpm2_ioports __iomem *iop = mm_gc->regs;
+
+ cpm2_gc->cpdata = in_be32(&iop->dat);
+}
+
+static int cpm2_gpio32_get(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm2_ioports __iomem *iop = mm_gc->regs;
+ u32 pin_mask;
+
+ pin_mask = 1 << (31 - gpio);
+
+ return !!(in_be32(&iop->dat) & pin_mask);
+}
+
+static void cpm2_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm2_gpio32_chip *cpm2_gc = to_cpm2_gpio32_chip(mm_gc);
+ struct cpm2_ioports __iomem *iop = mm_gc->regs;
+ unsigned long flags;
+ u32 pin_mask = 1 << (31 - gpio);
+
+ spin_lock_irqsave(&cpm2_gc->lock, flags);
+
+ if (value)
+ cpm2_gc->cpdata |= pin_mask;
+ else
+ cpm2_gc->cpdata &= ~pin_mask;
+
+ out_be32(&iop->dat, cpm2_gc->cpdata);
+
+ spin_unlock_irqrestore(&cpm2_gc->lock, flags);
+}
+
+static int cpm2_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm2_ioports __iomem *iop = mm_gc->regs;
+ u32 pin_mask;
+
+ pin_mask = 1 << (31 - gpio);
+
+ setbits32(&iop->dir, pin_mask);
+
+ cpm2_gpio32_set(gc, gpio, val);
+
+ return 0;
+}
+
+static int cpm2_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm2_ioports __iomem *iop = mm_gc->regs;
+ u32 pin_mask;
+
+ pin_mask = 1 << (31 - gpio);
+
+ clrbits32(&iop->dir, pin_mask);
+
+ return 0;
+}
+
+int cpm2_gpiochip_add32(struct device_node *np)
+{
+ struct cpm2_gpio32_chip *cpm2_gc;
+ struct of_mm_gpio_chip *mm_gc;
+ struct of_gpio_chip *of_gc;
+ struct gpio_chip *gc;
+
+ cpm2_gc = kzalloc(sizeof(*cpm2_gc), GFP_KERNEL);
+ if (!cpm2_gc)
+ return -ENOMEM;
+
+ spin_lock_init(&cpm2_gc->lock);
+
+ mm_gc = &cpm2_gc->mm_gc;
+ of_gc = &mm_gc->of_gc;
+ gc = &of_gc->gc;
+
+ mm_gc->save_regs = cpm2_gpio32_save_regs;
+ of_gc->gpio_cells = 1;
+ gc->ngpio = 32;
+ gc->direction_input = cpm2_gpio32_dir_in;
+ gc->direction_output = cpm2_gpio32_dir_out;
+ gc->get = cpm2_gpio32_get;
+ gc->set = cpm2_gpio32_set;
+
+ return of_mm_gpiochip_add(np, mm_gc);
+}
+#endif /* CONFIG_CPM2 || CONFIG_8xx_GPIO */
diff --git a/include/asm-powerpc/cpm.h b/include/asm-powerpc/cpm.h
index ede38ff..23b72ee 100644
--- a/include/asm-powerpc/cpm.h
+++ b/include/asm-powerpc/cpm.h
@@ -3,6 +3,7 @@
#include <linux/compiler.h>
#include <linux/types.h>
+#include <linux/of.h>
/* Opcodes common to CPM1 and CPM2
*/
@@ -99,4 +100,6 @@ void __iomem *cpm_muram_addr(unsigned long offset);
dma_addr_t cpm_muram_dma(void __iomem *addr);
int cpm_command(u32 command, u8 opcode);
+int cpm2_gpiochip_add32(struct device_node *np);
+
#endif
--
1.5.5
^ permalink raw reply related
* [PATCH2/2] [POWERPC] CPM1: implement GPIO LIB API on CPM1 Freescale SoC.
From: Jochen Friedrich @ 2008-04-18 17:10 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev list, Scott Wood
This patch implement GPIO LIB support for the CPM1 GPIOs.
Signed-off-by: Jochen Friedrich <jochen@scram.de>
---
arch/powerpc/platforms/8xx/Kconfig | 10 ++
arch/powerpc/sysdev/cpm1.c | 261 +++++++++++++++++++++++++++++++++++-
2 files changed, 266 insertions(+), 5 deletions(-)
diff --git a/arch/powerpc/platforms/8xx/Kconfig b/arch/powerpc/platforms/8xx/Kconfig
index 6fc849e..3488bb7 100644
--- a/arch/powerpc/platforms/8xx/Kconfig
+++ b/arch/powerpc/platforms/8xx/Kconfig
@@ -105,6 +105,16 @@ config 8xx_COPYBACK
If in doubt, say Y here.
+config 8xx_GPIO
+ bool "GPIO API Support"
+ select GENERIC_GPIO
+ select HAVE_GPIO_LIB
+ help
+ Saying Y here will cause the ports on an MPC8xx processor to be used
+ with the GPIO API. If you say N here, the kernel needs less memory.
+
+ If in doubt, say Y here.
+
config 8xx_CPU6
bool "CPU6 Silicon Errata (860 Pre Rev. C)"
help
diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c
index 58292a0..01ae3ae 100644
--- a/arch/powerpc/sysdev/cpm1.c
+++ b/arch/powerpc/sysdev/cpm1.c
@@ -30,6 +30,7 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/module.h>
+#include <linux/spinlock.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/8xx_immap.h>
@@ -42,6 +43,10 @@
#include <asm/fs_pd.h>
+#ifdef CONFIG_8xx_GPIO
+#include <linux/of_gpio.h>
+#endif
+
#define CPM_MAP_SIZE (0x4000)
cpm8xx_t __iomem *cpmp; /* Pointer to comm processor space */
@@ -290,20 +295,24 @@ struct cpm_ioport16 {
__be16 res[3];
};
-struct cpm_ioport32 {
- __be32 dir, par, sor;
+struct cpm_ioport32b {
+ __be32 dir, par, odr, dat;
+};
+
+struct cpm_ioport32e {
+ __be32 dir, par, sor, odr, dat;
};
static void cpm1_set_pin32(int port, int pin, int flags)
{
- struct cpm_ioport32 __iomem *iop;
+ struct cpm_ioport32e __iomem *iop;
pin = 1 << (31 - pin);
if (port == CPM_PORTB)
- iop = (struct cpm_ioport32 __iomem *)
+ iop = (struct cpm_ioport32e __iomem *)
&mpc8xx_immr->im_cpm.cp_pbdir;
else
- iop = (struct cpm_ioport32 __iomem *)
+ iop = (struct cpm_ioport32e __iomem *)
&mpc8xx_immr->im_cpm.cp_pedir;
if (flags & CPM_PIN_OUTPUT)
@@ -498,3 +507,245 @@ int cpm1_clk_setup(enum cpm_clk_target target, int clock, int mode)
return 0;
}
+
+/*
+ * GPIO LIB API implementation
+ */
+#ifdef CONFIG_8xx_GPIO
+
+struct cpm1_gpio16_chip {
+ struct of_mm_gpio_chip mm_gc;
+ spinlock_t lock;
+
+ /* shadowed data register to clear/set bits safely */
+ u16 cpdata;
+};
+
+static inline struct cpm1_gpio16_chip *
+to_cpm1_gpio16_chip(struct of_mm_gpio_chip *mm_gc)
+{
+ return container_of(mm_gc, struct cpm1_gpio16_chip, mm_gc);
+}
+
+static void cpm1_gpio16_save_regs(struct of_mm_gpio_chip *mm_gc)
+{
+ struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc);
+ struct cpm_ioport16 __iomem *iop = mm_gc->regs;
+
+ cpm1_gc->cpdata = in_be16(&iop->dat);
+}
+
+static int cpm1_gpio16_get(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm_ioport16 __iomem *iop = mm_gc->regs;
+ u16 pin_mask;
+
+ pin_mask = 1 << (15 - gpio);
+
+ return !!(in_be16(&iop->dat) & pin_mask);
+}
+
+static void cpm1_gpio16_set(struct gpio_chip *gc, unsigned int gpio, int value)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc);
+ struct cpm_ioport16 __iomem *iop = mm_gc->regs;
+ unsigned long flags;
+ u16 pin_mask = 1 << (15 - gpio);
+
+ spin_lock_irqsave(&cpm1_gc->lock, flags);
+
+ if (value)
+ cpm1_gc->cpdata |= pin_mask;
+ else
+ cpm1_gc->cpdata &= ~pin_mask;
+
+ out_be16(&iop->dat, cpm1_gc->cpdata);
+
+ spin_unlock_irqrestore(&cpm1_gc->lock, flags);
+}
+
+static int cpm1_gpio16_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm_ioport16 __iomem *iop = mm_gc->regs;
+ u16 pin_mask;
+
+ pin_mask = 1 << (15 - gpio);
+
+ setbits16(&iop->dir, pin_mask);
+
+ cpm1_gpio16_set(gc, gpio, val);
+
+ return 0;
+}
+
+static int cpm1_gpio16_dir_in(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm_ioport16 __iomem *iop = mm_gc->regs;
+ u16 pin_mask;
+
+ pin_mask = 1 << (15 - gpio);
+
+ clrbits16(&iop->dir, pin_mask);
+
+ return 0;
+}
+
+int cpm1_gpiochip_add16(struct device_node *np)
+{
+ struct cpm1_gpio16_chip *cpm1_gc;
+ struct of_mm_gpio_chip *mm_gc;
+ struct of_gpio_chip *of_gc;
+ struct gpio_chip *gc;
+
+ cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL);
+ if (!cpm1_gc)
+ return -ENOMEM;
+
+ spin_lock_init(&cpm1_gc->lock);
+
+ mm_gc = &cpm1_gc->mm_gc;
+ of_gc = &mm_gc->of_gc;
+ gc = &of_gc->gc;
+
+ mm_gc->save_regs = cpm1_gpio16_save_regs;
+ of_gc->gpio_cells = 1;
+ gc->ngpio = 16;
+ gc->direction_input = cpm1_gpio16_dir_in;
+ gc->direction_output = cpm1_gpio16_dir_out;
+ gc->get = cpm1_gpio16_get;
+ gc->set = cpm1_gpio16_set;
+
+ return of_mm_gpiochip_add(np, mm_gc);
+}
+
+struct cpm1_gpio32_chip {
+ struct of_mm_gpio_chip mm_gc;
+ spinlock_t lock;
+
+ /* shadowed data register to clear/set bits safely */
+ u32 cpdata;
+};
+
+static inline struct cpm1_gpio32_chip *
+to_cpm1_gpio32_chip(struct of_mm_gpio_chip *mm_gc)
+{
+ return container_of(mm_gc, struct cpm1_gpio32_chip, mm_gc);
+}
+
+static void cpm1_gpio32_save_regs(struct of_mm_gpio_chip *mm_gc)
+{
+ struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc);
+ struct cpm_ioport32b __iomem *iop = mm_gc->regs;
+
+ cpm1_gc->cpdata = in_be32(&iop->dat);
+}
+
+static int cpm1_gpio32_get(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm_ioport32b __iomem *iop = mm_gc->regs;
+ u32 pin_mask;
+
+ pin_mask = 1 << (31 - gpio);
+
+ return !!(in_be32(&iop->dat) & pin_mask);
+}
+
+static void cpm1_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc);
+ struct cpm_ioport32b __iomem *iop = mm_gc->regs;
+ unsigned long flags;
+ u32 pin_mask = 1 << (31 - gpio);
+
+ spin_lock_irqsave(&cpm1_gc->lock, flags);
+
+ if (value)
+ cpm1_gc->cpdata |= pin_mask;
+ else
+ cpm1_gc->cpdata &= ~pin_mask;
+
+ out_be32(&iop->dat, cpm1_gc->cpdata);
+
+ spin_unlock_irqrestore(&cpm1_gc->lock, flags);
+}
+
+static int cpm1_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm_ioport32b __iomem *iop = mm_gc->regs;
+ u32 pin_mask;
+
+ pin_mask = 1 << (31 - gpio);
+
+ setbits32(&iop->dir, pin_mask);
+
+ cpm1_gpio32_set(gc, gpio, val);
+
+ return 0;
+}
+
+static int cpm1_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm_ioport32b __iomem *iop = mm_gc->regs;
+ u32 pin_mask;
+
+ pin_mask = 1 << (31 - gpio);
+
+ clrbits32(&iop->dir, pin_mask);
+
+ return 0;
+}
+
+int cpm1_gpiochip_add32(struct device_node *np)
+{
+ struct cpm1_gpio32_chip *cpm1_gc;
+ struct of_mm_gpio_chip *mm_gc;
+ struct of_gpio_chip *of_gc;
+ struct gpio_chip *gc;
+
+ cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL);
+ if (!cpm1_gc)
+ return -ENOMEM;
+
+ spin_lock_init(&cpm1_gc->lock);
+
+ mm_gc = &cpm1_gc->mm_gc;
+ of_gc = &mm_gc->of_gc;
+ gc = &of_gc->gc;
+
+ mm_gc->save_regs = cpm1_gpio32_save_regs;
+ of_gc->gpio_cells = 1;
+ gc->ngpio = 32;
+ gc->direction_input = cpm1_gpio32_dir_in;
+ gc->direction_output = cpm1_gpio32_dir_out;
+ gc->get = cpm1_gpio32_get;
+ gc->set = cpm1_gpio32_set;
+
+ return of_mm_gpiochip_add(np, mm_gc);
+}
+
+static int cpm_init_par_io(void)
+{
+ struct device_node *np;
+
+ for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank16")
+ cpm1_gpiochip_add16(np);
+
+ for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank32b")
+ cpm1_gpiochip_add32(np);
+
+ /* Port E uses CPM2 layout */
+ for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank32e")
+ cpm2_gpiochip_add32(np);
+ return 0;
+}
+arch_initcall(cpm_init_par_io);
+
+#endif /* CONFIG_8xx_GPIO */
--
1.5.5
^ permalink raw reply related
* [PATCHv2 1/2] [POWERPC] CPM2: Implement GPIO LIB API on CPM2 Freescale SoC.
From: Jochen Friedrich @ 2008-04-18 17:16 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev list, Scott Wood
Based on earlier work by Laurent Pinchart.
This patch implement GPIO LIB support for the CPM2 GPIOs.
Signed-off-by: Jochen Friedrich <jochen@scram.de>
Cc: Laurent Pinchart <laurentp@cse-semaphore.com>
---
arch/powerpc/platforms/Kconfig | 2 +
arch/powerpc/sysdev/cpm2.c | 11 ++++
arch/powerpc/sysdev/cpm_common.c | 123 ++++++++++++++++++++++++++++++++++++++
include/asm-powerpc/cpm.h | 3 +
4 files changed, 139 insertions(+), 0 deletions(-)
Changes from version 1:
- conditionally include #include <linux/of_gpio.h> in cpm_common.c, so it compiles
when GPIO on 8xx is not selected.
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index f6eecd1..78911f6 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -283,6 +283,8 @@ config CPM2
depends on MPC85xx || 8260
select CPM
select PPC_LIB_RHEAP
+ select GENERIC_GPIO
+ select HAVE_GPIO_LIB
help
The CPM2 (Communications Processor Module) is a coprocessor on
embedded CPUs made by Freescale. Selecting this option means that
diff --git a/arch/powerpc/sysdev/cpm2.c b/arch/powerpc/sysdev/cpm2.c
index 5a6c5df..9311778 100644
--- a/arch/powerpc/sysdev/cpm2.c
+++ b/arch/powerpc/sysdev/cpm2.c
@@ -377,3 +377,14 @@ void cpm2_set_pin(int port, int pin, int flags)
else
clrbits32(&iop[port].odr, pin);
}
+
+static int cpm_init_par_io(void)
+{
+ struct device_node *np;
+
+ for_each_compatible_node(np, NULL, "fsl,cpm2-pario-bank")
+ cpm2_gpiochip_add32(np);
+ return 0;
+}
+arch_initcall(cpm_init_par_io);
+
diff --git a/arch/powerpc/sysdev/cpm_common.c b/arch/powerpc/sysdev/cpm_common.c
index cb7df2d..43bac6e 100644
--- a/arch/powerpc/sysdev/cpm_common.c
+++ b/arch/powerpc/sysdev/cpm_common.c
@@ -19,6 +19,8 @@
#include <linux/init.h>
#include <linux/of_device.h>
+#include <linux/spinlock.h>
+#include <linux/of.h>
#include <asm/udbg.h>
#include <asm/io.h>
@@ -28,6 +30,10 @@
#include <mm/mmu_decl.h>
+#if defined(CONFIG_CPM2) || defined(CONFIG_8xx_GPIO)
+#include <linux/of_gpio.h>
+#endif
+
#ifdef CONFIG_PPC_EARLY_DEBUG_CPM
static u32 __iomem *cpm_udbg_txdesc =
(u32 __iomem __force *)CONFIG_PPC_EARLY_DEBUG_CPM_ADDR;
@@ -198,3 +204,120 @@ dma_addr_t cpm_muram_dma(void __iomem *addr)
return muram_pbase + ((u8 __iomem *)addr - muram_vbase);
}
EXPORT_SYMBOL(cpm_muram_dma);
+
+#if defined(CONFIG_CPM2) || defined(CONFIG_8xx_GPIO)
+
+struct cpm2_ioports {
+ u32 dir, par, sor, odr, dat;
+ u32 res[3];
+};
+
+struct cpm2_gpio32_chip {
+ struct of_mm_gpio_chip mm_gc;
+ spinlock_t lock;
+
+ /* shadowed data register to clear/set bits safely */
+ u32 cpdata;
+};
+
+static inline struct cpm2_gpio32_chip *
+to_cpm2_gpio32_chip(struct of_mm_gpio_chip *mm_gc)
+{
+ return container_of(mm_gc, struct cpm2_gpio32_chip, mm_gc);
+}
+
+static void cpm2_gpio32_save_regs(struct of_mm_gpio_chip *mm_gc)
+{
+ struct cpm2_gpio32_chip *cpm2_gc = to_cpm2_gpio32_chip(mm_gc);
+ struct cpm2_ioports __iomem *iop = mm_gc->regs;
+
+ cpm2_gc->cpdata = in_be32(&iop->dat);
+}
+
+static int cpm2_gpio32_get(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm2_ioports __iomem *iop = mm_gc->regs;
+ u32 pin_mask;
+
+ pin_mask = 1 << (31 - gpio);
+
+ return !!(in_be32(&iop->dat) & pin_mask);
+}
+
+static void cpm2_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm2_gpio32_chip *cpm2_gc = to_cpm2_gpio32_chip(mm_gc);
+ struct cpm2_ioports __iomem *iop = mm_gc->regs;
+ unsigned long flags;
+ u32 pin_mask = 1 << (31 - gpio);
+
+ spin_lock_irqsave(&cpm2_gc->lock, flags);
+
+ if (value)
+ cpm2_gc->cpdata |= pin_mask;
+ else
+ cpm2_gc->cpdata &= ~pin_mask;
+
+ out_be32(&iop->dat, cpm2_gc->cpdata);
+
+ spin_unlock_irqrestore(&cpm2_gc->lock, flags);
+}
+
+static int cpm2_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm2_ioports __iomem *iop = mm_gc->regs;
+ u32 pin_mask;
+
+ pin_mask = 1 << (31 - gpio);
+
+ setbits32(&iop->dir, pin_mask);
+
+ cpm2_gpio32_set(gc, gpio, val);
+
+ return 0;
+}
+
+static int cpm2_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm2_ioports __iomem *iop = mm_gc->regs;
+ u32 pin_mask;
+
+ pin_mask = 1 << (31 - gpio);
+
+ clrbits32(&iop->dir, pin_mask);
+
+ return 0;
+}
+
+int cpm2_gpiochip_add32(struct device_node *np)
+{
+ struct cpm2_gpio32_chip *cpm2_gc;
+ struct of_mm_gpio_chip *mm_gc;
+ struct of_gpio_chip *of_gc;
+ struct gpio_chip *gc;
+
+ cpm2_gc = kzalloc(sizeof(*cpm2_gc), GFP_KERNEL);
+ if (!cpm2_gc)
+ return -ENOMEM;
+
+ spin_lock_init(&cpm2_gc->lock);
+
+ mm_gc = &cpm2_gc->mm_gc;
+ of_gc = &mm_gc->of_gc;
+ gc = &of_gc->gc;
+
+ mm_gc->save_regs = cpm2_gpio32_save_regs;
+ of_gc->gpio_cells = 1;
+ gc->ngpio = 32;
+ gc->direction_input = cpm2_gpio32_dir_in;
+ gc->direction_output = cpm2_gpio32_dir_out;
+ gc->get = cpm2_gpio32_get;
+ gc->set = cpm2_gpio32_set;
+
+ return of_mm_gpiochip_add(np, mm_gc);
+}
+#endif /* CONFIG_CPM2 || CONFIG_8xx_GPIO */
diff --git a/include/asm-powerpc/cpm.h b/include/asm-powerpc/cpm.h
index ede38ff..23b72ee 100644
--- a/include/asm-powerpc/cpm.h
+++ b/include/asm-powerpc/cpm.h
@@ -3,6 +3,7 @@
#include <linux/compiler.h>
#include <linux/types.h>
+#include <linux/of.h>
/* Opcodes common to CPM1 and CPM2
*/
@@ -99,4 +100,6 @@ void __iomem *cpm_muram_addr(unsigned long offset);
dma_addr_t cpm_muram_dma(void __iomem *addr);
int cpm_command(u32 command, u8 opcode);
+int cpm2_gpiochip_add32(struct device_node *np);
+
#endif
--
1.5.5
^ permalink raw reply related
* Re: RFC: MPC5200 PSC AC97 driver
From: Matt Sealey @ 2008-04-18 18:11 UTC (permalink / raw)
To: Juergen Beisert; +Cc: linuxppc-dev
In-Reply-To: <200804181802.34833.jbe@pengutronix.de>
Juergen Beisert wrote:
> On Friday 18 April 2008 17:43, Peter Czanik wrote:
> I'm not sure if "cell-index" is a correct property. I copied it from the uart
> driver, because this driver needs something to distinguish between PSC1 and
> PSC2. Maybe there is a better and correct oftree solution? Any oftree expert
> here?
cell-index is correct by legacy, but I think it has been said by that you could
just as well pick which PSC you are running on by it's address.
I would prefer the address approach, but everyone's going to keep cell-index
around anyway so why not leave it there and why not keep using it?
--
Matt Sealey <matt@genesi-usa.com>
Genesi, Manager, Developer Relations
^ permalink raw reply
* [PATCH 0/5 v2] Few more patches for Kumar's powerpc.git
From: Anton Vorontsov @ 2008-04-18 19:06 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev
Hello Kumar,
This is the second try...
--
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2
^ permalink raw reply
* Re: [PATCH] pseries: phyp dump: Variable size reserve space.
From: Manish Ahuja @ 2008-04-18 19:08 UTC (permalink / raw)
To: linasvepstas; +Cc: mahuja, linuxppc-dev, paulus
In-Reply-To: <3ae3aa420804161322i10e5efe2v2f74e1f9d6698e90@mail.gmail.com>
Yeah, that makes sense, I will shortly send a documentation patch for all the boot vars
that I have added.
Thanks for reminding.
-Manish
Linas Vepstas wrote:
> On 07/04/2008, Manish Ahuja <ahuja@austin.ibm.com> wrote:
>> A small proposed change in the amount of reserve space we allocate during boot.
>> Currently we reserve 256MB only.
>> The proposed change does one of the 3 things.
>>
>> A. It checks to see if there is cmdline variable set and if found sets the
>> value to it. OR
>> B. It computes 5% of total ram and rounds it down to multiples of 256MB. AND
>> C. Compares the rounded down value and returns larger of two values, the new
>> computed value or 256MB.
>>
>> Again this is for large systems who have excess memory.
>>
> [...]
>> early_param("phyp_dump", early_phyp_dump_enabled);
>
> I'm pretty sure you will want to document this boot param in the documentation,
> as well as add a few words about why it might be interesting to users (i.e.
> that its for large systems...)
>
> --linas
^ permalink raw reply
* [PATCH 1/5] [POWERPC] sysdev: implement FSL GTM support
From: Anton Vorontsov @ 2008-04-18 19:09 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev
In-Reply-To: <20080418190632.GA32204@polina.dev.rtsoft.ru>
GTM stands for General-purpose Timers Module and able to generate
timer{1,2,3,4} interrupts. These timers are used by the drivers that
need time precise interrupts (like for USB transactions scheduling for
the Freescale USB Host controller as found in some QE and CPM chips),
or these timers could be used as wakeup events from the CPU deep-sleep
mode.
Things unimplemented:
1. Cascaded (32 bit) timers (1-2, 3-4).
This is straightforward to implement when needed, two timers should
be marked as "requested" and configured as appropriate.
2. Super-cascaded (64 bit) timers (1-2-3-4).
This is also straightforward to implement when needed, all timers
should be marked as "requested" and configured as appropriate.
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
Documentation/powerpc/booting-without-of.txt | 32 +++-
arch/powerpc/Kconfig | 5 +
arch/powerpc/sysdev/Makefile | 1 +
arch/powerpc/sysdev/fsl_gtm.c | 365 ++++++++++++++++++++++++++
include/asm-powerpc/fsl_gtm.h | 108 ++++++++
5 files changed, 510 insertions(+), 1 deletions(-)
create mode 100644 arch/powerpc/sysdev/fsl_gtm.c
create mode 100644 include/asm-powerpc/fsl_gtm.h
diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index 4cc7800..827b630 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -57,7 +57,8 @@ Table of Contents
n) 4xx/Axon EMAC ethernet nodes
o) Xilinx IP cores
p) Freescale Synchronous Serial Interface
- q) USB EHCI controllers
+ q) USB EHCI controllers
+ r) Freescale General-purpose Timers Module
VII - Marvell Discovery mv64[345]6x System Controller chips
1) The /system-controller node
@@ -2825,6 +2826,35 @@ platforms are moved over to use the flattened-device-tree model.
big-endian;
};
+ r) Freescale General-purpose Timers Module
+
+ Required properties:
+ - compatible : should be "fsl,gtm" ("fsl,qe-gtm" in addition for QE
+ GTMs or "fsl,cpm2-gtm" for CPM2 GTMs).
+ - reg : should contain gtm registers location and length (0x40).
+ - interrupts : should contain four interrupts.
+ - interrupt-parent : interrupt source phandle.
+ - clock-frequency : specifies the frequency driving the timer.
+
+ Example:
+
+ timer@500 {
+ compatible = "fsl,gtm";
+ reg = <0x500 0x40>;
+ interrupts = <90 8 78 8 84 8 72 8>;
+ interrupt-parent = <&ipic>;
+ /* filled by u-boot */
+ clock-frequency = <0>;
+ };
+
+ timer@440 {
+ compatible = "fsl,qe-gtm", "fsl,gtm";
+ reg = <0x440 0x40>;
+ interrupts = <12 13 14 15>;
+ interrupt-parent = <&qeic>;
+ /* filled by u-boot */
+ clock-frequency = <0>;
+ };
VII - Marvell Discovery mv64[345]6x System Controller chips
===========================================================
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 7f2f126..ad874e4 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -525,6 +525,11 @@ config FSL_LBC
help
Freescale Localbus support
+config FSL_GTM
+ bool
+ help
+ Freescale General-purpose Timers support
+
# Yes MCA RS/6000s exist but Linux-PPC does not currently support any
config MCA
bool
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 6d386d0..9d3ddd2 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o
obj-$(CONFIG_FSL_SOC) += fsl_soc.o
obj-$(CONFIG_FSL_PCI) += fsl_pci.o
obj-$(CONFIG_FSL_LBC) += fsl_lbc.o
+obj-$(CONFIG_FSL_GTM) += fsl_gtm.o
obj-$(CONFIG_RAPIDIO) += fsl_rio.o
obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o
obj-$(CONFIG_QUICC_ENGINE) += qe_lib/
diff --git a/arch/powerpc/sysdev/fsl_gtm.c b/arch/powerpc/sysdev/fsl_gtm.c
new file mode 100644
index 0000000..d29df56
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_gtm.c
@@ -0,0 +1,365 @@
+/*
+ * Freescale General-purpose Timers Module
+ *
+ * Copyright (c) Freescale Semicondutor, Inc. 2006.
+ * Shlomi Gridish <gridish@freescale.com>
+ * Jerry Huang <Chang-Ming.Huang@freescale.com>
+ * Copyright (c) MontaVista Software, Inc. 2008.
+ * Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/spinlock.h>
+#include <linux/bitops.h>
+#include <asm/fsl_gtm.h>
+
+/**
+ * gtm_get_timer - request GTM timer to use it with the rest of GTM API
+ * @width: timer width (only 16 bits wide timers implemented so far)
+ *
+ * This function reserves GTM timer for later use. It returns gtm_timer
+ * structure to use with the rest of GTM API, you should use timer->irq
+ * to manage timer interrupt.
+ */
+struct gtm_timer *gtm_get_timer(int width)
+{
+ struct device_node *np;
+ struct gtm *gtm = NULL;
+ int i;
+
+ if (width != 16)
+ return ERR_PTR(-ENOSYS);
+
+ for_each_compatible_node(np, NULL, "fsl,gtm") {
+ if (!np->data) {
+ WARN_ON(1);
+ continue;
+ }
+ gtm = np->data;
+
+ spin_lock_irq(>m->lock);
+
+ for (i = 0; i < ARRAY_SIZE(gtm->timers); i++) {
+ if (!gtm->timers[i].requested) {
+ gtm->timers[i].requested = true;
+ spin_unlock_irq(>m->lock);
+ of_node_put(np);
+ return >m->timers[i];
+ }
+ }
+
+ spin_unlock_irq(>m->lock);
+ }
+
+ if (gtm)
+ return ERR_PTR(-EBUSY);
+ return ERR_PTR(-ENODEV);
+}
+EXPORT_SYMBOL(gtm_get_timer);
+
+/**
+ * gtm_get_specific_timer - request specific GTM timer
+ * @gtm: specific GTM, pass here GTM's device_node->data
+ * @timer: specific timer number, Timer1 is 0.
+ * @width: timer width (only 16 bits wide timers implemented so far)
+ *
+ * This function reserves GTM timer for later use. It returns gtm_timer
+ * structure to use with the rest of GTM API, you should use timer->irq
+ * to manage timer interrupt.
+ */
+struct gtm_timer *gtm_get_specific_timer(struct gtm *gtm, int timer, int width)
+{
+ struct gtm_timer *ret = ERR_PTR(-EBUSY);
+
+ if (width != 16)
+ return ERR_PTR(-ENOSYS);
+
+ spin_lock_irq(>m->lock);
+
+ if (gtm->timers[timer].requested)
+ goto out;
+
+ ret = >m->timers[timer];
+ ret->requested = true;
+
+out:
+ spin_unlock_irq(>m->lock);
+ return ret;
+}
+EXPORT_SYMBOL(gtm_get_specific_timer);
+
+/**
+ * gtm_put_timer - release GTM timer
+ * @width: timer width (only 16 bits wide timers implemented so far)
+ *
+ * This function releases GTM timer so others may request it.
+ */
+void gtm_put_timer(struct gtm_timer *tmr)
+{
+ spin_lock_irq(&tmr->gtm->lock);
+
+ tmr->requested = false;
+
+ spin_unlock_irq(&tmr->gtm->lock);
+}
+EXPORT_SYMBOL(gtm_put_timer);
+
+/*
+ * This is back-end for the exported functions, it's used to reset single
+ * timer in reference mode.
+ */
+static int gtm_reset_ref_timer16(struct gtm_timer *tmr, int frequency,
+ int reference_value, bool free_run)
+{
+ struct gtm *gtm = tmr->gtm;
+ int num = tmr - >m->timers[0];
+ unsigned int prescaler;
+ u8 iclk = GTMDR_ICLK_ICLK;
+ u8 psr;
+ u8 sps;
+ unsigned long flags;
+ int max_prescaler = 256 * 256 * 16;
+
+ /* CPM2 doesn't have primary prescaler */
+ if (!tmr->gtpsr)
+ max_prescaler /= 256;
+
+ prescaler = gtm->clock / frequency;
+ /*
+ * We have two 8 bit prescalers -- primary and secondary (psr, sps),
+ * plus "slow go" mode (clk / 16). So, total prescale value is
+ * 16 * (psr + 1) * (sps + 1). Though, for CPM2 GTMs we losing psr.
+ */
+ if (prescaler > max_prescaler)
+ return -EINVAL;
+
+ if (prescaler > max_prescaler / 16) {
+ iclk = GTMDR_ICLK_SLGO;
+ prescaler /= 16;
+ }
+
+ if (prescaler <= 256) {
+ psr = 0;
+ sps = prescaler - 1;
+ } else {
+ psr = 256 - 1;
+ sps = prescaler / 256 - 1;
+ }
+
+ spin_lock_irqsave(>m->lock, flags);
+
+ /*
+ * Properly reset timers: stop, reset, set up prescalers, reference
+ * value and clear event register.
+ */
+ clrsetbits_8(tmr->gtcfr, ~(GTCFR_STP(num) | GTCFR_RST(num)),
+ GTCFR_STP(num) | GTCFR_RST(num));
+
+ setbits8(tmr->gtcfr, GTCFR_STP(num));
+
+ if (tmr->gtpsr)
+ out_be16(tmr->gtpsr, psr);
+ clrsetbits_be16(tmr->gtmdr, 0xFFFF, iclk | GTMDR_SPS(sps) |
+ GTMDR_ORI | (free_run ? GTMDR_FRR : 0));
+ out_be16(tmr->gtcnr, 0);
+ out_be16(tmr->gtrfr, reference_value);
+ out_be16(tmr->gtevr, 0xFFFF);
+
+ /* Let it be. */
+ clrbits8(tmr->gtcfr, GTCFR_STP(num));
+
+ spin_unlock_irqrestore(>m->lock, flags);
+
+ return 0;
+}
+/**
+ * gtm_reset_timer16 - reset 16 bit timer with arbitrary precision
+ * @tmr: pointer to the gtm_timer structure obtained from gtm_get_timer
+ * @usec: timer interval in microseconds
+ * @reload: if set, the timer will reset upon expiry rather than
+ * continue running free.
+ *
+ * This function (re)sets the GTM timer so that it counts up to the requested
+ * interval value, and fires the interrupt when the value is reached. This
+ * function will reduce the precision of the timer as needed in order for the
+ * requested timeout to fit in a 16-bit register.
+ */
+int gtm_reset_timer16(struct gtm_timer *tmr, unsigned long usec, bool reload)
+{
+ /* quite obvious, frequency which is enough for µSec precision */
+ int freq = 1000000;
+ unsigned int bit;
+
+ bit = fls_long(usec);
+ if (bit > 15) {
+ freq >>= bit - 15;
+ usec >>= bit - 15;
+ }
+
+ if (!freq)
+ return -EINVAL;
+
+ return gtm_reset_ref_timer16(tmr, freq, usec, reload);
+}
+EXPORT_SYMBOL(gtm_reset_timer16);
+
+/**
+ * gtm_reset_utimer16 - reset 16 bits timer
+ * @tmr: pointer to the gtm_timer structure obtained from gtm_get_timer
+ * @usec: timer interval in microseconds
+ * @reload: if set, the timer will reset upon expiry rather than
+ * continue running free.
+ *
+ * This function (re)sets GTM timer so that it counts up to the requested
+ * interval value, and fires the interrupt when the value is reached. If reload
+ * flag was set, timer will also reset itself upon reference value, otherwise
+ * it continues to increment.
+ */
+int gtm_reset_utimer16(struct gtm_timer *tmr, u16 usec, bool reload)
+{
+ /* quite obvious, frequency which is enough for µSec precision */
+ const int freq = 1000000;
+
+ /*
+ * We can lower the frequency (and probably power consumption) by
+ * dividing both frequency and usec by 2 until there is no remainder.
+ * But we won't bother with this unless savings are measured, so just
+ * run the timer as is.
+ */
+
+ return gtm_reset_ref_timer16(tmr, freq, usec, reload);
+}
+EXPORT_SYMBOL(gtm_reset_utimer16);
+
+/**
+ * gtm_stop_timer16 - stop single timer
+ * @tmr: pointer to the gtm_timer structure obtained from gtm_get_timer
+ *
+ * This function simply stops the GTM timer.
+ */
+void gtm_stop_timer16(struct gtm_timer *tmr)
+{
+ struct gtm *gtm = tmr->gtm;
+ int num = tmr - >m->timers[0];
+ unsigned long flags;
+
+ spin_lock_irqsave(>m->lock, flags);
+
+ setbits8(tmr->gtcfr, GTCFR_STP(num));
+ out_be16(tmr->gtevr, 0xFFFF);
+
+ spin_unlock_irqrestore(>m->lock, flags);
+}
+EXPORT_SYMBOL(gtm_stop_timer16);
+
+static void __init gtm_set_shortcuts(struct device_node *np,
+ struct gtm_timer *timers,
+ struct gtm_timers_regs __iomem *regs)
+{
+ /*
+ * Yeah, I don't like this either, but timers' registers a bit messed,
+ * so we have to provide shortcuts to write timer independent code.
+ * Alternative option is to create gt*() accessors, but that will be
+ * even uglier and cryptic.
+ */
+ timers[0].gtcfr = ®s->gtcfr1;
+ timers[0].gtmdr = ®s->gtmdr1;
+ timers[0].gtcnr = ®s->gtcnr1;
+ timers[0].gtrfr = ®s->gtrfr1;
+ timers[0].gtevr = ®s->gtevr1;
+
+ timers[1].gtcfr = ®s->gtcfr1;
+ timers[1].gtmdr = ®s->gtmdr2;
+ timers[1].gtcnr = ®s->gtcnr2;
+ timers[1].gtrfr = ®s->gtrfr2;
+ timers[1].gtevr = ®s->gtevr2;
+
+ timers[2].gtcfr = ®s->gtcfr2;
+ timers[2].gtmdr = ®s->gtmdr3;
+ timers[2].gtcnr = ®s->gtcnr3;
+ timers[2].gtrfr = ®s->gtrfr3;
+ timers[2].gtevr = ®s->gtevr3;
+
+ timers[3].gtcfr = ®s->gtcfr2;
+ timers[3].gtmdr = ®s->gtmdr4;
+ timers[3].gtcnr = ®s->gtcnr4;
+ timers[3].gtrfr = ®s->gtrfr4;
+ timers[3].gtevr = ®s->gtevr4;
+
+ /* CPM2 doesn't have primary prescaler */
+ if (!of_device_is_compatible(np, "fsl,cpm2-gtm")) {
+ timers[0].gtpsr = ®s->gtpsr1;
+ timers[1].gtpsr = ®s->gtpsr2;
+ timers[2].gtpsr = ®s->gtpsr3;
+ timers[3].gtpsr = ®s->gtpsr4;
+ }
+}
+
+static int __init gtm_init(void)
+{
+ struct device_node *np;
+
+ for_each_compatible_node(np, NULL, "fsl,gtm") {
+ int i;
+ struct gtm *gtm;
+ const u32 *clock;
+ int size;
+
+ gtm = kzalloc(sizeof(*gtm), GFP_KERNEL);
+ if (!gtm) {
+ pr_err("%s: unable to allocate memory\n",
+ np->full_name);
+ continue;
+ }
+
+ spin_lock_init(>m->lock);
+
+ clock = of_get_property(np, "clock-frequency", &size);
+ if (!clock || size != sizeof(*clock)) {
+ pr_err("%s: no clock-frequency\n", np->full_name);
+ goto err;
+ }
+ gtm->clock = *clock;
+
+ for (i = 0; i < ARRAY_SIZE(gtm->timers); i++) {
+ int ret;
+ struct resource irq;
+
+ ret = of_irq_to_resource(np, i, &irq);
+ if (ret == NO_IRQ) {
+ pr_err("%s: not enough interrupts specified\n",
+ np->full_name);
+ goto err;
+ }
+ gtm->timers[i].irq = irq.start;
+ gtm->timers[i].gtm = gtm;
+ }
+
+ gtm->regs = of_iomap(np, 0);
+ if (!gtm->regs) {
+ pr_err("%s: unable to iomap registers\n",
+ np->full_name);
+ goto err;
+ }
+
+ gtm_set_shortcuts(np, gtm->timers, gtm->regs);
+
+ /* We don't want to lose the node and its ->data */
+ of_node_get(np);
+ np->data = gtm;
+
+ continue;
+err:
+ kfree(gtm);
+ }
+ return 0;
+}
+arch_initcall(gtm_init);
diff --git a/include/asm-powerpc/fsl_gtm.h b/include/asm-powerpc/fsl_gtm.h
new file mode 100644
index 0000000..3eafb21
--- /dev/null
+++ b/include/asm-powerpc/fsl_gtm.h
@@ -0,0 +1,108 @@
+/*
+ * Freescale General-purpose Timers Module
+ *
+ * Copyright (c) Freescale Semicondutor, Inc. 2006.
+ * Shlomi Gridish <gridish@freescale.com>
+ * Jerry Huang <Chang-Ming.Huang@freescale.com>
+ * Copyright (c) MontaVista Software, Inc. 2008.
+ * Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __ASM_FSL_GTM_H
+#define __ASM_FSL_GTM_H
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+
+#define GTCFR_STP(x) ((x) & 1 ? 1 << 5 : 1 << 1)
+#define GTCFR_RST(x) ((x) & 1 ? 1 << 4 : 1 << 0)
+
+#define GTMDR_ICLK_MASK (3 << 1)
+#define GTMDR_ICLK_ICAS (0 << 1)
+#define GTMDR_ICLK_ICLK (1 << 1)
+#define GTMDR_ICLK_SLGO (2 << 1)
+#define GTMDR_FRR (1 << 3)
+#define GTMDR_ORI (1 << 4)
+#define GTMDR_SPS(x) ((x) << 8)
+
+struct gtm_timers_regs {
+ u8 gtcfr1; /* Timer 1, Timer 2 global config register */
+ u8 res0[0x3];
+ u8 gtcfr2; /* Timer 3, timer 4 global config register */
+ u8 res1[0xB];
+ __be16 gtmdr1; /* Timer 1 mode register */
+ __be16 gtmdr2; /* Timer 2 mode register */
+ __be16 gtrfr1; /* Timer 1 reference register */
+ __be16 gtrfr2; /* Timer 2 reference register */
+ __be16 gtcpr1; /* Timer 1 capture register */
+ __be16 gtcpr2; /* Timer 2 capture register */
+ __be16 gtcnr1; /* Timer 1 counter */
+ __be16 gtcnr2; /* Timer 2 counter */
+ __be16 gtmdr3; /* Timer 3 mode register */
+ __be16 gtmdr4; /* Timer 4 mode register */
+ __be16 gtrfr3; /* Timer 3 reference register */
+ __be16 gtrfr4; /* Timer 4 reference register */
+ __be16 gtcpr3; /* Timer 3 capture register */
+ __be16 gtcpr4; /* Timer 4 capture register */
+ __be16 gtcnr3; /* Timer 3 counter */
+ __be16 gtcnr4; /* Timer 4 counter */
+ __be16 gtevr1; /* Timer 1 event register */
+ __be16 gtevr2; /* Timer 2 event register */
+ __be16 gtevr3; /* Timer 3 event register */
+ __be16 gtevr4; /* Timer 4 event register */
+ __be16 gtpsr1; /* Timer 1 prescale register */
+ __be16 gtpsr2; /* Timer 2 prescale register */
+ __be16 gtpsr3; /* Timer 3 prescale register */
+ __be16 gtpsr4; /* Timer 4 prescale register */
+ u8 res2[0x40];
+} __attribute__ ((packed));
+
+struct gtm_timer {
+ unsigned int irq;
+
+ struct gtm *gtm;
+ bool requested;
+ u8 __iomem *gtcfr;
+ __be16 __iomem *gtmdr;
+ __be16 __iomem *gtpsr;
+ __be16 __iomem *gtcnr;
+ __be16 __iomem *gtrfr;
+ __be16 __iomem *gtevr;
+};
+
+struct gtm {
+ unsigned int clock;
+ struct gtm_timers_regs __iomem *regs;
+ struct gtm_timer timers[4];
+ spinlock_t lock;
+};
+
+extern struct gtm_timer *gtm_get_timer(int width);
+extern struct gtm_timer *gtm_get_specific_timer(struct gtm *gtm, int timer,
+ int width);
+extern void gtm_put_timer(struct gtm_timer *tmr);
+extern int gtm_reset_timer16(struct gtm_timer *tmr, unsigned long usec,
+ bool reload);
+extern int gtm_reset_utimer16(struct gtm_timer *tmr, u16 usec, bool reload);
+extern void gtm_stop_timer16(struct gtm_timer *tmr);
+
+/**
+ * gtm_ack_timer16 - acknowledge timer event (free-run timers only)
+ * @tmr: pointer to the gtm_timer structure obtained from gtm_get_timer
+ * @events: events mask to ack
+ *
+ * Thus function used to acknowledge timer interrupt event, use it inside the
+ * interrupt handler.
+ */
+static inline void gtm_ack_timer16(struct gtm_timer *tmr, u16 events)
+{
+ out_be16(tmr->gtevr, events);
+}
+
+#endif /* __ASM_FSL_GTM_H */
--
1.5.5
^ permalink raw reply related
* [PATCH 2/5] [POWERPC] QE: add support for QE USB clocks routing
From: Anton Vorontsov @ 2008-04-18 19:09 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev
In-Reply-To: <20080418190632.GA32204@polina.dev.rtsoft.ru>
This patch adds a function to the qe_lib to setup QE USB clocks routing.
To setup clocks safely, cmxgcr register needs locking, so I just reused
ucc_lock since it was used only to protect cmxgcr.
The idea behind placing clocks routing functions into the qe_lib is that
later we'll hopefully switch to the generic Linux Clock API, thus, for
example, FHCI driver may be used for QE and CPM chips without nasty #ifdefs.
This patch also fixes QE_USB_RESTART_TX command definition in the qe.h.
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
arch/powerpc/sysdev/qe_lib/Kconfig | 4 ++
arch/powerpc/sysdev/qe_lib/Makefile | 1 +
arch/powerpc/sysdev/qe_lib/ucc.c | 7 ++--
arch/powerpc/sysdev/qe_lib/usb.c | 56 +++++++++++++++++++++++++++++++++++
include/asm-powerpc/qe.h | 23 +++++++++++++-
5 files changed, 87 insertions(+), 4 deletions(-)
create mode 100644 arch/powerpc/sysdev/qe_lib/usb.c
diff --git a/arch/powerpc/sysdev/qe_lib/Kconfig b/arch/powerpc/sysdev/qe_lib/Kconfig
index adc6621..76ffbc4 100644
--- a/arch/powerpc/sysdev/qe_lib/Kconfig
+++ b/arch/powerpc/sysdev/qe_lib/Kconfig
@@ -20,3 +20,7 @@ config UCC
bool
default y if UCC_FAST || UCC_SLOW
+config QE_USB
+ bool
+ help
+ QE USB Host Controller support
diff --git a/arch/powerpc/sysdev/qe_lib/Makefile b/arch/powerpc/sysdev/qe_lib/Makefile
index 874fe1a..e9ff888 100644
--- a/arch/powerpc/sysdev/qe_lib/Makefile
+++ b/arch/powerpc/sysdev/qe_lib/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_QUICC_ENGINE)+= qe.o qe_ic.o qe_io.o
obj-$(CONFIG_UCC) += ucc.o
obj-$(CONFIG_UCC_SLOW) += ucc_slow.o
obj-$(CONFIG_UCC_FAST) += ucc_fast.o
+obj-$(CONFIG_QE_USB) += usb.o
diff --git a/arch/powerpc/sysdev/qe_lib/ucc.c b/arch/powerpc/sysdev/qe_lib/ucc.c
index 0e348d9..d3c7f5a 100644
--- a/arch/powerpc/sysdev/qe_lib/ucc.c
+++ b/arch/powerpc/sysdev/qe_lib/ucc.c
@@ -26,7 +26,8 @@
#include <asm/qe.h>
#include <asm/ucc.h>
-static DEFINE_SPINLOCK(ucc_lock);
+DEFINE_SPINLOCK(cmxgcr_lock);
+EXPORT_SYMBOL(cmxgcr_lock);
int ucc_set_qe_mux_mii_mng(unsigned int ucc_num)
{
@@ -35,10 +36,10 @@ int ucc_set_qe_mux_mii_mng(unsigned int ucc_num)
if (ucc_num > UCC_MAX_NUM - 1)
return -EINVAL;
- spin_lock_irqsave(&ucc_lock, flags);
+ spin_lock_irqsave(&cmxgcr_lock, flags);
clrsetbits_be32(&qe_immr->qmx.cmxgcr, QE_CMXGCR_MII_ENET_MNG,
ucc_num << QE_CMXGCR_MII_ENET_MNG_SHIFT);
- spin_unlock_irqrestore(&ucc_lock, flags);
+ spin_unlock_irqrestore(&cmxgcr_lock, flags);
return 0;
}
diff --git a/arch/powerpc/sysdev/qe_lib/usb.c b/arch/powerpc/sysdev/qe_lib/usb.c
new file mode 100644
index 0000000..69ce78c
--- /dev/null
+++ b/arch/powerpc/sysdev/qe_lib/usb.c
@@ -0,0 +1,56 @@
+/*
+ * QE USB routines
+ *
+ * Copyright (c) Freescale Semicondutor, Inc. 2006.
+ * Shlomi Gridish <gridish@freescale.com>
+ * Jerry Huang <Chang-Ming.Huang@freescale.com>
+ * Copyright (c) MontaVista Software, Inc. 2008.
+ * Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <asm/immap_qe.h>
+#include <asm/qe.h>
+
+int qe_usb_clock_set(enum qe_clock clk, int rate)
+{
+ struct qe_mux __iomem *mux = &qe_immr->qmx;
+ unsigned long flags;
+ u32 val;
+
+ switch (clk) {
+ case QE_CLK3: val = QE_CMXGCR_USBCS_CLK3; break;
+ case QE_CLK5: val = QE_CMXGCR_USBCS_CLK5; break;
+ case QE_CLK7: val = QE_CMXGCR_USBCS_CLK7; break;
+ case QE_CLK9: val = QE_CMXGCR_USBCS_CLK9; break;
+ case QE_CLK13: val = QE_CMXGCR_USBCS_CLK13; break;
+ case QE_CLK17: val = QE_CMXGCR_USBCS_CLK17; break;
+ case QE_CLK19: val = QE_CMXGCR_USBCS_CLK19; break;
+ case QE_CLK21: val = QE_CMXGCR_USBCS_CLK21; break;
+ case QE_BRG9: val = QE_CMXGCR_USBCS_BRG9; break;
+ case QE_BRG10: val = QE_CMXGCR_USBCS_BRG10; break;
+ default:
+ pr_err("%s: requested unknown clock %d\n", __func__, clk);
+ return -EINVAL;
+ }
+
+ if (qe_clock_is_brg(clk))
+ qe_setbrg(clk, rate, 1);
+
+ spin_lock_irqsave(&cmxgcr_lock, flags);
+
+ clrsetbits_be32(&mux->cmxgcr, QE_CMXGCR_USBCS, val);
+
+ spin_unlock_irqrestore(&cmxgcr_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(qe_usb_clock_set);
diff --git a/include/asm-powerpc/qe.h b/include/asm-powerpc/qe.h
index c3be6e2..d217288 100644
--- a/include/asm-powerpc/qe.h
+++ b/include/asm-powerpc/qe.h
@@ -16,6 +16,7 @@
#define _ASM_POWERPC_QE_H
#ifdef __KERNEL__
+#include <linux/spinlock.h>
#include <asm/immap_qe.h>
#define QE_NUM_OF_SNUM 28
@@ -74,6 +75,13 @@ enum qe_clock {
QE_CLK_DUMMY
};
+static inline bool qe_clock_is_brg(enum qe_clock clk)
+{
+ return clk >= QE_BRG1 && clk <= QE_BRG16;
+}
+
+extern spinlock_t cmxgcr_lock;
+
/* Export QE common operations */
extern void qe_reset(void);
extern int par_io_init(struct device_node *np);
@@ -156,6 +164,9 @@ int qe_upload_firmware(const struct qe_firmware *firmware);
/* Obtain information on the uploaded firmware */
struct qe_firmware_info *qe_get_firmware_info(void);
+/* QE USB */
+int qe_usb_clock_set(enum qe_clock clk, int rate);
+
/* Buffer descriptors */
struct qe_bd {
__be16 status;
@@ -254,6 +265,16 @@ enum comm_dir {
#define QE_CMXGCR_MII_ENET_MNG 0x00007000
#define QE_CMXGCR_MII_ENET_MNG_SHIFT 12
#define QE_CMXGCR_USBCS 0x0000000f
+#define QE_CMXGCR_USBCS_CLK3 0x1
+#define QE_CMXGCR_USBCS_CLK5 0x2
+#define QE_CMXGCR_USBCS_CLK7 0x3
+#define QE_CMXGCR_USBCS_CLK9 0x4
+#define QE_CMXGCR_USBCS_CLK13 0x5
+#define QE_CMXGCR_USBCS_CLK17 0x6
+#define QE_CMXGCR_USBCS_CLK19 0x7
+#define QE_CMXGCR_USBCS_CLK21 0x8
+#define QE_CMXGCR_USBCS_BRG9 0x9
+#define QE_CMXGCR_USBCS_BRG10 0xa
/* QE CECR Commands.
*/
@@ -283,7 +304,7 @@ enum comm_dir {
#define QE_HPAC_START_TX 0x0000060b
#define QE_HPAC_START_RX 0x0000070b
#define QE_USB_STOP_TX 0x0000000a
-#define QE_USB_RESTART_TX 0x0000000b
+#define QE_USB_RESTART_TX 0x0000000c
#define QE_QMC_STOP_TX 0x0000000c
#define QE_QMC_STOP_RX 0x0000000d
#define QE_SS7_SU_FIL_RESET 0x0000000e
--
1.5.5
^ permalink raw reply related
* [PATCH 3/5] [POWERPC] QE: prepare QE PIO code for GPIO LIB support
From: Anton Vorontsov @ 2008-04-18 19:09 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev
In-Reply-To: <20080418190632.GA32204@polina.dev.rtsoft.ru>
- split and export __par_io_config_pin() out of par_io_config_pin(), so we
could use the prefixed version with GPIO LIB API;
- rename struct port_regs to qe_pio_regs, and place it into qe.h;
- rename #define NUM_OF_PINS to QE_PIO_PINS, and place it into qe.h.
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
arch/powerpc/sysdev/qe_lib/qe_io.c | 94 +++++++++++++++++-------------------
include/asm-powerpc/qe.h | 19 +++++++
2 files changed, 64 insertions(+), 49 deletions(-)
diff --git a/arch/powerpc/sysdev/qe_lib/qe_io.c b/arch/powerpc/sysdev/qe_lib/qe_io.c
index 93916a4..7c87460 100644
--- a/arch/powerpc/sysdev/qe_lib/qe_io.c
+++ b/arch/powerpc/sysdev/qe_lib/qe_io.c
@@ -28,21 +28,7 @@
#undef DEBUG
-#define NUM_OF_PINS 32
-
-struct port_regs {
- __be32 cpodr; /* Open drain register */
- __be32 cpdata; /* Data register */
- __be32 cpdir1; /* Direction register */
- __be32 cpdir2; /* Direction register */
- __be32 cppar1; /* Pin assignment register */
- __be32 cppar2; /* Pin assignment register */
-#ifdef CONFIG_PPC_85xx
- u8 pad[8];
-#endif
-};
-
-static struct port_regs __iomem *par_io;
+static struct qe_pio_regs __iomem *par_io;
static int num_par_io_ports = 0;
int par_io_init(struct device_node *np)
@@ -64,69 +50,79 @@ int par_io_init(struct device_node *np)
return 0;
}
-int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain,
- int assignment, int has_irq)
+void __par_io_config_pin(struct qe_pio_regs __iomem *par_io, u8 pin, int dir,
+ int open_drain, int assignment, int has_irq)
{
- u32 pin_mask1bit, pin_mask2bits, new_mask2bits, tmp_val;
-
- if (!par_io)
- return -1;
+ u32 pin_mask1bit;
+ u32 pin_mask2bits;
+ u32 new_mask2bits;
+ u32 tmp_val;
/* calculate pin location for single and 2 bits information */
- pin_mask1bit = (u32) (1 << (NUM_OF_PINS - (pin + 1)));
+ pin_mask1bit = (u32) (1 << (QE_PIO_PINS - (pin + 1)));
/* Set open drain, if required */
- tmp_val = in_be32(&par_io[port].cpodr);
+ tmp_val = in_be32(&par_io->cpodr);
if (open_drain)
- out_be32(&par_io[port].cpodr, pin_mask1bit | tmp_val);
+ out_be32(&par_io->cpodr, pin_mask1bit | tmp_val);
else
- out_be32(&par_io[port].cpodr, ~pin_mask1bit & tmp_val);
+ out_be32(&par_io->cpodr, ~pin_mask1bit & tmp_val);
/* define direction */
- tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ?
- in_be32(&par_io[port].cpdir2) :
- in_be32(&par_io[port].cpdir1);
+ tmp_val = (pin > (QE_PIO_PINS / 2) - 1) ?
+ in_be32(&par_io->cpdir2) :
+ in_be32(&par_io->cpdir1);
/* get all bits mask for 2 bit per port */
- pin_mask2bits = (u32) (0x3 << (NUM_OF_PINS -
- (pin % (NUM_OF_PINS / 2) + 1) * 2));
+ pin_mask2bits = (u32) (0x3 << (QE_PIO_PINS -
+ (pin % (QE_PIO_PINS / 2) + 1) * 2));
/* Get the final mask we need for the right definition */
- new_mask2bits = (u32) (dir << (NUM_OF_PINS -
- (pin % (NUM_OF_PINS / 2) + 1) * 2));
+ new_mask2bits = (u32) (dir << (QE_PIO_PINS -
+ (pin % (QE_PIO_PINS / 2) + 1) * 2));
/* clear and set 2 bits mask */
- if (pin > (NUM_OF_PINS / 2) - 1) {
- out_be32(&par_io[port].cpdir2,
+ if (pin > (QE_PIO_PINS / 2) - 1) {
+ out_be32(&par_io->cpdir2,
~pin_mask2bits & tmp_val);
tmp_val &= ~pin_mask2bits;
- out_be32(&par_io[port].cpdir2, new_mask2bits | tmp_val);
+ out_be32(&par_io->cpdir2, new_mask2bits | tmp_val);
} else {
- out_be32(&par_io[port].cpdir1,
+ out_be32(&par_io->cpdir1,
~pin_mask2bits & tmp_val);
tmp_val &= ~pin_mask2bits;
- out_be32(&par_io[port].cpdir1, new_mask2bits | tmp_val);
+ out_be32(&par_io->cpdir1, new_mask2bits | tmp_val);
}
/* define pin assignment */
- tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ?
- in_be32(&par_io[port].cppar2) :
- in_be32(&par_io[port].cppar1);
+ tmp_val = (pin > (QE_PIO_PINS / 2) - 1) ?
+ in_be32(&par_io->cppar2) :
+ in_be32(&par_io->cppar1);
- new_mask2bits = (u32) (assignment << (NUM_OF_PINS -
- (pin % (NUM_OF_PINS / 2) + 1) * 2));
+ new_mask2bits = (u32) (assignment << (QE_PIO_PINS -
+ (pin % (QE_PIO_PINS / 2) + 1) * 2));
/* clear and set 2 bits mask */
- if (pin > (NUM_OF_PINS / 2) - 1) {
- out_be32(&par_io[port].cppar2,
+ if (pin > (QE_PIO_PINS / 2) - 1) {
+ out_be32(&par_io->cppar2,
~pin_mask2bits & tmp_val);
tmp_val &= ~pin_mask2bits;
- out_be32(&par_io[port].cppar2, new_mask2bits | tmp_val);
+ out_be32(&par_io->cppar2, new_mask2bits | tmp_val);
} else {
- out_be32(&par_io[port].cppar1,
+ out_be32(&par_io->cppar1,
~pin_mask2bits & tmp_val);
tmp_val &= ~pin_mask2bits;
- out_be32(&par_io[port].cppar1, new_mask2bits | tmp_val);
+ out_be32(&par_io->cppar1, new_mask2bits | tmp_val);
}
+}
+EXPORT_SYMBOL(__par_io_config_pin);
+
+int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain,
+ int assignment, int has_irq)
+{
+ if (!par_io || port >= num_par_io_ports)
+ return -EINVAL;
+ __par_io_config_pin(&par_io[port], pin, dir, open_drain, assignment,
+ has_irq);
return 0;
}
EXPORT_SYMBOL(par_io_config_pin);
@@ -137,10 +133,10 @@ int par_io_data_set(u8 port, u8 pin, u8 val)
if (port >= num_par_io_ports)
return -EINVAL;
- if (pin >= NUM_OF_PINS)
+ if (pin >= QE_PIO_PINS)
return -EINVAL;
/* calculate pin location */
- pin_mask = (u32) (1 << (NUM_OF_PINS - 1 - pin));
+ pin_mask = (u32) (1 << (QE_PIO_PINS - 1 - pin));
tmp_val = in_be32(&par_io[port].cpdata);
diff --git a/include/asm-powerpc/qe.h b/include/asm-powerpc/qe.h
index d217288..c4523ac 100644
--- a/include/asm-powerpc/qe.h
+++ b/include/asm-powerpc/qe.h
@@ -84,8 +84,27 @@ extern spinlock_t cmxgcr_lock;
/* Export QE common operations */
extern void qe_reset(void);
+
+/* QE PIO */
+#define QE_PIO_PINS 32
+
+struct qe_pio_regs {
+ __be32 cpodr; /* Open drain register */
+ __be32 cpdata; /* Data register */
+ __be32 cpdir1; /* Direction register */
+ __be32 cpdir2; /* Direction register */
+ __be32 cppar1; /* Pin assignment register */
+ __be32 cppar2; /* Pin assignment register */
+#ifdef CONFIG_PPC_85xx
+ u8 pad[8];
+#endif
+};
+
extern int par_io_init(struct device_node *np);
extern int par_io_of_config(struct device_node *np);
+extern void __par_io_config_pin(struct qe_pio_regs __iomem *par_io, u8 pin,
+ int dir, int open_drain, int assignment,
+ int has_irq);
extern int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain,
int assignment, int has_irq);
extern int par_io_data_set(u8 port, u8 pin, u8 val);
--
1.5.5
^ permalink raw reply related
* [PATCH 4/5] [POWERPC] QE: implement support for the GPIO LIB API
From: Anton Vorontsov @ 2008-04-18 19:09 UTC (permalink / raw)
To: Kumar Gala; +Cc: David Brownell, linuxppc-dev
In-Reply-To: <20080418190632.GA32204@polina.dev.rtsoft.ru>
This is needed to access QE GPIOs via Linux GPIO API.
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
On Thu, Apr 17, 2008 at 09:21:40PM -0500, Kumar Gala wrote:
>
> On Apr 17, 2008, at 5:41 PM, Anton Vorontsov wrote:
>> On Thu, Apr 17, 2008 at 05:35:53PM -0500, Kumar Gala wrote:
>>>> index a3f9c3f..a4a195a 100644
>>>> --- a/arch/powerpc/sysdev/qe_lib/qe_io.c
>>>> +++ b/arch/powerpc/sysdev/qe_lib/qe_io.c
>>>> @@ -20,7 +20,8 @@
>>>> #include <linux/errno.h>
>>>> #include <linux/module.h>
>>>> #include <linux/ioport.h>
>>>> -
>>>> +#include <linux/spinlock.h>
>>>> +#include <linux/of_gpio.h>
>>>> #include <asm/io.h>
>>>> #include <asm/qe.h>
>>>> #include <asm/prom.h>
>>>> @@ -214,6 +215,140 @@ int par_io_of_config(struct device_node *np)
>>>> }
>>>> EXPORT_SYMBOL(par_io_of_config);
>>>
>>> can we split this out into a new file since its pretty much a driver.
>>
>> No problem. Would you prefer this to go under drivers/gpio/ ?
>
>
> Yes that would be better. We actively worked on pull drivers out of
> arch/ppc back in the day.
Hi David,
Do we need your Ack to go this through powerpc tree, and if so, could
you provide one?
Thanks.
Documentation/powerpc/booting-without-of.txt | 34 ++++---
arch/powerpc/platforms/Kconfig | 2 +
drivers/gpio/Kconfig | 9 ++
drivers/gpio/Makefile | 1 +
drivers/gpio/qe.c | 147 ++++++++++++++++++++++++++
5 files changed, 180 insertions(+), 13 deletions(-)
create mode 100644 drivers/gpio/qe.c
diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index 827b630..5c9cfab 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -1721,24 +1721,32 @@ platforms are moved over to use the flattened-device-tree model.
information.
Required properties:
- - device_type : should be "par_io".
+ - #gpio-cells : should be "2".
+ - compatible : should be "fsl,qe-pario-bank-<bank>", "fsl,qe-pario-bank"
- reg : offset to the register set and its length.
- - num-ports : number of Parallel I/O ports
+ - gpio-controller : node to identify gpio controllers.
- Example:
- par_io@1400 {
- reg = <1400 100>;
- #address-cells = <1>;
- #size-cells = <0>;
- device_type = "par_io";
- num-ports = <7>;
- ucc_pin@01 {
- ......
- };
+ For example, two QE Par I/O banks:
+ qe_pio_a: gpio-controller@1400 {
+ #gpio-cells = <2>;
+ compatible = "fsl,qe-pario-bank-a", "fsl,qe-pario-bank";
+ reg = <0x1400 0x18>;
+ gpio-controller;
+ };
+ qe_pio_e: gpio-controller@1460 {
+ #gpio-cells = <2>;
+ compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank";
+ reg = <0x1460 0x18>;
+ gpio-controller;
+ };
vi) Pin configuration nodes
+ NOTE: pin configuration nodes are obsolete. Usually, their existance
+ is an evidence of the firmware shortcomings. Such fixups are
+ better handled by the Linux board file, not the device tree.
+
Required properties:
- linux,phandle : phandle of this node; likely referenced by a QE
device.
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index f38c50b..f6eecd1 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -270,6 +270,8 @@ config QUICC_ENGINE
bool
select PPC_LIB_RHEAP
select CRC32
+ select GENERIC_GPIO
+ select HAVE_GPIO_LIB
help
The QUICC Engine (QE) is a new generation of communications
coprocessors on Freescale embedded CPUs (akin to CPM in older chips).
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index bbd2834..cee56f9 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -25,6 +25,15 @@ config DEBUG_GPIO
# put expanders in the right section, in alphabetical order
+comment "On-chip GPIOs:"
+
+config GPIO_QE
+ bool "QUICC Engine GPIOs"
+ depends on QUICC_ENGINE
+ help
+ Say Y here to use GPIOs on the Freescale PowerPC CPUs with
+ QUICC Engine block.
+
comment "I2C GPIO expanders:"
config GPIO_PCA953X
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index fdde992..fd0a41f 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_HAVE_GPIO_LIB) += gpiolib.o
obj-$(CONFIG_GPIO_MCP23S08) += mcp23s08.o
obj-$(CONFIG_GPIO_PCA953X) += pca953x.o
obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o
+obj-$(CONFIG_GPIO_QE) += qe.o
diff --git a/drivers/gpio/qe.c b/drivers/gpio/qe.c
new file mode 100644
index 0000000..474bc44
--- /dev/null
+++ b/drivers/gpio/qe.c
@@ -0,0 +1,147 @@
+/*
+ * QUICC Engine GPIOs
+ *
+ * Copyright (c) MontaVista Software, Inc. 2008.
+ *
+ * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+#include <asm/qe.h>
+
+struct qe_gpio_chip {
+ struct of_mm_gpio_chip mm_gc;
+ spinlock_t lock;
+
+ /* shadowed data register to clear/set bits safely */
+ u32 cpdata;
+};
+
+static inline struct qe_gpio_chip *
+to_qe_gpio_chip(struct of_mm_gpio_chip *mm_gc)
+{
+ return container_of(mm_gc, struct qe_gpio_chip, mm_gc);
+}
+
+static void qe_gpio_save_regs(struct of_mm_gpio_chip *mm_gc)
+{
+ struct qe_gpio_chip *qe_gc = to_qe_gpio_chip(mm_gc);
+ struct qe_pio_regs __iomem *regs = mm_gc->regs;
+
+ qe_gc->cpdata = in_be32(®s->cpdata);
+}
+
+static int qe_gpio_get(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct qe_pio_regs __iomem *regs = mm_gc->regs;
+ u32 pin_mask = 1 << (QE_PIO_PINS - 1 - gpio);
+
+ return !!(in_be32(®s->cpdata) & pin_mask);
+}
+
+static void qe_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct qe_gpio_chip *qe_gc = to_qe_gpio_chip(mm_gc);
+ struct qe_pio_regs __iomem *regs = mm_gc->regs;
+ unsigned long flags;
+ u32 pin_mask = 1 << (QE_PIO_PINS - 1 - gpio);
+
+ spin_lock_irqsave(&qe_gc->lock, flags);
+
+ if (val)
+ qe_gc->cpdata |= pin_mask;
+ else
+ qe_gc->cpdata &= ~pin_mask;
+
+ out_be32(®s->cpdata, qe_gc->cpdata);
+
+ spin_unlock_irqrestore(&qe_gc->lock, flags);
+}
+
+static int qe_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct qe_gpio_chip *qe_gc = to_qe_gpio_chip(mm_gc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&qe_gc->lock, flags);
+
+ __par_io_config_pin(mm_gc->regs, gpio, 2, 0, 0, 0);
+
+ spin_unlock_irqrestore(&qe_gc->lock, flags);
+
+ return 0;
+}
+
+static int qe_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct qe_gpio_chip *qe_gc = to_qe_gpio_chip(mm_gc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&qe_gc->lock, flags);
+
+ __par_io_config_pin(mm_gc->regs, gpio, 1, 0, 0, 0);
+
+ spin_unlock_irqrestore(&qe_gc->lock, flags);
+
+ qe_gpio_set(gc, gpio, val);
+
+ return 0;
+}
+
+static int __init qe_add_gpiochips(void)
+{
+ int ret;
+ struct device_node *np;
+
+ for_each_compatible_node(np, NULL, "fsl,qe-pario-bank") {
+ struct qe_gpio_chip *qe_gc;
+ struct of_mm_gpio_chip *mm_gc;
+ struct of_gpio_chip *of_gc;
+ struct gpio_chip *gc;
+
+ qe_gc = kzalloc(sizeof(*qe_gc), GFP_KERNEL);
+ if (!qe_gc) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ spin_lock_init(&qe_gc->lock);
+
+ mm_gc = &qe_gc->mm_gc;
+ of_gc = &mm_gc->of_gc;
+ gc = &of_gc->gc;
+
+ mm_gc->save_regs = qe_gpio_save_regs;
+ of_gc->gpio_cells = 2;
+ gc->ngpio = QE_PIO_PINS;
+ gc->direction_input = qe_gpio_dir_in;
+ gc->direction_output = qe_gpio_dir_out;
+ gc->get = qe_gpio_get;
+ gc->set = qe_gpio_set;
+
+ ret = of_mm_gpiochip_add(np, mm_gc);
+ if (ret)
+ goto err;
+ }
+
+ return 0;
+err:
+ pr_err("%s: registration failed with status %d\n", np->full_name, ret);
+ of_node_put(np);
+ return ret;
+}
+arch_initcall(qe_add_gpiochips);
--
1.5.5
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox