LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 4/4] bootwrapper: cuboot for 83xx
From: Scott Wood @ 2007-04-16 23:25 UTC (permalink / raw)
  To: paulus; +Cc: linuxppc-dev
In-Reply-To: <20070416232451.GA26667@ld0162-tx32.am.freescale.net>

This adds cuboot support for MPC83xx platforms.

A device tree used with this must have linux,stdout-path in /chosen and
linux,network-index in any network device nodes that need mac addresses
assigned.

Signed-off-by: Scott Wood <scottwood@freescale.com>
---
 arch/powerpc/boot/Makefile      |    3 +-
 arch/powerpc/boot/cuboot-83xx.c |   68 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 70 insertions(+), 1 deletions(-)
 create mode 100644 arch/powerpc/boot/cuboot-83xx.c

diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index d602b7c..3e172ff 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -43,7 +43,7 @@ $(addprefix $(obj)/,$(zlib) main.o): $(addprefix $(obj)/,$(zliblinuxheader)) \
 src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \
 		ns16550.c serial.c simple_alloc.c div64.S util.S \
 		gunzip_util.c elf_util.c $(zlib) devtree.c
-src-plat := of.c
+src-plat := of.c cuboot-83xx.c
 src-boot := $(src-wlib) $(src-plat) empty.c
 
 src-boot := $(addprefix $(obj)/, $(src-boot))
@@ -162,6 +162,7 @@ $(obj)/zImage.initrd.ps3: vmlinux
 $(obj)/uImage: vmlinux $(wrapperbits)
 	$(call if_changed,wrap,uboot)
 
+cuboot-plat-$(CONFIG_83xx) += 83xx
 cuboot-plat-y += unknown-platform
 
 dts = $(if $(shell echo $(CONFIG_) | grep '^/'),\
diff --git a/arch/powerpc/boot/cuboot-83xx.c b/arch/powerpc/boot/cuboot-83xx.c
new file mode 100644
index 0000000..8f11d1e
--- /dev/null
+++ b/arch/powerpc/boot/cuboot-83xx.c
@@ -0,0 +1,68 @@
+/*
+ * Old U-boot compatibility for 83xx
+ *
+ * Author: Scott Wood <scottwood@freescale.com>
+ *
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include "ops.h"
+#include "stdio.h"
+
+#define TARGET_83xx
+#include "ppcboot.h"
+
+static bd_t bd;
+extern char _end[];
+extern char _dtb_start[], _dtb_end[];
+
+static void platform_fixups(void)
+{
+	void *soc;
+
+	dt_fixup_memory(bd.bi_memstart, bd.bi_memsize);
+	dt_fixup_mac_addresses(bd.bi_enetaddr, bd.bi_enet1addr);
+	dt_fixup_cpu_clocks(bd.bi_intfreq, bd.bi_busfreq / 4, bd.bi_busfreq);
+
+	/* Unfortunately, the specific model number is encoded in the
+	 * soc node name in existing dts files -- once that is fixed,
+	 * this can do a simple path lookup.
+	 */
+	soc = find_node_by_devtype(NULL, "soc");
+	if (soc) {
+		void *serial = NULL;
+
+		setprop(soc, "bus-frequency", &bd.bi_busfreq,
+		        sizeof(bd.bi_busfreq));
+
+		while ((serial = find_node_by_devtype(serial, "serial"))) {
+			if (get_parent(serial) != soc)
+				continue;
+
+			setprop(serial, "clock-frequency", &bd.bi_busfreq,
+			        sizeof(bd.bi_busfreq));
+		}
+	}
+}
+
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+                   unsigned long r6, unsigned long r7)
+{
+	unsigned long end_of_ram = bd.bi_memstart + bd.bi_memsize;
+	unsigned long avail_ram = end_of_ram - (unsigned long)_end;
+
+	memcpy(&bd, (bd_t *)r3, sizeof(bd));
+	loader_info.initrd_addr = r4;
+	loader_info.initrd_size = r4 ? r5 : 0;
+	loader_info.cmdline = (char *)r6;
+	loader_info.cmdline_len = r7 - r6;
+
+	simple_alloc_init(_end, avail_ram, 32, 64);
+	ft_init(_dtb_start, _dtb_end - _dtb_start, 32);
+	serial_console_init();
+	platform_ops.fixups = platform_fixups;
+}
-- 
1.5.0.3

^ permalink raw reply related

* Re: [PATCH] hvc_console polling mode timer backoff
From: Michael Ellerman @ 2007-04-17  0:13 UTC (permalink / raw)
  To: will_schmidt; +Cc: Olof Johansson, ppcdev, Milton Miller
In-Reply-To: <1176754943.28514.133.camel@farscape.rchland.ibm.com>

[-- Attachment #1: Type: text/plain, Size: 1209 bytes --]

On Mon, 2007-04-16 at 15:22 -0500, Will Schmidt wrote:
> On Sat, 2007-14-04 at 14:42 -0500, Milton Miller wrote:
> > Michael Ellerman wrote:
> 
> > Did you consider making MAX_TIMEOUT a module parameter?   It could then
> > be changed at runtime through /sys/modules/.
> 
> Yup, considered that.
> 
> Decided against it, for no reason other than "keeping it simple".  Not
> sure that extra function does more good or bad. 
> 
> Who really wants the ability to tune their console timeout value
> anyway? :-)    hrm, maybe thats a silly question.

Patch looks good. But I think it's overkill to have a parameter.

The range of useful values for MAX_TIMEOUT is 0 to perhaps 5000, it's
not like there's a vast array of possible values that people might
sensibly want to use. This is one of those places where we should just
pick a good value and stick with it.

If people really think we've got the wrong value, patches welcome.

cheers

-- 
Michael Ellerman
OzLabs, IBM Australia Development Lab

wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)

We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* Re: PROBLEM: kernel 2.6.20.6 build failed for ppc board chestnut(ibm ppc 750GX/FX)
From: Josh Boyer @ 2007-04-17  0:24 UTC (permalink / raw)
  To: Wang, Baojun; +Cc: linux-kernel, linuxppc-embedded
In-Reply-To: <200704161313.04359.wangbj@lzu.edu.cn>

On Mon, Apr 16, 2007 at 01:13:01PM +0800, Wang, Baojun wrote:
> PROBLEM: linux kernel 2.6.20.6 build failed for ppc board chestnut(ibm ppc 
> 750GX/FX)
> 

Confirmed.  arch/ppc isn't getting much love these days.

<snip>

> this brute force patch sould solve the problem:

This is missing a Signed-off-by: line.

> diff -Nru /tmp/linux-2.6.20.6/arch/ppc/platforms/chestnut.c \  
> linux-2.6.20.6/arch/ppc/platforms/chestnut.c
> 
> --- /tmp/linux-2.6.20.6/arch/ppc/platforms/chestnut.c   2007-04-07 
> 04:02:48.000000000 +0800
> +++ linux-2.6.20.6/arch/ppc/platforms/chestnut.c        2007-04-13 
> 17:09:03.000000000 +0800
> @@ -432,7 +432,9 @@
>         ptbl.name = "User FS";
>         ptbl.size = CHESTNUT_32BIT_SIZE;
> 
> -       physmap_map.size = CHESTNUT_32BIT_SIZE;
> +       // physmap_map.size = CHESTNUT_32BIT_SIZE;

Just remove this completely.  It's not needed any longer.

> +       physmap_configure(CHESTNUT_32BIT_BASE, CHESTNUT_32BIT_SIZE, 
> CONFIG_MTD_PHYSMAP_BANKWIDTH, NULL);

Technically, this call isn't needed.  The chestnut_defconfig already provides
the correct variables.

josh

^ permalink raw reply

* Re: [PATCH] [5/5] pasemi: GPIO MDIO of_platform driver
From: Olof Johansson @ 2007-04-17  0:47 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linuxppc-dev, paulus
In-Reply-To: <200704170107.12709.arnd@arndb.de>

On Tue, Apr 17, 2007 at 01:07:12AM +0200, Arnd Bergmann wrote:
> On Monday 16 April 2007, Olof Johansson wrote:
> > +static int __devinit hack_init(void)
> > +{
> > +???????struct platform_device *pdev;
> > +
> > +???????pdev = platform_device_register_simple("gpio-mdio-bitbang", 0, NULL, 0);
> > +
> > +???????return 0;
> > +}
> > +late_initcall(hack_init);
> 
> Why do you need this? The name already suggests that you are aware that this
> should be autoprobed, but it would be good to have a comment explaining
> why you did it this way.

Because I'm an idiot and forgot to take it away before posting. :-)
Thanks, will clean it up.


-Olof

^ permalink raw reply

* Re: [PATCH 1/4 v2] powerpc: document max-speed and interface-type properties
From: Kim Phillips @ 2007-04-17  0:31 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: linuxppc-dev
In-Reply-To: <53810df560c7af272cd1c71c9d5fa1ab@kernel.crashing.org>

On Tue, 17 Apr 2007 01:18:56 +0200
Segher Boessenkool <segher@kernel.crashing.org> wrote:

> > I don't need to know what type the PHY is, e.g. whether it's m88e11x1
> > compatible or not, the phylib handles that.
> 
> You need to tell the phylib what kind of bus the PHY uses.

sure, and ucc_geth does just that based on the interface-type property,
in addition to correspondingly programming the UCC.

> You can put "rgmii" or whatever in the "compatible" property
> as well.
> 
I don't understand how intermixing PHY device compatibility with the
UCC connection to the PHY would be a good thing.

> > If I were to put the properties in the PHY node, I wouldn't be able to
> > describe a 1000Mbit/s capable UCC connected to a 100Mbit/s capable PHY,
> > or vice versa.
> 
> Of course you can.  The "compatible" in the enet node
> implies it can do 1000Mbps; the "compatible" in the
> PHY node implies it does 100Mbps.

compatible in the UCC node is currently set to "ucc_geth", which does
not necessarily imply that that UCC can do 1000Mbit/s.  Some UCCs can
only do 100Mbit/s.

We currently do not have hardware that connects UCC with max-speed x
with a PHY with max. speed capability of y, where x != y, so there is
currently no need to specify the speed of the PHY.  Not that that would
be needed; the phylib would call ucc_geth's adjust_link with the new
speed.  Note that the max-speed property is used to set registers in the
UCC only.

Kim

^ permalink raw reply

* [PATCH] Initialise spinlock in the DEBUG_PAGEALLOC code
From: Michael Ellerman @ 2007-04-17  1:43 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev

Fixes:

BUG: spinlock bad magic on CPU#0, swapper/0
 lock: c00000000064ec30, .magic: 00000000, .owner: <none>/-1, .owner_cpu: 0
Call Trace:
[c00000000062b980] [c00000000000f920] .show_stack+0x6c/0x1a0 (unreliable)
[c00000000062ba20] [c0000000001c2b40] .spin_bug+0xb0/0xd4
[c00000000062bab0] [c0000000001c2ed0] ._raw_spin_lock+0x44/0x184
[c00000000062bb50] [c0000000003a42b4] ._spin_lock+0x10/0x24
[c00000000062bbd0] [c00000000002b4dc] .kernel_map_pages+0x198/0x278
[c00000000062bc90] [c000000000079720] .free_hot_cold_page+0x124/0x418
[c00000000062bd70] [c000000000530278] .free_all_bootmem_core+0x14c/0x224
[c00000000062be50] [c00000000052a178] .mem_init+0x68/0x170
[c00000000062bee0] [c00000000051d874] .start_kernel+0x2a0/0x37c
[c00000000062bf90] [c0000000000084c8] .start_here_common+0x54/0x8c


Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---

 arch/powerpc/mm/hash_utils_64.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Index: powerpc/arch/powerpc/mm/hash_utils_64.c
===================================================================
--- powerpc.orig/arch/powerpc/mm/hash_utils_64.c
+++ powerpc/arch/powerpc/mm/hash_utils_64.c
@@ -103,7 +103,7 @@ int mmu_ci_restrictions;
 #ifdef CONFIG_DEBUG_PAGEALLOC
 static u8 *linear_map_hash_slots;
 static unsigned long linear_map_hash_count;
-static spinlock_t linear_map_hash_lock;
+static spinlock_t linear_map_hash_lock = SPIN_LOCK_UNLOCKED;
 #endif /* CONFIG_DEBUG_PAGEALLOC */
 
 /* There are definitions of page sizes arrays to be used when none

^ permalink raw reply

* Re: RFC: MPC52xx serial port configuration from DT blob
From: Grant Likely @ 2007-04-17  5:34 UTC (permalink / raw)
  To: Dale Farnsworth; +Cc: linuxppc-embedded
In-Reply-To: <20070413232422.11827.qmail@farnsworth.org>

On 13 Apr 2007 16:24:22 -0700, Dale Farnsworth <dale@farnsworth.org> wrote:
> Bartlomiej wrote:
> > We have a MPC5200B-based board running an arch/powerpc kernel and we
> > need the ability to configure a non-console serial port for a particular
> > baud rate during system start-up. It seems that the UART driver in
> > drivers/serial/mpc52xx_uart.c does not support this. It only allows to
> > set parameters for a port that is used as a console, and for which those
> > parameters are passed in the kernel command line. We would like to
> > extend the mpc52xx_uart.c driver to be able to retrieve port options
> > from the DT blob and configure a given port accordingly. A new
> > port-specific property called "options" would be used for this. It would
> > have syntax following its namesake in "console" kernel parameter, as
> > described in Documentation/kernel-parameters.txt.
> >
> > For example, the following settings in the .dts file would make UART5 to
> > be configured at 115200 baud, no parity, 8 bits.
> >
> > serial@2800 {           // PSC5
> >          device_type = "serial";
> >          compatible = "mpc5200b-psc-uart\0mpc5200-psc-uart";
> >          port-number = <4>;  // Logical port assignment
> >          options = "115200n8"
> >          cell-index = <4>;
> >          reg = <2800 100>;
> >          interrupts = <2 c 0>;
> >          interrupt-parent = <500>;
> > };
> >
> >
> > In case a console port has conflicting options given in the kernel
> > command line and in the DT blob, the command line values would be used.
> >
> > Any comments on the above will be appreciated.
>
> The device tree is intended to be an OS-independent description of the
> state of the platform hardware as left by firmware (or bootwrapper).
> It is not intended to contain kernel configuration parameters or options,
> though there are a few exceptions.
>
> So, this kind of change is unlikely to be accepted.

Isn't the /chosen node intended for this kind of data?  Although I
must admit that I'm not at all familiar with the conventions used in
/chosen.

g.

-- 
Grant Likely, B.Sc. P.Eng.
Secret Lab Technologies Ltd.
grant.likely@secretlab.ca
(403) 399-0195

^ permalink raw reply

* Re: RFC: MPC52xx serial port configuration from DT blob
From: Sylvain Munaut @ 2007-04-17  6:07 UTC (permalink / raw)
  To: Bartlomiej Sieka; +Cc: linuxppc-embedded
In-Reply-To: <461FF442.8090807@semihalf.com>

Bartlomiej Sieka wrote:
> Hi All,
>
> We have a MPC5200B-based board running an arch/powerpc kernel and we
> need the ability to configure a non-console serial port for a particular
> baud rate during system start-up. It seems that the UART driver in
> drivers/serial/mpc52xx_uart.c does not support this. It only allows to
> set parameters for a port that is used as a console, and for which those
> parameters are passed in the kernel command line. We would like to
> extend the mpc52xx_uart.c driver to be able to retrieve port options
> from the DT blob and configure a given port accordingly. A new
> port-specific property called "options" would be used for this. It would
> have syntax following its namesake in "console" kernel parameter, as
> described in Documentation/kernel-parameters.txt.
>
> For example, the following settings in the .dts file would make UART5 to 
> be configured at 115200 baud, no parity, 8 bits.
>
> serial@2800 {           // PSC5
>          device_type = "serial";
>          compatible = "mpc5200b-psc-uart\0mpc5200-psc-uart";
>          port-number = <4>;  // Logical port assignment
>          options = "115200n8"
>          cell-index = <4>;
>          reg = <2800 100>;
>          interrupts = <2 c 0>;
>          interrupt-parent = <500>;
> };
>
>
> In case a console port has conflicting options given in the kernel 
> command line and in the DT blob, the command line values would be used.
>
> Any comments on the above will be appreciated.
>   
The kernel only "use" the serial for console. If it's not a console,
then it's used
by userspace and it's userspace job to configure it as it sees fit imho ...


Sylvain

^ permalink raw reply

* Re: [PATCH 1/4 v2] powerpc: document max-speed and interface-type properties
From: Andy Fleming @ 2007-04-17  7:04 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: linuxppc-dev
In-Reply-To: <9f68fb3023e258ad0fbe314099a9ffbf@kernel.crashing.org>


On Apr 16, 2007, at 18:25, Segher Boessenkool wrote:

>>> Yep.  The whole reason why any property is wanted here is
>>> to say what type the PHY is, as the enet controller can
>>> be attached to several kinds.  And what type the PHY is
>>> belongs in the PHY node, obviously.  In its "compatible"
>>> property to be exact.
>>
>> It's not saying what type the PHY is, though.  It's describing the  
>> connection.  The PHY is just as flexible wrt connection type as  
>> the ethernet controller.
>
> Huh, I've never seen that.  I'll take your word for it.

Well, mostly this just means that the PHY has pins, and can be told  
which pins have what meaning in the same way that the ethernet  
controller can.

>
>> This is actually a property of the board.  In some cases its a  
>> fixed property of the board.  In some cases it's changeable  
>> through dip switches, or even through software.
>
> In such a case you cannot describe this with a fixed
> flat device tree *at all*.


This is true to the extent that the device tree can't change on the  
fly.  But the device tree could be used to tell the software which  
one was chosen (by setting it manually, or by detecting it at runtime  
in the firmware), or it can be used to tell the software which one to  
choose.  This is really a side point to my argument, though.


>
>> Ethernet controllers need to know what the connection is so they  
>> can establish a data connection with the PHYs
>
> Can't you probe for PHYs?


I'm beginning to suspect you are confusing the PHY management bus  
with the PHY data bus.  PHYs are almost universally controlled  
through an MDIO bus which consists of 2 pins: clock and data.  This  
is not the ethernet packet data, though, it is configuration data.   
The PHYs can all be discovered on this bus, regardless of what  
interface is chosen for the data.


>
>> The reason for choosing the ethernet controller in this case has  
>> to do with the flow of information.
>>
>> 1) The driver tells the PHY what interface to use
>
> The device tree is not structured after how Linux device
> drivers want to use the information; instead, it describes
> the hardware.

My point was merely that the location of the information is  
arbitrary, and so here are three reasons for arbitrarily putting it  
in the ethernet node, rather than the PHY node.

>
>> 2) The ethernet controller is the endpoint of this connection  
>> which is accessible by everyone else.  IE data is not sent through  
>> PHYs by any means but through the ethernet controller, and data is  
>> not received from PHYs by any means but through the ethernet  
>> controller.
>
> So?

Same point as above

>
>> 3) The UCC needs to be told the connection type, because it does  
>> not have logic to detect it on its own.
>
> Just try all possible kinds, see if you can see a PHY
> connected?


To extend on the point above, this is nearly impossible.  As I said,  
the management bus and the data bus are different.  This interface  
property describes the pin configuration for the data bus.  It also  
describes the "rate" at which the data is sent or received (some  
interfaces double-pump, some use echo cancellation).  The result of a  
misconfiguration is that you receive gibberish and you send  
gibberish.  The PHY will happily misunderstand the ethernet  
controller, and visa-versa.

They *both* need to know how they are wired to the other one.


>
>> The truth is, this is a somewhat intractable problem because of  
>> the myriad possibilities for how board designers can hook up  
>> ethernet controllers to PHYs.  One can envision scenarios where  
>> controllers can hook up to multiple PHYs, each of one fixed type.
>
> Yeah, seen that.  Quite a common scenario.
>
>> One can envision scenarios where multiple controllers are hooked  
>> up to one PHY, and each of the controllers can use different  
>> connections.
>
> How would that work at all, except when only one controller
> is active and the rest are shut down?


Right.  It's exactly like the previous example, except the previous  
example has some PHYs sitting around, inactive.


>
>> If we put the information in the PHY node, we allow for the first  
>> scenario, but not the second.  If we put it in the ethernet node,  
>> we reverse that situation.  In either case, we'd currently have to  
>> modify our dts to specify which PHY we want to use.
>
> Which brings me back to, can't you just probe for it?

Again, no.  You would have to convince me that the interface is more  
closely tied to the PHY than to the controller.  I believe it's an  
equal weighting, and have provided three arguments above for why the  
ethernet node is more appropriate.  Feel free to do so for the PHY.   
But you need four or more, or I win.  ;)

Andy

^ permalink raw reply

* Re: [PATCH 4/5] mpc52xx suspend: deep-sleep
From: Domen Puncer @ 2007-04-17  7:05 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-embedded
In-Reply-To: <528646bc0704152240u60bf24dbx6a1ca8dd15aaaf53@mail.gmail.com>

Implement deep-sleep on MPC52xx.
SDRAM is put into self-refresh with help of SRAM code
(alternatives would be code in FLASH, I-cache).
Interrupt code must also not be in SDRAM, so put it
in I-cache.
MPC52xx core is static, so contents will remain intact even
with clocks turned off.


Signed-off-by: Domen Puncer <domen.puncer@telargo.com>

---
 arch/powerpc/platforms/52xx/Makefile        |    2 
 arch/powerpc/platforms/52xx/efika.c         |   15 ++
 arch/powerpc/platforms/52xx/lite5200.c      |   28 ++++
 arch/powerpc/platforms/52xx/mpc52xx_pm.c    |  187 ++++++++++++++++++++++++++++
 arch/powerpc/platforms/52xx/mpc52xx_sleep.S |  154 +++++++++++++++++++++++
 include/asm-powerpc/mpc52xx.h               |   11 +
 6 files changed, 397 insertions(+)

Index: grant.git/arch/powerpc/platforms/52xx/Makefile
===================================================================
--- grant.git.orig/arch/powerpc/platforms/52xx/Makefile
+++ grant.git/arch/powerpc/platforms/52xx/Makefile
@@ -10,3 +10,5 @@ endif
 
 obj-$(CONFIG_PPC_EFIKA)		+= efika.o
 obj-$(CONFIG_PPC_LITE5200)	+= lite5200.o
+
+obj-$(CONFIG_PM)		+= mpc52xx_sleep.o mpc52xx_pm.o
Index: grant.git/arch/powerpc/platforms/52xx/mpc52xx_pm.c
===================================================================
--- /dev/null
+++ grant.git/arch/powerpc/platforms/52xx/mpc52xx_pm.c
@@ -0,0 +1,187 @@
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/io.h>
+#include <asm/time.h>
+#include <asm/cacheflush.h>
+#include <asm/mpc52xx.h>
+#include "bestcomm.h"
+
+
+/* these are defined in mpc52xx_sleep.S, and only used here */
+extern void mpc52xx_deep_sleep(void *sram, void *sdram_regs,
+		struct mpc52xx_cdm *, struct mpc52xx_intr *);
+extern void mpc52xx_ds_sram(void);
+extern const long mpc52xx_ds_sram_size;
+extern void mpc52xx_ds_cached(void);
+extern const long mpc52xx_ds_cached_size;
+
+static void __iomem *mbar;
+static void __iomem *sdram;
+static struct mpc52xx_cdm __iomem *cdm;
+static struct mpc52xx_intr __iomem *intr;
+static struct mpc52xx_gpio_wkup __iomem *gpiow;
+
+struct mpc52xx_suspend mpc52xx_suspend;
+
+static int mpc52xx_pm_valid(suspend_state_t state)
+{
+	switch (state) {
+	case PM_SUSPEND_STANDBY:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+int mpc52xx_set_wakeup_gpio(u8 pin, u8 level)
+{
+	u16 tmp;
+
+	/* enable gpio */
+	out_8(&gpiow->wkup_gpioe, in_8(&gpiow->wkup_gpioe) | (1 << pin));
+	/* set as input */
+	out_8(&gpiow->wkup_ddr, in_8(&gpiow->wkup_ddr) & ~(1 << pin));
+	/* enable deep sleep interrupt */
+	out_8(&gpiow->wkup_inten, in_8(&gpiow->wkup_inten) | (1 << pin));
+	/* low/high level creates wakeup interrupt */
+	tmp = in_be16(&gpiow->wkup_itype);
+	tmp &= ~(0x3 << (pin * 2));
+	tmp |= (!level + 1) << (pin * 2);
+	out_be16(&gpiow->wkup_itype, tmp);
+	/* master enable */
+	out_8(&gpiow->wkup_maste, 1);
+
+	return 0;
+}
+
+int mpc52xx_pm_prepare(suspend_state_t state)
+{
+	if (state != PM_SUSPEND_STANDBY)
+		return -EINVAL;
+
+	/* map the whole register space */
+	mbar = mpc52xx_find_and_map("mpc5200");
+	if (!mbar) {
+		printk(KERN_ERR "%s:%i Error mapping registers\n", __func__, __LINE__);
+		return -ENOSYS;
+	}
+	/* these offsets are from mpc5200 users manual */
+	sdram = mbar + 0x100;
+	cdm = mbar + 0x200;
+	intr = mbar + 0x500;
+	gpiow = mbar + 0xc00;
+
+
+	/* call board suspend code, if applicable */
+	if (mpc52xx_suspend.board_suspend_prepare)
+		mpc52xx_suspend.board_suspend_prepare(mbar);
+	else {
+		printk(KERN_ALERT "%s: %i don't know how to wake up the board\n",
+				__func__, __LINE__);
+		goto out_unmap;
+	}
+
+	return 0;
+
+ out_unmap:
+	iounmap(mbar);
+	return -ENOSYS;
+}
+
+
+char saved_sram[0x4000];
+
+int mpc52xx_pm_enter(suspend_state_t state)
+{
+	u32 clk_enables;
+	u32 msr, hid0;
+	u32 intr_main_mask;
+	void __iomem * irq_0x500 = (void *)CONFIG_KERNEL_START + 0x500;
+	unsigned long irq_0x500_stop = (unsigned long)irq_0x500 + mpc52xx_ds_cached_size;
+	char saved_0x500[mpc52xx_ds_cached_size];
+
+	/* disable all interrupts in PIC */
+	intr_main_mask = in_be32(&intr->main_mask);
+	out_be32(&intr->main_mask, intr_main_mask | 0x1ffff);
+
+	/* don't let DEC expire any time soon */
+	mtspr(SPRN_DEC, 0x7fffffff);
+
+	/* save SRAM */
+	memcpy(saved_sram, sdma.sram, sdma.sram_size);
+
+	/* copy low level suspend code to sram */
+	memcpy(sdma.sram, mpc52xx_ds_sram, mpc52xx_ds_sram_size);
+
+	out_8(&cdm->ccs_sleep_enable, 1);
+	out_8(&cdm->osc_sleep_enable, 1);
+	out_8(&cdm->ccs_qreq_test, 1);
+
+	/* disable all but SDRAM and bestcomm (SRAM) clocks */
+	clk_enables = in_be32(&cdm->clk_enables);
+	out_be32(&cdm->clk_enables, clk_enables & 0x00088000);
+
+	/* disable power management */
+	msr = mfmsr();
+	mtmsr(msr & ~MSR_POW);
+
+	/* enable sleep mode, disable others */
+	hid0 = mfspr(SPRN_HID0);
+	mtspr(SPRN_HID0, (hid0 & ~(HID0_DOZE | HID0_NAP | HID0_DPM)) | HID0_SLEEP);
+
+	/* save original, copy our irq handler, flush from dcache and invalidate icache */
+	memcpy(saved_0x500, irq_0x500, mpc52xx_ds_cached_size);
+	memcpy(irq_0x500, mpc52xx_ds_cached, mpc52xx_ds_cached_size);
+	flush_icache_range((unsigned long)irq_0x500, irq_0x500_stop);
+
+	/* call low-level sleep code */
+	mpc52xx_deep_sleep(sdma.sram, sdram, cdm, intr);
+
+	/* restore original irq handler */
+	memcpy(irq_0x500, saved_0x500, mpc52xx_ds_cached_size);
+	flush_icache_range((unsigned long)irq_0x500, irq_0x500_stop);
+
+	/* restore old power mode */
+	mtmsr(msr & ~MSR_POW);
+	mtspr(SPRN_HID0, hid0);
+	mtmsr(msr);
+
+	out_be32(&cdm->clk_enables, clk_enables);
+	out_8(&cdm->ccs_sleep_enable, 0);
+	out_8(&cdm->osc_sleep_enable, 0);
+
+	/* restore SRAM */
+	memcpy(sdma.sram, saved_sram, sdma.sram_size);
+
+	/* restart jiffies */
+	wakeup_decrementer();
+
+	/* reenable interrupts in PIC */
+	out_be32(&intr->main_mask, intr_main_mask);
+
+	return 0;
+}
+
+int mpc52xx_pm_finish(suspend_state_t state)
+{
+	/* call board resume code */
+	if (mpc52xx_suspend.board_resume_finish)
+		mpc52xx_suspend.board_resume_finish(mbar);
+
+	iounmap(mbar);
+
+	return 0;
+}
+
+static struct pm_ops mpc52xx_pm_ops = {
+	.valid		= mpc52xx_pm_valid,
+	.prepare	= mpc52xx_pm_prepare,
+	.enter		= mpc52xx_pm_enter,
+	.finish		= mpc52xx_pm_finish,
+};
+
+int __init mpc52xx_pm_init(void)
+{
+	pm_set_ops(&mpc52xx_pm_ops);
+	return 0;
+}
Index: grant.git/arch/powerpc/platforms/52xx/mpc52xx_sleep.S
===================================================================
--- /dev/null
+++ grant.git/arch/powerpc/platforms/52xx/mpc52xx_sleep.S
@@ -0,0 +1,154 @@
+#include <asm/reg.h>
+#include <asm/ppc_asm.h>
+#include <asm/processor.h>
+
+
+.text
+
+_GLOBAL(mpc52xx_deep_sleep)
+mpc52xx_deep_sleep: /* args r3-r6: SRAM, SDRAM regs, CDM regs, INTR regs */
+
+	/* enable interrupts */
+	mfmsr	r7
+	ori	r7, r7, 0x8000 /* EE */
+	mtmsr	r7
+	sync; isync;
+
+	li	r10, 0 /* flag that irq handler sets */
+
+	/* enable tmr7 (or any other) interrupt */
+	lwz	r8, 0x14(r6) /* intr->main_mask */
+	ori	r8, r8, 0x1
+	xori	r8, r8, 0x1
+	stw	r8, 0x14(r6)
+	sync
+
+	/* emulate tmr7 interrupt */
+	li	r8, 0x1
+	stw	r8, 0x40(r6) /* intr->main_emulate */
+	sync
+
+	/* wait for it to happen */
+1:
+	cmpi	cr0, r10, 1
+	bne	cr0, 1b
+
+	/* lock icache */
+	mfspr	r10, SPRN_HID0
+	ori	r10, r10, 0x2000
+	sync; isync;
+	mtspr	SPRN_HID0, r10
+	sync; isync;
+
+
+	mflr	r9 /* save LR */
+
+	/* jump to sram */
+	mtlr	r3
+	blrl
+
+	mtlr	r9 /* restore LR */
+
+	/* unlock icache */
+	mfspr	r10, SPRN_HID0
+	ori	r10, r10, 0x2000
+	xori	r10, r10, 0x2000
+	sync; isync;
+	mtspr	SPRN_HID0, r10
+	sync; isync;
+
+
+	/* return to C code */
+	blr
+
+
+_GLOBAL(mpc52xx_ds_sram)
+mpc52xx_ds_sram:
+	/* put SDRAM into self-refresh */
+	lwz	r8, 0x4(r4)	/* sdram->ctrl */
+
+	oris	r8, r8, 0x8000 /* mode_en */
+	stw	r8, 0x4(r4)
+	sync
+
+	ori	r8, r8, 0x0002 /* soft_pre */
+	stw	r8, 0x4(r4)
+	sync
+	xori	r8, r8, 0x0002
+
+	xoris	r8, r8, 0x8000 /* !mode_en */
+	stw	r8, 0x4(r4)
+	sync
+
+	oris	r8, r8, 0x5000
+	xoris	r8, r8, 0x4000 /* ref_en !cke */
+	stw	r8, 0x4(r4)
+	sync
+
+	/* disable SDRAM clock */
+	lwz	r8, 0x14(r5) /* cdm->clkenable */
+	ori	r8, r8, 0x0008
+	xori	r8, r8, 0x0008
+	stw	r8, 0x14(r5)
+	sync
+
+
+	/* put mpc5200 to sleep */
+	mfmsr	r10
+	oris	r10, r10, 0x0004	/* POW = 1 */
+	sync; isync;
+	mtmsr	r10
+	sync; isync;
+
+
+	/* enable clock */
+	lwz	r8, 0x14(r5)
+	ori	r8, r8, 0x0008
+	stw	r8, 0x14(r5)
+	sync
+
+	/* get ram out of self-refresh */
+	lwz	r8, 0x4(r4)
+	oris	r8, r8, 0x5000 /* cke ref_en */
+	stw	r8, 0x4(r4)
+	sync
+
+	blr
+_GLOBAL(mpc52xx_ds_sram_size)
+mpc52xx_ds_sram_size:
+	.long $-mpc52xx_ds_sram
+
+
+/* ### interrupt handler for wakeup from deep-sleep ### */
+_GLOBAL(mpc52xx_ds_cached)
+mpc52xx_ds_cached:
+	mtspr	SPRN_SPRG0, r7
+	mtspr	SPRN_SPRG1, r8
+
+	/* disable emulated interrupt */
+	mfspr	r7, 311 /* MBAR */
+	addi	r7, r7, 0x540	/* intr->main_emul */
+	li	r8, 0
+	stw	r8, 0(r7)
+	sync
+	dcbf	0, r7
+
+	/* acknowledge wakeup, so CCS releases power pown */
+	mfspr	r7, 311	/* MBAR */
+	addi	r7, r7, 0x524	/* intr->enc_status */
+	lwz	r8, 0(r7)
+	ori	r8, r8, 0x0400
+	stw	r8, 0(r7)
+	sync
+	dcbf	0, r7
+
+	/* flag - we handled the interrupt */
+	li	r10, 1
+
+	mfspr	r8, SPRN_SPRG1
+	mfspr	r7, SPRN_SPRG0
+
+	rfi
+_GLOBAL(mpc52xx_ds_cached_size)
+mpc52xx_ds_cached_size:
+	.long $-mpc52xx_ds_cached
Index: grant.git/arch/powerpc/platforms/52xx/efika.c
===================================================================
--- grant.git.orig/arch/powerpc/platforms/52xx/efika.c
+++ grant.git/arch/powerpc/platforms/52xx/efika.c
@@ -185,6 +185,16 @@ static void efika_show_cpuinfo(struct se
 	of_node_put(root);
 }
 
+#ifdef CONFIG_PM
+static void efika_suspend_prepare(void __iomem *mbar)
+{
+	u8 pin = 4;	/* GPIO_WKUP_4 (GPIO_PSC6_0 - IRDA_RX) */
+	u8 level = 1;	/* wakeup on high level */
+	/* IOW. to wake it up, short pins 1 and 3 on IRDA connector */
+	mpc52xx_set_wakeup_gpio(pin, level);
+}
+#endif
+
 static void __init efika_setup_arch(void)
 {
 	rtas_initialize();
@@ -200,6 +210,11 @@ static void __init efika_setup_arch(void
 
 	efika_pcisetup();
 
+#ifdef CONFIG_PM
+	mpc52xx_suspend.board_suspend_prepare = efika_suspend_prepare;
+	mpc52xx_pm_init();
+#endif
+
 	if (ppc_md.progress)
 		ppc_md.progress("Linux/PPC " UTS_RELEASE " running on Efika ;-)\n", 0x0);
 }
Index: grant.git/arch/powerpc/platforms/52xx/lite5200.c
===================================================================
--- grant.git.orig/arch/powerpc/platforms/52xx/lite5200.c
+++ grant.git/arch/powerpc/platforms/52xx/lite5200.c
@@ -85,6 +85,28 @@ error:
 	iounmap(gpio);
 }
 
+#ifdef CONFIG_PM
+static u32 descr_a;
+static void lite5200_suspend_prepare(void __iomem *mbar)
+{
+	u8 pin = 1;	/* GPIO_WKUP_1 (GPIO_PSC2_4) */
+	u8 level = 0;	/* wakeup on low level */
+	mpc52xx_set_wakeup_gpio(pin, level);
+
+	/*
+	 * power down usb port
+	 * this needs to be called before of-ohci suspend code
+	 */
+	descr_a = in_be32(mbar + 0x1048);
+	out_be32(mbar + 0x1048, (descr_a & ~0x200) | 0x100);
+}
+
+static void lite5200_resume_finish(void __iomem *mbar)
+{
+	out_be32(mbar + 0x1048, descr_a);
+}
+#endif
+
 static void __init lite5200_setup_arch(void)
 {
 	struct device_node *np;
@@ -107,6 +129,12 @@ static void __init lite5200_setup_arch(v
 	mpc52xx_setup_cpu();	/* Generic */
 	lite5200_setup_cpu();	/* Platorm specific */
 
+#ifdef CONFIG_PM
+	mpc52xx_suspend.board_suspend_prepare = lite5200_suspend_prepare;
+	mpc52xx_suspend.board_resume_finish = lite5200_resume_finish;
+	mpc52xx_pm_init();
+#endif
+
 #ifdef CONFIG_PCI
 	np = of_find_node_by_type(np, "pci");
 	if (np)
Index: grant.git/include/asm-powerpc/mpc52xx.h
===================================================================
--- grant.git.orig/include/asm-powerpc/mpc52xx.h
+++ grant.git/include/asm-powerpc/mpc52xx.h
@@ -253,5 +253,16 @@ extern int __init mpc52xx_add_bridge(str
 
 #endif /* __ASSEMBLY__ */
 
+#ifdef CONFIG_PM
+struct mpc52xx_suspend {
+	void (*board_suspend_prepare)(void __iomem *mbar);
+	void (*board_resume_finish)(void __iomem *mbar);
+};
+
+extern struct mpc52xx_suspend mpc52xx_suspend;
+extern int __init mpc52xx_pm_init(void);
+extern int mpc52xx_set_wakeup_gpio(u8 pin, u8 level);
+#endif /* CONFIG_PM */
+
 #endif /* __ASM_POWERPC_MPC52xx_H__ */
 

^ permalink raw reply

* Re: [PATCH 4/5] mpc52xx suspend: deep-sleep
From: Grant Likely @ 2007-04-17  7:10 UTC (permalink / raw)
  To: Domen Puncer; +Cc: linuxppc-embedded
In-Reply-To: <20070417070513.GL18236@moe.telargo.com>

On 4/17/07, Domen Puncer <domen.puncer@telargo.com> wrote:
> Implement deep-sleep on MPC52xx.
> SDRAM is put into self-refresh with help of SRAM code
> (alternatives would be code in FLASH, I-cache).
> Interrupt code must also not be in SDRAM, so put it
> in I-cache.
> MPC52xx core is static, so contents will remain intact even
> with clocks turned off.
>
>
> Signed-off-by: Domen Puncer <domen.puncer@telargo.com>
Acked-by: Grant Likely <grant.likely@secretlab.ca>

^ permalink raw reply

* Re: [PATCH 5/5] lite5200b suspend: low-power mode
From: Domen Puncer @ 2007-04-17  7:11 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-embedded
In-Reply-To: <528646bc0703150709v49af8085p959bd36e0adf1e4a@mail.gmail.com>

Low-power mode implementation for Lite5200b.  (Most of devices
on board, including the CPU, are powered down)

Some I/O registers are also saved here.

A patch to U-Boot that wakes up SDRAM, and transfers control
to address saved at physical 0x0 is needed, and is already
merged in git://www.denx.de/git/u-boot-ppc4xx.git tree.


Signed-off-by: Domen Puncer <domen.puncer@telargo.com>

---
 arch/powerpc/platforms/52xx/Makefile         |    3 
 arch/powerpc/platforms/52xx/lite5200.c       |    2 
 arch/powerpc/platforms/52xx/lite5200_pm.c    |  210 +++++++++++++
 arch/powerpc/platforms/52xx/lite5200_sleep.S |  413 +++++++++++++++++++++++++++
 include/asm-powerpc/mpc52xx.h                |   10 
 5 files changed, 637 insertions(+), 1 deletion(-)

Index: grant.git/arch/powerpc/platforms/52xx/lite5200_pm.c
===================================================================
--- /dev/null
+++ grant.git/arch/powerpc/platforms/52xx/lite5200_pm.c
@@ -0,0 +1,210 @@
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <asm/io.h>
+#include <asm/time.h>
+#include <asm/mpc52xx.h>
+#include "bestcomm.h"
+
+/* defined in lite5200_sleep.S and only used here */
+extern void lite5200_low_power(void *sram, void *mbar);
+
+static struct mpc52xx_cdm __iomem *cdm;
+static struct mpc52xx_intr __iomem *pic;
+static struct mpc52xx_sdma __iomem *bes;
+static struct mpc52xx_xlb __iomem *xlb;
+static struct mpc52xx_gpio __iomem *gps;
+static struct mpc52xx_gpio_wkup __iomem *gpw;
+static void __iomem *mbar;
+
+static int lite5200_pm_valid(suspend_state_t state)
+{
+	switch (state) {
+	case PM_SUSPEND_STANDBY:
+	case PM_SUSPEND_MEM:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static int lite5200_pm_prepare(suspend_state_t state)
+{
+	/* deep sleep? let mpc52xx code handle that */
+	if (state == PM_SUSPEND_STANDBY)
+		return mpc52xx_pm_prepare(state);
+
+	if (state != PM_SUSPEND_MEM)
+		return -EINVAL;
+
+	/* map registers */
+	mbar = mpc52xx_find_and_map("mpc5200");
+	if (!mbar) {
+		printk(KERN_ERR "%s:%i Error mapping registers\n", __func__, __LINE__);
+		return -ENOSYS;
+	}
+
+	cdm = mbar + 0x200;
+	pic = mbar + 0x500;
+	gps = mbar + 0xb00;
+	gpw = mbar + 0xc00;
+	bes = mbar + 0x1200;
+	xlb = mbar + 0x1f00;
+
+	return 0;
+}
+
+/* save and restore registers not bound to any real devices */
+static struct mpc52xx_cdm scdm;
+static struct mpc52xx_intr spic;
+static struct mpc52xx_sdma sbes;
+static struct mpc52xx_xlb sxlb;
+static struct mpc52xx_gpio sgps;
+static struct mpc52xx_gpio_wkup sgpw;
+
+static void lite5200_save_regs(void)
+{
+	_memcpy_fromio(&spic, pic, sizeof(*pic));
+	_memcpy_fromio(&sbes, bes, sizeof(*bes));
+	_memcpy_fromio(&scdm, cdm, sizeof(*cdm));
+	_memcpy_fromio(&sxlb, xlb, sizeof(*xlb));
+	_memcpy_fromio(&sgps, gps, sizeof(*gps));
+	_memcpy_fromio(&sgpw, gpw, sizeof(*gpw));
+
+	memcpy(saved_sram, sdma.sram, sdma.sram_size);
+}
+
+static void lite5200_restore_regs(void)
+{
+	int i;
+	memcpy(sdma.sram, saved_sram, sdma.sram_size);
+
+
+	/*
+	 * GPIOs. Interrupt Master Enable has higher address then other
+	 * registers, so just memcpy is ok.
+	 */
+	_memcpy_toio(gpw, &sgpw, sizeof(*gpw));
+	_memcpy_toio(gps, &sgps, sizeof(*gps));
+
+
+	/* XLB Arbitrer */
+	out_be32(&xlb->snoop_window, sxlb.snoop_window);
+	out_be32(&xlb->master_priority, sxlb.master_priority);
+	out_be32(&xlb->master_pri_enable, sxlb.master_pri_enable);
+
+	/* enable */
+	out_be32(&xlb->int_enable, sxlb.int_enable);
+	out_be32(&xlb->config, sxlb.config);
+
+
+	/* CDM - Clock Distribution Module */
+	out_8(&cdm->ipb_clk_sel, scdm.ipb_clk_sel);
+	out_8(&cdm->pci_clk_sel, scdm.pci_clk_sel);
+
+	out_8(&cdm->ext_48mhz_en, scdm.ext_48mhz_en);
+	out_8(&cdm->fd_enable, scdm.fd_enable);
+	out_be16(&cdm->fd_counters, scdm.fd_counters);
+
+	out_be32(&cdm->clk_enables, scdm.clk_enables);
+
+	out_8(&cdm->osc_disable, scdm.osc_disable);
+
+	out_be16(&cdm->mclken_div_psc1, scdm.mclken_div_psc1);
+	out_be16(&cdm->mclken_div_psc2, scdm.mclken_div_psc2);
+	out_be16(&cdm->mclken_div_psc3, scdm.mclken_div_psc3);
+	out_be16(&cdm->mclken_div_psc6, scdm.mclken_div_psc6);
+
+
+	/* BESTCOMM */
+	out_be32(&bes->taskBar, sbes.taskBar);
+	out_be32(&bes->currentPointer, sbes.currentPointer);
+	out_be32(&bes->endPointer, sbes.endPointer);
+	out_be32(&bes->variablePointer, sbes.variablePointer);
+
+	out_8(&bes->IntVect1, sbes.IntVect1);
+	out_8(&bes->IntVect2, sbes.IntVect2);
+	out_be16(&bes->PtdCntrl, sbes.PtdCntrl);
+
+	for (i=0; i<32; i++)
+		out_8(&bes->ipr[i], sbes.ipr[i]);
+
+	out_be32(&bes->cReqSelect, sbes.cReqSelect);
+	out_be32(&bes->task_size0, sbes.task_size0);
+	out_be32(&bes->task_size1, sbes.task_size1);
+	out_be32(&bes->MDEDebug, sbes.MDEDebug);
+	out_be32(&bes->ADSDebug, sbes.ADSDebug);
+	out_be32(&bes->Value1, sbes.Value1);
+	out_be32(&bes->Value2, sbes.Value2);
+	out_be32(&bes->Control, sbes.Control);
+	out_be32(&bes->Status, sbes.Status);
+	out_be32(&bes->PTDDebug, sbes.PTDDebug);
+
+	/* restore tasks */
+	for (i=0; i<16; i++)
+		out_be16(&bes->tcr[i], sbes.tcr[i]);
+
+	/* enable interrupts */
+	out_be32(&bes->IntPend, sbes.IntPend);
+	out_be32(&bes->IntMask, sbes.IntMask);
+
+
+	/* PIC */
+	out_be32(&pic->per_pri1, spic.per_pri1);
+	out_be32(&pic->per_pri2, spic.per_pri2);
+	out_be32(&pic->per_pri3, spic.per_pri3);
+
+	out_be32(&pic->main_pri1, spic.main_pri1);
+	out_be32(&pic->main_pri2, spic.main_pri2);
+
+	out_be32(&pic->enc_status, spic.enc_status);
+
+	/* unmask and enable interrupts */
+	out_be32(&pic->per_mask, spic.per_mask);
+	out_be32(&pic->main_mask, spic.main_mask);
+	out_be32(&pic->ctrl, spic.ctrl);
+}
+
+static int lite5200_pm_enter(suspend_state_t state)
+{
+	/* deep sleep? let mpc52xx code handle that */
+	if (state == PM_SUSPEND_STANDBY) {
+		return mpc52xx_pm_enter(state);
+	}
+
+	lite5200_save_regs();
+
+	/* effectively save FP regs */
+	enable_kernel_fp();
+
+	lite5200_low_power(sdma.sram, mbar);
+
+	lite5200_restore_regs();
+
+	/* restart jiffies */
+	wakeup_decrementer();
+
+	iounmap(mbar);
+	return 0;
+}
+
+static int lite5200_pm_finish(suspend_state_t state)
+{
+	/* deep sleep? let mpc52xx code handle that */
+	if (state == PM_SUSPEND_STANDBY) {
+		return mpc52xx_pm_finish(state);
+	}
+	return 0;
+}
+
+static struct pm_ops lite5200_pm_ops = {
+	.valid		= lite5200_pm_valid,
+	.prepare	= lite5200_pm_prepare,
+	.enter		= lite5200_pm_enter,
+	.finish		= lite5200_pm_finish,
+};
+
+int __init lite5200_pm_init(void)
+{
+	pm_set_ops(&lite5200_pm_ops);
+	return 0;
+}
Index: grant.git/arch/powerpc/platforms/52xx/lite5200_sleep.S
===================================================================
--- /dev/null
+++ grant.git/arch/powerpc/platforms/52xx/lite5200_sleep.S
@@ -0,0 +1,413 @@
+#include <asm/reg.h>
+#include <asm/ppc_asm.h>
+#include <asm/processor.h>
+#include <asm/cache.h>
+
+
+#define SDRAM_CTRL	0x104
+#define SC_MODE_EN	(1<<31)
+#define SC_CKE		(1<<30)
+#define SC_REF_EN	(1<<28)
+#define SC_SOFT_PRE	(1<<1)
+
+#define GPIOW_GPIOE	0xc00
+#define GPIOW_DDR	0xc08
+#define GPIOW_DVO	0xc0c
+
+#define CDM_CE		0x214
+#define CDM_SDRAM	(1<<3)
+
+
+/* helpers... beware: r10 and r4 are overwritten */
+#define SAVE_SPRN(reg, addr)		\
+	mfspr	r10, SPRN_##reg;	\
+	stw	r10, ((addr)*4)(r4);
+
+#define LOAD_SPRN(reg, addr)		\
+	lwz	r10, ((addr)*4)(r4);	\
+	mtspr	SPRN_##reg, r10;	\
+	sync;				\
+	isync;
+
+
+	.data
+registers:
+	.space 0x5c*4
+	.text
+
+/* ---------------------------------------------------------------------- */
+/* low-power mode with help of M68HLC908QT1 */
+
+	.globl lite5200_low_power
+lite5200_low_power:
+
+	mr	r7, r3	/* save SRAM va */
+	mr	r8, r4	/* save MBAR va */
+
+	/* setup wakeup address for u-boot at physical location 0x0 */
+	lis	r3, CONFIG_KERNEL_START@h
+	lis	r4, lite5200_wakeup@h
+	ori	r4, r4, lite5200_wakeup@l
+	sub	r4, r4, r3
+	stw	r4, 0(r3)
+
+
+	/*
+	 * save stuff BDI overwrites
+	 * 0xf0 (0xe0->0x100 gets overwritten when BDI connected;
+	 *   even when CONFIG_BDI* is disabled and MMU XLAT commented; heisenbug?))
+	 * WARNING: self-refresh doesn't seem to work when BDI2000 is connected,
+	 *   possibly because BDI sets SDRAM registers before wakeup code does
+	 */
+	lis	r4, registers@h
+	ori	r4, r4, registers@l
+	lwz	r10, 0xf0(r3)
+	stw	r10, (0x1d*4)(r4)
+
+	/* save registers to r4 [destroys r10] */
+	SAVE_SPRN(LR, 0x1c)
+	bl	save_regs
+
+	/* flush caches [destroys r3, r4] */
+	bl	flush_data_cache
+
+
+	/* copy code to sram */
+	mr	r4, r7
+	li	r3, (sram_code_end - sram_code)/4
+	mtctr	r3
+	lis	r3, sram_code@h
+	ori	r3, r3, sram_code@l
+1:
+	lwz	r5, 0(r3)
+	stw	r5, 0(r4)
+	addi	r3, r3, 4
+	addi	r4, r4, 4
+	bdnz	1b
+
+	/* get tb_ticks_per_usec */
+	lis	r3, tb_ticks_per_usec@h
+	lwz	r11, tb_ticks_per_usec@l(r3)
+
+	/* disable I and D caches */
+	mfspr	r3, SPRN_HID0
+	ori	r3, r3, HID0_ICE | HID0_DCE
+	xori	r3, r3, HID0_ICE | HID0_DCE
+	sync; isync;
+	mtspr	SPRN_HID0, r3
+	sync; isync;
+
+	/* jump to sram */
+	mtlr	r7
+	blrl
+	/* doesn't return */
+
+
+sram_code:
+	/* self refresh */
+	lwz	r4, SDRAM_CTRL(r8)
+
+	/* send NOP (precharge) */
+	oris	r4, r4, SC_MODE_EN@h	/* mode_en */
+	stw	r4, SDRAM_CTRL(r8)
+	sync
+
+	ori	r4, r4, SC_SOFT_PRE	/* soft_pre */
+	stw	r4, SDRAM_CTRL(r8)
+	sync
+	xori	r4, r4, SC_SOFT_PRE
+
+	xoris	r4, r4, SC_MODE_EN@h	/* !mode_en */
+	stw	r4, SDRAM_CTRL(r8)
+	sync
+
+	/* delay (for NOP to finish) */
+	li	r12, 1
+	bl	udelay
+
+	/*
+	 * mode_en must not be set when enabling self-refresh
+	 * send AR with CKE low (self-refresh)
+	 */
+	oris	r4, r4, (SC_REF_EN | SC_CKE)@h
+	xoris	r4, r4, (SC_CKE)@h	/* ref_en !cke */
+	stw	r4, SDRAM_CTRL(r8)
+	sync
+
+	/* delay (after !CKE there should be two cycles) */
+	li	r12, 1
+	bl	udelay
+
+	/* disable clock */
+	lwz	r4, CDM_CE(r8)
+	ori	r4, r4, CDM_SDRAM
+	xori	r4, r4, CDM_SDRAM
+	stw	r4, CDM_CE(r8)
+	sync
+
+	/* delay a bit */
+	li	r12, 1
+	bl	udelay
+
+
+	/* turn off with QT chip */
+	li	r4, 0x02
+	stb	r4, GPIOW_GPIOE(r8)	/* enable gpio_wkup1 */
+	sync
+
+	stb	r4, GPIOW_DVO(r8)	/* "output" high */
+	sync
+	stb	r4, GPIOW_DDR(r8)	/* output */
+	sync
+	stb	r4, GPIOW_DVO(r8)	/* output high */
+	sync
+
+	/* 10uS delay */
+	li	r12, 10
+	bl	udelay
+
+	/* turn off */
+	li	r4, 0
+	stb	r4, GPIOW_DVO(r8)	/* output low */
+	sync
+
+	/* wait until we're offline */
+  1:
+	b	1b
+
+
+	/* local udelay in sram is needed */
+  udelay: /* r11 - tb_ticks_per_usec, r12 - usecs, overwrites r13 */
+	mullw	r12, r12, r11
+	mftb	r13	/* start */
+	addi	r12, r13, r12 /* end */
+    1:
+	mftb	r13	/* current */
+	cmp	cr0, r13, r12
+	blt	1b
+	blr
+
+sram_code_end:
+
+
+
+/* uboot jumps here on resume */
+lite5200_wakeup:
+	bl	restore_regs
+
+
+	/* HIDs, MSR */
+	LOAD_SPRN(HID1, 0x19)
+	LOAD_SPRN(HID2, 0x1a)
+
+
+	/* address translation is tricky (see turn_on_mmu) */
+	mfmsr	r10
+	ori	r10, r10, MSR_DR | MSR_IR
+
+
+	mtspr	SPRN_SRR1, r10
+	lis	r10, mmu_on@h
+	ori	r10, r10, mmu_on@l
+	mtspr	SPRN_SRR0, r10
+	sync
+	rfi
+mmu_on:
+	/* kernel offset (r4 is still set from restore_registers) */
+	addis	r4, r4, CONFIG_KERNEL_START@h
+
+
+	/* restore MSR */
+	lwz	r10, (4*0x1b)(r4)
+	mtmsr	r10
+	sync; isync;
+
+	/* invalidate caches */
+	mfspr	r10, SPRN_HID0
+	ori	r5, r10, HID0_ICFI | HID0_DCI
+	mtspr	SPRN_HID0, r5	/* invalidate caches */
+	sync; isync;
+	mtspr	SPRN_HID0, r10
+	sync; isync;
+
+	/* enable caches */
+	lwz	r10, (4*0x18)(r4)
+	mtspr	SPRN_HID0, r10	/* restore (enable caches, DPM) */
+	/* ^ this has to be after address translation set in MSR */
+	sync
+	isync
+
+
+	/* restore 0xf0 (BDI2000) */
+	lis	r3, CONFIG_KERNEL_START@h
+	lwz	r10, (0x1d*4)(r4)
+	stw	r10, 0xf0(r3)
+
+	LOAD_SPRN(LR, 0x1c)
+
+
+	blr
+
+
+/* ---------------------------------------------------------------------- */
+/* boring code: helpers */
+
+/* save registers */
+#define SAVE_BAT(n, addr)		\
+	SAVE_SPRN(DBAT##n##L, addr);	\
+	SAVE_SPRN(DBAT##n##U, addr+1);	\
+	SAVE_SPRN(IBAT##n##L, addr+2);	\
+	SAVE_SPRN(IBAT##n##U, addr+3);
+
+#define SAVE_SR(n, addr)		\
+	mfsr	r10, n;			\
+	stw	r10, ((addr)*4)(r4);
+
+#define SAVE_4SR(n, addr)	\
+	SAVE_SR(n, addr);	\
+	SAVE_SR(n+1, addr+1);	\
+	SAVE_SR(n+2, addr+2);	\
+	SAVE_SR(n+3, addr+3);
+
+save_regs:
+	stw	r0, 0(r4)
+	stw	r1, 0x4(r4)
+	stw	r2, 0x8(r4)
+	stmw	r11, 0xc(r4) /* 0xc -> 0x5f, (0x18*4-1) */
+
+	SAVE_SPRN(HID0, 0x18)
+	SAVE_SPRN(HID1, 0x19)
+	SAVE_SPRN(HID2, 0x1a)
+	mfmsr	r10
+	stw	r10, (4*0x1b)(r4)
+	/*SAVE_SPRN(LR, 0x1c) have to save it before the call */
+	/* 0x1d reserved by 0xf0 */
+	SAVE_SPRN(RPA,   0x1e)
+	SAVE_SPRN(SDR1,  0x1f)
+
+	/* save MMU regs */
+	SAVE_BAT(0, 0x20)
+	SAVE_BAT(1, 0x24)
+	SAVE_BAT(2, 0x28)
+	SAVE_BAT(3, 0x2c)
+	SAVE_BAT(4, 0x30)
+	SAVE_BAT(5, 0x34)
+	SAVE_BAT(6, 0x38)
+	SAVE_BAT(7, 0x3c)
+
+	SAVE_4SR(0, 0x40)
+	SAVE_4SR(4, 0x44)
+	SAVE_4SR(8, 0x48)
+	SAVE_4SR(12, 0x4c)
+
+	SAVE_SPRN(SPRG0, 0x50)
+	SAVE_SPRN(SPRG1, 0x51)
+	SAVE_SPRN(SPRG2, 0x52)
+	SAVE_SPRN(SPRG3, 0x53)
+	SAVE_SPRN(SPRG4, 0x54)
+	SAVE_SPRN(SPRG5, 0x55)
+	SAVE_SPRN(SPRG6, 0x56)
+	SAVE_SPRN(SPRG7, 0x57)
+
+	SAVE_SPRN(IABR,  0x58)
+	SAVE_SPRN(DABR,  0x59)
+	SAVE_SPRN(TBRL,  0x5a)
+	SAVE_SPRN(TBRU,  0x5b)
+
+	blr
+
+
+/* restore registers */
+#define LOAD_BAT(n, addr)		\
+	LOAD_SPRN(DBAT##n##L, addr);	\
+	LOAD_SPRN(DBAT##n##U, addr+1);	\
+	LOAD_SPRN(IBAT##n##L, addr+2);	\
+	LOAD_SPRN(IBAT##n##U, addr+3);
+
+#define LOAD_SR(n, addr)		\
+	lwz	r10, ((addr)*4)(r4);	\
+	mtsr	n, r10;
+
+#define LOAD_4SR(n, addr)	\
+	LOAD_SR(n, addr);	\
+	LOAD_SR(n+1, addr+1);	\
+	LOAD_SR(n+2, addr+2);	\
+	LOAD_SR(n+3, addr+3);
+
+restore_regs:
+	lis	r4, registers@h
+	ori	r4, r4, registers@l
+
+	/* MMU is not up yet */
+	subis	r4, r4, CONFIG_KERNEL_START@h
+
+	lwz	r0, 0(r4)
+	lwz	r1, 0x4(r4)
+	lwz	r2, 0x8(r4)
+	lmw	r11, 0xc(r4)
+
+	/*
+	 * these are a bit tricky
+	 *
+	 * 0x18 - HID0
+	 * 0x19 - HID1
+	 * 0x1a - HID2
+	 * 0x1b - MSR
+	 * 0x1c - LR
+	 * 0x1d - reserved by 0xf0 (BDI2000)
+	 */
+	LOAD_SPRN(RPA,   0x1e);
+	LOAD_SPRN(SDR1,  0x1f);
+
+	/* restore MMU regs */
+	LOAD_BAT(0, 0x20)
+	LOAD_BAT(1, 0x24)
+	LOAD_BAT(2, 0x28)
+	LOAD_BAT(3, 0x2c)
+	LOAD_BAT(4, 0x30)
+	LOAD_BAT(5, 0x34)
+	LOAD_BAT(6, 0x38)
+	LOAD_BAT(7, 0x3c)
+
+	LOAD_4SR(0, 0x40)
+	LOAD_4SR(4, 0x44)
+	LOAD_4SR(8, 0x48)
+	LOAD_4SR(12, 0x4c)
+
+	/* rest of regs */
+	LOAD_SPRN(SPRG0, 0x50);
+	LOAD_SPRN(SPRG1, 0x51);
+	LOAD_SPRN(SPRG2, 0x52);
+	LOAD_SPRN(SPRG3, 0x53);
+	LOAD_SPRN(SPRG4, 0x54);
+	LOAD_SPRN(SPRG5, 0x55);
+	LOAD_SPRN(SPRG6, 0x56);
+	LOAD_SPRN(SPRG7, 0x57);
+
+	LOAD_SPRN(IABR,  0x58);
+	LOAD_SPRN(DABR,  0x59);
+	LOAD_SPRN(TBWL,  0x5a);	/* these two have separate R/W regs */
+	LOAD_SPRN(TBWU,  0x5b);
+
+	blr
+
+
+
+/* cache flushing code. copied from arch/ppc/boot/util.S */
+#define NUM_CACHE_LINES (128*8)
+
+/*
+ * Flush data cache
+ * Do this by just reading lots of stuff into the cache.
+ */
+        .globl flush_data_cache
+flush_data_cache:
+	lis	r3,CONFIG_KERNEL_START@h
+	ori	r3,r3,CONFIG_KERNEL_START@l
+	li	r4,NUM_CACHE_LINES
+	mtctr	r4
+1:
+	lwz	r4,0(r3)
+	addi	r3,r3,L1_CACHE_BYTES	/* Next line, please */
+	bdnz	1b
+	blr
Index: grant.git/arch/powerpc/platforms/52xx/Makefile
===================================================================
--- grant.git.orig/arch/powerpc/platforms/52xx/Makefile
+++ grant.git/arch/powerpc/platforms/52xx/Makefile
@@ -12,3 +12,6 @@ obj-$(CONFIG_PPC_EFIKA)		+= efika.o
 obj-$(CONFIG_PPC_LITE5200)	+= lite5200.o
 
 obj-$(CONFIG_PM)		+= mpc52xx_sleep.o mpc52xx_pm.o
+ifeq ($(CONFIG_PPC_LITE5200),y)
+	obj-$(CONFIG_PM)	+= lite5200_sleep.o lite5200_pm.o
+endif
Index: grant.git/arch/powerpc/platforms/52xx/lite5200.c
===================================================================
--- grant.git.orig/arch/powerpc/platforms/52xx/lite5200.c
+++ grant.git/arch/powerpc/platforms/52xx/lite5200.c
@@ -132,7 +132,7 @@ static void __init lite5200_setup_arch(v
 #ifdef CONFIG_PM
 	mpc52xx_suspend.board_suspend_prepare = lite5200_suspend_prepare;
 	mpc52xx_suspend.board_resume_finish = lite5200_resume_finish;
-	mpc52xx_pm_init();
+ 	lite5200_pm_init();
 #endif
 
 #ifdef CONFIG_PCI
Index: grant.git/include/asm-powerpc/mpc52xx.h
===================================================================
--- grant.git.orig/include/asm-powerpc/mpc52xx.h
+++ grant.git/include/asm-powerpc/mpc52xx.h
@@ -262,6 +262,16 @@ struct mpc52xx_suspend {
 extern struct mpc52xx_suspend mpc52xx_suspend;
 extern int __init mpc52xx_pm_init(void);
 extern int mpc52xx_set_wakeup_gpio(u8 pin, u8 level);
+
+#ifdef CONFIG_PPC_LITE5200
+extern int __init lite5200_pm_init(void);
+
+/* lite5200 calls mpc5200 suspend functions, so here they are */
+extern int mpc52xx_pm_prepare(suspend_state_t);
+extern int mpc52xx_pm_enter(suspend_state_t);
+extern int mpc52xx_pm_finish(suspend_state_t);
+extern char saved_sram[0x4000]; /* reuse buffer from mpc52xx suspend */
+#endif
 #endif /* CONFIG_PM */
 
 #endif /* __ASM_POWERPC_MPC52xx_H__ */

^ permalink raw reply

* [PATCH 1/2] Use a weak symbol for the empty version of pcibios_add_platform_entries()
From: Michael Ellerman @ 2007-04-17  7:18 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: James.Bottomley, linuxppc-dev, linux-pci

Use a weak empty definition of pcibios_add_platform_entries() to avoid
needing an empty definition for every arch.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---

 arch/ppc/kernel/pci.c       |    6 ------
 drivers/pci/pci-sysfs.c     |    5 +++++
 include/asm-alpha/pci.h     |    5 -----
 include/asm-arm/pci.h       |    4 ----
 include/asm-cris/pci.h      |    4 ----
 include/asm-frv/pci.h       |    4 ----
 include/asm-h8300/pci.h     |    4 ----
 include/asm-i386/pci.h      |    4 ----
 include/asm-ia64/pci.h      |    4 ----
 include/asm-m68k/pci.h      |    4 ----
 include/asm-m68knommu/pci.h |    4 ----
 include/asm-mips/pci.h      |    4 ----
 include/asm-parisc/pci.h    |    4 ----
 include/asm-powerpc/pci.h   |    2 --
 include/asm-ppc/pci.h       |    2 --
 include/asm-sh/pci.h        |    4 ----
 include/asm-sh64/pci.h      |    4 ----
 include/asm-sparc/pci.h     |    4 ----
 include/asm-sparc64/pci.h   |    4 ----
 include/asm-v850/pci.h      |    4 ----
 include/asm-x86_64/pci.h    |    4 ----
 include/asm-xtensa/pci.h    |    4 ----
 include/linux/pci.h         |    2 ++
 23 files changed, 7 insertions(+), 83 deletions(-)

Index: powerpc/arch/ppc/kernel/pci.c
===================================================================
--- powerpc.orig/arch/ppc/kernel/pci.c
+++ powerpc/arch/ppc/kernel/pci.c
@@ -633,12 +633,6 @@ void pcibios_make_OF_bus_map(void)
 {
 }
 
-/* Add sysfs properties */
-void pcibios_add_platform_entries(struct pci_dev *pdev)
-{
-}
-
-
 static int __init
 pcibios_init(void)
 {
Index: powerpc/drivers/pci/pci-sysfs.c
===================================================================
--- powerpc.orig/drivers/pci/pci-sysfs.c
+++ powerpc/drivers/pci/pci-sysfs.c
@@ -600,6 +600,11 @@ static struct bin_attribute pcie_config_
 	.write = pci_write_config,
 };
 
+void __attribute__ ((weak)) pcibios_add_platform_entries(struct pci_dev *dev)
+{
+	return;
+}
+
 int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
 {
 	struct bin_attribute *rom_attr = NULL;
Index: powerpc/include/asm-alpha/pci.h
===================================================================
--- powerpc.orig/include/asm-alpha/pci.h
+++ powerpc/include/asm-alpha/pci.h
@@ -275,11 +275,6 @@ static inline int pci_proc_domain(struct
 	return hose->need_domain_info;
 }
 
-static inline void
-pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 struct pci_dev *alpha_gendev_to_pci(struct device *dev);
 
 #endif /* __KERNEL__ */
Index: powerpc/include/asm-arm/pci.h
===================================================================
--- powerpc.orig/include/asm-arm/pci.h
+++ powerpc/include/asm-arm/pci.h
@@ -76,10 +76,6 @@ pcibios_select_root(struct pci_dev *pdev
 	return root;
 }
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 #endif /* __KERNEL__ */
  
 #endif
Index: powerpc/include/asm-cris/pci.h
===================================================================
--- powerpc.orig/include/asm-cris/pci.h
+++ powerpc/include/asm-cris/pci.h
@@ -89,10 +89,6 @@ extern int pci_mmap_page_range(struct pc
 			       enum pci_mmap_state mmap_state, int write_combine);
 
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 #endif /* __KERNEL__ */
 
 /* implement the pci_ DMA API in terms of the generic device dma_ one */
Index: powerpc/include/asm-frv/pci.h
===================================================================
--- powerpc.orig/include/asm-frv/pci.h
+++ powerpc/include/asm-frv/pci.h
@@ -22,10 +22,6 @@ struct pci_dev;
 
 #define pcibios_assign_all_busses()	0
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 extern void pcibios_set_master(struct pci_dev *dev);
 
 extern void pcibios_penalize_isa_irq(int irq);
Index: powerpc/include/asm-h8300/pci.h
===================================================================
--- powerpc.orig/include/asm-h8300/pci.h
+++ powerpc/include/asm-h8300/pci.h
@@ -22,8 +22,4 @@ static inline void pcibios_penalize_isa_
 
 #define PCI_DMA_BUS_IS_PHYS	(1)
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 #endif /* _ASM_H8300_PCI_H */
Index: powerpc/include/asm-i386/pci.h
===================================================================
--- powerpc.orig/include/asm-i386/pci.h
+++ powerpc/include/asm-i386/pci.h
@@ -94,10 +94,6 @@ extern int pci_mmap_page_range(struct pc
 			       enum pci_mmap_state mmap_state, int write_combine);
 
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 #ifdef CONFIG_PCI
 static inline void pci_dma_burst_advice(struct pci_dev *pdev,
 					enum pci_dma_burst_strategy *strat,
Index: powerpc/include/asm-ia64/pci.h
===================================================================
--- powerpc.orig/include/asm-ia64/pci.h
+++ powerpc/include/asm-ia64/pci.h
@@ -143,10 +143,6 @@ static inline int pci_proc_domain(struct
 	return (pci_domain_nr(bus) != 0);
 }
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 extern void pcibios_resource_to_bus(struct pci_dev *dev,
 		struct pci_bus_region *region, struct resource *res);
 
Index: powerpc/include/asm-m68k/pci.h
===================================================================
--- powerpc.orig/include/asm-m68k/pci.h
+++ powerpc/include/asm-m68k/pci.h
@@ -54,8 +54,4 @@ static inline void pcibios_penalize_isa_
  */
 #define PCI_DMA_BUS_IS_PHYS	(1)
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 #endif /* _ASM_M68K_PCI_H */
Index: powerpc/include/asm-m68knommu/pci.h
===================================================================
--- powerpc.orig/include/asm-m68knommu/pci.h
+++ powerpc/include/asm-m68knommu/pci.h
@@ -30,10 +30,6 @@ static inline int pci_dma_supported(stru
  */
 #define pci_dac_dma_supported(pci_dev, mask) (0)
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 #endif /* CONFIG_COMEMPCI */
 
 #endif /* M68KNOMMU_PCI_H */
Index: powerpc/include/asm-mips/pci.h
===================================================================
--- powerpc.orig/include/asm-mips/pci.h
+++ powerpc/include/asm-mips/pci.h
@@ -181,10 +181,6 @@ static inline int pci_proc_domain(struct
 /* implement the pci_ DMA API in terms of the generic device dma_ one */
 #include <asm-generic/pci-dma-compat.h>
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 /* Do platform specific device initialization at pci_enable_device() time */
 extern int pcibios_plat_dev_init(struct pci_dev *dev);
 
Index: powerpc/include/asm-parisc/pci.h
===================================================================
--- powerpc.orig/include/asm-parisc/pci.h
+++ powerpc/include/asm-parisc/pci.h
@@ -284,10 +284,6 @@ pcibios_select_root(struct pci_dev *pdev
 	return root;
 }
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 static inline void pcibios_penalize_isa_irq(int irq, int active)
 {
 	/* We don't need to penalize isa irq's */
Index: powerpc/include/asm-powerpc/pci.h
===================================================================
--- powerpc.orig/include/asm-powerpc/pci.h
+++ powerpc/include/asm-powerpc/pci.h
@@ -243,8 +243,6 @@ extern void of_scan_bus(struct device_no
 
 extern int pci_read_irq_line(struct pci_dev *dev);
 
-extern void pcibios_add_platform_entries(struct pci_dev *dev);
-
 struct file;
 extern pgprot_t	pci_phys_mem_access_prot(struct file *file,
 					 unsigned long pfn,
Index: powerpc/include/asm-ppc/pci.h
===================================================================
--- powerpc.orig/include/asm-ppc/pci.h
+++ powerpc/include/asm-ppc/pci.h
@@ -145,8 +145,6 @@ pcibios_select_root(struct pci_dev *pdev
 	return root;
 }
 
-extern void pcibios_add_platform_entries(struct pci_dev *dev);
-
 struct file;
 extern pgprot_t	pci_phys_mem_access_prot(struct file *file,
 					 unsigned long pfn,
Index: powerpc/include/asm-sh/pci.h
===================================================================
--- powerpc.orig/include/asm-sh/pci.h
+++ powerpc/include/asm-sh/pci.h
@@ -134,10 +134,6 @@ int pcibios_map_platform_irq(struct pci_
 int pciauto_assign_resources(int busno, struct pci_channel *hose);
 #endif
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 #endif /* __KERNEL__ */
 
 /* generic pci stuff */
Index: powerpc/include/asm-sh64/pci.h
===================================================================
--- powerpc.orig/include/asm-sh64/pci.h
+++ powerpc/include/asm-sh64/pci.h
@@ -104,10 +104,6 @@ extern void pcibios_fixup_irqs(void);
 extern int pciauto_assign_resources(int busno, struct pci_channel *hose);
 #endif
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 #endif /* __KERNEL__ */
 
 /* generic pci stuff */
Index: powerpc/include/asm-sparc/pci.h
===================================================================
--- powerpc.orig/include/asm-sparc/pci.h
+++ powerpc/include/asm-sparc/pci.h
@@ -154,10 +154,6 @@ static inline void pci_dma_burst_advice(
 }
 #endif
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 #define PCI_DMA_ERROR_CODE      (~(dma_addr_t)0x0)
 
 static inline int pci_dma_mapping_error(dma_addr_t dma_addr)
Index: powerpc/include/asm-sparc64/pci.h
===================================================================
--- powerpc.orig/include/asm-sparc64/pci.h
+++ powerpc/include/asm-sparc64/pci.h
@@ -303,10 +303,6 @@ pcibios_bus_to_resource(struct pci_dev *
 
 extern struct resource *pcibios_select_root(struct pci_dev *, struct resource *);
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
 {
 	return PCI_IRQ_NONE;
Index: powerpc/include/asm-v850/pci.h
===================================================================
--- powerpc.orig/include/asm-v850/pci.h
+++ powerpc/include/asm-v850/pci.h
@@ -116,8 +116,4 @@ static inline void pci_dma_burst_advice(
 extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
 extern void pci_iounmap (struct pci_dev *dev, void __iomem *addr);
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 #endif /* __V850_PCI_H__ */
Index: powerpc/include/asm-x86_64/pci.h
===================================================================
--- powerpc.orig/include/asm-x86_64/pci.h
+++ powerpc/include/asm-x86_64/pci.h
@@ -135,10 +135,6 @@ static inline void pci_dma_burst_advice(
 extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
 			       enum pci_mmap_state mmap_state, int write_combine);
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 #endif /* __KERNEL__ */
 
 /* generic pci stuff */
Index: powerpc/include/asm-xtensa/pci.h
===================================================================
--- powerpc.orig/include/asm-xtensa/pci.h
+++ powerpc/include/asm-xtensa/pci.h
@@ -74,10 +74,6 @@ int pci_mmap_page_range(struct pci_dev *
 /* Tell drivers/pci/proc.c that we have pci_mmap_page_range() */
 #define HAVE_PCI_MMAP	1
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
 #endif /* __KERNEL__ */
 
 /* Implement the pci_ DMA API in terms of the generic device dma_ one */
Index: powerpc/include/linux/pci.h
===================================================================
--- powerpc.orig/include/linux/pci.h
+++ powerpc/include/linux/pci.h
@@ -853,5 +853,7 @@ extern int pci_pci_problems;
 extern unsigned long pci_cardbus_io_size;
 extern unsigned long pci_cardbus_mem_size;
 
+extern void pcibios_add_platform_entries(struct pci_dev *dev);
+
 #endif /* __KERNEL__ */
 #endif /* LINUX_PCI_H */

^ permalink raw reply

* [PATCH 2/2] Make pcibios_add_platform_entries() return errors
From: Michael Ellerman @ 2007-04-17  7:18 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: James.Bottomley, linuxppc-dev, linux-pci

Currently pcibios_add_platform_entries() returns void, but could fail,
so instead have it return an int and propagate errors up to
pci_create_sysfs_dev_files().

Fixes:
arch/powerpc/kernel/pci_64.c: In function 'pcibios_add_platform_entries':
arch/powerpc/kernel/pci_64.c:878: warning: ignoring return value of
	'device_create_file', declared with attribute warn_unused_result
arch/powerpc/kernel/pci_32.c: In function 'pcibios_add_platform_entries':
  arch/powerpc/kernel/pci_32.c:1043: warning: ignoring return value of
	'device_create_file', declared with attribute warn_unused_result

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---

 arch/powerpc/kernel/pci_32.c |    4 ++--
 arch/powerpc/kernel/pci_64.c |    4 ++--
 drivers/pci/pci-sysfs.c      |   10 +++++++---
 include/linux/pci.h          |    2 +-
 4 files changed, 12 insertions(+), 8 deletions(-)

Index: powerpc/arch/powerpc/kernel/pci_32.c
===================================================================
--- powerpc.orig/arch/powerpc/kernel/pci_32.c
+++ powerpc/arch/powerpc/kernel/pci_32.c
@@ -1037,10 +1037,10 @@ void pcibios_make_OF_bus_map(void)
 #endif /* CONFIG_PPC_OF */
 
 /* Add sysfs properties */
-void pcibios_add_platform_entries(struct pci_dev *pdev)
+int pcibios_add_platform_entries(struct pci_dev *pdev)
 {
 #ifdef CONFIG_PPC_OF
-	device_create_file(&pdev->dev, &dev_attr_devspec);
+	return device_create_file(&pdev->dev, &dev_attr_devspec);
 #endif /* CONFIG_PPC_OF */
 }
 
Index: powerpc/arch/powerpc/kernel/pci_64.c
===================================================================
--- powerpc.orig/arch/powerpc/kernel/pci_64.c
+++ powerpc/arch/powerpc/kernel/pci_64.c
@@ -873,9 +873,9 @@ static ssize_t pci_show_devspec(struct d
 }
 static DEVICE_ATTR(devspec, S_IRUGO, pci_show_devspec, NULL);
 
-void pcibios_add_platform_entries(struct pci_dev *pdev)
+int pcibios_add_platform_entries(struct pci_dev *pdev)
 {
-	device_create_file(&pdev->dev, &dev_attr_devspec);
+	return device_create_file(&pdev->dev, &dev_attr_devspec);
 }
 
 #define ISA_SPACE_MASK 0x1
Index: powerpc/drivers/pci/pci-sysfs.c
===================================================================
--- powerpc.orig/drivers/pci/pci-sysfs.c
+++ powerpc/drivers/pci/pci-sysfs.c
@@ -600,9 +600,9 @@ static struct bin_attribute pcie_config_
 	.write = pci_write_config,
 };
 
-void __attribute__ ((weak)) pcibios_add_platform_entries(struct pci_dev *dev)
+int __attribute__ ((weak)) pcibios_add_platform_entries(struct pci_dev *dev)
 {
-	return;
+	return 0;
 }
 
 int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
@@ -644,10 +644,14 @@ int __must_check pci_create_sysfs_dev_fi
 		}
 	}
 	/* add platform-specific attributes */
-	pcibios_add_platform_entries(pdev);
+	if (pcibios_add_platform_entries(pdev))
+		goto err_rom_file;
 
 	return 0;
 
+err_rom_file:
+	if (pci_resource_len(pdev, PCI_ROM_RESOURCE))
+		sysfs_remove_bin_file(&pdev->dev.kobj, rom_attr);
 err_rom:
 	kfree(rom_attr);
 err_bin_file:
Index: powerpc/include/linux/pci.h
===================================================================
--- powerpc.orig/include/linux/pci.h
+++ powerpc/include/linux/pci.h
@@ -853,7 +853,7 @@ extern int pci_pci_problems;
 extern unsigned long pci_cardbus_io_size;
 extern unsigned long pci_cardbus_mem_size;
 
-extern void pcibios_add_platform_entries(struct pci_dev *dev);
+extern int pcibios_add_platform_entries(struct pci_dev *dev);
 
 #endif /* __KERNEL__ */
 #endif /* LINUX_PCI_H */

^ permalink raw reply

* Re: [PATCH 5/5] lite5200b suspend: low-power mode
From: Grant Likely @ 2007-04-17  7:25 UTC (permalink / raw)
  To: Domen Puncer; +Cc: linuxppc-embedded
In-Reply-To: <20070417071148.GM18236@moe.telargo.com>

On 4/17/07, Domen Puncer <domen.puncer@telargo.com> wrote:
> Low-power mode implementation for Lite5200b.  (Most of devices
> on board, including the CPU, are powered down)
>
> Some I/O registers are also saved here.
>
> A patch to U-Boot that wakes up SDRAM, and transfers control
> to address saved at physical 0x0 is needed, and is already
> merged in git://www.denx.de/git/u-boot-ppc4xx.git tree.
>
>
> Signed-off-by: Domen Puncer <domen.puncer@telargo.com>
Acked-by: Grant Likely <grant.likely@secretlab.ca>

^ permalink raw reply

* Re: git tree
From: Grant Likely @ 2007-04-17  7:48 UTC (permalink / raw)
  To: Wolfgang Reissnegger, Linux PPC
In-Reply-To: <20070417022050.26A645C0062@mail41-blu.bigfish.com>

On 4/16/07, Wolfgang Reissnegger <wolfgang.reissnegger@xilinx.com> wrote:
> Hi Grant,
>
> just checked out your virtex-dev branch. I noticed that you also have a
> virtex-temac and a virtex-sysace branch that got merged into the
> virtex-dev branch.
>
> I was wondering what your branching strategy is. How is your workflow
> if, say a TEMAC bug is being fixed? Do you plan on removing the
> individual driver branches around? In which branches do you fix the
> bugs? What do you pull from where?

I haven't quite decided yet.  The -temac and -sysace branches are a
bit of an experiment.  I thought it might be a good idea to maintain
the drivers in seperate branches so it is easy to get a diff on just
that driver; but the individual drivers are pretty seperate anyway (in
different directories).  I think I'll probably drop the -temac and
-sysace branches, and just maintain all my changes in the -dev branch.
 The -forupstream branch is specifically for patches that are due to
go upstream.  I'll add patches there when I think they are suitable
for mainline, and post them to the list.

>
> Do you pull changes from mainline back into your tree(s) on a daily basis?

No.  I'll rebase them once in a while as needed, but I'm not going to
try to stay perpetually up-to-date. The best way to get perpetual
up-to-dateness is to get the drivers iinto a good state and get them
into mainline (which is certainly my goal)

>
> Right now I branched off a 2.6.20 branch and then added my patches (e.g.
> uc0, mb). For each patch I created a new branch. Once I finished adding
> the patches, I consolidated everything into a "Xilinx" branch. I'm
> beginning to wonder if this was a good way to do it. My branches look
> like this now:
>
> * 2.6.20-xlnx
>   b2.6.20
>   b2.6.20-uc0
>   b2.6.20-uc0-mb
>   b2.6.20-uc0-mb-xlnx
>   master
>   origin
>
> Is it common practice to keep individual branches in the repository?

In public trees, no, not really.  In my private tree I've got task
branches galore, but it's probably too confusing to have loads of
branches in a public tree.

>
> I like the way you have the branches separated out for each driver. I
> think I should get them from your tree, merge them with what I have and
> add new driver branches as I add more drivers. This way it would be
> easiest to sync your tree with Xilinx's

As I said, the drivers are already split out by directories; so what I
did is probably unnecessary.  But, yes, feel free to pull my tree into
yours.

Cheers,
g.

-- 
Grant Likely, B.Sc. P.Eng.
Secret Lab Technologies Ltd.
grant.likely@secretlab.ca
(403) 399-0195

^ permalink raw reply

* Re: [PATCH] Initialise spinlock in the DEBUG_PAGEALLOC code
From: Milton Miller @ 2007-04-17  7:57 UTC (permalink / raw)
  To: Michael Ellerman; +Cc: ppcdev, Paul Mackerras
In-Reply-To: <20070417014331.85276DDEBC@ozlabs.org>

On Tue Apr 17 11:43:12 EST 2007, Michael Ellerman wrote:
> -static spinlock_t linear_map_hash_lock;
> +static spinlock_t linear_map_hash_lock = SPIN_LOCK_UNLOCKED;

I think the people in this thread

[KJ][PATCH]SPIN_LOCK_UNLOCKED cleanup in arch/powerpc
http://ozlabs.org/pipermail/linuxppc-dev/2007-April/034210.html

SPIN_LOCK_UNLOCKED cleanup,use DEFINE_SPINLOCK or
__SPIN_LOCK_UNLOCKED where ever appropriate.

would like you to initialize it differently.  (I think it has
to do with the lock dependancy stuff).

milton

^ permalink raw reply

* Re: [PATCH 3/4] bootwrapper: Add ppcboot.h.
From: Wolfgang Denk @ 2007-04-17  9:03 UTC (permalink / raw)
  To: Scott Wood; +Cc: linuxppc-dev, paulus
In-Reply-To: <20070416232553.GB26693@ld0162-tx32.am.freescale.net>

In message <20070416232553.GB26693@ld0162-tx32.am.freescale.net> you wrote:
> This file describes the bd_t struct, which is used by old versions of
> U-boot to pass information to the kernel.  Platform code that needs to
> interoperate with such firmware can use this; it should not be used for
> anything new.
> 
> Signed-off-by: Scott Wood <scottwood@freescale.com>
> ---
>  arch/powerpc/boot/ppcboot.h |  108 +++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 108 insertions(+), 0 deletions(-)
>  create mode 100644 arch/powerpc/boot/ppcboot.h
> 
> diff --git a/arch/powerpc/boot/ppcboot.h b/arch/powerpc/boot/ppcboot.h
> new file mode 100644
> index 0000000..5290ff2
> --- /dev/null
> +++ b/arch/powerpc/boot/ppcboot.h

Shouldn't we finally get this straight and call the file "u-boot.h" as
it is called in U-Boot?

The PPCBoot projects has been discontinued for many years by now...


Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH, HRB 165235 Munich, CEO: Wolfgang Denk
Office:  Kirchenstr. 5,       D-82194 Groebenzell,            Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
The man on tops walks a lonely street;  the  "chain"  of  command  is
often a noose.

^ permalink raw reply

* Re: [PATCH 1/4 v2] powerpc: document max-speed and interface-type properties
From: Segher Boessenkool @ 2007-04-17 10:25 UTC (permalink / raw)
  To: Kim Phillips; +Cc: linuxppc-dev
In-Reply-To: <20070416193110.77b63e4b.kim.phillips@freescale.com>

>> You can put "rgmii" or whatever in the "compatible" property
>> as well.
>>
> I don't understand how intermixing PHY device compatibility with the
> UCC connection to the PHY would be a good thing.

"compatible" means "what kind of device is this", for the
purposes of a client program (i.e., Linux) matching a
driver to it (i.e., it should say what kind of PHY it
is, and phylib should use that info -- in most cases,
it won't need more than the least specific entry in
"compatible", i.e. "rgmii" or whatever.

>>> If I were to put the properties in the PHY node, I wouldn't be able 
>>> to
>>> describe a 1000Mbit/s capable UCC connected to a 100Mbit/s capable 
>>> PHY,
>>> or vice versa.
>>
>> Of course you can.  The "compatible" in the enet node
>> implies it can do 1000Mbps; the "compatible" in the
>> PHY node implies it does 100Mbps.
>
> compatible in the UCC node is currently set to "ucc_geth", which does
> not necessarily imply that that UCC can do 1000Mbit/s.  Some UCCs can
> only do 100Mbit/s.

So those UCCs should have a different "compatible" entry.
It's not rocket science.

> We currently do not have hardware that connects UCC with max-speed x
> with a PHY with max. speed capability of y, where x != y, so there is
> currently no need to specify the speed of the PHY.  Not that that would
> be needed; the phylib would call ucc_geth's adjust_link with the new
> speed.  Note that the max-speed property is used to set registers in 
> the
> UCC only.

max-speed of connection = min(max-speed of enet, max-speed
of PHY) -- and both of those are implied by their respective
"compatible" properties.


Segher

^ permalink raw reply

* Re: Problem cloning Linus' GIT tree!
From: Laurent Pinchart @ 2007-04-17 10:28 UTC (permalink / raw)
  To: linuxppc-embedded
In-Reply-To: <18A49CF3586FC14290887ECC63C9141F0104D042@exchange2003.dspace.de>

Hi Gerald,

> stupid newbie question:
>
> I'm trying to get Grant Likelys latest TEMAC driver from his git-tree.
> Follwing the directions on the secretlab.ca website I start by cloning
> Linus' tree.  Since I'm behind a firewall which blocks the git port I use:
>
>    git clone
> http://www.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
>
> At first everything is fine and git happily seems to download the tree.
> After a while however, git exits with the following error message:
>
>    error: Couldn't get
> http://www.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git/refs/
>tags/v2.6.11 for tags/v2.6.11 The requested URL returned error: 404
>    error: Could not interpret tags/v2.6.11 as something to pull
>    rm: cannot remove directory
> `/cygdrive/c/home/git/linux-2.6/.git/clone-tmp': Directory not empty
>
> Any hint what I did wrong?

Try upgrading git to the last version.

Best regards,

Laurent Pinchart

^ permalink raw reply

* Re: [PATCH 1/4 v2] powerpc: document max-speed and interface-type properties
From: Segher Boessenkool @ 2007-04-17 10:40 UTC (permalink / raw)
  To: Andy Fleming; +Cc: linuxppc-dev
In-Reply-To: <236CD796-DFDF-41B5-A92B-6C15876327E0@freescale.com>

>>> It's not saying what type the PHY is, though.  It's describing the 
>>> connection.  The PHY is just as flexible wrt connection type as the 
>>> ethernet controller.
>>
>> Huh, I've never seen that.  I'll take your word for it.
>
> Well, mostly this just means that the PHY has pins, and can be told 
> which pins have what meaning in the same way that the ethernet 
> controller can.

Oh I see.  But the PHY is connected in only one way, so
its node should say which way that is.

>>> Ethernet controllers need to know what the connection is so they can 
>>> establish a data connection with the PHYs
>>
>> Can't you probe for PHYs?
>
> I'm beginning to suspect you are confusing the PHY management bus with 
> the PHY data bus.

No I'm not -- not this time, anyway ;-)

>>> 1) The driver tells the PHY what interface to use
>>
>> The device tree is not structured after how Linux device
>> drivers want to use the information; instead, it describes
>> the hardware.
>
> My point was merely that the location of the information is arbitrary, 
> and so here are three reasons for arbitrarily putting it in the 
> ethernet node, rather than the PHY node.

The max speed of the controller, and the types of MII buses
it supports, belongs in the controller node (perhaps as
implicit information).

The max speed of the PHY, and the types of MII buses it
supports, belongs in the PHY node.

I don't see anything arbitrary here.

>>> 3) The UCC needs to be told the connection type, because it does not 
>>> have logic to detect it on its own.
>>
>> Just try all possible kinds, see if you can see a PHY
>> connected?
>
> To extend on the point above, this is nearly impossible.  As I said, 
> the management bus and the data bus are different.  This interface 
> property describes the pin configuration for the data bus.  It also 
> describes the "rate" at which the data is sent or received (some 
> interfaces double-pump, some use echo cancellation).  The result of a 
> misconfiguration is that you receive gibberish and you send gibberish. 
>  The PHY will happily misunderstand the ethernet controller, and 
> visa-versa.
>
> They *both* need to know how they are wired to the other one.

I was thinking you could put the PHY in loopback mode and see
what works.  This might not be too reliable of course.

> Again, no.  You would have to convince me that the interface is more 
> closely tied to the PHY than to the controller.  I believe it's an 
> equal weighting, and have provided three arguments above for why the 
> ethernet node is more appropriate.  Feel free to do so for the PHY.  
> But you need four or more, or I win.  ;)

It seems you misunderstand me.  I say the controller information
belongs in the controller node, and the PHY information belongs
in the PHY node.  If there are multiple modes possible for a
given controller+PHY combination, that information should be put
in the PHY node, since a controller can have multiple PHYs but
not the other way around (for a given PHY->controller assignment,
which is a configuration option for the firmware to decide on,
so any given device tree will describe only one such assignment).


Segher

^ permalink raw reply

* Problem cloning Linus' GIT tree!
From: Gerald Ruescher @ 2007-04-17 10:42 UTC (permalink / raw)
  To: Linuxppc-embedded

[-- Attachment #1: Type: text/plain, Size: 1272 bytes --]

Hi Folks,

stupid newbie question:

I'm trying to get Grant Likelys latest TEMAC driver from his git-tree.
Follwing the directions on the secretlab.ca website I start by cloning 
Linus' tree.  Since I'm behind a firewall which blocks the git port I use:

   git clone http://www.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git

At first everything is fine and git happily seems to download the tree.
After a while however, git exits with the following error message:

   error: Couldn't get http://www.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git/refs/tags/v2.6.11 for tags/v2.6.11
   The requested URL returned error: 404
   error: Could not interpret tags/v2.6.11 as something to pull
   rm: cannot remove directory `/cygdrive/c/home/git/linux-2.6/.git/clone-tmp': Directory not empty

Any hint what I did wrong?  

Many thanks in advance,
	Gerald

_______________________________________________

Gerald Rüscher
Software Development Engineer
Core Real-Time Implementation

dSPACE GmbH          Tel.:  +49 5251 1638-1826
Technologiepark 25   Fax:   +49 5251 16198-1826
33100 Paderborn      http://www.dspace.de
Germany              mailto:GRuescher@dspace.de
_______________________________________________



[-- Attachment #2: Type: text/html, Size: 3513 bytes --]

^ permalink raw reply

* [RFC 0/3] Experiments with AES-AltiVec, part 2
From: Sebastian Siewior @ 2007-04-17 11:52 UTC (permalink / raw)
  To: linuxppc-dev

I implemented ECB & CBC block mode for AES. This implementation performs
better then my initial attempt but the generic code is better in most 
cases therefore no need to add it to the kernel.

Sebastian
--

^ permalink raw reply

* [RFC 2/3] PowerPC: lazy altivec enabling in kernel
From: Sebastian Siewior @ 2007-04-17 11:52 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <20070417115206.709701000@linux.vnet.ibm.com>

This patch works only for 64bit kernel and will break any 32bit kernel. 
Switching on altivec takes some time due to the MSR access. The speed-up is
about 50% in my aes-code. It might be usefull for the raid module as well. 

Signed-off-by: Sebastian Siewior <bigeasy@linux.vnet.ibm.com>
Index: linux/arch/powerpc/kernel/head_64.S
===================================================================
--- linux.orig/arch/powerpc/kernel/head_64.S
+++ linux/arch/powerpc/kernel/head_64.S
@@ -1229,6 +1229,14 @@ altivec_unavailable_common:
 #ifdef CONFIG_ALTIVEC
 BEGIN_FTR_SECTION
 	bne	.load_up_altivec	/* if from user, just load it up */
+	/*
+	 * the kernel is going to use AltiVec.
+	 * hopefully enable_kernel_altivec() has been called
+	 */
+	addi r3,r1,STACK_FRAME_OVERHEAD
+	bl .altivec_enable_for_kernel_exception
+	b .ret_from_except
+
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 #endif
 	bl	.save_nvgprs
Index: linux/arch/powerpc/kernel/misc_64.S
===================================================================
--- linux.orig/arch/powerpc/kernel/misc_64.S
+++ linux/arch/powerpc/kernel/misc_64.S
@@ -493,6 +493,8 @@ _GLOBAL(giveup_altivec)
 	mfmsr	r5
 	oris	r5,r5,MSR_VEC@h
 	mtmsrd	r5			/* enable use of VMX now */
+
+giveup_user_altivec_save_vmx:
 	isync
 	cmpdi	0,r3,0
 	beqlr-				/* if no previous owner, done */
@@ -516,6 +518,14 @@ _GLOBAL(giveup_altivec)
 #endif /* CONFIG_SMP */
 	blr
 
+/*
+ * giveup_user_altivec(tsk)
+ * Same as giveup_altivec() but lets the exception handler
+ * enable AltiVec
+ */
+_GLOBAL(giveup_user_altivec)
+		b giveup_user_altivec_save_vmx
+
 #endif /* CONFIG_ALTIVEC */
 
 _GLOBAL(kernel_execve)
Index: linux/arch/powerpc/kernel/process.c
===================================================================
--- linux.orig/arch/powerpc/kernel/process.c
+++ linux/arch/powerpc/kernel/process.c
@@ -119,15 +119,21 @@ int dump_task_fpu(struct task_struct *ts
 #ifdef CONFIG_ALTIVEC
 void enable_kernel_altivec(void)
 {
-	WARN_ON(preemptible());
+	BUG_ON(preemptible());
+	/*
+	 * enable_kernel_altivec() will just save current AltiVec registers (if needed) and
+	 * return to caller (with MSR_VEC unchanged (probably not set)). The first AltiVec
+	 * instruction will raise an exception and the exception will enable the AltiVec for
+	 * the kernel. This is done to avoid the expensive "enable altivec" operation if it
+	 * is allready enabled. However, you have to disable preemtion while you are using
+	 * AltiVec.
+	 */
 
 #ifdef CONFIG_SMP
 	if (current->thread.regs && (current->thread.regs->msr & MSR_VEC))
-		giveup_altivec(current);
-	else
-		giveup_altivec(NULL);	/* just enable AltiVec for kernel - force */
+		giveup_user_altivec(current);
 #else
-	giveup_altivec(last_task_used_altivec);
+	giveup_user_altivec(last_task_used_altivec);
 #endif /* CONFIG_SMP */
 }
 EXPORT_SYMBOL(enable_kernel_altivec);
Index: linux/arch/powerpc/kernel/traps.c
===================================================================
--- linux.orig/arch/powerpc/kernel/traps.c
+++ linux/arch/powerpc/kernel/traps.c
@@ -886,6 +886,12 @@ void altivec_unavailable_exception(struc
 	die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT);
 }
 
+void altivec_enable_for_kernel_exception(struct pt_regs *regs)
+{
+	printk("altivec_enable_for_kernel_exception: AltiVec mode on for kernel\n");
+	regs->msr |= MSR_VEC;
+}
+
 void performance_monitor_exception(struct pt_regs *regs)
 {
 	perf_irq(regs);
Index: linux/include/asm-powerpc/system.h
===================================================================
--- linux.orig/include/asm-powerpc/system.h
+++ linux/include/asm-powerpc/system.h
@@ -129,6 +129,7 @@ extern void enable_kernel_fp(void);
 extern void flush_fp_to_thread(struct task_struct *);
 extern void enable_kernel_altivec(void);
 extern void giveup_altivec(struct task_struct *);
+extern void giveup_user_altivec(struct task_struct *);
 extern void load_up_altivec(struct task_struct *);
 extern int emulate_altivec(struct pt_regs *);
 extern void giveup_spe(struct task_struct *);

--

^ permalink raw reply

* [RFC 1/3] cryptoapi: AES with AltiVec support
From: Sebastian Siewior @ 2007-04-17 11:52 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <20070417115206.709701000@linux.vnet.ibm.com>

The aes module supports now CBC & ECB block mode, the performance improves
for encryption, decyption remains the same. There is no difference between
CBC and ECB cipher mode (128b):

ECB encryption: Average: 3172 msec, approx. 50441 kb/sec || 49 mb/sec
ECB decryption: Average: 5330 msec, approx. 30018 kb/sec || 29 mb/sec
CBC encryption: Average: 3185 msec, approx. 50235 kb/sec || 49 mb/sec
CBC decryption: Average: 5362 msec, approx. 29839 kb/sec || 29 mb/sec

The generic code performs better:
ECB encryption: Average: 3058 msec, approx. 52321 kb/sec || 51 mb/sec
ECB decryption: Average: 3058 msec, approx. 52321 kb/sec || 51 mb/sec
CBC encryption: Average: 3696 msec, approx. 43290 kb/sec || 42 mb/sec
CBC decryption: Average: 3706 msec, approx. 43173 kb/sec || 42 mb/sec

It would be nice if someone could play around with different machines.
This numbers are from a ps3.

Signed-off-by: Sebastian Siewior <bigeasy@linux.vnet.ibm.com>
Index: linux/crypto/aes-alti.c
===================================================================
--- /dev/null
+++ linux/crypto/aes-alti.c
@@ -0,0 +1,274 @@
+/*
+ * based on crypto/aes.c
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/crypto.h>
+#include <asm/byteorder.h>
+#include <asm/system.h>
+#include <crypto/algapi.h>
+
+#include "aes-altivec.h"
+
+#define AES_MIN_KEY_SIZE	16
+#define AES_MAX_KEY_SIZE	32
+
+#define AES_BLOCK_SIZE		16
+
+/* max rounds is 14. Every round needs 1 vector as key (=4 ints or 16 bytes)
+ * The first slot is the given key
+ */
+
+#define MAX_AES_ROUNDS 15
+#define MAX_AES_KEYSIZE_INT (MAX_AES_ROUNDS *4)
+#define MAX_AES_KEYSIZE_BYTE (MAX_AES_KEYSIZE_INT *4)
+#define ENCRYPT 0
+#define DECRYPT 1
+
+struct aes_ctx {
+	unsigned char key_enc_ch[MAX_AES_KEYSIZE_BYTE] __attribute__ ((aligned (16)));
+	unsigned char key_dec_ch[MAX_AES_KEYSIZE_BYTE] __attribute__ ((aligned (16)));
+	unsigned int key_length;
+};
+
+static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+		       unsigned int key_len)
+{
+	struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
+	u32 *flags = &tfm->crt_flags;
+	u32 i;
+
+	switch (key_len) {
+	case 16:
+	case 24:
+	case 32:
+		break;
+
+	default:
+		 *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+		 return -EINVAL;
+	}
+
+	preempt_disable();
+	enable_kernel_altivec();
+
+	ctx->key_length = key_len;
+	i = expand_key(in_key, key_len/4 , ctx->key_enc_ch, ctx->key_dec_ch);
+
+	preempt_enable();
+	return i;
+}
+
+static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+	const struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	preempt_disable();
+	enable_kernel_altivec();
+
+	aes_encrypt_altivec(in, out, ctx->key_enc_ch, ctx->key_length);
+
+	preempt_enable();
+}
+
+static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+	const struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	preempt_disable();
+	enable_kernel_altivec();
+
+	aes_decrypt_altivec(in, out, ctx->key_dec_ch, ctx->key_length);
+
+	preempt_enable();
+}
+
+static struct crypto_alg aes_alg = {
+	.cra_name			=	"aes",
+	.cra_driver_name	=	"aes-altivec",
+	.cra_priority		=	123,
+	.cra_flags			=	CRYPTO_ALG_TYPE_CIPHER,
+	.cra_blocksize		=	AES_BLOCK_SIZE,
+	.cra_ctxsize		=	sizeof(struct aes_ctx),
+	.cra_alignmask		=	15,
+	.cra_module			=	THIS_MODULE,
+	.cra_list			=	LIST_HEAD_INIT(aes_alg.cra_list),
+	.cra_u				=	{
+		.cipher = {
+			.cia_min_keysize	=	AES_MIN_KEY_SIZE,
+			.cia_max_keysize	=	AES_MAX_KEY_SIZE,
+			.cia_setkey	   		= 	aes_set_key,
+			.cia_encrypt	 	=	aes_encrypt,
+			.cia_decrypt	  	=	aes_decrypt
+		}
+	}
+};
+
+/*
+ * The fn pointer is the last parameter, the remaining parameter are in caller's order.
+ * That way the compiler must not reorder everything :)
+ */
+static int mode_aes_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		struct scatterlist *src, unsigned int nbytes,
+		int (*fn) (const unsigned char *in,
+			unsigned char *out, const unsigned char *kp, unsigned int key_len,
+			unsigned int len, unsigned char *iv_), unsigned int mode)
+{
+	struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+	struct blkcipher_walk walk;
+	const unsigned char *kp;
+	int ret;
+	u8 *out, *in;
+
+	kp = mode == ENCRYPT ? ctx->key_enc_ch : ctx->key_dec_ch;
+	blkcipher_walk_init(&walk, dst, src, nbytes);
+	ret = blkcipher_walk_virt(desc, &walk);
+
+	preempt_disable();
+	enable_kernel_altivec();
+
+	while ((nbytes = walk.nbytes)) {
+		/* only use complete blocks */
+		unsigned int n = nbytes & ~(15);
+
+		out = walk.dst.virt.addr;
+		in = walk.src.virt.addr;
+
+		nbytes = fn(in, out, kp, ctx->key_length, n, walk.iv);
+
+		nbytes &= 15;
+		ret = blkcipher_walk_done(desc, &walk, nbytes);
+	}
+
+	preempt_enable();
+	return ret;
+}
+
+static int aes_encrypt_ecb(struct blkcipher_desc *desc,
+		struct scatterlist *dst, struct scatterlist *src,
+		unsigned int nbytes)
+{
+	return mode_aes_crypt(desc, dst, src, nbytes, aes_encrypt_ecb_altivec, ENCRYPT);
+}
+
+static int aes_decrypt_ecb(struct blkcipher_desc *desc,
+		struct scatterlist *dst, struct scatterlist *src,
+		unsigned int nbytes)
+{
+	return mode_aes_crypt(desc, dst, src, nbytes, aes_decrypt_ecb_altivec, DECRYPT);
+}
+
+static struct crypto_alg aes_ecb_alg = {
+	.cra_name           =   "ecb(aes)",
+	.cra_driver_name    =   "ecb-aes-altivec",
+	.cra_priority       =   125,
+	.cra_flags          =   CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_blocksize      =   AES_BLOCK_SIZE,
+	.cra_alignmask		=	15,
+	.cra_ctxsize        =   sizeof(struct aes_ctx),
+	.cra_type           =   &crypto_blkcipher_type,
+	.cra_module         =   THIS_MODULE,
+	.cra_list           =   LIST_HEAD_INIT(aes_ecb_alg.cra_list),
+	.cra_u              =   {
+		.blkcipher = {
+			.min_keysize    =   AES_MIN_KEY_SIZE,
+			.max_keysize    =   AES_MAX_KEY_SIZE,
+			.setkey         =   aes_set_key,
+			.encrypt        =   aes_encrypt_ecb,
+			.decrypt        =   aes_decrypt_ecb,
+		}
+	}
+};
+
+static int aes_encrypt_cbc(struct blkcipher_desc *desc,
+		struct scatterlist *dst, struct scatterlist *src,
+		unsigned int nbytes)
+{
+	return mode_aes_crypt(desc, dst, src, nbytes, aes_encrypt_cbc_altivec, ENCRYPT);
+}
+
+static int aes_decrypt_cbc(struct blkcipher_desc *desc,
+		struct scatterlist *dst, struct scatterlist *src,
+		unsigned int nbytes)
+{
+	return mode_aes_crypt(desc, dst, src, nbytes, aes_decrypt_cbc_altivec, DECRYPT);
+}
+
+static struct crypto_alg aes_cbc_alg = {
+	.cra_name           =   "cbc(aes)",
+	.cra_driver_name    =   "cbc-aes-altivec",
+	.cra_priority       =   125,
+	.cra_flags          =   CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_blocksize      =   AES_BLOCK_SIZE,
+	.cra_alignmask		=	15,
+	.cra_ctxsize        =   sizeof(struct aes_ctx),
+	.cra_type           =   &crypto_blkcipher_type,
+	.cra_module         =   THIS_MODULE,
+	.cra_list           =   LIST_HEAD_INIT(aes_ecb_alg.cra_list),
+	.cra_u              =   {
+		.blkcipher = {
+			.min_keysize    =   AES_MIN_KEY_SIZE,
+			.max_keysize    =   AES_MAX_KEY_SIZE,
+			.setkey         =   aes_set_key,
+			.encrypt        =   aes_encrypt_cbc,
+			.decrypt        =   aes_decrypt_cbc,
+			.ivsize         =   AES_BLOCK_SIZE,
+		}
+	}
+};
+
+static int __init aes_init(void)
+{
+	unsigned int ret;
+
+	if (!(cpu_has_feature(CPU_FTR_ALTIVEC))) {
+		printk("aes-alti: No altivec unit available\n");
+		return -ENODEV;
+	}
+#ifdef CONFIG_CRYPTO_AES_ALTIVEC_TABLE
+	printk("Table lookup mode\n");
+#endif
+
+	ret = crypto_register_alg(&aes_alg);
+	if (ret) {
+		printk("Failed to register aes\n");
+		goto failed_aes;
+	}
+
+	ret = crypto_register_alg(&aes_ecb_alg);
+	if (ret) {
+		printk("Failed to register aes-ecb\n");
+		goto failed_aes_ecb;
+	}
+
+	ret = crypto_register_alg(&aes_cbc_alg);
+	if (ret) {
+		printk("Failed to register aes-cbc\n");
+		goto failed_aes_cbc;
+	}
+
+	return 0;
+
+failed_aes_cbc:
+	crypto_unregister_alg(&aes_ecb_alg);
+
+failed_aes_ecb:
+	crypto_unregister_alg(&aes_alg);
+
+failed_aes:
+	return -ENODEV;
+}
+
+static void __exit aes_fini(void)
+{
+	crypto_unregister_alg(&aes_alg);
+	crypto_unregister_alg(&aes_ecb_alg);
+	crypto_unregister_alg(&aes_cbc_alg);
+}
+
+module_init(aes_init);
+module_exit(aes_fini);
+
+MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm");
+MODULE_LICENSE("GPL");
Index: linux/crypto/aes-altivec.c
===================================================================
--- /dev/null
+++ linux/crypto/aes-altivec.c
@@ -0,0 +1,799 @@
+/*
+ * AES implementation with AltiVec support.
+ * v.02
+ *
+ * Author:
+ * 			Sebastian Siewior (bigeasy _at_ breakpoint.cc)
+ * 			Arnd Bergmann (arnd _at_ arndb.de)
+ *
+ * License: GPL v2
+ *
+ * Code based on ideas from "Effincient Galois Field Arithmetic on SIMD Architectures" by
+ * Raghav Bhaskar, Prapdeep K. Dubey, Vijay Kumar, Atri Rudra and Animesh Sharma.
+ *
+ * This implementation makes use of AltiVec and asumes therefore big endian (on the other
+ * hand only Intel makes it (still) wrong (well it made porting to 64bit probably a lot of
+ * easier)).
+ * Tables for MixColumn() and InvMixColumn() are adjusted in order to omit ShiftRow in all but
+ * last round.
+ */
+
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <altivec.h>
+#include <linux/autoconf.h>
+#include "aes-altivec.h"
+
+static const vector unsigned char imm_7Fh = {
+	0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+	0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f
+};
+
+/*
+ * This values are either defined in AES standard or can be
+ * computed.
+ */
+static const unsigned int Rcon[] = {
+	0x00000000, 0x01000000, 0x02000000, 0x04000000, 0x08000000,
+	0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1b000000,
+	0x36000000
+};
+
+static const vector unsigned char sbox_enc[16] = {
+	{ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
+	  0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76 },
+	{ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
+	  0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0 },
+	{ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
+	  0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15 },
+	{ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
+	  0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75 },
+	{ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
+	  0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84 },
+	{ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
+	  0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf },
+	{ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
+	  0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8 },
+	{ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
+	  0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2 },
+	{ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
+	  0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73 },
+	{ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
+	  0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb },
+	{ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
+	  0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79 },
+	{ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
+	  0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08 },
+	{ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
+	  0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a },
+	{ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
+	  0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e },
+	{ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
+	  0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf },
+	{ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
+	  0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }
+};
+
+static const vector unsigned char shift_round = {
+	0x00, 0x05, 0x0a, 0x0f,
+	0x04, 0x09, 0x0e, 0x03,
+	0x08, 0x0d, 0x02, 0x07,
+	0x0c, 0x01, 0x06, 0x0b
+};
+
+static const vector unsigned char pre_xor_s0 = {
+	0x10, 0x00, 0x00, 0x10,
+	0x14, 0x04, 0x04, 0x14,
+	0x18, 0x08, 0x08, 0x18,
+	0x1c, 0x0c, 0x0c, 0x1c
+};
+
+static const vector unsigned char pre_xor_s1 = {
+	0x15, 0x15, 0x05, 0x00,
+	0x19, 0x19, 0x09, 0x04,
+	0x1d, 0x1d, 0x0d, 0x08,
+	0x11, 0x11, 0x01, 0x0c
+};
+
+static const vector unsigned char pre_xor_s2 = {
+	0x05, 0x1a, 0x1a, 0x05,
+	0x09, 0x1e, 0x1e, 0x09,
+	0x0d, 0x12, 0x12, 0x0d,
+	0x01, 0x16, 0x16, 0x01
+};
+
+static const vector unsigned char pre_xor_s3 = {
+	0x0a, 0x0a, 0x1f, 0x0a,
+	0x0e, 0x0e, 0x13, 0x0e,
+	0x02, 0x02, 0x17, 0x02,
+	0x06, 0x06, 0x1b, 0x06
+};
+
+static const vector unsigned char pre_xor_s4 = {
+	0x0f, 0x0f, 0x0f, 0x1f,
+	0x03, 0x03, 0x03, 0x13,
+	0x07, 0x07, 0x07, 0x17,
+	0x0b, 0x0b, 0x0b, 0x1b
+};
+
+static const vector unsigned char sbox_dec[16] = {
+	{ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38,
+	  0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb },
+	{ 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
+	  0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb },
+	{ 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d,
+	  0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e },
+	{ 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2,
+	  0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25 },
+	{ 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
+	  0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92 },
+	{ 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda,
+	  0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84 },
+	{ 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a,
+	  0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06 },
+	{ 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
+	  0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b },
+	{ 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea,
+	  0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73 },
+	{ 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85,
+	  0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e },
+	{ 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
+	  0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b },
+	{ 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20,
+	  0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4 },
+	{ 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31,
+	  0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f },
+	{ 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
+	  0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef },
+	{ 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0,
+	  0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61 },
+	{ 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26,
+	  0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d }
+};
+
+static const vector unsigned char inv_shift_round = {
+	0x00, 0x0d, 0x0a, 0x07,
+	0x04, 0x01, 0x0e, 0x0B,
+	0x08, 0x05, 0x02, 0x0f,
+	0x0c, 0x09, 0x06, 0x03
+};
+
+static const vector unsigned char inv_select_0e_shifted = {
+	0x00, 0x0d, 0x0a, 0x07,
+	0x04, 0x01, 0x0e, 0x0B,
+	0x08, 0x05, 0x02, 0x0f,
+	0x0c, 0x09, 0x06, 0x03
+};
+
+static const vector unsigned char inv_select_0b_shifted = {
+	0x0d, 0x0a, 0x07, 0x00,
+	0x01, 0x0e, 0x0b, 0x04,
+	0x05, 0x02, 0x0f, 0x08,
+	0x09, 0x06, 0x03, 0x0c
+};
+
+static const vector unsigned char inv_select_0d_shifted = {
+	0x0a, 0x07, 0x00, 0x0d,
+	0x0e, 0x0b, 0x04, 0x01,
+	0x02, 0x0f, 0x08, 0x05,
+	0x06, 0x03, 0x0c, 0x09
+};
+
+static const vector unsigned char inv_select_09_shifted = {
+	0x07, 0x00, 0x0d, 0x0a,
+	0x0b, 0x04, 0x01, 0x0e,
+	0x0f, 0x08, 0x05, 0x02,
+	0x03, 0x0c, 0x09, 0x06
+};
+
+static const vector unsigned char inv_select_0e_norm = {
+	0x00, 0x01, 0x02, 0x03,
+	0x04, 0x05, 0x06, 0x07,
+	0x08, 0x09, 0x0a, 0x0b,
+	0x0c, 0x0d, 0x0e, 0x0f
+};
+
+static const vector unsigned char inv_select_0b_norm = {
+	0x01, 0x02, 0x03, 0x00,
+	0x05, 0x06, 0x07, 0x04,
+	0x09, 0x0a, 0x0b, 0x08,
+	0x0d, 0x0e, 0x0f, 0x0c
+};
+
+static const vector unsigned char inv_select_0d_norm = {
+	0x02, 0x03, 0x00, 0x01,
+	0x06, 0x07, 0x04, 0x05,
+	0x0a, 0x0b, 0x08, 0x09,
+	0x0e, 0x0f, 0x0c, 0x0d
+};
+
+static const vector unsigned char inv_select_09_norm = {
+	0x03, 0x00, 0x01, 0x02,
+	0x07, 0x04, 0x05, 0x06,
+	0x0b, 0x08, 0x09, 0x0a,
+	0x0f, 0x0c, 0x0d, 0x0e
+};
+
+#ifdef CONFIG_CRYPTO_AES_ALTIVEC_TABLE
+/* small GF lookup table */
+static const vector unsigned char gf_mul_9_high = {
+	0x00, 0x90, 0x3b, 0xab, 0x76, 0xe6, 0x4d, 0xdd,
+	0xec, 0x7c, 0xd7, 0x47, 0x9a, 0x0a, 0xa1, 0x31
+};
+static const vector unsigned char gf_mul_b_high = {
+	0x00, 0xb0, 0x7b, 0xcb, 0xf6, 0x46, 0x8d, 0x3d,
+	0xf7, 0x47, 0x8c, 0x3c, 0x01, 0xb1, 0x7a, 0xca
+};
+static const vector unsigned char gf_mul_d_high = {
+	0x00, 0xd0, 0xbb, 0x6b, 0x6d, 0xbd, 0xd6, 0x06,
+	0xda, 0x0a, 0x61, 0xb1, 0xb7, 0x67, 0x0c, 0xdc
+};
+static const vector unsigned char gf_mul_e_high = {
+	0x00, 0xe0, 0xdb, 0x3b, 0xad, 0x4d, 0x76, 0x96,
+	0x41, 0xa1, 0x9a, 0x7a, 0xec, 0x0c, 0x37, 0xd7
+};
+static const vector unsigned char gf_mul_9_low = {
+	0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f,
+	0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77
+};
+static const vector unsigned char gf_mul_b_low = {
+	0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31,
+	0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69
+};
+static const vector unsigned char gf_mul_d_low = {
+	0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23,
+	0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b
+};
+static const vector unsigned char gf_mul_e_low = {
+	0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a,
+	0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a
+};
+#endif
+/* encryption code */
+
+static vector unsigned char ByteSub(vector unsigned char state)
+{
+	/* line of the s-box */
+	vector unsigned char line_01, line_23, line_45, line_67,
+		   line_89, line_AB, line_CD, line_EF;
+	/* selector */
+	vector unsigned char sel1, sel2, sel7;
+	/* correct lines */
+	vector unsigned char cor_0123, cor_4567, cor_89AB, cor_CDEF,
+		cor_0to7, cor_8toF;
+	vector unsigned char ret_state;
+	vector unsigned char state_shift2, state_shift1;
+
+	line_01 = vec_perm(sbox_enc[0], sbox_enc[1], state);
+	line_23 = vec_perm(sbox_enc[2], sbox_enc[3], state);
+	line_45 = vec_perm(sbox_enc[4], sbox_enc[5], state);
+	line_67 = vec_perm(sbox_enc[6], sbox_enc[7], state);
+	line_89 = vec_perm(sbox_enc[8], sbox_enc[9], state);
+	line_AB = vec_perm(sbox_enc[10], sbox_enc[11], state);
+	line_CD = vec_perm(sbox_enc[12], sbox_enc[13], state);
+	line_EF = vec_perm(sbox_enc[14], sbox_enc[15], state);
+
+	state_shift2 = vec_vslb(state, vec_splat_u8(2));
+	sel2 = (typeof (sel2)) vec_vcmpgtub(state_shift2, imm_7Fh);
+	cor_0123 = vec_sel(line_01, line_23, sel2);
+	cor_4567 = vec_sel(line_45, line_67, sel2);
+	cor_89AB = vec_sel(line_89, line_AB, sel2);
+	cor_CDEF = vec_sel(line_CD, line_EF, sel2);
+
+	state_shift1 = vec_vslb(state, vec_splat_u8(1));
+	sel1 = (typeof (sel1))vec_vcmpgtub(state_shift1, imm_7Fh);
+	cor_0to7 = vec_sel(cor_0123, cor_4567, sel1);
+	cor_8toF = vec_sel(cor_89AB, cor_CDEF, sel1);
+
+	sel7 = (typeof (sel7))vec_vcmpgtub(state, imm_7Fh);
+	ret_state = vec_sel(cor_0to7, cor_8toF, sel7);
+
+	return ret_state;
+}
+
+static vector unsigned char ShiftRow(vector unsigned char state)
+{
+
+	return vec_perm(state, state, shift_round);
+}
+
+static vector unsigned char MixColumn(vector unsigned char state)
+{
+	vector unsigned char imm_00h, imm_01h;
+	vector unsigned char need_add;
+	vector unsigned char shifted_vec, modul;
+	vector unsigned char toadd, xtimed;
+	vector unsigned char op1, op2, op3, op4, op5;
+	vector unsigned char xor_12, xor_34, xor_1234, ret;
+
+	imm_00h = vec_splat_u8(0x00);
+	imm_01h = vec_splat_u8(0x01);
+
+	modul = vec_splat( vec_lvsr(0, (unsigned char *) 0), 0x0b); // 0x1b
+
+	need_add = (vector unsigned char)vec_vcmpgtub(state, imm_7Fh);
+	shifted_vec = vec_vslb(state, imm_01h);
+
+	toadd = vec_sel(imm_00h, modul, need_add);
+
+	xtimed = vec_xor(toadd, shifted_vec);
+
+	op1 = vec_perm(state, xtimed, pre_xor_s0);
+	op2 = vec_perm(state, xtimed, pre_xor_s1);
+	op3 = vec_perm(state, xtimed, pre_xor_s2);
+	op4 = vec_perm(state, xtimed, pre_xor_s3);
+	op5 = vec_perm(state, xtimed, pre_xor_s4);
+
+	xor_12 = vec_xor(op1, op2);
+	xor_34 = vec_xor(op3, op4);
+	xor_1234 = vec_xor(xor_12, xor_34);
+	ret = vec_xor(xor_1234, op5);
+
+	return ret;
+}
+
+static vector unsigned char AddRoundKey(vector unsigned char state,
+		vector unsigned char key)
+{
+	return vec_xor(state,key);
+}
+
+static vector unsigned char normalRound(vector unsigned char state, vector unsigned char key)
+{
+	vector unsigned char pstate;
+
+	pstate = ByteSub(state);
+	pstate = MixColumn(pstate);
+	pstate = AddRoundKey(pstate, key);
+	return pstate;
+}
+
+static vector unsigned char finalRound(vector unsigned char state, vector unsigned char key)
+{
+	vector unsigned char pstate;
+
+	pstate = ByteSub(state);
+	pstate = ShiftRow(pstate);
+	pstate = AddRoundKey(pstate, key);
+	return pstate;
+}
+
+static vector unsigned char _aes_encrypt_altivec(vector unsigned char in,
+		const vector unsigned char *key, unsigned char key_len)
+{
+	unsigned char i;
+	vector unsigned char pstate;
+
+	pstate = vec_xor(in, *key++);
+	switch (key_len) {
+
+		case 32: /* 14 rounds */
+			pstate = normalRound(pstate, *key++);
+			pstate = normalRound(pstate, *key++);
+
+		case 24: /* 12 rounds */
+			pstate = normalRound(pstate, *key++);
+			pstate = normalRound(pstate, *key++);
+
+		case 16: /* 10 rounds */
+			for (i=0; i<9; i++)
+				pstate = normalRound(pstate, *key++);
+
+			break;
+
+		default:
+			/* unsupported */
+			BUG();
+	}
+
+	pstate = finalRound(pstate, *key);
+	return pstate;
+}
+
+int aes_encrypt_altivec(const unsigned char *in, unsigned char *out,
+		const unsigned char *kp, unsigned int key_len)
+{
+	vector unsigned char pstate;
+
+	pstate = vec_ld(0, in);
+	pstate = _aes_encrypt_altivec(pstate, (const vector unsigned char*) kp, key_len);
+
+	vec_st(pstate, 0, out);
+	return 0;
+}
+/* decryption code, alternative version */
+
+static vector unsigned char InvByteSub(vector unsigned char state)
+{
+	/* line of the s-box */
+	vector unsigned char line_01, line_23, line_45, line_67,
+		   line_89, line_AB, line_CD, line_EF;
+	/* selector */
+	vector unsigned char sel1, sel2, sel7;
+	/* correct lines */
+	vector unsigned char cor_0123, cor_4567, cor_89AB, cor_CDEF,
+		cor_0to7, cor_8toF;
+	vector unsigned char ret_state;
+	vector unsigned char state_shift2, state_shift1;
+
+	line_01 = vec_perm(sbox_dec[0], sbox_dec[1], state);
+	line_23 = vec_perm(sbox_dec[2], sbox_dec[3], state);
+	line_45 = vec_perm(sbox_dec[4], sbox_dec[5], state);
+	line_67 = vec_perm(sbox_dec[6], sbox_dec[7], state);
+	line_89 = vec_perm(sbox_dec[8], sbox_dec[9], state);
+	line_AB = vec_perm(sbox_dec[10], sbox_dec[11], state);
+	line_CD = vec_perm(sbox_dec[12], sbox_dec[13], state);
+	line_EF = vec_perm(sbox_dec[14], sbox_dec[15], state);
+
+	state_shift2 = vec_vslb(state, vec_splat_u8(2));
+	sel2 = (typeof (sel2)) vec_vcmpgtub(state_shift2, imm_7Fh);
+	cor_0123 = vec_sel(line_01, line_23, sel2);
+	cor_4567 = vec_sel(line_45, line_67, sel2);
+	cor_89AB = vec_sel(line_89, line_AB, sel2);
+	cor_CDEF = vec_sel(line_CD, line_EF, sel2);
+
+	state_shift1 = vec_vslb(state, vec_splat_u8(1));
+	sel1 = (typeof (sel1))vec_vcmpgtub(state_shift1, imm_7Fh);
+	cor_0to7 = vec_sel(cor_0123, cor_4567, sel1);
+	cor_8toF = vec_sel(cor_89AB, cor_CDEF, sel1);
+
+	sel7 = (typeof (sel7))vec_vcmpgtub(state, imm_7Fh);
+	ret_state = vec_sel(cor_0to7, cor_8toF, sel7);
+
+	return ret_state;
+}
+
+static vector unsigned char InvShiftRow(vector unsigned char state)
+{
+
+	return vec_perm(state, state, inv_shift_round);
+}
+
+static vector unsigned char InvMixColumn(vector unsigned char state,
+		vector unsigned char inv_select_0e, vector unsigned char inv_select_0b,
+		vector unsigned char inv_select_0d, vector unsigned char inv_select_09 )
+{
+	vector unsigned char op0, op1, op2, op3, op4, op5;
+	vector unsigned char mul_0e, mul_09, mul_0d, mul_0b;
+	vector unsigned char ret;
+
+#ifdef CONFIG_CRYPTO_AES_ALTIVEC_TABLE
+	/* 14 operations, 1x 8 memory loads */
+
+	vector unsigned char state_high;
+	vector unsigned char imm_04h;
+	vector unsigned char mul_09_hi, mul_09_lo, mul_0b_hi, mul_0b_lo, mul_0d_hi,
+		   mul_0d_lo, mul_0e_hi, mul_0e_lo;
+
+	imm_04h = vec_splat_u8(0x04);
+
+	state_high = vec_sr(state, imm_04h);
+
+	mul_09_hi = vec_perm(gf_mul_9_high, gf_mul_9_high, state_high);
+	mul_0b_hi = vec_perm(gf_mul_b_high, gf_mul_b_high, state_high);
+	mul_0d_hi = vec_perm(gf_mul_d_high, gf_mul_d_high, state_high);
+	mul_0e_hi = vec_perm(gf_mul_e_high, gf_mul_e_high, state_high);
+
+	mul_09_lo = vec_perm(gf_mul_9_low, gf_mul_9_low, state);
+	mul_0b_lo = vec_perm(gf_mul_b_low, gf_mul_b_low, state);
+	mul_0d_lo = vec_perm(gf_mul_d_low, gf_mul_d_low, state);
+	mul_0e_lo = vec_perm(gf_mul_e_low, gf_mul_e_low, state);
+
+	mul_09 = vec_xor(mul_09_hi, mul_09_lo);
+	mul_0b = vec_xor(mul_0b_hi, mul_0b_lo);
+	mul_0d = vec_xor(mul_0d_hi, mul_0d_lo);
+	mul_0e = vec_xor(mul_0e_hi, mul_0e_lo);
+
+#else
+	/* 21 operations, 3x 1 memory loads */
+
+	vector unsigned char imm_00h, imm_01h;
+	vector unsigned char need_add;
+	vector unsigned char shifted_vec, modul;
+	vector unsigned char toadd;
+	vector unsigned char mul_2, mul_4, mul_8;
+	vector unsigned char mul_2_4;
+
+	/* compute 0e, 0b, 0d, 09 in GF */
+	imm_00h = vec_splat_u8(0x00);
+	imm_01h = vec_splat_u8(0x01);
+
+	modul = vec_splat( vec_lvsr(0, (unsigned char *) 0), 0x0b); // 0x1b
+
+	need_add = (vector unsigned char)vec_vcmpgtub(state, imm_7Fh);
+	shifted_vec = vec_vslb(state, imm_01h);
+	toadd = vec_sel(imm_00h, modul, need_add);
+	mul_2 = vec_xor(toadd, shifted_vec);
+
+	need_add = (vector unsigned char)vec_vcmpgtub(mul_2, imm_7Fh);
+	shifted_vec = vec_vslb(mul_2, imm_01h);
+	toadd = vec_sel(imm_00h, modul, need_add);
+	mul_4 = vec_xor(toadd, shifted_vec);
+
+	need_add = (vector unsigned char)vec_vcmpgtub(mul_4, imm_7Fh);
+	shifted_vec = vec_vslb(mul_4, imm_01h);
+	toadd = vec_sel(imm_00h, modul, need_add);
+	mul_8 = vec_xor(toadd, shifted_vec);
+
+	mul_2_4 = vec_xor(mul_2, mul_4);
+	/* 09 = 8 * 1 */
+	mul_09 = vec_xor(mul_8, state);
+
+	/* 0e = 2 * 4 * 8 */
+	mul_0e = vec_xor(mul_2_4, mul_8);
+
+	/* 0b = 2 * 8 * 1 */
+	mul_0b = vec_xor(mul_2, mul_09);
+
+	/* 0d = 4 * 8 * 1 */
+	mul_0d = vec_xor(mul_4, mul_09);
+#endif
+
+	/* prepare vectors for add */
+
+	op0 = vec_perm(mul_0e, mul_0e, inv_select_0e);
+	op1 = vec_perm(mul_0b, mul_0b, inv_select_0b);
+	op2 = vec_perm(mul_0d, mul_0d, inv_select_0d);
+	op3 = vec_perm(mul_09, mul_09, inv_select_09);
+
+	op4 = vec_xor(op0, op1);
+	op5 = vec_xor(op2, op3);
+	ret = vec_xor(op4, op5);
+	return ret;
+}
+
+static vector unsigned char InvNormalRound(vector unsigned char state,
+		vector unsigned char key)
+{
+	vector unsigned char pstate;
+
+	pstate = InvByteSub(state);
+	pstate = InvMixColumn(pstate, inv_select_0e_shifted, inv_select_0b_shifted,
+			inv_select_0d_shifted, inv_select_09_shifted);
+	pstate = AddRoundKey(pstate, key);
+	return pstate;
+}
+
+static vector unsigned char InvfinalRound(vector unsigned char state,
+		vector unsigned char key)
+{
+	vector unsigned char pstate;
+
+	pstate = InvByteSub(state);
+	pstate = InvShiftRow(pstate);
+	pstate = AddRoundKey(pstate, key);
+	return pstate;
+}
+
+
+static vector unsigned char _aes_decrypt_altivec(vector unsigned char in,
+		vector const unsigned char *key, unsigned int key_len)
+{
+	vector unsigned char pstate;
+	unsigned int i;
+
+	pstate = vec_xor(in, *key++);
+
+	switch (key_len) {
+		case 32: /* 14 rounds */
+			pstate = InvNormalRound(pstate, *key++);
+			pstate = InvNormalRound(pstate, *key++);
+
+		case 24: /* 12 rounds */
+			pstate = InvNormalRound(pstate, *key++);
+			pstate = InvNormalRound(pstate, *key++);
+
+		case 16: /* 10 rounds */
+			for (i=0; i<9; i++)
+				pstate = InvNormalRound(pstate, *key++);
+
+			break;
+
+		default:
+			BUG();
+	}
+
+	pstate = InvfinalRound(pstate, *key);
+	return pstate;
+}
+
+int aes_decrypt_altivec(const unsigned char *in, unsigned char *out,
+		const unsigned char *kp, unsigned int key_len)
+{
+	vector unsigned char pstate;
+
+	pstate = vec_ld(0, in);
+	pstate = _aes_decrypt_altivec(pstate, (const vector unsigned char*) kp, key_len);
+	vec_st(pstate, 0, out);
+	return 0;
+}
+
+/* expand key */
+
+static unsigned int SubWord(unsigned int in)
+{
+	unsigned char buff[16] __attribute__ ((aligned (16)));
+	vector unsigned char vec_buf;
+
+	buff[0] =  in >> 24;
+	buff[1] = (in >> 16) & 0xff;
+	buff[2] = (in >>  8) & 0xff;
+	buff[3] = in & 0xff;
+
+	vec_buf = vec_ld(0, buff);
+	vec_buf = ByteSub(vec_buf);
+	vec_st(vec_buf, 0, buff);
+	return buff[0] << 24 | buff[1] << 16 | buff[2] << 8 | buff[3];
+}
+
+static unsigned int  RotWord(unsigned int word)
+{
+	return (word << 8 | word >> 24);
+}
+
+int expand_key(const unsigned char *key, unsigned int keylen,
+		unsigned char exp_enc_key[15 *4*4], unsigned char exp_dec_key[15*4*4])
+{
+	unsigned int tmp, i, rounds;
+	unsigned int expanded_key[15 *4] __attribute__ ((aligned (16)));
+	vector unsigned char expanded_dec_key[15];
+	vector unsigned char mixed_key;
+	vector unsigned char *cur_key;
+
+	switch (keylen) {
+		case 4:
+			rounds = 10;
+			break;
+
+		case 6:
+			rounds = 12;
+			break;
+
+		case 8:
+			rounds = 14;
+			break;
+
+		default:
+			/* wrong key size */
+			return -EINVAL;
+	}
+
+	memcpy(expanded_key, key, keylen*4);
+
+	i = keylen;
+
+	/* setup enc key */
+
+	for (; i< 4 * (rounds+1); i++) {
+		tmp = expanded_key[i-1];
+
+		if (!(i % keylen)) {
+			tmp = RotWord(tmp);
+			tmp = SubWord(tmp);
+			tmp ^= Rcon[i / keylen ];
+		} else if (keylen > 6 &&  (i % keylen == 4))
+				tmp = SubWord(tmp);
+
+		expanded_key[i] = expanded_key[i-keylen] ^ tmp;
+	}
+
+	memcpy(exp_enc_key, expanded_key, 15*4*4);
+
+	/* setup dec key: the key is turned arround and prepared for the
+	 * "alternative decryption" mode
+	 */
+
+	cur_key = (vector unsigned char*) expanded_key;
+
+	memcpy(&expanded_dec_key[rounds],      &expanded_key[0], 4*4);
+	memcpy(&expanded_dec_key[0], &expanded_key[rounds *4], 4*4);
+
+	cur_key++;
+	for (i = (rounds-1); i> 0; i--) {
+
+		mixed_key = InvMixColumn(*cur_key++, inv_select_0e_norm, inv_select_0b_norm,
+				inv_select_0d_norm, inv_select_09_norm);
+		expanded_dec_key[i] = mixed_key;
+	}
+
+	memcpy(exp_dec_key, expanded_dec_key, 15*4*4);
+	return 0;
+}
+
+int aes_encrypt_ecb_altivec(const unsigned char *in, unsigned char *out,
+		const unsigned char *kp, unsigned int key_len, unsigned int len,
+		unsigned char *iv_)
+{
+	unsigned int left = len;
+
+	while (left >= 32) {
+		aes_encrypt_altivec(in, out, kp, key_len);
+		aes_encrypt_altivec(in+16, out+16, kp, key_len);
+		left -= 32;
+		in += 32;
+		out += 32;
+	}
+
+	while (left >= 16) {
+		aes_encrypt_altivec(in, out, kp, key_len);
+		left -= 16;
+		in += 16;
+		out += 16;
+	}
+
+	return len;
+}
+
+int aes_decrypt_ecb_altivec(const unsigned char *in, unsigned char *out,
+		const unsigned char *kp, unsigned int key_len, unsigned int len,
+		unsigned char *iv_)
+{
+	unsigned int left = len;
+
+	while (left >= 32) {
+		aes_decrypt_altivec(in, out, kp, key_len);
+		aes_decrypt_altivec(in+16, out+16, kp, key_len);
+		left -= 32;
+		in += 32;
+		out += 32;
+	}
+
+	while (left >= 16) {
+		aes_decrypt_altivec(in, out, kp, key_len);
+		left -= 16;
+		in += 16;
+		out += 16;
+	}
+	return len;
+}
+
+int  aes_encrypt_cbc_altivec(const unsigned char *in, unsigned char *out,
+		const unsigned char *kp, unsigned int key_len, unsigned int len,
+		unsigned char *iv_)
+{
+	unsigned int i;
+	vector unsigned char iv, input;
+
+	iv = vec_ld(0, iv_);
+	for (i=0; i< len; i += 16) {
+		input = vec_ld(0, in);
+		input = vec_xor(input, iv);
+
+		iv = _aes_encrypt_altivec(input, (const vector unsigned char*) kp, key_len);
+
+		vec_st(iv, 0, out);
+
+		in += 16;
+		out += 16;
+	}
+
+	vec_st(iv, 0, iv_);
+	return len;
+}
+
+int aes_decrypt_cbc_altivec(const unsigned char *in, unsigned char *out,
+		const unsigned char *kp, unsigned int key_len, unsigned int len,
+		unsigned char *iv_)
+{
+	unsigned int i;
+	vector unsigned char iv, input, vret, decrypted;
+
+	iv = vec_ld(0, iv_);
+	for (i=0; i< len; i += 16) {
+
+		input = vec_ld(0, in);
+		vret = _aes_decrypt_altivec(input, (const vector unsigned char*) kp, key_len);
+
+		decrypted = vec_xor(vret, iv);
+		iv = input;
+
+		vec_st(decrypted, 0, out);
+
+		in += 16;
+		out += 16;
+	}
+
+	vec_st(iv, 0, iv_);
+	return len;
+}
Index: linux/crypto/aes-altivec.h
===================================================================
--- /dev/null
+++ linux/crypto/aes-altivec.h
@@ -0,0 +1,28 @@
+#ifndef  __AES_ALTIVEC_H__
+#define  __AES_ALTIVEC_H__
+
+extern int expand_key(const unsigned char *key, unsigned int keylen,
+		unsigned char exp_enc_key[15 *4*4], unsigned char expanded_dec_key[15*4*4]);
+
+extern int aes_encrypt_altivec(const unsigned char *in, unsigned char *out,
+		const unsigned char *kp, unsigned int key_len);
+
+extern int aes_decrypt_altivec(const unsigned char *in, unsigned char *out,
+		const unsigned char *kp, unsigned int key_len);
+
+extern int aes_encrypt_ecb_altivec(const unsigned char *in, unsigned char *out,
+		const unsigned char *kp, unsigned int key_len, unsigned int len,
+		unsigned char *iv_);
+
+extern int aes_decrypt_ecb_altivec(const unsigned char *in, unsigned char *out,
+		const unsigned char *kp, unsigned int key_len, unsigned int len,
+		unsigned char *iv_);
+
+extern int aes_encrypt_cbc_altivec(const unsigned char *in, unsigned char *out,
+		const unsigned char *kp, unsigned int key_len, unsigned int len,
+		unsigned char *iv_);
+
+extern int aes_decrypt_cbc_altivec(const unsigned char *in, unsigned char *out,
+		const unsigned char *kp, unsigned int key_len, unsigned int len,
+		unsigned char *iv_);
+#endif
Index: linux/crypto/Kconfig
===================================================================
--- linux.orig/crypto/Kconfig
+++ linux/crypto/Kconfig
@@ -325,6 +325,21 @@ config CRYPTO_AES_X86_64
 
 	  See <http://csrc.nist.gov/encryption/aes/> for more information.
 
+config CRYPTO_AES_ALTIVEC
+	tristate "AES with AltiVec support"
+	select CRYPTO_ALGAPI
+	depends on ALTIVEC
+	help
+	  AES cipher algorithms (FIPS-197). AES uses the Rijndael
+	  algorithm. This implementation has AltiVec support.
+
+config CRYPTO_AES_ALTIVEC_TABLE
+	bool "Use table lookup for decryption"
+	depends on CRYPTO_AES_ALTIVEC
+	help
+	  Use precomputed tables for decryption instead of computing
+	  "by hand" in GF. This solution is slower.
+
 config CRYPTO_CAST5
 	tristate "CAST5 (CAST-128) cipher algorithm"
 	select CRYPTO_ALGAPI
Index: linux/crypto/Makefile
===================================================================
--- linux.orig/crypto/Makefile
+++ linux/crypto/Makefile
@@ -48,3 +48,7 @@ obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += mich
 obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
 
 obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
+
+CFLAGS_aes-altivec.o += -O3  -maltivec
+aes_altivec-objs := aes-alti.o aes-altivec.o
+obj-$(CONFIG_CRYPTO_AES_ALTIVEC) += aes_altivec.o

--

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox