* Re: [Alsa-devel] RFC: dma_mmap_coherent() for powerpc/ppc architecture and ALSA?
From: Takashi Iwai @ 2006-06-29 9:27 UTC (permalink / raw)
To: Gerhard Pircher; +Cc: linuxppc-dev, rlrevell, alsa-devel, linux-kernel
In-Reply-To: <20060628202753.198630@gmx.net>
At Wed, 28 Jun 2006 22:27:53 +0200,
Gerhard Pircher wrote:
>
> Hi,
>
> It took a little bit longer to integrate the patch, as I didn't figure out first how to implement the __dma_mmap_coherent() function for PPC systems with CONFIG_NOT_COHERENT_CACHE defined. :)
>
> Unfortunately my system still crashes within snd_pcm_mmap_data_nopage()
> (sound/core/pcm_native.c), as you can see below. I guess it tries to remap
> a DMA buffer allocated by the not cache coherent DMA memory allocation
> function in arch/ppc/kernel/dma-mapping.c.
Strange, nopage will be never called if you apply my patch and modify
to use dma_mmap_coherent().
Takashi
^ permalink raw reply
* RE: [PATCH 1/7] powerpc: Add mpc8360epb platform support
From: Li Yang-r58472 @ 2006-06-29 9:28 UTC (permalink / raw)
To: 'Vitaly Bordug'
Cc: Phillips Kim-R1AAHA, Yin Olivia-r63875,
'linux-kernel@vger.kernel.org', linuxppc-dev,
'Paul Mackerras', Chu hanjin-r52514
> -----Original Message-----
> From: Vitaly Bordug [mailto:vbordug@ru.mvista.com]
> Sent: Thursday, June 29, 2006 12:59 AM
> To: Li Yang-r58472
> Cc: 'Paul Mackerras'; linuxppc-dev@ozlabs.org; Phillips Kim-R1AAHA; Chu
> hanjin-r52514; Yin Olivia-r63875; 'linux-kernel@vger.kernel.org'
> Subject: Re: [PATCH 1/7] powerpc: Add mpc8360epb platform support
>
> On Wed, 28 Jun 2006 22:23:03 +0800
> Li Yang-r58472 <LeoLi@freescale.com> wrote:
>
> > The patch adds mpc8360e MDS Processor Board support.
> Far too short comment I guess.. There should be some information at least, what
> u-boot modifications are required, what family being introduced, etc.
The new revision goes like this:
The patch adds mpc8360e MDS Processor Board support. MPC8360E is a new processor in the PowerQUICC II pro family, and it's the first one to use the new generation of communication coprocessor called QUICC ENGINE (QE in abbreviation).
The patch needs a flat device tree to work. It means either u-boot provides a flat device tree blob or somehow a kernel shim passes the tree. The final mechanism of providing FDT is far beyond this patch.
>
> >
> > Signed-off-by: Li Yang <leoli@freescale.com>
> > Signed-off-by: Yin Olivia <hong-hua.yin@freescale.com>
> > Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
> >
> > ---
> > arch/powerpc/platforms/83xx/Kconfig | 13 ++
> > arch/powerpc/platforms/83xx/Makefile | 1
> > arch/powerpc/platforms/83xx/mpc8360e_pb.c | 213
> +++++++++++++++++++++++++++++
> > arch/powerpc/platforms/83xx/mpc8360e_pb.h | 31 ++++
> > 4 files changed, 258 insertions(+), 0 deletions(-)
> >
> > diff --git a/arch/powerpc/platforms/83xx/Kconfig
> b/arch/powerpc/platforms/83xx/Kconfig
> > index 7675e67..04c4508 100644
> > --- a/arch/powerpc/platforms/83xx/Kconfig
> > +++ b/arch/powerpc/platforms/83xx/Kconfig
> > @@ -16,6 +16,13 @@ config MPC834x_SYS
> > 3 PCI slots. The PIBs PCI initialization is the bootloader's
> > responsiblilty.
> >
> > +config MPC8360E_PB
> > + bool "Freescale MPC8360E PB"
> > + select DEFAULT_UIMAGE
> > + select QUICC_ENGINE
> > + help
> > + This option enables support for the MPC836x EMDS Processor Board.
> > +
> > endchoice
>
> I don't think this is really required option. I guess 836x + QUICC_ENGINE should
> be enough (with a proviso that 8360 won't boot without qe.
We select a board and the board implies cpu family and soc feature. That will be better for users rather than expecting them to know the very detail.
>
> >
> > config MPC834x
> > @@ -24,4 +31,10 @@ config MPC834x
> > select PPC_INDIRECT_PCI
> > default y if MPC834x_SYS
> >
> > +config MPC836x
> > + bool
> > + select PPC_UDBG_16550
>
> debug option made default?
good catch.
> > + select PPC_INDIRECT_PCI
> > + default y if MPC8360E_PB
> > +
> > endmenu
> > diff --git a/arch/powerpc/platforms/83xx/Makefile
> b/arch/powerpc/platforms/83xx/Makefile
> > index 5c72367..0c9ea5c 100644
> > --- a/arch/powerpc/platforms/83xx/Makefile
> > +++ b/arch/powerpc/platforms/83xx/Makefile
> > @@ -4,3 +4,4 @@ #
> > obj-y := misc.o
> > obj-$(CONFIG_PCI) += pci.o
> > obj-$(CONFIG_MPC834x_SYS) += mpc834x_sys.o
> > +obj-$(CONFIG_MPC8360E_PB) += mpc8360e_pb.o
> > diff --git a/arch/powerpc/platforms/83xx/mpc8360e_pb.c
> b/arch/powerpc/platforms/83xx/mpc8360e_pb.c
> > new file mode 100644
> > index 0000000..b4ddb0a
> > --- /dev/null
> > +++ b/arch/powerpc/platforms/83xx/mpc8360e_pb.c
> > @@ -0,0 +1,213 @@
> > +/*
> > + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
> > + *
> > + * Author: Li Yang <LeoLi@freescale.com>
> > + * Yin Olivia <Hong-hua.Yin@freescale.com>
> > + *
> > + * Description:
> > + * MPC8360E MDS PB board specific routines.
> > + *
> > + * Changelog:
> > + * Jun 21, 2006 Initial version
> > + *
> No changelog entries for new files please... git tracks it good enough.
This is Freescale protocol. If it is not welcomed, we will change it.
>
> > + * This program is free software; you can redistribute it and/or modify
> it
> > + * under the terms of the GNU General Public License as published by the
> > + * Free Software Foundation; either version 2 of the License, or (at your
> > + * option) any later version.
> > + */
> > +
> > +#include <linux/config.h>
> > +#include <linux/stddef.h>
> > +#include <linux/kernel.h>
> > +#include <linux/init.h>
> > +#include <linux/errno.h>
> > +#include <linux/reboot.h>
> > +#include <linux/pci.h>
> > +#include <linux/kdev_t.h>
> > +#include <linux/major.h>
> > +#include <linux/console.h>
> > +#include <linux/delay.h>
> > +#include <linux/seq_file.h>
> > +#include <linux/root_dev.h>
> > +#include <linux/initrd.h>
> > +
> > +#include <asm/system.h>
> > +#include <asm/atomic.h>
> > +#include <asm/time.h>
> > +#include <asm/io.h>
> > +#include <asm/machdep.h>
> > +#include <asm/ipic.h>
> > +#include <asm/bootinfo.h>
> > +#include <asm/irq.h>
> > +#include <asm/prom.h>
> > +#include <asm/udbg.h>
> > +#include <sysdev/fsl_soc.h>
> > +#ifdef CONFIG_QUICC_ENGINE
> > +#include <asm/immap_qe.h>
> > +#include <asm/qe_ic.h>
> > +#endif /* CONFIG_QUICC_ENGINE */
> > +#include "mpc83xx.h"
> > +#include "mpc8360e_pb.h"
> > +
> > +#undef DEBUG
> > +
>
> hmmm? Does it relate nicely with below ?
> > +#ifdef DEBUG
> > +#define DBG(fmt...) udbg_printf(fmt)
> > +#else
> > +#define DBG(fmt...)
> > +#endif
> > +
> > +
> > +#ifndef CONFIG_PCI
> > +unsigned long isa_io_base = 0;
> > +unsigned long isa_mem_base = 0;
> > +#endif
> > +
> > +#ifdef CONFIG_QUICC_ENGINE
> > +extern void qe_reset(void);
> > +extern int par_io_of_config(struct device_node *np);
> > +#endif /* CONFIG_QUICC_ENGINE */
>
> I bet this should go to the .h file...
> > +
> > +/*
> ************************************************************************
> > + *
> > + * Setup the architecture
> > + *
> > + */
> > +static void __init mpc8360_sys_setup_arch(void)
> > +{
> > + struct device_node *np;
> > +
> > +#ifdef CONFIG_QUICC_ENGINE
> > + u8 *bcsr_regs;
> > +#endif
> > +
> > + if (ppc_md.progress)
> > + ppc_md.progress("mpc8360_sys_setup_arch()", 0);
> > +
> > + np = of_find_node_by_type(NULL, "cpu");
> > + if (np != 0) {
> > + unsigned int *fp =
> > + (int *)get_property(np, "clock-frequency", NULL);
> > + if (fp != 0)
> > + loops_per_jiffy = *fp / HZ;
> > + else
> > + loops_per_jiffy = 50000000 / HZ;
> > + of_node_put(np);
> > + }
> > +#ifdef CONFIG_PCI
> > + for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
> > + add_bridge(np);
> > +
> > + ppc_md.pci_swizzle = common_swizzle;
> > + ppc_md.pci_exclude_device = mpc83xx_exclude_device;
> > +#endif
> > +
> > +#ifdef CONFIG_QUICC_ENGINE
> > + qe_reset();
> > +
> > + for (np = NULL; (np = of_find_node_by_name(np, "ucc")) != NULL;)
> > + par_io_of_config(np);
> > +
> > + /* Reset the Ethernet PHY */
> > + bcsr_regs = (u8 *) ioremap(BCSR_PHYS_ADDR, BCSR_SIZE);
> > + bcsr_regs[9] &= ~0x20;
> > + udelay(1000);
> > + bcsr_regs[9] |= 0x20;
> > + iounmap(bcsr_regs);
> > +
> And if we have a design, which do not contain real ethernet UCC usage? Or UCC
> geth is disabled somehow explicitly? Stuff like that normally goes to the
> callback that is going to be triggered upon Etherbet init.
I will move it.
>
>
> > +#endif /* CONFIG_QUICC_ENGINE */
> > +
> > +#ifdef CONFIG_BLK_DEV_INITRD
> > + if (initrd_start)
> > + ROOT_DEV = Root_RAM0;
> > + else
> > +#endif
> > +#ifdef CONFIG_ROOT_NFS
> > + ROOT_DEV = Root_NFS;
> > +#else
> > + ROOT_DEV = Root_HDA1;
> > +#endif
> > +}
> > +
> > +void __init mpc8360_sys_init_IRQ(void)
> > +{
> > + u8 senses[8] = {
> > + 0, /* EXT 0 */
> > + IRQ_SENSE_LEVEL, /* EXT 1 */
> > + IRQ_SENSE_LEVEL, /* EXT 2 */
> > + 0, /* EXT 3 */
> > +#ifdef CONFIG_PCI
> > + IRQ_SENSE_LEVEL, /* EXT 4 */
> > + IRQ_SENSE_LEVEL, /* EXT 5 */
> > + IRQ_SENSE_LEVEL, /* EXT 6 */
> > + IRQ_SENSE_LEVEL, /* EXT 7 */
> > +#else
> > + 0, /* EXT 4 */
> > + 0, /* EXT 5 */
> > + 0, /* EXT 6 */
> > + 0, /* EXT 7 */
> > +#endif
> > + };
> > +
> > + ipic_init(get_immrbase() + 0x00700, 0, 0, senses, 8);
> > +
> > + /* Initialize the default interrupt mapping priorities,
> > + * in case the boot rom changed something on us.
> > + */
> > + ipic_set_default_priority();
> > +
> > +#ifdef CONFIG_QUICC_ENGINE
> > + qe_ic_init(get_qe_base() + 0x00000080,
> > + (QE_IC_LOW_SIGNAL | QE_IC_HIGH_SIGNAL), QE_IRQ_OFFSET);
> > +#endif /* CONFIG_QUICC_ENGINE */
> > +}
> > +
> > +#if defined(CONFIG_I2C_MPC) && defined(CONFIG_SENSORS_DS1374)
> > +extern ulong ds1374_get_rtc_time(void);
> > +extern int ds1374_set_rtc_time(ulong);
> > +
> > +static int __init mpc8360_rtc_hookup(void)
> > +{
> > + struct timespec tv;
> > +
> > + ppc_md.get_rtc_time = ds1374_get_rtc_time;
> > + ppc_md.set_rtc_time = ds1374_set_rtc_time;
> > +
> > + tv.tv_nsec = 0;
> > + tv.tv_sec = (ppc_md.get_rtc_time) ();
> > + do_settimeofday(&tv);
> > +
> > + return 0;
> > +}
> > +
> > +late_initcall(mpc8360_rtc_hookup);
> > +#endif
> > +
> > +/*
> > + * Called very early, MMU is off, device-tree isn't unflattened
> > + */
> > +static int __init mpc8360_sys_probe(void)
> > +{
> > + char *model = of_get_flat_dt_prop(of_get_flat_dt_root(),
> > + "model", NULL);
> > + if (model == NULL)
> > + return 0;
> > + if (strcmp(model, "MPC8360EPB"))
> > + return 0;
> > +
> > + DBG("MPC8360EMDS-PB found\n");
> > +
> > + return 1;
> > +}
> > +
> > +define_machine(mpc8360_sys) {
> > + .name = "MPC8360E PB",
> > + .probe = mpc8360_sys_probe,
> > + .setup_arch = mpc8360_sys_setup_arch,
> > + .init_IRQ = mpc8360_sys_init_IRQ,
> > + .get_irq = ipic_get_irq,
> > + .restart = mpc83xx_restart,
> > + .time_init = mpc83xx_time_init,
> > + .calibrate_decr = generic_calibrate_decr,
> > + .progress = udbg_progress,
> > +};
> > diff --git a/arch/powerpc/platforms/83xx/mpc8360e_pb.h
> b/arch/powerpc/platforms/83xx/mpc8360e_pb.h
> > new file mode 100644
> > index 0000000..4243f4a
> > --- /dev/null
> > +++ b/arch/powerpc/platforms/83xx/mpc8360e_pb.h
> > @@ -0,0 +1,31 @@
> > +/*
> > + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
> > + *
> > + * Author: Li Yang <LeoLi@freescale.com>
> > + * Yin Olivia <Hong-hua.Yin@freescale.com>
> > + *
> > + * Description:
> > + * MPC8360E MDS PB board specific header.
> > + *
> > + * Changelog:
> > + * Jun 21, 2006 Initial version
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> it
> > + * under the terms of the GNU General Public License as published by the
> > + * Free Software Foundation; either version 2 of the License, or (at your
> > + * option) any later version.
> > + *
> > + */
> > +
> > +#ifndef __MACH_MPC83XX_SYS_H__
> > +#define __MACH_MPC83XX_SYS_H__
> > +
> > +#define BCSR_PHYS_ADDR ((uint)0xf8000000)
> > +#define BCSR_SIZE ((uint)(32 * 1024))
> > +
> > +#define PIRQA MPC83xx_IRQ_EXT4
> > +#define PIRQB MPC83xx_IRQ_EXT5
> > +#define PIRQC MPC83xx_IRQ_EXT6
> > +#define PIRQD MPC83xx_IRQ_EXT7
> > +
>
> Hrm, isn't PCI irq stuff encoded to the dts? Upper pci-related defines seem
> redundant...
I'll remove.
>
> > +#endif /* __MACH_MPC83XX_SYS_H__ */
> >
> > _______________________________________________
> > Linuxppc-dev mailing list
> > Linuxppc-dev@ozlabs.org
> > https://ozlabs.org/mailman/listinfo/linuxppc-dev
> >
> >
>
>
> --
> Sincerely,
> Vitaly
^ permalink raw reply
* 8541 FCC transmit timed out
From: Stephen Cheng @ 2006-06-29 9:55 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 2553 bytes --]
Hi the community,
I encountered the "transmit timed out" problem when I try to bring up the
FCC on an mpc8541 based board.
I found there are a lot of such issues posted in the list, unfortunately,
I didn't find a workaround could solve my problem.
The FCC port works fine under U-boot, I can ping the host and download
files from TFTP server, so the tx/rx clk route should be no problem. The
command line U-boot transfer to Linux Kernel should be fine too, because
kernel startup message says: IP-Config Complete ...
When I tried to ping the host after Linux is up, I got the following
dumped messages:
PING 192.168.1.2 (192.168.1.2) from 192.168.1.192 : 56(84) bytes of data.
>From 192.168.1.192: Destination Host Unreachable
>From 192.168.1.192: Destination Host Unreachable
>From 192.168.1.192: Destination Host Unreachable
>From 192.168.1.192: Destination Host Unreachable
>From 192.168.1.192: Destination Host Unreachable
>From 192.168.1.192: Destination Host Unreachable
NETDEV WATCHDOG: eth0: transmit timed out
eth0: transmit timed out.
Ring data dump: cur_tx c0218100 tx_free 0 cur_rx c0218000.
Tx @base c0218100 :
1c01 0062 0039e962
1c01 0062 0039e662
1c01 0062 0039e862
1c01 0062 0039ea62
5c01 002a 07f45de2
5c01 002a 07f45e62
5c01 002a 07f45ee2
5c01 002a 07f45f62
5c01 002a 07a2b0a2
5c01 002a 07a2b122
5c01 002a 07a2b1a2
5c01 002a 07a2b222
5c01 002a 07a2b2a2
5c01 002a 07a2b322
5c01 002a 07a2b3a2
7c01 002a 07a2b422
Rx @base c0218000 :
1c80 0040 07706000
1c80 0040 07706800
1c80 0040 07705000
1c00 0040 07705800
1c00 0040 07704000
1c00 0040 07704800
1c00 0040 07703000
1c00 0040 07703800
1c00 0040 07702000
1c00 0040 07702800
1c00 0040 07701000
1c00 0040 07701800
1c00 0040 07700000
1c00 0040 07700800
1c00 0040 003ff000
9000 0000 003ff800
9000 0000 003fe000
9000 0000 003fe800
9000 0000 003fd000
9000 0000 003fd800
9000 0000 003fc000
9000 0000 003fc800
9000 0000 003fb000
9000 0000 003fb800
9000 0000 003fa000
9000 0000 003fa800
9000 0000 003f9000
9000 0000 003f9800
9000 0000 003f8000
9000 0000 003f8800
9000 0000 003f7000
b000 0000 003f7800
NETDEV WATCHDOG: eth0: transmit timed out
eth0: transmit timed out.
......
The last bit of TxBD_CSR is 1, which means "Carrier Sense Lost", I have no
idea about why this could happen.
I captured the package at the host side, the host had received the ARP
request package and had also sent the ARP reply package, however, no ICMP
package followed.
The Linux version is 2.4.20.
Any comment will be appreciated!
(PS: sorry for my poor English.)
Thanks & Best Regards,
Stephen C.
[-- Attachment #2: Type: text/html, Size: 5730 bytes --]
^ permalink raw reply
* [PATCH] [powerpc] change get_property to return void *
From: Jeremy Kerr @ 2006-06-29 10:28 UTC (permalink / raw)
To: linuxppc-dev
Change the get_property() function to return a void *. This allows us
to later remove the cast done in the majority of callers.
Built for pseries, iseries, pmac32, cell, cbesim, g5, systemsim, maple,
and mpc* defconfigs
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
---
arch/powerpc/kernel/prom.c | 3 +--
include/asm-powerpc/prom.h | 4 ++--
2 files changed, 3 insertions(+), 4 deletions(-)
Index: linux-2.6/arch/powerpc/kernel/prom.c
===================================================================
--- linux-2.6.orig/arch/powerpc/kernel/prom.c
+++ linux-2.6/arch/powerpc/kernel/prom.c
@@ -1975,8 +1975,7 @@ struct property *of_find_property(struct
* Find a property with a given name for a given node
* and return the value.
*/
-unsigned char *get_property(struct device_node *np, const char *name,
- int *lenp)
+void *get_property(struct device_node *np, const char *name, int *lenp)
{
struct property *pp = of_find_property(np,name,lenp);
return pp ? pp->value : NULL;
Index: linux-2.6/include/asm-powerpc/prom.h
===================================================================
--- linux-2.6.orig/include/asm-powerpc/prom.h
+++ linux-2.6/include/asm-powerpc/prom.h
@@ -167,8 +167,8 @@ extern void unflatten_device_tree(void);
extern void early_init_devtree(void *);
extern int device_is_compatible(struct device_node *device, const char *);
extern int machine_is_compatible(const char *compat);
-extern unsigned char *get_property(struct device_node *node, const char *name,
- int *lenp);
+extern void *get_property(struct device_node *node, const char *name,
+ int *lenp);
extern void print_properties(struct device_node *node);
extern int prom_n_addr_cells(struct device_node* np);
extern int prom_n_size_cells(struct device_node* np);
^ permalink raw reply
* Re: [PATCH] [powerpc] change get_property to return void *
From: Benjamin Herrenschmidt @ 2006-06-29 10:37 UTC (permalink / raw)
To: Jeremy Kerr; +Cc: linuxppc-dev
In-Reply-To: <1151576898.883498.737885160345.qpush@pokey>
On Thu, 2006-06-29 at 20:28 +1000, Jeremy Kerr wrote:
> Change the get_property() function to return a void *. This allows us
> to later remove the cast done in the majority of callers.
>
> Built for pseries, iseries, pmac32, cell, cbesim, g5, systemsim, maple,
> and mpc* defconfigs
>
> Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
It was time to do that !
Acked-by: Benjamin Herremschmidt <benh@kernel.crashing.org>
^ permalink raw reply
* Re: Xilinx SystemACE driver for 2.6
From: Ameet Patil @ 2006-06-29 10:56 UTC (permalink / raw)
To: linuxppc-embedded
In-Reply-To: <44A2C7CE.9070302@gmail.com>
Here is the patch containing the SysAce driver for 2.6 Linux kernel.
http://www.cs.york.ac.uk/rtslab/demos/amos/xupv2pro/patches/linuxppc-2.6.17_sysace.patch
Please test it and let me know in case of any issues!
cheers,
-Ameet
Ameet Patil wrote:
> Hi,
> I have ported System Ace driver from 2.4 to 2.6. Please post the
> patch soon.
>
> -Ameet
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
>
^ permalink raw reply
* Re: Xilinx SystemACE driver for 2.6
From: Ameet Patil @ 2006-06-29 10:58 UTC (permalink / raw)
To: linuxppc-embedded
In-Reply-To: <44A3A77D.6000804@gmail.com>
Hi Sudheer,
Sorry, I ate my words there. I meant - I shall soon be posting a
patch that contains my port of the SystemAce driver for 2.6 kernel.
-Ameet
> sudheer wrote:
>> Hi Ameet,
>>
>> Your mail is not clear.
>>
>>
>> Ameet Patil wrote:
>>
>>> Hi,
>>> I have ported System Ace driver from 2.4 to 2.6.
>> Hope you have ported System Ace Driver from 2.4 to 2.6.
>>
>>> Please post the patch soon.
>>>
>>>
>> Or else you are asking the group for patch to port it.
>> Please make it clear.
>> I am looking for the same .
>>
>> Thanks
>> Sudheer
>>
>>> -Ameet
>>> _______________________________________________
>>> Linuxppc-embedded mailing list
>>> Linuxppc-embedded@ozlabs.org
>>> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
>>>
>>>
>>>
>>
>
^ permalink raw reply
* Re: [PATCH] [powerpc] change get_property to return void *
From: Benjamin Herrenschmidt @ 2006-06-29 11:29 UTC (permalink / raw)
To: Jeremy Kerr; +Cc: linuxppc-dev
In-Reply-To: <1151577436.28229.47.camel@localhost.localdomain>
> Acked-by: Benjamin Herremschmidt <benh@kernel.crashing.org>
And as Segher-lynx-eye noticed, there is a typo :) Here's a proper one
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
:)
Ben.
^ permalink raw reply
* please pull powerpc.git 'master' branch
From: Paul Mackerras @ 2006-06-29 11:35 UTC (permalink / raw)
To: torvalds; +Cc: linuxppc-dev
Linus,
Please do a pull from the "master" branch of
git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc.git
to get some more powerpc updates, as listed below.
Thanks,
Paul.
arch/powerpc/Kconfig | 23 -
arch/powerpc/Kconfig.debug | 9
arch/powerpc/configs/cell_defconfig | 7
arch/powerpc/configs/mpc7448_hpc2_defconfig | 923 +++++++++++++++++++++
arch/powerpc/kernel/Makefile | 3
arch/powerpc/kernel/cpu_setup_power4.S | 14
arch/powerpc/kernel/cputable.c | 12
arch/powerpc/kernel/crash.c | 147 +++
arch/powerpc/kernel/head_64.S | 62 -
arch/powerpc/kernel/iommu.c | 30 +
arch/powerpc/kernel/legacy_serial.c | 11
arch/powerpc/kernel/lparcfg.c | 147 ++-
arch/powerpc/kernel/machine_kexec_64.c | 4
arch/powerpc/kernel/misc.S | 203 +++++
arch/powerpc/kernel/misc_32.S | 156 ----
arch/powerpc/kernel/misc_64.S | 223 -----
arch/powerpc/kernel/paca.c | 1
arch/powerpc/kernel/prom.c | 49 +
arch/powerpc/kernel/rtas.c | 119 ++-
arch/powerpc/kernel/setup_64.c | 22 -
arch/powerpc/kernel/traps.c | 27 -
arch/powerpc/kernel/udbg.c | 7
arch/powerpc/mm/hash_native_64.c | 3
arch/powerpc/mm/hash_utils_64.c | 106 +-
arch/powerpc/mm/mmu_context_64.c | 2
arch/powerpc/platforms/86xx/Kconfig | 6
arch/powerpc/platforms/86xx/Makefile | 3
arch/powerpc/platforms/86xx/mpc8641_hpcn.h | 1
arch/powerpc/platforms/86xx/mpc86xx.h | 8
arch/powerpc/platforms/86xx/mpc86xx_hpcn.c | 129 +++
arch/powerpc/platforms/86xx/mpc86xx_smp.c | 10
arch/powerpc/platforms/86xx/pci.c | 137 ---
arch/powerpc/platforms/Makefile | 1
arch/powerpc/platforms/cell/Kconfig | 2
arch/powerpc/platforms/cell/setup.c | 16
arch/powerpc/platforms/cell/spu_base.c | 8
arch/powerpc/platforms/cell/spufs/file.c | 10
arch/powerpc/platforms/cell/spufs/switch.c | 6
arch/powerpc/platforms/embedded6xx/Kconfig | 15
arch/powerpc/platforms/embedded6xx/Makefile | 4
arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c | 335 ++++++++
arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h | 26 +
arch/powerpc/platforms/iseries/dt.c | 2
arch/powerpc/platforms/iseries/htab.c | 4
arch/powerpc/platforms/iseries/lpevents.c | 55 +
arch/powerpc/platforms/iseries/proc.c | 1
arch/powerpc/platforms/iseries/setup.c | 19
arch/powerpc/platforms/maple/setup.c | 7
arch/powerpc/platforms/powermac/setup.c | 9
arch/powerpc/platforms/pseries/iommu.c | 33 +
arch/powerpc/platforms/pseries/lpar.c | 4
arch/powerpc/platforms/pseries/setup.c | 10
arch/powerpc/sysdev/Makefile | 2
arch/powerpc/sysdev/dart.h | 6
arch/powerpc/sysdev/dart_iommu.c | 49 +
arch/powerpc/sysdev/todc.c | 392 +++++++++
arch/powerpc/sysdev/tsi108_dev.c | 145 +++
arch/powerpc/sysdev/tsi108_pci.c | 412 +++++++++
drivers/ide/Kconfig | 9
drivers/ide/ppc/pmac.c | 125 ---
drivers/macintosh/Kconfig | 12
drivers/macintosh/Makefile | 1
drivers/macintosh/via-pmu-led.c | 144 +++
include/asm-powerpc/cputable.h | 48 -
include/asm-powerpc/iseries/it_lp_queue.h | 40 -
include/asm-powerpc/kdump.h | 2
include/asm-powerpc/kexec.h | 9
include/asm-powerpc/machdep.h | 2
include/asm-powerpc/mmu.h | 1
include/asm-powerpc/mmu_context.h | 7
include/asm-powerpc/mpc86xx.h | 5
include/asm-powerpc/rtas.h | 3
include/asm-powerpc/time.h | 6
include/asm-powerpc/todc.h | 487 +++++++++++
include/asm-powerpc/tsi108.h | 109 ++
include/asm-powerpc/udbg.h | 3
kernel/kexec.c | 6
77 files changed, 4086 insertions(+), 1110 deletions(-)
create mode 100644 arch/powerpc/configs/mpc7448_hpc2_defconfig
create mode 100644 arch/powerpc/kernel/misc.S
create mode 100644 arch/powerpc/platforms/embedded6xx/Makefile
create mode 100644 arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
create mode 100644 arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h
create mode 100644 arch/powerpc/sysdev/todc.c
create mode 100644 arch/powerpc/sysdev/tsi108_dev.c
create mode 100644 arch/powerpc/sysdev/tsi108_pci.c
create mode 100644 drivers/macintosh/via-pmu-led.c
create mode 100644 include/asm-powerpc/todc.h
create mode 100644 include/asm-powerpc/tsi108.h
Andrew Morton:
[POWERPC] powerpc: kconfig warning fix
Arnd Bergmann:
[POWERPC] spufs: fix class0 interrupt assignment
Benjamin Herrenschmidt:
[POWERPC] spufs: map mmio space as guarded into user space
[POWERPC] spufs: fix MFC command queue purge
David Wilder:
[POWERPC] Add the use of the firmware soft-reset-nmi to kdump.
Geoff Levand:
[POWERPC] spufs: fix memory hotplug dependency
Haren Myneni:
[POWERPC] kdump: Reserve the existing TCE mappings left by the first kernel
Jimi Xenidis:
[POWERPC] Don't access HID registers if running on a Hypervisor.
[POWERPC] Skip the "copy down" of the kernel if it is already at zero.
Johannes Berg:
[POWERPC] Convert powermac ide blink to new led infrastructure
Jon Loeliger:
[POWERPC] Remove redundant PPC_86XX check.
[POWERPC] Move I8259 selection under MPC8641HPCN board
[POWERPC] Remove redundant STD_MMU selection.
[POWERPC] Remove obsolete #include <linux/config.h>.
Kumar Gala:
powerpc: minor cleanups for mpc86xx
Mark A. Greer:
[POWERPC] todc: add support for Time-Of-Day-Clock
Michael Ellerman:
[POWERPC] Remove remaining iSeries debugger cruft
[POWERPC] Export flat device tree via debugfs for debugging
[POWERPC] powerpc: Initialise ppc_md htab pointers earlier
[POWERPC] Use ppc_md.hpte_insert() in htab_bolt_mapping()
[POWERPC] Make kexec_setup() a regular initcall
[POWERPC] Setup the boot cpu's paca pointer in C rather than asm
[POWERPC] Make rtas_call() safe if RTAS hasn't been initialised
[POWERPC] Move RTAS exports next to their declarations
[POWERPC] Setup RTAS values earlier, to enable rtas_call() earlier
[POWERPC] Add udbg support for RTAS console
[POWERPC] Enable the RTAS udbg console on IBM Cell Blade
[POWERPC] Enable XMON in cell_defconfig
[POWERPC] Make sure smp_processor_id works very early in boot
Olof Johansson:
[POWERPC] U4 DART improvements
Paul Mackerras:
[POWERPC] Simplify the code defining the 64-bit CPU features
[POWERPC] Make sure we select CONFIG_NEW_LEDS if ADB_PMU_LED is set
[POWERPC] Correct the MAX_CONTEXT definition
[POWERPC] Use little-endian bit from firmware ibm,pa-features property
Sonny Rao:
[POWERPC] Fix idr locking in init_new_context
Stephen Rothwell:
[POWERPC] Clean up it_lp_queue.h
[POWERPC] update asm-powerpc/time.h
[POWERPC] Remove unused function call_with_mmu_off
[POWERPC] Consolidate some of kernel/misc*.S
[POWERPC] Make lparcfg.c work when both iseries and pseries are selected
Zang Roy-r61911:
[POWERPC] Add general support for mpc7448hpc2 (Taiga) platform
[POWERPC] Add tsi108 pci and platform device data register function
[POWERPC] mpc7448hpc2 (taiga) board config file
^ permalink raw reply
* Re: entry point of kernel in RAM at 0x0c--linux tree file name
From: Arun Kumar @ 2006-06-29 11:52 UTC (permalink / raw)
To: Laurent Pinchart; +Cc: linuxppc-embedded
In-Reply-To: <200606231218.14788.laurent.pinchart@tbox.biz>
[-- Attachment #1: Type: text/plain, Size: 4062 bytes --]
Hi Laurent ,
I have made marginally more progress in my porting effort .Now I can see the
early debug text by enabling the CONFIG_SERIAL_TEXT_DEBUG and pointing the
gen550.c code to my sandpoint 8260 LSP code and UART adresses .
I have a Sandpoint 8260 LSP .However now my code crashes in mapin_ram
roputine .
Here is a dump of serial console :
loaded at: 00800000 0099A1D8
zimage at: 008057B7 0086B0E9
initrd at: 0086C000 0099645B
avail ram: 00400000 00800000
Linux/PPC load: console=ttyS0,9600 console=tty0 root=/dev/ram
Uncompressing Linux...done.
Now booting the kernel
id mach(): init
MMU:mapin
MMU:have_bats
MMU:PPC_STD_MMU
The mapin_ram code in pgtable.c is as follows :
void __init mapin_ram(void)
{
unsigned long v, s, f;
phys_addr_t p;
#ifdef HAVE_BATS
if (!__map_without_bats)
{ bat_mapin_ram(__bat2, __bat3);
ppc_md.progress("MMU:have_bats", 0x401);
}
#endif /* HAVE_BATS */
v = KERNELBASE;
p = PPC_MEMSTART;
for (s = 0; s < total_lowmem; s += PAGE_SIZE) {
/* On the MPC8xx, we want the page shared so we
* don't get ASID compares on kernel space.
*/
f = _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_SHARED | _PAGE_HWEXEC;
#ifdef CONFIG_440
/* Prevent bogus speculative cycles */
f |= _PAGE_GUARDED;
#endif
#if defined(CONFIG_KGDB) || defined(CONFIG_XMON) ||
defined(CONFIG_BDI_SWITCH)
/* Allows stub to set breakpoints everywhere */
f |= _PAGE_WRENABLE;
ppc_md.progress("MMU:in kgdb", 0x401);
#else /* !CONFIG_KGDB && !CONFIG_XMON && !CONFIG_BDI_SWITCH */
if ((char *) v < _stext || (char *) v >= etext)
{ f |= _PAGE_WRENABLE;
ppc_md.progress("MMU:else of kgdb", 0x401);
}
#ifdef CONFIG_PPC_STD_MMU
else
/* On the powerpc (not all), no user access
forces R/W kernel access */
f |= _PAGE_USER;
ppc_md.progress("MMU:PPC_STD_MMU", 0x401);
#endif /* CONFIG_PPC_STD_MMU */
#endif /* CONFIG_KGDB || CONFIG_XMON */
map_page(v, p, f);
v += PAGE_SIZE;
p += PAGE_SIZE;
}
if (ppc_md.progress)
ppc_md.progress("MMU:mapin_ram done", 0x401);
}
This is crashing somewhere in map_page routine .
I have 64Mb in DRAM and 8 Mb of Flash .I have really no idea why my MMU_init
code is crashing .. Any help would be greatly appreciated .
Thanks,
Arun
On 6/23/06, Laurent Pinchart <laurent.pinchart@tbox.biz> wrote:
>
> Hi Arun,
>
> please keep the list posted when you reply.
>
> > Thanks for the response .I would also like to ask another query hoever
> > naive it might sound .I am using a Linux 2.4.1
>
> That's very old. Can't you upgrade to 2.6 ?
>
> > wherein my entry point
> > code at 0x0c expects at R3 ,R4,R5,R6 some parameters which I strongly
> > suspect to be residual record bi_rec *,start of initrd and end of initrd
> > sections as my kernel is crashing immediately after MMU_init and I
> > suspect that machine _init that is done prior to MMU_init expects __res
> > in R3 as a input parameter .Please confirm .
>
> Depending on your platform and boot loader, r3 to r7 are initialized with
> different values. If you're using ppcboot, the kernel expects r3 to be
> initialized with the residual record, right.
>
> > I am using ppcboot2..0.0 as my bootloader .
>
> That' very old too. You should upgrade to U-Boot.
>
> > Also I would like to know how can i enable serial console in these early
> > kernel initialsaiotns process. I am using a CONFIG_SANDPOINT(8260) on a
> > MPC 8245 platform and trying to port the code on MPC8245 platform .the
> > board has a very similar config as a SANDPOINT board .
>
> If I'm not mistaken, you can't enable a serial console that early. Do you
> have
> a hardware debugger (BDI2000) ? If not, you could try LED debugging.
>
> Best regards,
>
> Laurent Pinchart
>
--
Arun Kumar Singh
Tech Lead.
Agere India
Bangalore
[-- Attachment #2: Type: text/html, Size: 5684 bytes --]
^ permalink raw reply
* [PATCH] Add QE device tree definition
From: Li Yang-r58472 @ 2006-06-29 12:53 UTC (permalink / raw)
To: linuxppc-dev
This is the device tree definition for QE SOC for Freescale CPUs.
I have discussed with Vitaly. We agreed on having CPM and QE definition ultimately merged. He will add in CPM specified definition later.
Signed-off-by: Jiang Bo <Tanya.jiang@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
Signed-off-by: Vitaly Bordug <vbordug@ru.mvista.com>
---
Documentation/powerpc/booting-without-of.txt | 222 ++++++++++++++++++++++++++
1 files changed, 222 insertions(+), 0 deletions(-)
diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index 217e517..096063f 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -1442,6 +1442,227 @@ platforms are moved over to use the flat
};
+ h) Freescale QUICC Engine module (QE)
+ This represents qe module that is installed on PowerQUICC II Pro.
+ Hopefully it will merge backward compatibility with CPM/CPM2.
+ Basically, it is a bus of devices, that could act more or less
+ as a complete entity (UCC, USB etc ). All of them should be siblings on
+ the "root" qe node, using the common properties from there.
+ The description below applies to the the qe of MPC8360 and
+ more nodes and properties would be extended in the future.
+
+ 1) Root QE device
+
+ Required properties:
+ - device_type : should be "qe";
+ - model : precise model of the QE, Can be "QE", "CPM", or "CPM2"
+ - reg : Offset and length of the register set for the device.
+ - bus-frequency : the clock frequency for QUICC Engine.
+
+ Recommended properties
+ - brg-frequency : the internal clock source frequency for baud-rate
+ generators in Hz.
+
+ Example:
+ qe@e0100000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ #interrupt-cells = <2>;
+ device_type = "qe";
+ model = "QE";
+ ranges = <0 e0100000 00100000>;
+ reg = <e0100000 480>;
+ brg-frequency = <0>;
+ bus-frequency = <179A7B00>;
+ }
+
+
+ 2) SPI (Serial Peripheral Interface)
+
+ Required properties:
+ - device_type : should be "spi".
+ - compatible : should be "fsl_spi".
+ - mode : the spi operation mode, it can be "cpu" or "qe".
+ - reg : offset to the register set and its length.
+ - interrupts : <a b> where a is the interrupt number and b is a
+ field that represents an encoding of the sense and level
+ information for the interrupt. This should be encoded based on
+ the information in section 2) depending on the type of interrupt
+ controller you have.
+ - interrupt-parent : the phandle for the interrupt controller that
+ services interrupts for this device.
+
+ Example:
+ spi@4c0 {
+ device_type = "spi";
+ compatible = "fsl_spi";
+ reg = <4c0 40>;
+ interrupts = <82 0>;
+ interrupt-parent = <700>;
+ mode = "cpu";
+ };
+
+
+ 3) USB (Universal Serial Bus Controller)
+
+ Required properties:
+ - device_type : should be "usb".
+ - compatible : could be "qe_udc" or "fhci-hcd".
+ - model : the could be "host" or "slave".
+ - reg : there will be two tuples of "address size". The first tuple is
+ offset and length of the device registers respectively; the second is
+ offset and length of the device parameter RAM respectively.
+ - interrupts : <a b> where a is the interrupt number and b is a
+ field that represents an encoding of the sense and level
+ information for the interrupt. This should be encoded based on
+ the information in section 2) depending on the type of interrupt
+ controller you have.
+ - interrupt-parent : the phandle for the interrupt controller that
+ services interrupts for this device.
+
+ Example(slave):
+ usb@6c0 {
+ device_type = "usb";
+ compatible = "qe_udc";
+ reg = <6c0 40 8B00 100>;
+ interrupts = <8b 0>;
+ interrupt-parent = <700>;
+ mode = "slave";
+ };
+
+
+ 4) UCC (Unified Communications Controllers)
+
+ Required properties:
+ - device_type : should be "network", "hldc", "uart", "transparent"
+ "bisync" or "atm".
+ - compatible : could be "ucc_geth" or "fsl_atm" and so on.
+ - model : should be "UCC".
+ - device-id : the ucc number(1-8), corresponding to UCCx in UM.
+ - reg : there will be two tuples of "address size". The first tuple is
+ offset and length of the device registers respectively; the second is
+ offset and length of the device parameter RAM respectively.
+ - interrupts : <a b> where a is the interrupt number and b is a
+ field that represents an encoding of the sense and level
+ information for the interrupt. This should be encoded based on
+ the information in section 2) depending on the type of interrupt
+ controller you have.
+ - interrupt-parent : the phandle for the interrupt controller that
+ services interrupts for this device.
+ - pio-handle : The phandle for the Parallel I/O port configuration.
+
+ Required properties for network device_type:
+ - mac-address : list of bytes representing the ethernet address.
+ - rx-clock : a string represents the UCC receive clock source.
+ "brgx" : clock source is BRG1~BRG16 respectively;
+ "clkx" : clock source is QE_CLK1~QE_CLK24 respectively.
+ others : clock source is disabled;
+ - tx-clock: a string represents the UCC transmit clock source;
+ "brgx" : clock source is BRG1~BRG16 respectively;
+ "clkx" : clock source is QE_CLK1~QE_CLK24 respectively.
+ others : clock source is disabled;
+ - phy-handle : The phandle for the PHY connected to this controller.
+
+ Example:
+ ucc@2000 {
+ device_type = "network";
+ compatible = "ucc_geth";
+ model = "UCC";
+ device-id = <1>;
+ reg = <2000 200 8400 100>;
+ interrupts = <a0 0>;
+ interrupt-parent = <700>;
+ mac-address = [ 00 04 9f 00 23 23 ];
+ rx-clock = "none";
+ tx-clock = "clk9";
+ phy-handle = <212000>;
+ pio-handle = <140001>;
+ };
+
+
+ 5) Parallel I/O Ports
+
+ This node configures Parallel I/O ports for CPUs with QE support.
+ The node should reside in the "soc" node of the tree. For each
+ device that using parallel I/O ports, a child node should be created.
+ See the definition of the Pin configuration nodes below for more
+ information.
+
+ Required properties:
+ - device_type : should be "par_io".
+ - reg : offset to the register set and its length.
+
+ Example:
+ par_io@1400 {
+ reg = <1400 100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ device_type = "par_io";
+ ucc_pin@01 {
+ ......
+ };
+
+
+ 6) Pin configuration nodes
+
+ Required properties:
+ - linux,phandle : phandle of this node; likely referenced by a QE
+ device.
+ - pio-map : array of pin configurations. Each pin is defined by 6
+ integers. The six numbers are respectively: port, pin, dir,
+ open_drain, assignment, has_irq.
+ - port : port number of the pin; 0-6 represent port A-G in UM.
+ - pin : pin number in the port.
+ - dir : direction of the pin, should encode as follows:
+
+ 0 = The pin is disabled
+ 1 = The pin is an output
+ 2 = The pin is an input
+ 3 = The pin is I/O
+
+ - open_drain : indicates the pin is normal or wired-OR:
+
+ 0 = The pin is actively driven as an output
+ 1 = The pin is an open-drain driver. As an output, the pin is
+ driven active-low, otherwise it is three-stated.
+
+ - assignment : function number of the pin according to the Pin Assignment
+ tables in User Manual. Each pin can have up to 4 possible functions in
+ QE and two options for CPM.
+ - has_irq : indicates if the pin is used as source of exteral
+ interrupts.
+
+ Example:
+ ucc_pin@01 {
+ linux,phandle = <140001>;
+ pio-map = <
+ /* port pin dir open_drain assignment has_irq */
+ 0 3 1 0 1 0 /* TxD0 */
+ 0 4 1 0 1 0 /* TxD1 */
+ 0 5 1 0 1 0 /* TxD2 */
+ 0 6 1 0 1 0 /* TxD3 */
+ 1 6 1 0 3 0 /* TxD4 */
+ 1 7 1 0 1 0 /* TxD5 */
+ 1 9 1 0 2 0 /* TxD6 */
+ 1 a 1 0 2 0 /* TxD7 */
+ 0 9 2 0 1 0 /* RxD0 */
+ 0 a 2 0 1 0 /* RxD1 */
+ 0 b 2 0 1 0 /* RxD2 */
+ 0 c 2 0 1 0 /* RxD3 */
+ 0 d 2 0 1 0 /* RxD4 */
+ 1 1 2 0 2 0 /* RxD5 */
+ 1 0 2 0 2 0 /* RxD6 */
+ 1 4 2 0 2 0 /* RxD7 */
+ 0 7 1 0 1 0 /* TX_EN */
+ 0 8 1 0 1 0 /* TX_ER */
+ 0 f 2 0 1 0 /* RX_DV */
+ 0 10 2 0 1 0 /* RX_ER */
+ 0 0 2 0 1 0 /* RX_CLK */
+ 2 9 1 0 3 0 /* GTX_CLK - CLK10 */
+ 2 8 2 0 1 0>; /* GTX125 - CLK9 */
+ };
+
+
More devices will be defined as this spec matures.
^ permalink raw reply related
* Re: new IRQ work status
From: Arnd Bergmann @ 2006-06-29 13:25 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <1151570165.28229.15.camel@localhost.localdomain>
On Thursday 29 June 2006 10:36, Benjamin Herrenschmidt wrote:
> http://gate.crashing.org/~benh/irq-WIP/
>
> Comments welcome.
>
Looks great!
> -}
> -
> /* Get an IRQ number from the pending state register of the IIC */
> -int iic_get_irq(struct pt_regs *regs)
> +unsigned int iic_get_irq(struct pt_regs *regs)
Is unsigned the right thing here? NO_IRQ is defined as (-1).
> +
> +/*
> + * Hardcoded setup part to be compatible with older firmware. We don't
> + * associate a device-node to the hosts in this case, which mean that
> + * no mapping from the device-tree is supposed. That's ok as there is
> + * none anyway
> + */
> static int __init setup_iic_hardcoded(void)
> {
I'd prefer to throw out the hardcoded part from the official tree
completely. It's only needed on the very first FW versions that
were shipped and those need some other patches that we never merged
upstream anyway. So better move it to an extra patch that we keep
external for some time and eventually drop.
> static irqreturn_t iic_ipi_action(int irq, void *dev_id, struct pt_regs
> *regs) {
> - smp_message_recv(iic_irq_to_ipi(irq), regs);
> + int ipi = (int)(long)dev_id;
> + smp_message_recv(ipi, regs);
> return IRQ_HANDLED;
> }
Nice one. this looks a lot cleaner than looking at the irq number here.
> static void iic_request_ipi(int ipi, const char *name)
> {
> - int irq;
> -
> - irq = iic_ipi_to_irq(ipi);
> + int node, virq;
>
> - /* IPIs are marked SA_INTERRUPT as they must run with irqs
> - * disabled */
> - set_irq_chip_and_handler(irq, &iic_chip, handle_percpu_irq);
> - request_irq(irq, iic_ipi_action, SA_INTERRUPT, name, NULL);
> + for (node = 0; node < IIC_NODE_COUNT; node++) {
> + char *rname;
> + if (iic_hosts[node] == NULL)
> + continue;
> + virq = irq_create_mapping(iic_hosts[node],
> + iic_ipi_to_irq(ipi), 0);
> +
> + if (virq == NO_IRQ) {
> + printk(KERN_ERR
> + "iic: failed to map IPI %s on node %d\n",
> + name, node);
> + continue;
> + }
> + rname = kzalloc(strlen(name) + 16, GFP_KERNEL);
> + if (rname)
> + sprintf(rname, "%s node %d", name, node);
> + else
> + rname = (char *)name;
Considering that name is know to be rather short and we have a fixed
number of these, can't we just put the strings into struct iic
instead of doing the kzalloc?
> enum {
> - IIC_EXT_OFFSET = 0x00, /* Start of south bridge IRQs */
> - IIC_EXT_CASCADE = 0x20, /* There is no interrupt 32 on spider */
> - IIC_NUM_EXT = 0x40, /* Number of south bridge IRQs */
> - IIC_SPE_OFFSET = 0x40, /* Start of SPE interrupts */
> - IIC_CLASS_STRIDE = 0x10, /* SPE IRQs per class */
> - IIC_IPI_OFFSET = 0x70, /* Start of IPI IRQs */
> - IIC_NUM_IPIS = 0x10, /* IRQs reserved for IPI */
> - IIC_NODE_STRIDE = 0x80, /* Total IRQs per node */
> + IIC_IRQ_INVALID = 0xff,
Where is IIC_IRQ_INVALID used?
> + }
> + } else if (device_is_compatible(dn, "sti,platform-spider-pic")
> + && (chip < 2)) {
> + static long hard_coded_pics[] =
> + { 0x24000008000, 0x34000008000 };
> + r.start = hard_coded_pics[chip];
> } else
See above about the hardcoded stuff.
> @@ -664,11 +688,18 @@ static int __init create_spu(struct devi
> if (ret)
> goto out_free;
>
> + /* XXX FIXME: Those node vs. nid things are crap, we need
> + * only one information, but fixing that goes along with fixing
> + * all of the node vs chip vs thread code all over the cell
> + * platform. To do soon hopefully...
> + */
> spu->node = find_spu_node_id(spe);
> spu->nid = of_node_to_nid(spe);
> if (spu->nid == -1)
> spu->nid = 0;
The idea at some point was to keep the notion of nid (as in address
on the inter-chip protocol) separate from the NUMA node ID, which
may in theory be less fine-grained. Defining them to be the same
at least requires the device tree to be very careful with the numbers
in ibm,associativity properties to match the bus numbers.
> Index: linux-work-mm/include/asm-powerpc/spu.h
> ===================================================================
> --- linux-work-mm.orig/include/asm-powerpc/spu.h 2006-06-23
> 13:38:19.000000000 +1000 +++
> linux-work-mm/include/asm-powerpc/spu.h 2006-06-29 16:32:35.000000000 +1000
> @@ -117,7 +117,7 @@ struct spu {
> struct list_head sched_list;
> int number;
> int nid;
> - u32 isrc;
> + unsigned int irqs[3];
> u32 node;
> u64 flags;
> u64 dar;
We've started exporting the isrc property in sysfs recently, so I think
we need to keep that in here.
Arnd <><
^ permalink raw reply
* Re: new IRQ work status
From: Segher Boessenkool @ 2006-06-29 13:41 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: linuxppc-dev
In-Reply-To: <200606291525.53254.arnd.bergmann@de.ibm.com>
>> /* Get an IRQ number from the pending state register of the IIC */
>> -int iic_get_irq(struct pt_regs *regs)
>> +unsigned int iic_get_irq(struct pt_regs *regs)
>
> Is unsigned the right thing here? NO_IRQ is defined as (-1).
It used to be -1, it's 0 now...
Segher
^ permalink raw reply
* [0/5][POWERPC] boot: create zImage.kexec
From: Milton Miller @ 2006-06-29 13:24 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras
What follows is a series of 5 patches that take the existing zImge code
from the arch/powerpc/boot directory and add an alternative image that
will boot with a device tree struct but not with a prom interface
callback.
It searches the flat device tree (read-only) to find the
memory size, reserved ranges, and rtas. Messages are sent through
rtas to eiher the new for cell put-term-char or display-character
interfaces.
[1/5][POWERPC] boot: prepare for zImage.kexec
I tried to keep the changes to main.c and prom.h minimal.
[2/5][POWERPC] boot: Add kexec callable zImage wrapper
The actual code and crt0 for this method.
[3/5][POWERPC] boot: use more Kbuild rules
I had a bit of trouble with rebuilds. This trys to get some
rules more right. However, the final target changes to cmd
should go to if_changed and add FORCE to the dependency
(rebuild gets make[2]: arch/powerpc/boot/zImage is up to date..
It also renames linuxheader to be more generic and renames
OBJCOPYFLAGS to allow usage of the $(objcopy) rule.
[4/5][POWERPC] boot: Makefile and linker scripts for zImage.kexec
delta to above and inker scripts for the existing link.
zImage.kexec is 32 biz, there is also altnernate link that
pretends to be 64 bit which allows kexec-tools to load it
without writing ompat code.
[5/5][POWERPC] boot: generate lds file from lds.S
An alterative file ploferations, generate the lds from .S using
the Kbuild rule. If you like this patch then I can avoid creating
two files that are immediately removed.
Status: The patch survived 3 kexec reboots with a large initramfs yesterday.
Since then I reworked the Makefile and rearranged include files. It compiles
clean, and if it passes a regression then I think its mergable. The
is up to date regression in patch 3 and taking the update in 5, as well as
actually trying to use this version are my any hesitations. The rtas
display-character has not been tested and is commented out
milton
^ permalink raw reply
* [1/5][POWERPC] boot: prepare for zImage.kexec
From: Milton Miller @ 2006-06-29 13:25 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras
This patch moves the initializations of prom variables to boot/prom.c
to allow it to be replaced for kexec. Kexec does not care about
the stdout handle, but will care about the location of the device
tree and will search for RTAS.
It also checks if we stop trying to claim so that we print an error
instead of storing to address -1.
Signed-off-by: Milton Miller <miltonm@bga.com>
Index: kernel/arch/powerpc/boot/main.c
===================================================================
--- kernel.orig/arch/powerpc/boot/main.c 2006-06-29 02:14:51.347560058 -0500
+++ kernel/arch/powerpc/boot/main.c 2006-06-29 02:14:57.344543429 -0500
@@ -17,14 +17,12 @@
#include "prom.h"
#include "zlib.h"
-extern void flush_cache(void *, unsigned long);
-
-
/* Value picked to match that used by yaboot */
#define PROG_START 0x01400000 /* only used on 64-bit systems */
-#define RAM_END (512<<20) /* Fixme: use OF */
#define ONE_MB 0x100000
+unsigned long ram_end; /* end of usable memory, set by init_prom */
+
extern char _start[];
extern char __bss_start[];
extern char _end[];
@@ -119,7 +117,7 @@ static unsigned long try_claim(unsigned
{
unsigned long addr = 0;
- for(; claim_base < RAM_END; claim_base += ONE_MB) {
+ for(; claim_base < ram_end; claim_base += ONE_MB) {
#ifdef DEBUG
printf(" trying: 0x%08lx\n\r", claim_base);
#endif
@@ -127,7 +125,7 @@ static unsigned long try_claim(unsigned
if ((void *)addr != (void *)-1)
break;
}
- if (addr == 0)
+ if ((addr == 0) || (void *)addr == (void *)-1)
return 0;
claim_base = PAGE_ALIGN(claim_base + size);
return addr;
@@ -211,12 +209,7 @@ void start(unsigned long a1, unsigned lo
memset(__bss_start, 0, _end - __bss_start);
- prom = (int (*)(void *)) promptr;
- chosen_handle = finddevice("/chosen");
- if (chosen_handle == (void *) -1)
- exit();
- if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4)
- exit();
+ init_prom(a1, a2, promptr);
printf("\n\rzImage starting: loaded at 0x%p (sp: 0x%p)\n\r", _start, sp);
@@ -297,6 +290,7 @@ void start(unsigned long a1, unsigned lo
vmlinux.addr += elfoffset;
flush_cache((void *)vmlinux.addr, vmlinux.size);
+ prom_smp_hook(vmlinux.addr);
kernel_entry = (kernel_entry_t)vmlinux.addr;
#ifdef DEBUG
Index: kernel/arch/powerpc/boot/prom.c
===================================================================
--- kernel.orig/arch/powerpc/boot/prom.c 2006-06-29 02:14:51.379554992 -0500
+++ kernel/arch/powerpc/boot/prom.c 2006-06-29 02:48:30.069204787 -0500
@@ -16,6 +16,22 @@ int (*prom)(void *);
phandle chosen_handle;
ihandle stdout;
+void init_prom(unsigned long a1, unsigned long a2, void *p)
+{
+ prom = (int (*)(void *)) p;
+ chosen_handle = finddevice("/chosen");
+ if (chosen_handle == (void *) -1)
+ exit();
+ if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4)
+ exit();
+ ram_end = (512<<20); /* Fixme: use OF */
+}
+
+void prom_smp_hook(unsigned long kernel_start)
+{
+ return;
+}
+
int call_prom(const char *service, int nargs, int nret, ...)
{
int i;
Index: kernel/arch/powerpc/boot/prom.h
===================================================================
--- kernel.orig/arch/powerpc/boot/prom.h 2006-06-29 02:14:51.429547077 -0500
+++ kernel/arch/powerpc/boot/prom.h 2006-06-29 02:14:57.348542796 -0500
@@ -12,8 +12,10 @@ int call_prom(const char *service, int n
int call_prom_ret(const char *service, int nargs, int nret,
unsigned int *rets, ...);
-extern int write(void *handle, void *ptr, int nb);
-extern void *claim(unsigned long virt, unsigned long size, unsigned long aln);
+void init_prom(unsigned long a1, unsigned long a2, void *p);
+void prom_smp_hook(unsigned long kernel_start);
+int write(void *handle, void *ptr, int nb);
+void *claim(unsigned long virt, unsigned long size, unsigned long aln);
static inline void exit(void)
{
@@ -31,4 +33,9 @@ static inline int getprop(void *phandle,
return call_prom("getprop", 4, 1, phandle, name, buf, buflen);
}
+
+extern unsigned long ram_end; /* end of usable memory */
+
+extern void flush_cache(void *, unsigned long);
+
#endif /* _PPC_BOOT_PROM_H_ */
^ permalink raw reply
* [3/5][POWERPC] boot: use more Kbuild rules
From: Milton Miller @ 2006-06-29 13:26 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras
Switch to if_changed_dep for bootcc, cmd for known rebuilds without deps,
and if_changed for other commands. Add FORCE for all if_changed rule uses.
Make sure targets includes all generated files.
Move clean-files to targets for if_changed files.
Rename OBJCOPYFLAGS to OBJCOPY_SEC_FLAGS so we can use $(objcopy) rule.
Rename zliblinuxheader to linuxheader
Remove explicit dependency of zlib files on zlib headers (if_changed_dep).
Oops, kelace with all sources depend on generated headers, as the
dependancy files don't exist on a clean compile.
Note: the obj-sec .c files are created/touched when the content file changes.
Signed-off-by: Milton Miller <miltonm@bga.com>
Index: kernel/arch/powerpc/boot/Makefile
===================================================================
--- kernel.orig/arch/powerpc/boot/Makefile 2006-06-29 03:47:01.063847526 -0500
+++ kernel/arch/powerpc/boot/Makefile 2006-06-29 06:01:36.507278027 -0500
@@ -25,16 +25,13 @@ HOSTCC := gcc
BOOTCFLAGS := $(HOSTCFLAGS) -fno-builtin -nostdinc -isystem \
$(shell $(CROSS32CC) -print-file-name=include) -fPIC
BOOTAFLAGS := -D__ASSEMBLY__ $(BOOTCFLAGS) -traditional -nostdinc
-OBJCOPYFLAGS := contents,alloc,load,readonly,data
+OBJCOPY_SEC_FLAGS := contents,alloc,load,readonly,data
OBJCOPY_COFF_ARGS := -O aixcoff-rs6000 --set-start 0x500000
OBJCOPY_MIB_ARGS := -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment
zlib := infblock.c infcodes.c inffast.c inflate.c inftrees.c infutil.c
zlibheader := infblock.h infcodes.h inffast.h inftrees.h infutil.h
-zliblinuxheader := zlib.h zconf.h zutil.h
-
-$(addprefix $(obj)/,$(zlib) main.o): $(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
-#$(addprefix $(obj)/,main.o): $(addprefix $(obj)/,zlib.h)
+linuxheader := zlib.h zconf.h zutil.h
src-boot := crt0.S string.S prom.c stdio.c main.c div64.S
src-boot += $(zlib)
@@ -48,21 +45,26 @@ quiet_cmd_copy_zlib = COPY $@
quiet_cmd_copy_zlibheader = COPY $@
cmd_copy_zlibheader = sed "s@<linux/\([^>]\+\).*@\"\1\"@" $< > $@
+
# stddef.h for NULL
-quiet_cmd_copy_zliblinuxheader = COPY $@
- cmd_copy_zliblinuxheader = sed "s@<linux/string.h>@\"string.h\"@;s@<linux/kernel.h>@<stddef.h>@;s@<linux/\([^>]\+\).*@\"\1\"@" $< > $@
+quiet_cmd_copy_linuxheader = COPY $@
+ cmd_copy_linuxheader = sed "s@<linux/string.h>@\"string.h\"@;s@<linux/kernel.h>@<stddef.h>@;s@<linux/\([^>]\+\).*@\"\1\"@" $< > $@
-$(addprefix $(obj)/,$(zlib)): $(obj)/%: $(srctree)/lib/zlib_inflate/%
- $(call cmd,copy_zlib)
+$(addprefix $(obj)/,$(zlib)): $(obj)/%: $(srctree)/lib/zlib_inflate/% FORCE
+ $(call if_changed,copy_zlib)
-$(addprefix $(obj)/,$(zlibheader)): $(obj)/%: $(srctree)/lib/zlib_inflate/%
- $(call cmd,copy_zlibheader)
+$(addprefix $(obj)/,$(zlibheader)): $(obj)/%: $(srctree)/lib/zlib_inflate/% \
+ FORCE
+ $(call if_changed,copy_zlibheader)
-$(addprefix $(obj)/,$(zliblinuxheader)): $(obj)/%: $(srctree)/include/linux/%
- $(call cmd,copy_zliblinuxheader)
+$(addprefix $(obj)/,$(linuxheader)): $(obj)/%: $(srctree)/include/linux/% FORCE
+ $(call if_changed,copy_linuxheader)
-clean-files := $(zlib) $(zlibheader) $(zliblinuxheader)
+targets += $(zlib) $(zlibheader) $(linuxheader)
+targets += $(patsubst $(obj)/%,%, $(obj-boot))
+# copy all headers before trying to build objects
+$(obj-boot): $(addprefix $(obj)/,$(linuxheader) $(zlibheader))
quiet_cmd_bootcc = BOOTCC $@
cmd_bootcc = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTCFLAGS) -c -o $@ $<
@@ -73,9 +75,10 @@ quiet_cmd_bootas = BOOTAS $@
quiet_cmd_bootld = BOOTLD $@
cmd_bootld = $(CROSS32LD) -T $(srctree)/$(src)/$(3) -o $@ $(2)
-$(patsubst %.c,%.o, $(filter %.c, $(src-boot))): %.o: %.c
+$(patsubst %.c,%.o, $(filter %.c, $(src-boot))): %.o: %.c FORCE
$(call if_changed_dep,bootcc)
-$(patsubst %.S,%.o, $(filter %.S, $(src-boot))): %.o: %.S
+
+$(patsubst %.S,%.o, $(filter %.S, $(src-boot))): %.o: %.S FORCE
$(call if_changed_dep,bootas)
#-----------------------------------------------------------
@@ -104,15 +107,16 @@ quiet_cmd_ramdisk = RAMDISK $@
quiet_cmd_stripvm = STRIP $@
cmd_stripvm = $(STRIP) -s -R .comment $< -o $@
-vmlinux.strip: vmlinux
+vmlinux.strip: vmlinux FORCE
$(call if_changed,stripvm)
-$(obj)/vmlinux.initrd: vmlinux.strip $(obj)/addRamDisk $(obj)/ramdisk.image.gz
+$(obj)/vmlinux.initrd: vmlinux.strip $(obj)/addRamDisk \
+ $(obj)/ramdisk.image.gz FORCE
$(call if_changed,ramdisk)
quiet_cmd_addsection = ADDSEC $@
cmd_addsection = $(CROSS32OBJCOPY) $@ \
--add-section=.kernel:$(strip $(patsubst $(obj)/kernel-%.o,%, $@))=$(patsubst %.o,%.gz, $@) \
- --set-section-flags=.kernel:$(strip $(patsubst $(obj)/kernel-%.o,%, $@))=$(OBJCOPYFLAGS)
+ --set-section-flags=.kernel:$(strip $(patsubst $(obj)/kernel-%.o,%, $@))=$(OBJCOPY_SEC_FLAGS)
quiet_cmd_addnote = ADDNOTE $@
cmd_addnote = $(obj)/addnote $@
@@ -125,7 +129,13 @@ quiet_cmd_gencoff = COFF $@
cmd_gencoff = $(OBJCOPY) $(OBJCOPY_COFF_ARGS) $@ && \
$(obj)/hack-coff $@
-$(call gz-sec, $(required)): $(obj)/kernel-%.gz: %
+# $(required) is built in $(objtree) not $(obj) so read cmd files manually
+cmd_files := $(wildcard $(foreach f,$(required),$(dir $(f)).$(notdir $(f)).cmd))
+ifneq ($(cmd_files),)
+ include $(cmd_files)
+endif
+
+$(call gz-sec, $(required)): $(obj)/kernel-%.gz: % FORCE
$(call if_changed,gzip)
$(obj)/kernel-initrd.gz: $(obj)/ramdisk.image.gz
@@ -135,7 +145,7 @@ $(call src-sec, $(required) $(initrd)):
@touch $@
$(call obj-sec, $(required) $(initrd)): $(obj)/kernel-%.o: $(obj)/kernel-%.c
- $(call if_changed_dep,bootcc)
+ $(call cmd,bootcc)
$(call cmd,addsection)
$(obj)/zImage.vmode $(obj)/zImage.coff: obj-boot += $(call obj-sec, $(required))
@@ -156,12 +166,12 @@ mibrdimg-$(CONFIG_PPC_PMAC)-$(CONFIG_PPC
$(obj)/zImage: $(obj)/zImage.vmode $(obj)/addnote $(coffimage-y-y) \
$(mibootimg-y-y)
@cp -f $< $@
- $(call if_changed,addnote)
+ $(call cmd,addnote)
$(obj)/zImage.initrd: $(obj)/zImage.initrd.vmode $(obj)/addnote \
$(coffrdimg-y-y) $(mibrdimg-y-y)
@cp -f $< $@
- $(call if_changed,addnote)
+ $(call cmd,addnote)
$(obj)/zImage.coff: $(call obj-sec, $(required)) $(obj-boot) \
$(srctree)/$(src)/zImage.coff.lds $(obj)/hack-coff
^ permalink raw reply
* [4/5][POWERPC] boot: Makefile and linker scripts for zImage.kexec
From: Milton Miller @ 2006-06-29 13:27 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras
The Makefile and linker script changes to build zImage.kexec
This patch is based after the if_changed_dep patch.
Signed-off-by: Milton Miller <miltonm@bga.com>
Index: kernel/arch/powerpc/boot/Makefile
===================================================================
--- kernel.orig/arch/powerpc/boot/Makefile 2006-06-29 05:45:56.343109131 -0500
+++ kernel/arch/powerpc/boot/Makefile 2006-06-29 06:01:30.254334494 -0500
@@ -32,12 +32,22 @@ OBJCOPY_MIB_ARGS := -O aixcoff-rs6000 -
zlib := infblock.c infcodes.c inffast.c inflate.c inftrees.c infutil.c
zlibheader := infblock.h infcodes.h inffast.h inftrees.h infutil.h
linuxheader := zlib.h zconf.h zutil.h
+linuxheader += stringify.h
-src-boot := crt0.S string.S prom.c stdio.c main.c div64.S
-src-boot += $(zlib)
+src-common := string.S stdio.c main.c div64.S
+src-common += $(zlib)
+
+src-boot := crt0.S prom.c $(src-common)
src-boot := $(addprefix $(obj)/, $(src-boot))
obj-boot := $(addsuffix .o, $(basename $(src-boot)))
+src-kexec := crt0_kexec.S kexec.c $(src-common)
+src-kexec := $(addprefix $(obj)/, $(src-kexec))
+obj-kexec := $(addsuffix .o, $(basename $(src-kexec)))
+
+src-mult := $(sort $(src-boot) $(src-kexec))
+obj-mult := $(sort $(obj-boot) $(obj-kexec))
+
BOOTCFLAGS += -I$(obj) -I$(srctree)/$(obj)
quiet_cmd_copy_zlib = COPY $@
@@ -61,7 +71,7 @@ $(addprefix $(obj)/,$(linuxheader)): $(o
$(call if_changed,copy_linuxheader)
targets += $(zlib) $(zlibheader) $(linuxheader)
-targets += $(patsubst $(obj)/%,%, $(obj-boot))
+targets += $(patsubst $(obj)/%,%, $(obj-mult))
# copy all headers before trying to build objects
$(obj-boot): $(addprefix $(obj)/,$(linuxheader) $(zlibheader))
@@ -75,10 +85,10 @@ quiet_cmd_bootas = BOOTAS $@
quiet_cmd_bootld = BOOTLD $@
cmd_bootld = $(CROSS32LD) -T $(srctree)/$(src)/$(3) -o $@ $(2)
-$(patsubst %.c,%.o, $(filter %.c, $(src-boot))): %.o: %.c FORCE
+$(patsubst %.c,%.o, $(filter %.c, $(src-mult))): %.o: %.c FORCE
$(call if_changed_dep,bootcc)
-$(patsubst %.S,%.o, $(filter %.S, $(src-boot))): %.o: %.S FORCE
+$(patsubst %.S,%.o, $(filter %.S, $(src-mult))): %.o: %.S FORCE
$(call if_changed_dep,bootas)
#-----------------------------------------------------------
@@ -95,6 +105,7 @@ hostprogs-y := addnote addRamDisk hack-
targets += zImage.vmode zImage.initrd.vmode zImage zImage.initrd \
zImage.coff zImage.initrd.coff miboot.image miboot.initrd.image \
+ zImage.kexec zImage.kexec.3264 zImage.kexec64 \
$(patsubst $(obj)/%,%, $(call obj-sec, $(required) $(initrd))) \
$(patsubst $(obj)/%,%, $(call src-sec, $(required) $(initrd))) \
$(patsubst $(obj)/%,%, $(call gz-sec, $(required) $(initrd))) \
@@ -163,8 +174,36 @@ coffrdimg-$(CONFIG_PPC_PMAC)-$(CONFIG_PP
mibootimg-$(CONFIG_PPC_PMAC)-$(CONFIG_PPC32) := $(obj)/miboot.image
mibrdimg-$(CONFIG_PPC_PMAC)-$(CONFIG_PPC32) := $(obj)/miboot.initrd.image
+# The kexec entry point is valid for all kernels. This zImage should work
+# on all loaders (kexec or firmware) that do not use an openfirmware prom
+# callback, assuming the memory node constraints are met.
+#
+# Build if CONFIG_KEXEC=y or on master make zImage.kexec.
+#
+kexecimg-$(CONFIG_KEXEC)-$(CONFIG_PPC64) += $(obj)/zImage.kexec64
+kexecimg-$(CONFIG_KEXEC)-y += $(obj)/zImage.kexec
+
+# Build 64 bit and 32 bit package when 64 bit kernel is being built
+$(obj)/zImage.kexec: $(filter-out $(obj)/zImage.kexec, $(kexecimg-y-y))
+
+$(obj)/zImage.kexec: obj-kexec += $(call obj-sec, $(required))
+$(obj)/zImage.kexec: $(obj-kexec) $(srctree)/$(src)/zImage.kexec.lds \
+ $(call obj-sec, $(required)) FORCE
+ $(call if_changed,bootld,$(obj-kexec) $(call obj-sec, $(required)) \
+ ,zImage.kexec.lds)
+
+$(obj)/zImage.kexec.3264: obj-kexec += $(call obj-sec, $(required))
+$(obj)/zImage.kexec.3264: $(obj-kexec) $(srctree)/$(src)/zImage.kexec64.lds \
+ $(call obj-sec, $(required)) FORCE
+ $(call if_changed,bootld,$(obj-kexec) $(call obj-sec, $(required)) \
+ ,zImage.kexec64.lds)
+
+OBJCOPYFLAGS_zImage.kexec64 := -I elf32-powerpc -O elf64-powerpc
+$(obj)/zImage.kexec64: $(obj)/zImage.kexec.3264 FORCE
+ $(call if_changed,objcopy,$< $@)
+
$(obj)/zImage: $(obj)/zImage.vmode $(obj)/addnote $(coffimage-y-y) \
- $(mibootimg-y-y)
+ $(mibootimg-y-y) $(kexecimg-y-y)
@cp -f $< $@
$(call cmd,addnote)
@@ -222,4 +261,4 @@ $(obj)/uImage: $(obj)/vmlinux.gz
install: $(CONFIGURE) $(BOOTIMAGE)
sh -x $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" vmlinux System.map "$(INSTALL_PATH)" "$(BOOTIMAGE)"
-clean-files += $(addprefix $(objtree)/, $(obj-boot) vmlinux.strip)
+clean-files += $(addprefix $(objtree)/, $(obj-mult) vmlinux.strip)
Index: kernel/arch/powerpc/Makefile
===================================================================
--- kernel.orig/arch/powerpc/Makefile 2006-06-29 05:24:59.721841947 -0500
+++ kernel/arch/powerpc/Makefile 2006-06-29 05:51:17.300076495 -0500
@@ -147,7 +147,7 @@ all: $(KBUILD_IMAGE)
CPPFLAGS_vmlinux.lds := -Upowerpc
-BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd vmlinux.sm uImage vmlinux.bin
+BOOT_TARGETS = zImage zImage.initrd zImage.kexec znetboot znetboot.initrd vmlinux.sm uImage vmlinux.bin
PHONY += $(BOOT_TARGETS)
Index: kernel/arch/powerpc/boot/zImage.kexec.lds
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ kernel/arch/powerpc/boot/zImage.kexec.lds 2006-06-29 06:01:30.125354912 -0500
@@ -0,0 +1,51 @@
+OUTPUT_ARCH(powerpc:common)
+ENTRY(master)
+SECTIONS
+{
+ . = 0;
+ _start = .;
+ .text :
+ {
+ *(.text)
+ *(.fixup)
+ }
+ _etext = .;
+ . = ALIGN(4096);
+ .data :
+ {
+ *(.rodata*)
+ *(.data*)
+ *(.sdata*)
+ __got2_start = .;
+ *(.got2)
+ __got2_end = .;
+ }
+
+ . = ALIGN(4096);
+ _vmlinux_start = .;
+ .kernel:vmlinux.strip : { *(.kernel:vmlinux.strip) }
+ _vmlinux_end = .;
+
+ . = ALIGN(4096);
+ _initrd_start = .;
+ .kernel:initrd : { *(.kernel:initrd) }
+ _initrd_end = .;
+
+ . = ALIGN(4096);
+ _edata = .;
+
+ . = ALIGN(4096);
+ __stack_start = .;
+ .stack : { *(.stack) }
+ __stack_end = .;
+
+ . = ALIGN(4096);
+ __bss_start = .;
+ .bss :
+ {
+ *(.sbss)
+ *(.bss)
+ }
+ . = ALIGN(4096);
+ _end = . ;
+}
Index: kernel/arch/powerpc/boot/zImage.kexec64.lds
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ kernel/arch/powerpc/boot/zImage.kexec64.lds 2006-06-29 06:01:30.154350322 -0500
@@ -0,0 +1,52 @@
+OUTPUT_ARCH(powerpc:common)
+ENTRY(_master64)
+SECTIONS
+{
+ . = 0;
+ _start = .;
+ .text :
+ {
+ *(.text)
+ *(.fixup)
+ }
+ _etext = .;
+ . = ALIGN(4096);
+ .data :
+ {
+ *(.rodata*)
+ *(.data*)
+ *(.sdata*)
+ __got2_start = .;
+ *(.got2)
+ __got2_end = .;
+ }
+
+ . = ALIGN(4096);
+ _vmlinux_start = .;
+ .kernel:vmlinux.strip : { *(.kernel:vmlinux.strip) }
+ _vmlinux_end = .;
+
+ . = ALIGN(4096);
+ _initrd_start = .;
+ .kernel:initrd : { *(.kernel:initrd) }
+ _initrd_end = .;
+
+ . = ALIGN(4096);
+ _edata = .;
+
+ . = ALIGN(4096);
+ __stack_start = .;
+ .stack : { *(.stack) }
+ __stack_end = .;
+
+ . = ALIGN(4096);
+ __bss_start = .;
+ .bss :
+ {
+ *(.sbss)
+ *(.bss)
+ }
+ . = ALIGN(4096);
+ _end = . ;
+}
+
^ permalink raw reply
* [5/5][POWERPC] boot: generate lds file from lds.S
From: Milton Miller @ 2006-06-29 13:28 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras
The zImage.kexec and zImage.kexec64 linker files are almost identical to
the base elf file. Use the lds.S -> ld rule to share the source.
Tell the linker the fils is in $(obj) not $(srctree)/$(src)
zImage.coff.lds is different, it links the initrd and kernel in .data
rather than as a seperate section and without alignment, keep it seperate
for now.
Signed-off-by: Milton Miller <miltonm@bga.com>
Index: kernel/arch/powerpc/boot/Makefile
===================================================================
--- kernel.orig/arch/powerpc/boot/Makefile 2006-06-29 06:15:29.367203511 -0500
+++ kernel/arch/powerpc/boot/Makefile 2006-06-29 06:16:37.166736808 -0500
@@ -83,7 +83,7 @@ quiet_cmd_bootas = BOOTAS $@
cmd_bootas = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTAFLAGS) -c -o $@ $<
quiet_cmd_bootld = BOOTLD $@
- cmd_bootld = $(CROSS32LD) -T $(srctree)/$(src)/$(3) -o $@ $(2)
+ cmd_bootld = $(CROSS32LD) -T $(obj)/$(3) -o $@ $(2)
$(patsubst %.c,%.o, $(filter %.c, $(src-mult))): %.o: %.c FORCE
$(call if_changed_dep,bootcc)
@@ -106,6 +106,7 @@ hostprogs-y := addnote addRamDisk hack-
targets += zImage.vmode zImage.initrd.vmode zImage zImage.initrd \
zImage.coff zImage.initrd.coff miboot.image miboot.initrd.image \
zImage.kexec zImage.kexec.3264 zImage.kexec64 \
+ zImage.lds zImage.kexec.lds zImage.kexec64.lds zImage.coff.lds \
$(patsubst $(obj)/%,%, $(call obj-sec, $(required) $(initrd))) \
$(patsubst $(obj)/%,%, $(call src-sec, $(required) $(initrd))) \
$(patsubst $(obj)/%,%, $(call gz-sec, $(required) $(initrd))) \
@@ -159,12 +160,26 @@ $(call obj-sec, $(required) $(initrd)):
$(call cmd,bootcc)
$(call cmd,addsection)
+lds-fl := -P -C -Upowerpc
+CPPFLAGS_zImage.coff.lds := $(lds-fl)
+CPPFLAGS_zImage.lds := $(lds-fl) -D__entry__=_zimage_start
+CPPFLAGS_zImage.lds += -D__base__="4*1024*1024"
+CPPFLAGS_zImage.kexec.lds := $(lds-fl) -D__entry__=master -D__base__=0
+CPPFLAGS_zImage.kexec64.lds := $(lds-fl) -D__entry__=_master64 -D__base__=0
+
+$(addprefix $(obj)/, zImage.lds zImage.kexec.lds zImage.kexec64.lds): \
+ $(srctree)/$(src)/zImage.lds.S FORCE
+ $(call if_changed_dep,cpp_lds_S)
+
+$(obj)/zImage.coff.lds: $(srctree)/$(src)/$zImage.coff.lds.S FORCE
+ $(call if_changed_dep,cpp_lds_S)
+
$(obj)/zImage.vmode $(obj)/zImage.coff: obj-boot += $(call obj-sec, $(required))
-$(obj)/zImage.vmode: $(call obj-sec, $(required)) $(obj-boot) $(srctree)/$(src)/zImage.lds
+$(obj)/zImage.vmode: $(call obj-sec, $(required)) $(obj-boot) $(obj)/zImage.lds
$(call cmd,bootld,$(obj-boot),zImage.lds)
$(obj)/zImage.initrd.vmode $(obj)/zImage.initrd.coff: obj-boot += $(call obj-sec, $(required) $(initrd))
-$(obj)/zImage.initrd.vmode: $(call obj-sec, $(required) $(initrd)) $(obj-boot) $(srctree)/$(src)/zImage.lds
+$(obj)/zImage.initrd.vmode: $(call obj-sec, $(required) $(initrd)) $(obj-boot) $(obj)/zImage.lds
$(call cmd,bootld,$(obj-boot),zImage.lds)
# For 32-bit powermacs, build the COFF and miboot images
@@ -187,13 +202,13 @@ kexecimg-$(CONFIG_KEXEC)-y
$(obj)/zImage.kexec: $(filter-out $(obj)/zImage.kexec, $(kexecimg-y-y))
$(obj)/zImage.kexec: obj-kexec += $(call obj-sec, $(required))
-$(obj)/zImage.kexec: $(obj-kexec) $(srctree)/$(src)/zImage.kexec.lds \
+$(obj)/zImage.kexec: $(obj-kexec) $(obj)/zImage.kexec.lds \
$(call obj-sec, $(required)) FORCE
$(call if_changed,bootld,$(obj-kexec) $(call obj-sec, $(required)) \
,zImage.kexec.lds)
$(obj)/zImage.kexec.3264: obj-kexec += $(call obj-sec, $(required))
-$(obj)/zImage.kexec.3264: $(obj-kexec) $(srctree)/$(src)/zImage.kexec64.lds \
+$(obj)/zImage.kexec.3264: $(obj-kexec) $(obj)/zImage.kexec64.lds \
$(call obj-sec, $(required)) FORCE
$(call if_changed,bootld,$(obj-kexec) $(call obj-sec, $(required)) \
,zImage.kexec64.lds)
@@ -213,12 +228,12 @@ $(obj)/zImage.initrd: $(obj)/zImage.init
$(call cmd,addnote)
$(obj)/zImage.coff: $(call obj-sec, $(required)) $(obj-boot) \
- $(srctree)/$(src)/zImage.coff.lds $(obj)/hack-coff
+ $(obj)/zImage.coff.lds $(obj)/hack-coff
$(call cmd,bootld,$(obj-boot),zImage.coff.lds)
$(call cmd,gencoff)
$(obj)/zImage.initrd.coff: $(call obj-sec, $(required) $(initrd)) $(obj-boot) \
- $(srctree)/$(src)/zImage.coff.lds $(obj)/hack-coff
+ $(obj)/zImage.coff.lds $(obj)/hack-coff
$(call cmd,bootld,$(obj-boot),zImage.coff.lds)
$(call cmd,gencoff)
Index: kernel/arch/powerpc/boot/zImage.coff.lds
===================================================================
--- kernel.orig/arch/powerpc/boot/zImage.coff.lds 2006-06-29 06:15:29.185232311 -0500
+++ /dev/null 1970-01-01 00:00:00.000000000 +0000
@@ -1,46 +0,0 @@
-OUTPUT_ARCH(powerpc:common)
-ENTRY(_start)
-SECTIONS
-{
- . = (5*1024*1024);
- _start = .;
- .text :
- {
- *(.text)
- *(.fixup)
- }
- _etext = .;
- . = ALIGN(4096);
- .data :
- {
- *(.rodata*)
- *(.data*)
- *(.sdata*)
- __got2_start = .;
- *(.got2)
- __got2_end = .;
-
- _vmlinux_start = .;
- *(.kernel:vmlinux.strip)
- _vmlinux_end = .;
-
- _initrd_start = .;
- *(.kernel:initrd)
- _initrd_end = .;
- }
-
- . = ALIGN(4096);
- _edata = .;
- __bss_start = .;
- .bss :
- {
- *(.sbss)
- *(.bss)
- }
- _end = . ;
-
- /DISCARD/ :
- {
- *(.comment)
- }
-}
Index: kernel/arch/powerpc/boot/zImage.coff.lds.S
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ kernel/arch/powerpc/boot/zImage.coff.lds.S 2006-06-29 06:16:26.525823380 -0500
@@ -0,0 +1,46 @@
+OUTPUT_ARCH(powerpc:common)
+ENTRY(_start)
+SECTIONS
+{
+ . = (5*1024*1024);
+ _start = .;
+ .text :
+ {
+ *(.text)
+ *(.fixup)
+ }
+ _etext = .;
+ . = ALIGN(4096);
+ .data :
+ {
+ *(.rodata*)
+ *(.data*)
+ *(.sdata*)
+ __got2_start = .;
+ *(.got2)
+ __got2_end = .;
+
+ _vmlinux_start = .;
+ *(.kernel:vmlinux.strip)
+ _vmlinux_end = .;
+
+ _initrd_start = .;
+ *(.kernel:initrd)
+ _initrd_end = .;
+ }
+
+ . = ALIGN(4096);
+ _edata = .;
+ __bss_start = .;
+ .bss :
+ {
+ *(.sbss)
+ *(.bss)
+ }
+ _end = . ;
+
+ /DISCARD/ :
+ {
+ *(.comment)
+ }
+}
Index: kernel/arch/powerpc/boot/zImage.kexec.lds
===================================================================
--- kernel.orig/arch/powerpc/boot/zImage.kexec.lds 2006-06-29 06:15:29.238223924 -0500
+++ /dev/null 1970-01-01 00:00:00.000000000 +0000
@@ -1,51 +0,0 @@
-OUTPUT_ARCH(powerpc:common)
-ENTRY(master)
-SECTIONS
-{
- . = 0;
- _start = .;
- .text :
- {
- *(.text)
- *(.fixup)
- }
- _etext = .;
- . = ALIGN(4096);
- .data :
- {
- *(.rodata*)
- *(.data*)
- *(.sdata*)
- __got2_start = .;
- *(.got2)
- __got2_end = .;
- }
-
- . = ALIGN(4096);
- _vmlinux_start = .;
- .kernel:vmlinux.strip : { *(.kernel:vmlinux.strip) }
- _vmlinux_end = .;
-
- . = ALIGN(4096);
- _initrd_start = .;
- .kernel:initrd : { *(.kernel:initrd) }
- _initrd_end = .;
-
- . = ALIGN(4096);
- _edata = .;
-
- . = ALIGN(4096);
- __stack_start = .;
- .stack : { *(.stack) }
- __stack_end = .;
-
- . = ALIGN(4096);
- __bss_start = .;
- .bss :
- {
- *(.sbss)
- *(.bss)
- }
- . = ALIGN(4096);
- _end = . ;
-}
Index: kernel/arch/powerpc/boot/zImage.kexec64.lds
===================================================================
--- kernel.orig/arch/powerpc/boot/zImage.kexec64.lds 2006-06-29 06:15:29.266219493 -0500
+++ /dev/null 1970-01-01 00:00:00.000000000 +0000
@@ -1,52 +0,0 @@
-OUTPUT_ARCH(powerpc:common)
-ENTRY(_master64)
-SECTIONS
-{
- . = 0;
- _start = .;
- .text :
- {
- *(.text)
- *(.fixup)
- }
- _etext = .;
- . = ALIGN(4096);
- .data :
- {
- *(.rodata*)
- *(.data*)
- *(.sdata*)
- __got2_start = .;
- *(.got2)
- __got2_end = .;
- }
-
- . = ALIGN(4096);
- _vmlinux_start = .;
- .kernel:vmlinux.strip : { *(.kernel:vmlinux.strip) }
- _vmlinux_end = .;
-
- . = ALIGN(4096);
- _initrd_start = .;
- .kernel:initrd : { *(.kernel:initrd) }
- _initrd_end = .;
-
- . = ALIGN(4096);
- _edata = .;
-
- . = ALIGN(4096);
- __stack_start = .;
- .stack : { *(.stack) }
- __stack_end = .;
-
- . = ALIGN(4096);
- __bss_start = .;
- .bss :
- {
- *(.sbss)
- *(.bss)
- }
- . = ALIGN(4096);
- _end = . ;
-}
-
Index: kernel/arch/powerpc/boot/zImage.lds
===================================================================
--- kernel.orig/arch/powerpc/boot/zImage.lds 2006-06-29 06:15:29.295214904 -0500
+++ /dev/null 1970-01-01 00:00:00.000000000 +0000
@@ -1,46 +0,0 @@
-OUTPUT_ARCH(powerpc:common)
-ENTRY(_zimage_start)
-SECTIONS
-{
- . = (4*1024*1024);
- _start = .;
- .text :
- {
- *(.text)
- *(.fixup)
- }
- _etext = .;
- . = ALIGN(4096);
- .data :
- {
- *(.rodata*)
- *(.data*)
- *(.sdata*)
- __got2_start = .;
- *(.got2)
- __got2_end = .;
- }
-
- . = ALIGN(4096);
- _vmlinux_start = .;
- .kernel:vmlinux.strip : { *(.kernel:vmlinux.strip) }
- _vmlinux_end = .;
-
- . = ALIGN(4096);
- _initrd_start = .;
- .kernel:initrd : { *(.kernel:initrd) }
- _initrd_end = .;
-
- . = ALIGN(4096);
- _edata = .;
-
- . = ALIGN(4096);
- __bss_start = .;
- .bss :
- {
- *(.sbss)
- *(.bss)
- }
- . = ALIGN(4096);
- _end = . ;
-}
Index: kernel/arch/powerpc/boot/zImage.lds.S
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ kernel/arch/powerpc/boot/zImage.lds.S 2006-06-29 06:16:26.529822747 -0500
@@ -0,0 +1,51 @@
+OUTPUT_ARCH(powerpc:common)
+ENTRY(__entry__)
+SECTIONS
+{
+ . = __base__;
+ _start = .;
+ .text :
+ {
+ *(.text)
+ *(.fixup)
+ }
+ _etext = .;
+ . = ALIGN(4096);
+ .data :
+ {
+ *(.rodata*)
+ *(.data*)
+ *(.sdata*)
+ __got2_start = .;
+ *(.got2)
+ __got2_end = .;
+ }
+
+ . = ALIGN(4096);
+ _vmlinux_start = .;
+ .kernel:vmlinux.strip : { *(.kernel:vmlinux.strip) }
+ _vmlinux_end = .;
+
+ . = ALIGN(4096);
+ _initrd_start = .;
+ .kernel:initrd : { *(.kernel:initrd) }
+ _initrd_end = .;
+
+ . = ALIGN(4096);
+ _edata = .;
+
+ . = ALIGN(4096);
+ __stack_start = .;
+ .stack : { *(.stack) }
+ __stack_end = .;
+
+ . = ALIGN(4096);
+ __bss_start = .;
+ .bss :
+ {
+ *(.sbss)
+ *(.bss)
+ }
+ . = ALIGN(4096);
+ _end = . ;
+}
^ permalink raw reply
* [2/5][POWERPC] boot: Add kexec callable zImage wrapper
From: Milton Miller @ 2006-06-29 13:25 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras
This code creates a 32 bit zImage wrapper for a 32 or 64 bit PowerPC
Linux kernel. It does not support initrd at present. What it does
give you is a compressed kernel image that is expanded when used.
Limitations:
The memory node off the root with a name starting with "memory" must
contain enough free memory (not in the reserved ranges) in the first
reg range to uncompress the the kenrel with padding.
The claim allocator does not record its handouts.
Signed-off-by: Milton Miller <miltonm@bga.com>
Index: kernel/arch/powerpc/boot/kexec.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ kernel/arch/powerpc/boot/kexec.c 2006-06-29 03:47:06.865856735 -0500
@@ -0,0 +1,476 @@
+/*
+ * Copyright (C) 1997 Paul Mackerras 1997.
+ * Copyright (C) 2006 Milton Miller, IBM Corportation.
+ * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corportation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include "string.h"
+#include "stdio.h"
+#include "prom.h"
+#include "page.h"
+#include "dt.h"
+#include "stringify.h"
+
+#define BUG_ON(x) if (x) { printf("zImage BUG %s\n\r", __stringify(x)); exit();}
+
+extern unsigned int gohere; /* slaves poll and branch when told */
+
+int (*prom)(void *);
+phandle chosen_handle;
+ihandle stdout;
+
+#define MAX_MEM 0x80000000
+static unsigned int memsize;
+static unsigned int na=2, ns=1;
+
+
+static struct boot_param_header *initial_boot_params;
+
+static int (*rtas)(void *, void *);
+static void *rtas_data;
+static int rtas_put_term_char;
+static int rtas_display_char;
+
+int call_rtas(int token, int nargs, int nret, ...)
+{
+ int i;
+ struct rtas_args {
+ int token;
+ int nargs;
+ int nret;
+ unsigned int args[12];
+ } args;
+ va_list list;
+
+ if (!rtas || !token)
+ return -1; /* Hardware error */
+ if (nargs + nret > 12)
+ return -1; /* Hardware error */
+
+ args.token = token;
+ args.nargs = nargs;
+ args.nret = nret;
+
+ va_start(list, nret);
+ for (i = 0; i < nargs; i++)
+ args.args[i] = va_arg(list, unsigned int);
+ va_end(list);
+
+ for (i = 0; i < nret; i++)
+ args.args[nargs+i] = 0;
+
+ rtas(&args, rtas_data);
+
+ return args.args[nargs];
+}
+
+
+int write(void *handle, void *ptr, int nb)
+{
+ int i=0;
+ int err;
+ char *p;
+
+ p = ptr;
+ err = 0;
+
+ if (rtas_put_term_char)
+ for (; i < nb && !err; i++)
+ err = call_rtas(rtas_put_term_char, 1, 1, p[i]);
+#if 0
+ /* not tested, doesn't check line limits, do we care? */
+ else if (rtas_display_char)
+ for (; i < nb && !err; i++)
+ err = call_rtas(rtas_put_term_char, 1, 1, p[i]);
+#endif
+
+ return i-1;
+}
+
+
+/* returns true if s2 is a prefix of s1 */
+static int string_match(const char *s1, const char *s2)
+{
+ for (; *s2; ++s2)
+ if (*s1++ != *s2)
+ return 0;
+ return 1;
+}
+
+
+/* return -1 on fail, address on success */
+void *claim(unsigned long virt, unsigned long size, unsigned long align)
+{
+
+ unsigned long al = align ? align : 1;
+ unsigned long try = _ALIGN_UP(virt, al);
+ unsigned int *r;
+
+#if 0 /* Debug */
+
+ printf("claim: request %lx size %lx align %lx, aligned %p ",
+ virt, size, align, (void *)try);
+
+
+#define BUSY(s) printf("%s\n\r", s), ((void *)(-1))
+#define RANGE_PRINT printf("range %08x %08x ",r[1], r[3]);
+#define RANGE_CLEAR printf("is clear\n\r");
+#else
+#define BUSY(s) ((void *)(-1))
+#define RANGE_PRINT do {} while(0)
+#define RANGE_CLEAR do {} while(0)
+#endif
+
+
+ if (try + size < try)
+ return BUSY("wraps");
+
+ if (memsize && try + size > memsize)
+ return BUSY("overflows");
+
+ for (r = (unsigned int *)(((unsigned long)initial_boot_params)
+ + initial_boot_params->off_mem_rsvmap);
+ r[2] || r[3]; r += 4) {
+
+ if (r[0] || r[1] > try + size)
+ continue; /* starts after */
+ if (r[2] || r[1]+r[3] < r[1])
+ return BUSY("BEYOND"); /* extends beyond */
+ if (r[1] + r[3] < try)
+ continue; /* contained before */
+
+ RANGE_PRINT;
+ return BUSY("overlaps"); /* overlaps */
+ }
+
+ /*
+ * XXX: Fixme: we should keep track here and not hand out the
+ * same address again.
+ */
+
+ RANGE_CLEAR;
+ return (void *)(try);
+}
+
+
+
+/* code lifted from arch/powerpc/kernel/prom.c */
+
+static inline char *find_flat_dt_string(u32 offset)
+{
+ return ((char *)initial_boot_params) +
+ initial_boot_params->off_dt_strings + offset;
+}
+
+/**
+ * This function is used to scan the flattened device-tree, it is
+ * used to extract the memory informations at boot before we can
+ * unflatten the tree
+ */
+int of_scan_flat_dt(int (*it)(unsigned long node,
+ const char *uname, int depth,
+ void *data),
+ void *data)
+{
+ unsigned long p = ((unsigned long)initial_boot_params) +
+ initial_boot_params->off_dt_struct;
+ int rc = 0;
+ int depth = -1;
+
+ do {
+ u32 tag = *((u32 *)p);
+ char *pathp;
+
+ p += 4;
+ if (tag == OF_DT_END_NODE) {
+ depth --;
+ continue;
+ }
+ if (tag == OF_DT_NOP)
+ continue;
+ if (tag == OF_DT_END)
+ break;
+ if (tag == OF_DT_PROP) {
+ u32 sz = *((u32 *)p);
+ p += 8;
+ if (initial_boot_params->version < 0x10)
+ p = _ALIGN(p, sz >= 8 ? 8 : 4);
+ p += sz;
+ p = _ALIGN(p, 4);
+ continue;
+ }
+ if (tag != OF_DT_BEGIN_NODE) {
+ printf("Invalid tag %x scanning flattened"
+ " device tree !\n\r", tag);
+ return -1;
+ }
+ depth++;
+ pathp = (char *)p;
+ p = _ALIGN(p + strlen(pathp) + 1, 4);
+ if ((*pathp) == '/') {
+ char *lp, *np;
+ for (lp = NULL, np = pathp; *np; np++)
+ if ((*np) == '/')
+ lp = np+1;
+ if (lp != NULL)
+ pathp = lp;
+ }
+ rc = it(p, pathp, depth, data);
+ if (rc != 0)
+ break;
+ } while(1);
+
+ return rc;
+}
+
+unsigned long of_get_flat_dt_root(void)
+{
+ unsigned long p = ((unsigned long)initial_boot_params) +
+ initial_boot_params->off_dt_struct;
+
+ while(*((u32 *)p) == OF_DT_NOP)
+ p += 4;
+ BUG_ON (*((u32 *)p) != OF_DT_BEGIN_NODE);
+ p += 4;
+ return _ALIGN(p + strlen((char *)p) + 1, 4);
+}
+
+/**
+ * This function can be used within scan_flattened_dt callback to get
+ * access to properties
+ */
+void* of_get_flat_dt_prop(unsigned long node, const char *name,
+ unsigned long *size)
+{
+ unsigned long p = node;
+
+ do {
+ u32 tag = *((u32 *)p);
+ u32 sz, noff;
+ const char *nstr;
+
+ p += 4;
+ if (tag == OF_DT_NOP)
+ continue;
+ if (tag != OF_DT_PROP)
+ return NULL;
+
+ sz = *((u32 *)p);
+ noff = *((u32 *)(p + 4));
+ p += 8;
+ if (initial_boot_params->version < 0x10)
+ p = _ALIGN(p, sz >= 8 ? 8 : 4);
+
+ nstr = find_flat_dt_string(noff);
+ if (nstr == NULL) {
+ printf("Can't find property index"
+ " name !\n\r");
+ return NULL;
+ }
+ if (strcmp(name, nstr) == 0) {
+ if (size)
+ *size = sz;
+ return (void *)p;
+ }
+ p += sz;
+ p = _ALIGN(p, 4);
+ } while(1);
+}
+
+/* end code lifted from arch/powerpc/kernel/prom.c */
+
+
+/* This only handles device nodes directly off of the root node
+ * and will return on any partial name match
+ */
+static int match_device_node(unsigned long node, const char *uname,
+ int depth, void *data)
+{
+ if (depth == 1 && string_match(uname, data))
+ return node;
+ return 0;
+}
+
+/* Find Real Memory (offset) region. The first reg, size pair of the
+ * memory node defines the memory that is accessable in real mode on
+ * PPC64 LPAR systems. Assume that will be enough everywhere.
+ */
+static int find_rmo(unsigned long node, const char *uname, int depth,
+ void *data)
+{
+ if (match_device_node(node, uname, depth, data)) {
+ unsigned long size;
+ unsigned int *reg;
+ int i;
+
+ reg = of_get_flat_dt_prop(node, "reg", &size);
+ if (!reg || (size < (na + ns)*4)) {
+ printf("Warning: Can't parse reg property on %s\n\r",
+ uname);
+ return 0;
+ }
+
+ /* ignore if not address 0 */
+ for (i=0; i < na; i++)
+ if (reg[i])
+ return 0;
+
+ /* if more than 1 cell then MAX_MEM */
+ for (i=0; i < ns-1; i++)
+ if (reg[na+i])
+ return MAX_MEM;
+
+ /* else return size of first reg */
+ return reg[na+i];
+ }
+
+ return 0;
+}
+
+/* dummy prom that recognises the services used by elsewhere */
+int call_prom(const char *service, int nargs, int nret, ...)
+{
+ va_list list;
+
+ if (string_match(service, "finddevice")) {
+ char *path;
+
+ if ((nargs != 1) || (nret != 1)) {
+ printf("finddevice: unexpected arg counts %d %d\n\r",
+ nargs, nret);
+ return -1;
+ }
+ va_start(list, nret);
+ path = (void *)va_arg(list, unsigned int);
+ va_end(list);
+
+ if (path[0] == '/')
+ path++;
+
+ return (int) of_scan_flat_dt(match_device_node, path);
+
+ } else if (string_match(service, "getprop")) {
+ unsigned long node;
+ char *prop;
+ char *buf;
+ unsigned int len;
+ va_list list;
+ char *ret;
+ unsigned long size;
+
+ if ((nargs != 4) || (nret != 1)) {
+ printf("getprop: unexpected arg counts %d %d\n\r",
+ nargs, nret);
+ return -1;
+ }
+
+ va_start(list, nret);
+ node = va_arg(list, unsigned int);
+ prop = (void *)va_arg(list, unsigned int);
+ buf = (void *)va_arg(list, unsigned int);
+ len = va_arg(list, unsigned int);
+ va_end(list);
+
+ ret = of_get_flat_dt_prop(node, prop, &size);
+ if (ret) {
+ memcpy(buf, ret, len < size ? len : size);
+ }
+ return size;
+ } else if (!string_match(service, "exit")) {
+ printf("Unimplemented prom service %s(%d, %d) called\n\r",
+ service, nargs, nret);
+ /* fall through */
+ }
+ for(;;)
+ ; /* Forever */
+}
+
+void init_prom(unsigned long a1, unsigned long a2, void *p)
+{
+ unsigned long node;
+
+ if (p) /* this version doesn't support a prom interface */
+ exit();
+
+ initial_boot_params = (void *) a1;
+
+ BUG_ON(initial_boot_params->magic != OF_DT_HEADER);
+ BUG_ON(initial_boot_params->last_comp_version > 0x10);
+
+ chosen_handle = finddevice("/chosen");
+ if (chosen_handle == (void *) -1)
+ exit();
+
+ node = of_scan_flat_dt(match_device_node, "rtas");
+
+ if (node) {
+ unsigned int *p;
+ p = of_get_flat_dt_prop(node,
+ "linux,rtas-base", NULL);
+ if (p)
+ rtas_data = (void *)*p;
+ p = of_get_flat_dt_prop(node,
+ "linux,rtas-entry", NULL);
+ if (p)
+ rtas = (void *)*p;
+ p = of_get_flat_dt_prop(node,
+ "put-term-char", NULL);
+ if (p)
+ rtas_put_term_char = *p;
+ p = of_get_flat_dt_prop(node,
+ "display-character", NULL);
+ if (p)
+ rtas_display_char = *p;
+ }
+
+ node = of_get_flat_dt_root();
+ if (node) {
+ unsigned long tmp;
+ void *p;
+
+ p = of_get_flat_dt_prop(node, "#addr-cells", &tmp);
+ if (tmp == 4)
+ na = *(int *)p;
+ else
+ printf("Warning, could't find or parse #addr-cells\n\r");
+ p = of_get_flat_dt_prop(node, "#size-cells", &tmp);
+ if (tmp == 4)
+ ns = *(int *)p;
+ else
+ printf("Warning, could't find or parse #size-cells\n\r");
+ }
+
+ memsize = of_scan_flat_dt(find_rmo, "memory");
+
+ if (!memsize)
+ BUG_ON("Couldn't find RMO memory size\n\r");
+
+ if (memsize > MAX_MEM)
+ memsize = MAX_MEM;
+
+ printf("Can use %x bytes of memory in RMO\n\r", memsize);
+
+ ram_end = memsize;
+}
+
+/*
+ * Kexec smp hook:
+ * copy 0x100 bytes from the kernel entry point down to address zero,
+ * flush, then tell any slaves to branch down to address 0x60.
+ */
+void prom_smp_hook(unsigned long kernel_start)
+{
+ char *kern = (char *)kernel_start;
+ char *zero = (char *)0;
+
+ memcpy(zero, kern, 0x100);
+ flush_cache(zero, 0x100);
+
+ gohere = 0x60;
+}
Index: kernel/arch/powerpc/boot/crt0_kexec.S
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ kernel/arch/powerpc/boot/crt0_kexec.S 2006-06-29 03:47:06.868856261 -0500
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 1997 Paul Mackerras.
+ * Copyright (C) 2006 Milton Miller, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * NOTE: This code runs in 32 bit mode and is linked as ELF32.
+ * It will switch from 64 to 32 bit mode with some assumptions.
+ */
+
+#include "ppc_asm.h"
+
+ .text
+ /* This is the actual "entry" point as mentioned in the headers.
+ * It is this code that should be copied down to zero.
+ * This code must be loaded above 0x100 or the slaves will
+ * crash when we copy the kernels entry point down.
+ */
+ .globl master
+master:
+ /* Work out the offset between the address we were linked at
+ * and the address where we're running.
+ * Set 32 bit mode while we are at it.
+ */
+ bl set32
+1: mflr r0
+ lis r9,1b@ha
+ addi r9,r9,1b@l
+ subf. r0,r9,r0
+ beq 3f /* if running at same address as linked */
+
+ /* The .got2 section contains a list of addresses, so add
+ the address offset onto each entry. */
+ lis r9,__got2_start@ha
+ addi r9,r9,__got2_start@l
+ lis r8,__got2_end@ha
+ addi r8,r8,__got2_end@l
+ subf. r8,r9,r8
+ beq 3f
+ srwi. r8,r8,2
+ mtctr r8
+ add r9,r0,r9
+2: lwz r8,0(r9)
+ add r8,r8,r0
+ stw r8,0(r9)
+ addi r9,r9,4
+ bdnz 2b
+3:
+ b 3f
+
+
+
+
+ /* the slaves may be in 32 or 64 bit mode, we don't care */
+ .org master+0x60
+ .globl slave
+slave:
+ li 4,gohere-master /* read 0-relative */
+waiting:
+99: lwz r6,0(r4)
+ cmpwi 0,r6,0
+ beq 99b
+ mtctr r6
+ addi r4,r6,gohere-waiting /* read from gohere in image */
+ bctr
+
+ .global gohere
+gohere: .long 0 # when set the slave moves
+
+
+
+flushit:
+ /* Do a cache flush for our text, in case OF didn't */
+3: lis r9,_start@ha
+ addi r9,r9,_start@l
+ add r9,r0,r9
+ lis r8,_etext@ha
+ addi r8,r8,_etext@l
+ add r8,r0,r8
+4: dcbf r0,r9
+ icbi r0,r9
+ addi r9,r9,0x20
+ cmplw cr0,r9,r8
+ blt 4b
+ sync
+ isync
+
+ /* fill out a stack for c code */
+ lis r1,__stack_end@ha
+ addi r1,r1,__stack_end@l
+ add r1,r1,r0
+ stwu r5,-16(r1) /* r5 should be 0 */
+
+ /* tell slave to come to our copy */
+ lis r8,waiting@ha
+ addi r8,r8,waiting@l
+ add r8,r8,r0
+ stw r8,gohere-master(0)
+
+ mr r6,r1
+ b start
+
+
+ /*
+ * Check if the processor is running in 32 bit mode, using
+ * only 32 bit instructions which should be safe on 32 and
+ * 64 bit processors.
+ *
+ * The caller is assuming that the lr is used to return.
+ */
+set32: mfmsr r0 /* grab whole msr */
+ rlwinm r6,r0,0,0,31 /* extract bottom word */
+ subf. r6,r6,r0 /* subtract, same? */
+ beqlr /* yes: we are 32 bit mode */
+
+ /* Since the compare found other bits, we must be in 64 bit mode
+ * on a 64 bit processor. Since MSR[SF] is in the bits we masked
+ * off the compare will always fail in 64 bit mode, and will alway
+ * be equal in 32 bit mode (the size of the implicit compare).
+ *
+ * This program must run in 32 bit mode, so switch now.
+ * Assume we are actually running in low 32 bits of memory space,
+ * so we can just turn off MSR[SF] which is bit 0.
+ */
+ .machine push
+ .machine "ppc64"
+ rldicl r0,r0,0,1
+ sync
+ mtmsrd r0
+ isync
+ .machine pop
+ blr
+
+ .org master+0x100 /* make sure we don't go backwards */
+
+
+ /* this code needs a stack allocated in the image */
+ .section .stack,"aw",@nobits
+ .space 4096
+
+ .data
+
+ /* a procedure descriptor used when pretending to be elf64_powerpc */
+ .balign 8
+ .global _master64
+_master64:
+ .long 0, master /* big endian, supported reloc ppc32 */
+ .quad 0, 0, 0
+
+ /* a procedure descriptor used when booting this as a COFF file */
+ .global _master_opd
+_master_opd:
+ .long master, 0, 0, 0
Index: kernel/arch/powerpc/boot/dt.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ kernel/arch/powerpc/boot/dt.h 2006-06-29 03:47:06.870855944 -0500
@@ -0,0 +1,46 @@
+#ifndef _PPC_BOOT_DT_H_
+#define _PPC_BOOT_DT_H_
+
+typedef unsigned int u32;
+
+/* Definitions used by the flattened device tree */
+#define OF_DT_HEADER 0xd00dfeed /* marker */
+#define OF_DT_BEGIN_NODE 0x1 /* Start of node, full name */
+#define OF_DT_END_NODE 0x2 /* End node */
+#define OF_DT_PROP 0x3 /* Property: name off, size,
+ * content */
+#define OF_DT_NOP 0x4 /* nop */
+#define OF_DT_END 0x9
+
+#define OF_DT_VERSION 0x10
+
+/*
+ * This is what gets passed to the kernel by prom_init or kexec
+ *
+ * The dt struct contains the device tree structure, full pathes and
+ * property contents. The dt strings contain a separate block with just
+ * the strings for the property names, and is fully page aligned and
+ * self contained in a page, so that it can be kept around by the kernel,
+ * each property name appears only once in this page (cheap compression)
+ *
+ * the mem_rsvmap contains a map of reserved ranges of physical memory,
+ * passing it here instead of in the device-tree itself greatly simplifies
+ * the job of everybody. It's just a list of u64 pairs (base/size) that
+ * ends when size is 0
+ */
+struct boot_param_header
+{
+ u32 magic; /* magic word OF_DT_HEADER */
+ u32 totalsize; /* total size of DT block */
+ u32 off_dt_struct; /* offset to structure */
+ u32 off_dt_strings; /* offset to strings */
+ u32 off_mem_rsvmap; /* offset to memory reserve map */
+ u32 version; /* format version */
+ u32 last_comp_version; /* last compatible version */
+ /* version 2 fields below */
+ u32 boot_cpuid_phys; /* Physical CPU id we're booting on */
+ /* version 3 fields below */
+ u32 dt_strings_size; /* size of the DT strings block */
+};
+
+#endif /* _PPC_BOOT_DT_H_ */
^ permalink raw reply
* Re: [PATCH 1/3] Add support for the Freescale MPC8349E-mITX eval board
From: Kim Phillips @ 2006-06-29 14:58 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev
In-Reply-To: <99F42AA0-3028-4C80-86C1-14A210C41229@kernel.crashing.org>
On Thu, 29 Jun 2006 00:10:56 -0500
Kumar Gala <galak@kernel.crashing.org> wrote:
>
> On Jun 28, 2006, at 9:13 PM, Kim Phillips wrote:
>
> > Add support for the Freescale MPC8349E-mITX eval board
> >
> > This is largely based on 8349 SYS code except that it uses the new
> > rtc_class code in drivers/rtc instead of explicitly specifying the
> > rtc chip. SATA is untested, as this is work in progress.
> >
I forgot to mention the 5-port switch is also unsupported at this time..
<snip>
> > diff --git a/arch/powerpc/platforms/83xx/misc.c b/arch/powerpc/
> > platforms/83xx/misc.c
> > index 1455bce..568a8f7 100644
> > --- a/arch/powerpc/platforms/83xx/misc.c
> > +++ b/arch/powerpc/platforms/83xx/misc.c
> > @@ -53,3 +53,55 @@ long __init mpc83xx_time_init(void)
> >
> > return 0;
> > }
> > +
> > +#ifdef CONFIG_RTC_CLASS
> > +int mpc83xx_set_rtc_time(struct rtc_time *tm)
> > +{
> > + int err;
> > + struct class_device *class_dev =
> > + rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
> > +
> > + if (class_dev == NULL) {
> > + printk("%s: unable to open rtc device (%s)\n",
> > + __FUNCTION__, CONFIG_RTC_HCTOSYS_DEVICE);
> > + return -ENODEV;
> > + }
> > +
> > + err = rtc_set_time(class_dev, tm);
> > + if (err != 0)
> > + dev_err(class_dev->dev,
> > + "%s: unable to set the hardware clock\n",__FUNCTION__);
> > +
> > + rtc_class_close(class_dev);
> > +
> > + return 0;
> > +}
> > +
> > +void mpc83xx_get_rtc_time(struct rtc_time *tm)
> > +{
> > + int err;
> > + struct class_device *class_dev =
> > + rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
> > +
> > + if (class_dev == NULL) {
> > + printk("%s: unable to open rtc device (%s)\n",
> > + __FUNCTION__, CONFIG_RTC_HCTOSYS_DEVICE);
> > + return;
> > + }
> > +
> > + err = rtc_read_time(class_dev, tm);
> > + if (err == 0) {
> > + err = rtc_valid_tm(tm);
> > + if (err != 0)
> > + dev_err(class_dev->dev,
> > + "%s: invalid date/time\n",__FUNCTION__);
> > + }
> > + else
> > + dev_err(class_dev->dev,
> > + "%s: unable to read the hardware clock\n",__FUNCTION__);
> > +
> > + rtc_class_close(class_dev);
> > +
> > + return;
> > +}
> > +#endif /* CONFIG_RTC_CLASS */
>
> What is this trying to accomplish? What RTC chip is on 834x ITC and
> how's it connected?
It removes rtc chip-specific code from the platform code. It accomplishes this by using the new "RTC-framework" glue.
The board has a Dallas DS1339. The driver in drivers/i2c/chips is apparently obsolete, and there is a new way of doing all things i2c-rtc. See:
http://kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=1abb0dc92d706e8c73c7a62ca813738fe2259a7f
The defconfig I sent out has CONFIG_RTC_DRV_DS1307 set. The code works well and I have an upcoming patch to carry the i2c 'force' option in from the device tree, which instructs the i2c code to do a better job of identifying the ds133x chips from the ds130x chips. btw, setting system time from RTC on startup is now user-configurable.
<snip>
> > diff --git a/include/asm-ppc/mpc83xx.h b/include/asm-ppc/mpc83xx.h
> > index 02ed2c3..80076be 100644
> > --- a/include/asm-ppc/mpc83xx.h
> > +++ b/include/asm-ppc/mpc83xx.h
> > @@ -25,6 +25,10 @@
> > #include <platforms/83xx/mpc834x_sys.h>
> > #endif
> >
> > +#ifdef CONFIG_MPC834x_ITX
> > +#include <platforms/83xx/mpc834x_itx.h>
> > +#endif
> > +
>
> This shouldn't be needed, its a hold over from arch/ppc
>
Unfortunately it won't build without it.
Kim
^ permalink raw reply
* Have problem with Xilinx Uart Lite
From: Qichen Huang @ 2006-06-29 15:05 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 803 bytes --]
Hi all,
I'm trying to port linuxppc_2_4_devel to Xilinx ML403. I want to use
UartLite instead of Uart 16550. What changes should I do?
I have disabled "Standard/generic (8250/16550 and compatible UARTs) serial
support"
and enabled "Xilinx UART Lite" & "Console on UART Lite port" in character
devices.
And the initial kernel command string is changed to "console=ttl0
console=ttyS0,9600 ip=off root=/dev/xsysace/disc0/part3 rw".
The kernel boot log dosen't mention any serial device and it hangs up until
"System started." There is no login prompt.
My /etc/inittab is :
::sysinit:/etc/init.d/rcS
#::askfirst:-/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/sbin/swapoff -a
::shutdown:/bin/umount -a -r
::restart:/sbin/init
::respawn:/sbin/getty 9600 tts/0
What else should I do?
Thank you!
Qichen
[-- Attachment #2: Type: text/html, Size: 937 bytes --]
^ permalink raw reply
* Problem with Xilinx Uart Lite
From: Qichen Huang @ 2006-06-29 15:20 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 803 bytes --]
Hi all,
I'm trying to port linuxppc_2_4_devel to Xilinx ML403. I want to use
UartLite instead of Uart 16550. What changes should I do?
I have disabled "Standard/generic (8250/16550 and compatible UARTs) serial
support"
and enabled "Xilinx UART Lite" & "Console on UART Lite port" in character
devices.
And the initial kernel command string is changed to "console=ttl0
console=ttyS0,9600 ip=off root=/dev/xsysace/disc0/part3 rw".
The kernel boot log dosen't mention any serial device and it hangs up until
"System started." There is no login prompt.
My /etc/inittab is :
::sysinit:/etc/init.d/rcS
#::askfirst:-/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/sbin/swapoff -a
::shutdown:/bin/umount -a -r
::restart:/sbin/init
::respawn:/sbin/getty 9600 tts/0
What else should I do?
Thank you!
Qichen
[-- Attachment #2: Type: text/html, Size: 1007 bytes --]
^ permalink raw reply
* Re: Problem with Xilinx Uart Lite
From: Andrei Konovalov @ 2006-06-29 15:32 UTC (permalink / raw)
To: Qichen Huang; +Cc: linuxppc-embedded
In-Reply-To: <b4ebaa9d0606290820y4dce2ce2x8d28007b1d591eef@mail.gmail.com>
Qichen Huang wrote:
> Hi all,
>
> I'm trying to port linuxppc_2_4_devel to Xilinx ML403. I want to use
> UartLite instead of Uart 16550. What changes should I do?
>
> I have disabled "Standard/generic (8250/16550 and compatible UARTs)
> serial support"
> and enabled "Xilinx UART Lite" & "Console on UART Lite port" in
> character devices.
> And the initial kernel command string is changed to "console=ttl0
> console=ttyS0,9600 ip=off root=/dev/xsysace/disc0/part3 rw".
This command line sets default console to ttyS0.
Please remove "console=ttyS0,9600".
> The kernel boot log dosen't mention any serial device and it hangs up
> until "System started." There is no login prompt.
Are you using the correct xparameters_*.h - the one having the
#defines for UartLite?
> My /etc/inittab is :
>
> ::sysinit:/etc/init.d/rcS
> #::askfirst:-/bin/sh
> ::ctrlaltdel:/sbin/reboot
> ::shutdown:/sbin/swapoff -a
> ::shutdown:/bin/umount -a -r
> ::restart:/sbin/init
> ::respawn:/sbin/getty 9600 tts/0
>
>
> What else should I do?
> Thank you!
>
> Qichen
>
>
> ------------------------------------------------------------------------
>
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
^ permalink raw reply
* RE: [PATCH 3/7] powerpc: Add QE library qe_lib--common files
From: Gridish Shlomi-RM96313 @ 2006-06-29 16:06 UTC (permalink / raw)
To: Kumar Gala, Li Yang-r58472
Cc: linuxppc-dev, Phillips Kim-R1AAHA, Paul Mackerras, linux-kernel,
Chu hanjin-r52514
Hi all,
The reason why I chose to work with MM and not with RHEAP is that,
apparently, there is a BUG in the RHEAP module,=20
it is not allocating correctly blocks that require alignments grater
than 8.
The usage of MM is only a temporary solution till RHEAP is fixed.
Regards,
Shlomi
-----Original Message-----
From: Kumar Gala [mailto:galak@kernel.crashing.org]=20
Sent: Wednesday, June 28, 2006 22:20
To: Li Yang-r58472
Cc: 'Paul Mackerras'; linuxppc-dev@ozlabs.org;
'linux-kernel@vger.kernel.org'; Chu hanjin-r52514; Gridish
Shlomi-RM96313; Phillips Kim-R1AAHA
Subject: Re: [PATCH 3/7] powerpc: Add QE library qe_lib--common files
Nack, remove the mm allocation code and just use rheap.
- k
On Jun 28, 2006, at 9:23 AM, Li Yang-r58472 wrote:
>
> Signed-off-by: Shlomi Gridish <gridish@freescale.com>
> Signed-off-by: Li Yang <leoli@freescale.com>
> Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
>
> ---
> arch/powerpc/Kconfig | 12
> arch/powerpc/sysdev/Makefile | 1
> arch/powerpc/sysdev/ipic.c | 2
> arch/powerpc/sysdev/qe_lib/Kconfig | 315 +++++++++++++
> arch/powerpc/sysdev/qe_lib/Makefile | 8
> arch/powerpc/sysdev/qe_lib/mm.c | 770 +++++++++++++++++++++=20
> +++++++++++
> arch/powerpc/sysdev/qe_lib/mm.h | 6
> arch/powerpc/sysdev/qe_lib/qe.c | 181 ++++++++
> arch/powerpc/sysdev/qe_lib/qe_common.c | 401 +++++++++++++++++
> arch/powerpc/sysdev/qe_lib/qe_ic.c | 487 ++++++++++++++++++++
> arch/powerpc/sysdev/qe_lib/qe_ic.h | 83 +++
> arch/powerpc/sysdev/qe_lib/qe_io.c | 275 +++++++++++
> 12 files changed, 2541 insertions(+), 0 deletions(-)
>
> diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
> index 6729c98..6d4fc0b 100644
> --- a/arch/powerpc/Kconfig
> +++ b/arch/powerpc/Kconfig
> @@ -334,6 +334,16 @@ config APUS
> <http://linux-apus.sourceforge.net/>.
> endchoice
>
> +config QUICC_ENGINE
> + bool
> + depends on MPC836x
> + default y
> + help
> + The QE(QUICC Engine) is a new generation of coprocessor on
> + Freescale embedded CPUs(like CPM in older chips). Selecting
> + this option means that you wish to build a kernel for a
machine
> + with QE coprocessor on it.
> +
> config PPC_PSERIES
> depends on PPC_MULTIPLATFORM && PPC64
> bool " IBM pSeries & new (POWER5-based) iSeries"
> @@ -993,6 +1003,8 @@ # XXX source "arch/ppc/8xx_io/Kconfig"
>
> # XXX source "arch/ppc/8260_io/Kconfig"
>
> +source "arch/powerpc/sysdev/qe_lib/Kconfig"
> +
> source "arch/powerpc/platforms/iseries/Kconfig"
>
> source "lib/Kconfig"
> diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/=20
> Makefile
> index 4c2b356..cd1d5cc 100644
> --- a/arch/powerpc/sysdev/Makefile
> +++ b/arch/powerpc/sysdev/Makefile
> @@ -8,3 +8,4 @@ obj-$(CONFIG_U3_DART) +=3D dart_iommu.o
> obj-$(CONFIG_MMIO_NVRAM) +=3D mmio_nvram.o
> obj-$(CONFIG_PPC_83xx) +=3D ipic.o
> obj-$(CONFIG_FSL_SOC) +=3D fsl_soc.o
> +obj-$(CONFIG_QUICC_ENGINE) +=3D qe_lib/
> diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c
> index 8f01e0f..dbeccba 100644
> --- a/arch/powerpc/sysdev/ipic.c
> +++ b/arch/powerpc/sysdev/ipic.c
> @@ -537,12 +537,14 @@ void ipic_set_highest_priority(unsigned
>
> void ipic_set_default_priority(void)
> {
> +#ifdef CONFIG_MPC834x
> ipic_set_priority(MPC83xx_IRQ_TSEC1_TX, 0);
> ipic_set_priority(MPC83xx_IRQ_TSEC1_RX, 1);
> ipic_set_priority(MPC83xx_IRQ_TSEC1_ERROR, 2);
> ipic_set_priority(MPC83xx_IRQ_TSEC2_TX, 3);
> ipic_set_priority(MPC83xx_IRQ_TSEC2_RX, 4);
> ipic_set_priority(MPC83xx_IRQ_TSEC2_ERROR, 5);
> +#endif
> ipic_set_priority(MPC83xx_IRQ_USB2_DR, 6);
> ipic_set_priority(MPC83xx_IRQ_USB2_MPH, 7);
>
> diff --git a/arch/powerpc/sysdev/qe_lib/Kconfig b/arch/powerpc/=20
> sysdev/qe_lib/Kconfig
> new file mode 100644
> index 0000000..6105237
> --- /dev/null
> +++ b/arch/powerpc/sysdev/qe_lib/Kconfig
> @@ -0,0 +1,315 @@
> +#
> +# QE Communication options
> +#
> +
> +menu "QE Options"
> + depends on QUICC_ENGINE
> +=09
> +config UCC1
> + bool "Enable QE UCC1"
> +
> +choice
> + prompt "UCC1 speed selection"
> + depends on UCC1
> + default UCC1_SLOW
> +
> + config UCC1_SLOW
> + bool "UCC1 is slow"
> + config UCC1_FAST
> + bool "UCC1 is fast"
> +endchoice
> +
> +menu "UCC1 Protocols options"
> + depends on UCC1
> +
> + choice
> + prompt "UCC1 Slow Protocols selection"
> + depends on UCC1_SLOW
> + default UCC1_UART
> +
> + config UCC1_UART
> + bool "UCC1 is UART"
> + endchoice
> +
> + choice
> + prompt "UCC1 Fast Protocols selection"
> + depends on UCC1_FAST
> + default UCC1_GETH
> +
> + config UCC1_GETH
> + bool "UCC1 is GETH"
> + endchoice
> +endmenu
> +
> +config UCC2
> + bool "Enable QE UCC2"
> +
> +choice
> + prompt "UCC2 speed selection"
> + depends on UCC2
> + default UCC2_SLOW
> +
> + config UCC2_SLOW
> + bool "UCC2 is slow"
> + config UCC2_FAST
> + bool "UCC2 is fast"
> +endchoice
> +
> +menu "UCC2 Protocols options"
> + depends on UCC2
> +
> + choice
> + prompt "UCC2 Slow Protocols selection"
> + depends on UCC2_SLOW
> + default UCC2_UART
> +
> + config UCC2_UART
> + bool "UCC2 is UART"
> + endchoice
> +
> + choice
> + prompt "UCC2 Fast Protocols selection"
> + depends on UCC2_FAST
> + default UCC2_GETH
> +
> + config UCC2_GETH
> + bool "UCC2 is GETH"
> + endchoice
> +endmenu
> +
> +config UCC3
> + bool "Enable QE UCC3"
> +
> +choice
> + prompt "UCC3 speed selection"
> + depends on UCC3
> + default UCC3_SLOW
> +
> + config UCC3_SLOW
> + bool "UCC3 is slow"
> + config UCC3_FAST
> + bool "UCC3 is fast"
> +endchoice
> +
> +menu "UCC3 Protocols options"
> + depends on UCC3
> +
> + choice
> + prompt "UCC3 Slow Protocols selection"
> + depends on UCC3_SLOW
> + default UCC3_UART
> +
> + config UCC3_UART
> + bool "UCC3 is UART"
> + endchoice
> +
> + config UCC3_GETH
> + depends on UCC3_FAST
> + bool "UCC3 is GETH"
> +
> + config UCC3_ATM
> + depends on UCC3_FAST && !UCC3_GETH
> + tristate "UCC3 is ATM"
> +endmenu
> +
> +config UCC4
> + bool "Enable QE UCC4"
> +
> +choice
> + prompt "UCC4 speed selection"
> + depends on UCC4
> + default UCC4_SLOW
> +
> + config UCC4_SLOW
> + bool "UCC4 is slow"
> + config UCC4_FAST
> + bool "UCC4 is fast"
> +endchoice
> +
> +menu "UCC4 Protocols options"
> + depends on UCC4
> +
> + choice
> + prompt "UCC4 Slow Protocols selection"
> + depends on UCC4_SLOW
> + default UCC4_UART
> +
> + config UCC4_UART
> + bool "UCC4 is UART"
> + endchoice
> +
> + choice
> + prompt "UCC4 Fast Protocols selection"
> + depends on UCC4_FAST
> + default UCC4_GETH
> +
> + config UCC4_GETH
> + bool "UCC4 is GETH"
> + endchoice
> +endmenu
> +
> +config UCC5
> + bool "Enable QE UCC5"
> +
> +choice
> + prompt "UCC5 speed selection"
> + depends on UCC5
> + default UCC5_SLOW
> +
> + config UCC5_SLOW
> + bool "UCC5 is slow"
> + config UCC5_FAST
> + bool "UCC5 is fast"
> +endchoice
> +
> +menu "UCC5 Protocols options"
> + depends on UCC5
> +
> + choice
> + prompt "UCC5 Slow Protocols selection"
> + depends on UCC5_SLOW
> + default UCC5_UART
> +
> + config UCC5_UART
> + bool "UCC5 is UART"
> + endchoice
> +
> + choice
> + prompt "UCC5 Fast Protocols selection"
> + depends on UCC5_FAST
> + default UCC5_GETH
> +
> + config UCC5_GETH
> + bool "UCC5 is GETH"
> + endchoice
> +endmenu
> +
> +config UCC6
> + bool "Enable QE UCC6"
> +
> +choice
> + prompt "UCC6 speed selection"
> + depends on UCC6
> + default UCC6_SLOW
> +
> + config UCC6_SLOW
> + bool "UCC6 is slow"
> + config UCC6_FAST
> + bool "UCC6 is fast"
> +endchoice
> +
> +menu "UCC6 Protocols options"
> + depends on UCC6
> +
> + choice
> + prompt "UCC6 Slow Protocols selection"
> + depends on UCC6_SLOW
> + default UCC6_UART
> +
> + config UCC6_UART
> + bool "UCC6 is UART"
> + endchoice
> +
> + choice
> + prompt "UCC6 Fast Protocols selection"
> + depends on UCC6_FAST
> + default UCC6_GETH
> +
> + config UCC6_GETH
> + bool "UCC6 is GETH"
> + endchoice
> +endmenu
> +
> +config UCC7
> + bool "Enable QE UCC7"
> +
> +choice
> + prompt "UCC7 speed selection"
> + depends on UCC7
> + default UCC7_SLOW
> +
> + config UCC7_SLOW
> + bool "UCC7 is slow"
> + config UCC7_FAST
> + bool "UCC7 is fast"
> +endchoice
> +
> +menu "UCC7 Protocols options"
> + depends on UCC7
> +
> + choice
> + prompt "UCC7 Slow Protocols selection"
> + depends on UCC7_SLOW
> + default UCC7_UART
> +
> + config UCC7_UART
> + bool "UCC7 is UART"
> + endchoice
> +
> + choice
> + prompt "UCC7 Fast Protocols selection"
> + depends on UCC7_FAST
> + default UCC7_GETH
> +
> + config UCC7_GETH
> + bool "UCC7 is GETH"
> + endchoice
> +endmenu
> +
> +config UCC8
> + bool "Enable QE UCC8"
> +
> +choice
> + prompt "UCC8 speed selection"
> + depends on UCC8
> + default UCC8_SLOW
> +
> + config UCC8_SLOW
> + bool "UCC8 is slow"
> + config UCC8_FAST
> + bool "UCC8 is fast"
> +endchoice
> +
> +menu "UCC8 Protocols options"
> + depends on UCC8
> +
> + choice
> + prompt "UCC8 Slow Protocols selection"
> + depends on UCC8_SLOW
> + default UCC8_UART
> +
> + config UCC8_UART
> + bool "UCC8 is UART"
> + endchoice
> +
> + choice
> + prompt "UCC8 Fast Protocols selection"
> + depends on UCC8_FAST
> + default UCC8_GETH
> +
> + config UCC8_GETH
> + bool "UCC8 is GETH"
> + endchoice
> +endmenu
> +
> +config UCC
> + depends on UCC1 || UCC2 || UCC3 || UCC4 || UCC5 || UCC6 || UCC7
> || UCC8
> + default y
> + bool
> +
> +config UCC_SLOW
> + depends on UCC1_SLOW || UCC2_SLOW || UCC3_SLOW || UCC4_SLOW || =20
> UCC5_SLOW || UCC6_SLOW || UCC7_SLOW || UCC8_SLOW
> + default y
> + bool
> +
> +config UCC_FAST
> + depends on UCC1_FAST || UCC2_FAST || UCC3_FAST || UCC4_FAST || =20
> UCC5_FAST || UCC6_FAST || UCC7_FAST || UCC8_FAST
> + default y
> + bool
> +
> +config UCC_GETH_CONF
> + depends on UCC1_GETH || UCC2_GETH || UCC3_GETH || UCC4_GETH || =20
> UCC5_GETH || UCC6_GETH || UCC7_GETH || UCC8_GETH
> + default y
> + bool
> +endmenu
> +
> diff --git a/arch/powerpc/sysdev/qe_lib/Makefile b/arch/powerpc/=20
> sysdev/qe_lib/Makefile
> new file mode 100644
> index 0000000..c04a70c
> --- /dev/null
> +++ b/arch/powerpc/sysdev/qe_lib/Makefile
> @@ -0,0 +1,8 @@
> +#
> +# Makefile for the linux ppc-specific parts of QE
> +#
> +obj-$(CONFIG_QUICC_ENGINE)+=3D qe_common.o mm.o qe.o qe_ic.o qe_io.o
> +
> +obj-$(CONFIG_UCC) +=3D ucc.o
> +obj-$(CONFIG_UCC_SLOW) +=3D ucc_slow.o
> +obj-$(CONFIG_UCC_FAST) +=3D ucc_fast.o ucc_slow.o
> diff --git a/arch/powerpc/sysdev/qe_lib/mm.c b/arch/powerpc/sysdev/=20
> qe_lib/mm.c
> new file mode 100644
> index 0000000..58984ba
> --- /dev/null
> +++ b/arch/powerpc/sysdev/qe_lib/mm.c
> @@ -0,0 +1,770 @@
> +/*
> + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights =20
> reserved.
> + *
> + * Author: Shlomi Gridish <gridish@freescale.com>
> + *
> + * Description:
> + * QE Memory Manager.
> + *
> + * Changelog:
> + * Jun 28, 2006 Li Yang <LeoLi@freescale.com>
> + * - Reorganized as qe_lib
> + * - Merged to powerpc arch; add device tree support
> + * - Style fixes
> + *
> + * This program is free software; you can redistribute it and/or =20
> modify it
> + * under the terms of the GNU General Public License as =20
> published by the
> + * Free Software Foundation; either version 2 of the License, or =20
> (at your
> + * option) any later version.
> + */
> +#include <linux/errno.h>
> +#include <linux/sched.h>
> +#include <linux/kernel.h>
> +#include <linux/param.h>
> +#include <linux/string.h>
> +#include <linux/mm.h>
> +#include <linux/interrupt.h>
> +#include <linux/bootmem.h>
> +#include <linux/module.h>
> +#include <asm/irq.h>
> +#include <asm/page.h>
> +#include <asm/pgtable.h>
> +
> +#include "mm.h"
> +
> +#define MAX_ALIGNMENT 20
> +#define MAX_NAME_LEN 50
> +
> +#define MAKE_ALIGNED(adr, align) ( ((u32)adr + (align - 1)) & (~=20
> (align - 1)) )
> +
> +/* mem_block_t data stucutre defines parameters of the Memory =20
> Block */
> +typedef struct mem_block {
> + struct mem_block *next; /* Pointer to the next memory block */
> +
> + u32 base; /* base address of the memory block */
> + u32 end; /* end address of the memory block */
> +} mem_block_t;
> +
> +/* free_block_t data stucutre defines parameters of the Free Block */
> +typedef struct free_block {
> + struct free_block *next; /* Pointer to the next free
block */
> +
> + u32 base; /* base address of the block */
> + u32 end; /* end address of the block */
> +} free_block_t;
> +
> +/* busy_block_t data stucutre defines parameters of the Busy =20
> Block */
> +typedef struct busy_block {
> + struct busy_block *next; /* Pointer to the next free
block */
> +
> + u32 base; /* base address of the block */
> + u32 end; /* end address of the block */
> + char name[MAX_NAME_LEN];
> +} busy_block_t;
> +
> +/* mm_t data structure defines parameters of the MM object */
> +typedef struct mm {
> + mem_block_t *mem_blocks; /* List of memory blocks (Memory =20
> list) */
> + busy_block_t *busy_blocks; /* List of busy blocks (Busy
list) */
> + free_block_t *free_blocks[MAX_ALIGNMENT + 1];/* align lists of
free
> + blocks (Free
lists) */
> +} mm_t;
> +
> +/=20
> **********************************************************************
> + * MM internal routines =20
> set *
> + =20
> **********************************************************************
> /
> +
> +/****************************************************************
> + * Routine: mem_block_init
> + *
> + * Description:
> + * Initializes a new memory block of "size" bytes and started
> + * from "base" address.
> + *
> + * Arguments:
> + * mem_blk- handle to the mem_blk object
> + * base - base address of the memory block
> + * size - size of the memory block
> + *
> + * Return value:
> + * 0 is returned on success. E_NOMEMORY is returned
> + * if can't allocate memory for mem_blk object.
> + ****************************************************************/
> +static int mem_block_init(void **mem_blk, u32 base, u32 size)
> +{
> + mem_block_t *p_mem_blk;
> +
> + p_mem_blk =3D (mem_block_t *) kmalloc(sizeof(mem_block_t), =20
> GFP_KERNEL);
> + if (!p_mem_blk)
> + return -ENOMEM;
> +
> + p_mem_blk->base =3D base;
> + p_mem_blk->end =3D base + size;
> + p_mem_blk->next =3D 0;
> +
> + *mem_blk =3D p_mem_blk;
> +
> + return (0);
> +}
> +
> +/****************************************************************
> + * Routine: free_block_init
> + *
> + * Description:
> + * Initializes a new free block of of "size" bytes and
> + * started from "base" address.
> + *
> + * Arguments:
> + * FreeBlock - handle to the FreeBlock object
> + * base - base address of the free block
> + * size - size of the free block
> + *
> + * Return value:
> + * 0 is returned on success. E_NOMEMORY is returned
> + * if can't allocate memory for a free block.
> + ****************************************************************/
> +static int free_block_init(void **FreeBlock, u32 base, u32 size)
> +{
> + free_block_t *p_free_blk;
> +
> + p_free_blk =3D (free_block_t *) kmalloc(sizeof(free_block_t), =20
> GFP_KERNEL);
> + if (!p_free_blk)
> + return -ENOMEM;
> +
> + p_free_blk->base =3D base;
> + p_free_blk->end =3D base + size;
> + p_free_blk->next =3D 0;
> +
> + *FreeBlock =3D p_free_blk;
> +
> + return (0);
> +}
> +
> +/****************************************************************
> + * Routine: busy_block_init
> + *
> + * Description:
> + * Initializes a new busy block of "size" bytes and started
> + * rom "base" address. Each busy block has a name that
> + * specified the purpose of the memory allocation.
> + *
> + * Arguments:
> + * BusyBlock - handle to the BusyBlock object
> + * base - base address of the busy block
> + * size - size of the busy block
> + * name - name that specified the busy block
> + *
> + * Return value:
> + * 0 is returned on success. E_NOMEMORY is returned
> + * if can't allocate memory for busy block.
> + ****************************************************************/
> +static int busy_block_init(void **BusyBlock, u32 base, u32 size, =20
> char *name)
> +{
> + busy_block_t *p_busy_blk;
> + int n, NameLen;
> +
> + p_busy_blk =3D (busy_block_t *) kmalloc(sizeof(busy_block_t), =20
> GFP_KERNEL);
> + if (!p_busy_blk)
> + return -ENOMEM;
> +
> + p_busy_blk->base =3D base;
> + p_busy_blk->end =3D base + size;
> + NameLen =3D (int)strlen(name);
> + n =3D (NameLen > MAX_NAME_LEN - 1) ? MAX_NAME_LEN - 1 : NameLen;
> + strncpy(p_busy_blk->name, name, (u32) n);
> + p_busy_blk->name[n] =3D '\0';
> + p_busy_blk->next =3D 0;
> +
> + *BusyBlock =3D p_busy_blk;
> +
> + return (0);
> +}
> +
> +/****************************************************************
> + * Routine: add_free
> + *
> + * Description:
> + * Adds a new free block to the free lists. It updates each
> + * free list to include a new free block.
> + * Note, that all free block in each free list are ordered
> + * by their base address.
> + *
> + * Arguments:
> + * p_mm - pointer to the MM object
> + * base - base address of a given free block
> + * end - end address of a given free block
> + *
> + * Return value:
> + *
> + *
> + ****************************************************************/
> +static int add_free(mm_t * p_mm, u32 base, u32 end)
> +{
> + free_block_t *p_prev_blk, *p_curr_blk, *p_new_blk;
> + u32 align;
> + int i;
> + u32 align_base;
> +
> + /* Updates free lists to include a just released block */
> + for (i =3D 0; i <=3D MAX_ALIGNMENT; i++) {
> + p_prev_blk =3D p_new_blk =3D 0;
> + p_curr_blk =3D p_mm->free_blocks[i];
> +
> + align =3D (u32) (0x1 << i);
> + align_base =3D MAKE_ALIGNED(base, align);
> +
> + /* Goes to the next free list if there is no block to
free */
> + if (align_base >=3D end)
> + continue;
> +
> + /* Looks for a free block that should be updated */
> + while (p_curr_blk) {
> + if (align_base <=3D p_curr_blk->end) {
> + if (end > p_curr_blk->end) {
> + free_block_t *p_NextB;
> + while (p_curr_blk->next
> + && end >
p_curr_blk->next->end) {
> + p_NextB =3D
p_curr_blk->next;
> + p_curr_blk->next =3D
> +
p_curr_blk->next->next;
> + kfree(p_NextB);
> + }
> +
> + p_NextB =3D p_curr_blk->next;
> + if (!p_NextB
> + || (p_NextB
> + && end < p_NextB->base))
{
> + p_curr_blk->end =3D end;
> + } else {
> + p_curr_blk->end =3D
p_NextB->end;
> + p_curr_blk->next =3D
> + p_NextB->next;
> + kfree(p_NextB);
> + }
> + } else if (end < p_curr_blk->base
> + && ((end - align_base) >=3D
align)) {
> + if (free_block_init
> + ((void *)&p_new_blk,
align_base,
> + end - align_base) !=3D 0)
> + return -ENOMEM;
> + p_new_blk->next =3D p_curr_blk;
> + if (p_prev_blk)
> + p_prev_blk->next =3D
p_new_blk;
> + else
> + p_mm->free_blocks[i] =3D
> + p_new_blk;
> + break;
> + }
> +
> + if (align_base < p_curr_blk->base
> + && end >=3D p_curr_blk->base)
> + p_curr_blk->base =3D align_base;
> +
> + /* if size of the free block is less
then
> + * alignment deletes that free block
from
> + * the free list. */
> + if ((p_curr_blk->end - p_curr_blk->base)
<
> + align) {
> + if (p_prev_blk)
> + p_prev_blk->next =3D
> + p_curr_blk->next;
> + else
> + p_mm->free_blocks[i] =3D
> + p_curr_blk->next;
> + kfree(p_curr_blk);
> + }
> + break;
> + } else {
> + p_prev_blk =3D p_curr_blk;
> + p_curr_blk =3D p_curr_blk->next;
> + }
> + }
> +
> + /* If no free block found to be updated, insert a new
free block
> + * to the end of the free list. */
> + if (!p_curr_blk && ((end - base) % align =3D=3D 0)) {
> + if (free_block_init
> + ((void *)&p_new_blk, align_base, end - base)
!=3D 0)
> + return -ENOMEM;
> + if (p_prev_blk)
> + p_prev_blk->next =3D p_new_blk;
> + else
> + p_mm->free_blocks[i] =3D p_new_blk;
> + }
> +
> + /* Update boundaries of the new free block */
> + if (align =3D=3D 1 && !p_new_blk) {
> + if (p_curr_blk && base > p_curr_blk->base)
> + base =3D p_curr_blk->base;
> + if (p_curr_blk && end < p_curr_blk->end)
> + end =3D p_curr_blk->end;
> + }
> + }
> +
> + return (0);
> +}
> +
> +/****************************************************************
> + * Routine: cut_free
> + *
> + * Description:
> + * Cuts a free block from hold_base to hold_end from the free =20
> lists.
> + * That is, it updates all free lists of the MM object do
> + * not include a block of memory from hold_base to hold_end.
> + * For each free lists it seek for a free block that holds
> + * either hold_base or hold_end. If such block is found it =20
> updates it.
> + *
> + * Arguments:
> + * p_mm - pointer to the MM object
> + * hold_base - base address of the allocated block
> + * hold_end - end address of the allocated block
> + *
> + * Return value:
> + * 0 is returned on success,
> + * otherwise returns an error code.
> + *
> + ****************************************************************/
> +static int cut_free(mm_t * p_mm, u32 hold_base, u32 hold_end)
> +{
> + free_block_t *p_prev_blk, *p_curr_blk, *p_new_blk;
> + u32 align_base, base, end, align;
> + int i;
> +
> + for (i =3D 0; i <=3D MAX_ALIGNMENT; i++) {
> + p_prev_blk =3D p_new_blk =3D 0;
> + p_curr_blk =3D p_mm->free_blocks[i];
> +
> + align =3D (u32) 0x1 << i;
> + align_base =3D MAKE_ALIGNED(hold_end, align);
> +
> + while (p_curr_blk) {
> + base =3D p_curr_blk->base;
> + end =3D p_curr_blk->end;
> +
> + if (hold_base <=3D base && hold_end <=3D end
> + && hold_end > base) {
> + if (align_base >=3D end
> + || (align_base < end
> + && (end - align_base) < align))
{
> + if (p_prev_blk)
> + p_prev_blk->next =3D
> + p_curr_blk->next;
> + else
> + p_mm->free_blocks[i] =3D
> + p_curr_blk->next;
> + kfree(p_curr_blk);
> + } else {
> + p_curr_blk->base =3D align_base;
> + }
> + break;
> + } else if (hold_base > base && hold_end <=3D end)
{
> + if ((hold_base - base) >=3D align) {
> + if (align_base < end
> + && (end - align_base) >=3D
align) {
> + if (free_block_init
> + ((void *)&p_new_blk,
> + align_base,
> + (end - align_base))
!=3D 0)
> + return -ENOMEM;
> + p_new_blk->next =3D
> + p_curr_blk->next;
> + p_curr_blk->next =3D
p_new_blk;
> + }
> + p_curr_blk->end =3D hold_base;
> + } else if (align_base < end
> + && (end - align_base) >=3D
align) {
> + p_curr_blk->base =3D align_base;
> + } else {
> + if (p_prev_blk)
> + p_prev_blk->next =3D
> + p_curr_blk->next;
> + else
> + p_mm->free_blocks[i] =3D
> + p_curr_blk->next;
> + kfree(p_curr_blk);
> + }
> + break;
> + } else {
> + p_prev_blk =3D p_curr_blk;
> + p_curr_blk =3D p_curr_blk->next;
> + }
> + }
> + }
> +
> + return (0);
> +}
> +
> +/****************************************************************
> + * Routine: add_busy
> + *
> + * Description:
> + * Adds a new busy block to the list of busy blocks. Note,
> + * that all busy blocks are ordered by their base address in
> + * the busy list.
> + *
> + * Arguments:
> + * MM - handler to the MM object
> + * p_new_busy_blk - pointer to the a busy block
> + *
> + * Return value:
> + * None.
> + *
> + ****************************************************************/
> +static void add_busy(mm_t * p_mm, busy_block_t * p_new_busy_blk)
> +{
> + busy_block_t *p_cur_busy_blk, *p_prev_busy_blk;
> +
> + /* finds a place of a new busy block in the list of busy blocks
*/
> + p_prev_busy_blk =3D 0;
> + p_cur_busy_blk =3D p_mm->busy_blocks;
> +
> + while (p_cur_busy_blk && p_new_busy_blk->base > p_cur_busy_blk-=20
> >base) {
> + p_prev_busy_blk =3D p_cur_busy_blk;
> + p_cur_busy_blk =3D p_cur_busy_blk->next;
> + }
> +
> + /* insert the new busy block into the list of busy blocks */
> + if (p_cur_busy_blk)
> + p_new_busy_blk->next =3D p_cur_busy_blk;
> + if (p_prev_busy_blk)
> + p_prev_busy_blk->next =3D p_new_busy_blk;
> + else
> + p_mm->busy_blocks =3D p_new_busy_blk;
> +
> +}
> +
> +/****************************************************************
> + * Routine: get_greater_align
> + *
> + * Description:
> + * Allocates a block of memory according to the given size
> + * and the alignment. That routine is called from the mm_get
> + * routine if the required alignment is grater then =20
> MAX_ALIGNMENT.
> + * In that case, it goes over free blocks of 64 byte align list
> + * and checks if it has the required size of bytes of the =20
> required
> + * alignment. If no blocks found returns ILLEGAL_BASE.
> + * After the block is found and data is allocated, it calls
> + * the internal cut_free routine to update all free lists
> + * do not include a just allocated block. Of course, each
> + * free list contains a free blocks with the same alignment.
> + * It is also creates a busy block that holds
> + * information about an allocated block.
> + *
> + * Arguments:
> + * MM - handle to the MM object
> + * size - size of the MM
> + * align - index as a power of two defines
> + * a required alignment that is grater then =20
> 64.
> + * name - the name that specifies an allocated block.
> + *
> + * Return value:
> + * base address of an allocated block.
> + * ILLEGAL_BASE if can't allocate a block
> + *
> + ****************************************************************/
> +static int get_greater_align(void *MM, u32 size, int align, char =20
> *name)
> +{
> + mm_t *p_mm =3D (mm_t *) MM;
> + free_block_t *p_free_blk;
> + busy_block_t *p_new_busy_blk;
> + u32 hold_base, hold_end, align_base =3D 0;
> + u32 ret;
> +
> + /* goes over free blocks of the 64 byte alignment list
> + * and look for a block of the suitable size and
> + * base address according to the alignment.
> + */
> + p_free_blk =3D p_mm->free_blocks[MAX_ALIGNMENT];
> +
> + while (p_free_blk) {
> + align_base =3D MAKE_ALIGNED(p_free_blk->base, align);
> +
> + /* the block is found if the aligned base inside the
block
> + * and has the anough size.
> + */
> + if (align_base >=3D p_free_blk->base &&
> + align_base < p_free_blk->end &&
> + size <=3D (p_free_blk->end - align_base))
> + break;
> + else
> + p_free_blk =3D p_free_blk->next;
> + }
> +
> + /* If such block isn't found */
> + if (!p_free_blk)
> + return -EBUSY;
> +
> + hold_base =3D align_base;
> + hold_end =3D align_base + size;
> +
> + /* init a new busy block */
> + if ((ret =3D
> + busy_block_init((void *)&p_new_busy_blk, hold_base, size,
> + name)) !=3D 0)
> + return ret;
> +
> + /* calls Update routine to update a lists of free blocks */
> + if ((ret =3D cut_free(MM, hold_base, hold_end)) !=3D 0)
> + return ret;
> +
> + /* insert the new busy block into the list of busy blocks */
> + add_busy(p_mm, p_new_busy_blk);
> +
> + return (hold_base);
> +}
> +
> +/=20
> **********************************************************************
> + * MM API routines =20
> set *
> + =20
> **********************************************************************
> /
> +int mm_init(void **MM, u32 base, u32 size)
> +{
> + mm_t *p_mm;
> + int i;
> + u32 new_base, new_size;
> +
> + /* Initializes a new MM object */
> + p_mm =3D (mm_t *) kmalloc(sizeof(mm_t), GFP_KERNEL);
> + if (p_mm =3D=3D 0)
> + return -ENOMEM;
> +
> + /* initializes a new memory block */
> + if (mem_block_init((void *)&p_mm->mem_blocks, base, size) !=3D 0)
> + return -ENOMEM;
> +
> + /* A busy list is empty */
> + p_mm->busy_blocks =3D 0;
> +
> + /*Initializes a new free block for each free list */
> + for (i =3D 0; i <=3D MAX_ALIGNMENT; i++) {
> + new_base =3D MAKE_ALIGNED(base, (0x1 << i));
> + new_size =3D size - (new_base - base);
> + if (free_block_init((void *)&p_mm->free_blocks[i],
> + new_base, new_size) !=3D 0)
> + return -ENOMEM;
> + }
> +
> + *MM =3D p_mm;
> +
> + return (0);
> +}
> +
> +EXPORT_SYMBOL(mm_init);
> +
> +void mm_free(void *MM)
> +{
> + mm_t *p_mm =3D (mm_t *) MM;
> + mem_block_t *p_mem_blk;
> + busy_block_t *p_busy_blk;
> + free_block_t *p_free_blk;
> + void *p_blk;
> + int i;
> +
> + if (!p_mm)
> + return;
> +
> + /* release memory allocated for busy blocks */
> + p_busy_blk =3D p_mm->busy_blocks;
> + while (p_busy_blk) {
> + p_blk =3D p_busy_blk;
> + p_busy_blk =3D p_busy_blk->next;
> + kfree(p_blk);
> + }
> +
> + /* release memory allocated for free blocks */
> + for (i =3D 0; i <=3D MAX_ALIGNMENT; i++) {
> + p_free_blk =3D p_mm->free_blocks[i];
> + while (p_free_blk) {
> + p_blk =3D p_free_blk;
> + p_free_blk =3D p_free_blk->next;
> + kfree(p_blk);
> + }
> + }
> +
> + /* release memory allocated for memory blocks */
> + p_mem_blk =3D p_mm->mem_blocks;
> + while (p_mem_blk) {
> + p_blk =3D p_mem_blk;
> + p_mem_blk =3D p_mem_blk->next;
> + kfree(p_blk);
> + }
> +
> + /* release memory allocated for MM object itself */
> + kfree(p_mm);
> +}
> +
> +EXPORT_SYMBOL(mm_free);
> +
> +void *mm_get(void *MM, u32 size, int align, char *name)
> +{
> + mm_t *p_mm =3D (mm_t *) MM;
> + free_block_t *p_free_blk;
> + busy_block_t *p_new_busy_blk;
> + u32 hold_base, hold_end;
> + u32 i =3D 0, j =3D (u32) align;
> + u32 ret;
> +
> + if (!p_mm)
> + return ERR_PTR(-EINVAL);
> +
> + /* checks that align value is grater then zero */
> + if (align =3D=3D 0)
> + return ERR_PTR(-EINVAL);
> +
> + /* checks if alignment is a power of two,
> + * if it correct and if the required size
> + * is multiple of the given alignment.
> + */
> + while ((j & 0x1) =3D=3D 0) {
> + i++;
> + j =3D j >> 1;
> + }
> +
> + /* if the given alignment isn't power of two, returns an error
*/
> + if (j !=3D 1)
> + return ERR_PTR(-EINVAL);
> +
> + if (i > MAX_ALIGNMENT)
> + return ERR_PTR(get_greater_align(MM, size, align,
name));
> +
> + /* look for a block of the size grater or equal to the
> + * required size.
> + */
> + p_free_blk =3D p_mm->free_blocks[i];
> + while (p_free_blk && (p_free_blk->end - p_free_blk->base) <
size)
> + p_free_blk =3D p_free_blk->next;
> +
> + /* If such block is found */
> + if (!p_free_blk)
> + return ERR_PTR(-ENOMEM);
> +
> + hold_base =3D p_free_blk->base;
> + hold_end =3D hold_base + size;
> +
> + /* init a new busy block */
> + if ((ret =3D
> + busy_block_init((void *)&p_new_busy_blk, hold_base, size,
> + name)) !=3D 0)
> + return ERR_PTR(ret);
> +
> + /* calls Update routine to update a lists of free blocks */
> + if ((ret =3D cut_free(MM, hold_base, hold_end)) !=3D 0)
> + return ERR_PTR(ret);
> +
> + /* insert the new busy block into the list of busy blocks */
> + add_busy(p_mm, p_new_busy_blk);
> +
> + return (void *)(hold_base);
> +}
> +
> +EXPORT_SYMBOL(mm_get);
> +
> +void *mm_get_force(void *MM, u32 base, u32 size, char *name)
> +{
> + mm_t *p_mm =3D (mm_t *) MM;
> + free_block_t *p_free_blk;
> + busy_block_t *p_new_busy_blk;
> + int blk_is_free =3D 0;
> + u32 ret;
> +
> + p_free_blk =3D p_mm->free_blocks[0];/* The biggest free blocks are
in
> + the free list with
alignment 1 */
> + while (p_free_blk) {
> + if (base >=3D p_free_blk->base
> + && (base + size) <=3D p_free_blk->end) {
> + blk_is_free =3D 1;
> + break;
> + } else
> + p_free_blk =3D p_free_blk->next;
> + }
> +
> + if (!blk_is_free)
> + return ERR_PTR(-ENOMEM);
> +
> + /* init a new busy block */
> + if ((ret =3D
> + busy_block_init((void *)&p_new_busy_blk, base, size, name))
!=20
> =3D 0)
> + return ERR_PTR(ret);
> +
> + /* calls Update routine to update a lists of free blocks */
> + if ((ret =3D cut_free(MM, base, base + size)) !=3D 0)
> + return ERR_PTR(ret);
> +
> + /* insert the new busy block into the list of busy blocks */
> + add_busy(p_mm, p_new_busy_blk);
> + return (void *)(base);
> +}
> +
> +EXPORT_SYMBOL(mm_get_force);
> +
> +int mm_put(void *MM, u32 base)
> +{
> + mm_t *p_mm =3D (mm_t *) MM;
> + busy_block_t *p_busy_blk, *p_prev_busy_blk;
> + u32 size;
> + u32 ret;
> +
> + if (!p_mm)
> + return -EINVAL;
> +
> + /* Look for a busy block that have the given base value.
> + * That block will be returned back to the memory.
> + */
> + p_prev_busy_blk =3D 0;
> + p_busy_blk =3D p_mm->busy_blocks;
> + while (p_busy_blk && base !=3D p_busy_blk->base) {
> + p_prev_busy_blk =3D p_busy_blk;
> + p_busy_blk =3D p_busy_blk->next;
> + }
> +
> + if (!p_busy_blk)
> + return -EINVAL;
> +
> + if ((ret =3D add_free(p_mm, p_busy_blk->base, p_busy_blk->end)) !=3D
0)
> + return ret;
> +
> + /* removes a busy block form the list of busy blocks */
> + if (p_prev_busy_blk)
> + p_prev_busy_blk->next =3D p_busy_blk->next;
> + else
> + p_mm->busy_blocks =3D p_busy_blk->next;
> +
> + size =3D p_busy_blk->end - p_busy_blk->base;
> +
> + kfree(p_busy_blk);
> +
> + return (0);
> +}
> +
> +EXPORT_SYMBOL(mm_put);
> +
> +void mm_dump(void *MM)
> +{
> + mm_t *p_mm =3D (mm_t *) MM;
> + free_block_t *p_free_blk;
> + busy_block_t *p_busy_blk;
> + int i;
> +
> + p_busy_blk =3D p_mm->busy_blocks;
> + printk(KERN_INFO "List of busy blocks:\n");
> + while (p_busy_blk) {
> + printk(KERN_INFO "\t0x%08x: (%s: b=3D0x%08x, e=3D0x%08x)\n",
> + (u32) p_busy_blk, p_busy_blk->name,
p_busy_blk->base,
> + p_busy_blk->end);
> + p_busy_blk =3D p_busy_blk->next;
> + }
> +
> + printk(KERN_INFO "Lists of free blocks according to
alignment:\n");
> + for (i =3D 0; i <=3D MAX_ALIGNMENT; i++) {
> + printk(KERN_INFO "%d alignment:\n", (0x1 << i));
> + p_free_blk =3D p_mm->free_blocks[i];
> + while (p_free_blk) {
> + printk(KERN_INFO "\t0x%08x: (b=3D0x%08x,
e=3D0x%08x)\n",
> + (u32) p_free_blk, p_free_blk->base,
> + p_free_blk->end);
> + p_free_blk =3D p_free_blk->next;
> + }
> + printk(KERN_INFO "\n");
> + }
> +}
> +
> +EXPORT_SYMBOL(mm_dump);
> diff --git a/arch/powerpc/sysdev/qe_lib/mm.h b/arch/powerpc/sysdev/=20
> qe_lib/mm.h
> new file mode 100644
> index 0000000..ab30080
> --- /dev/null
> +++ b/arch/powerpc/sysdev/qe_lib/mm.h
> @@ -0,0 +1,6 @@
> +int mm_init ( void **MM, u32 base, u32 size );
> +void mm_free (void * MM);
> +void *mm_get ( void * MM, u32 size, int align, char* name );
> +void *mm_get_force ( void * MM, u32 base, u32 size, char* name );
> +int mm_put ( void * MM, u32 base );
> +void mm_dump ( void * MM );
> diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/=20
> qe_lib/qe.c
> new file mode 100644
> index 0000000..0fbb54c
> --- /dev/null
> +++ b/arch/powerpc/sysdev/qe_lib/qe.c
> @@ -0,0 +1,181 @@
> +/*
> + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights =20
> reserved.
> + *
> + * Author: Li Yang <LeoLi@freescale.com>
> + *
> + * Description:
> + * FSL QE SOC setup.
> + *
> + * Changelog:
> + * Jun 21, 2006 Initial version
> + *
> + * This program is free software; you can redistribute it and/or =20
> modify it
> + * under the terms of the GNU General Public License as =20
> published by the
> + * Free Software Foundation; either version 2 of the License, or =20
> (at your
> + * option) any later version.
> + */
> +
> +#include <linux/config.h>
> +#include <linux/stddef.h>
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/errno.h>
> +#include <linux/major.h>
> +#include <linux/delay.h>
> +#include <linux/irq.h>
> +#include <linux/module.h>
> +#include <linux/device.h>
> +#include <linux/platform_device.h>
> +#include <linux/fsl_devices.h>
> +
> +#include <asm/system.h>
> +#include <asm/atomic.h>
> +#include <asm/io.h>
> +#include <asm/irq.h>
> +#include <asm/prom.h>
> +#include <sysdev/fsl_soc.h>
> +#include <mm/mmu_decl.h>
> +
> +static phys_addr_t qebase =3D -1;
> +
> +phys_addr_t get_qe_base(void)
> +{
> + struct device_node *qe;
> +
> + if (qebase !=3D -1)
> + return qebase;
> +
> + qe =3D of_find_node_by_type(NULL, "qe");
> + if (qe) {
> + unsigned int size;
> + void *prop =3D get_property(qe, "reg", &size);
> + qebase =3D of_translate_address(qe, prop);
> + of_node_put(qe);
> + };
> +
> + return qebase;
> +}
> +
> +EXPORT_SYMBOL(get_qe_base);
> +
> +static int __init ucc_geth_of_init(void)
> +{
> + struct device_node *np;
> + unsigned int i, ucc_num;
> + struct platform_device *ugeth_dev;
> + struct resource res;
> + int ret;
> +
> + for (np =3D NULL, i =3D 0;
> + (np =3D of_find_compatible_node(np, "network", "ucc_geth"))
!=3D =20
> NULL;
> + i++) {
> + struct resource r[2];
> + struct device_node *phy, *mdio;
> + struct ucc_geth_platform_data ugeth_data;
> + unsigned int *id;
> + char *model;
> + void *mac_addr;
> + phandle *ph;
> +
> + memset(r, 0, sizeof(r));
> + memset(&ugeth_data, 0, sizeof(ugeth_data));
> +
> + ret =3D of_address_to_resource(np, 0, &r[0]);
> + if (ret)
> + goto err;
> +
> + ugeth_data.phy_reg_addr =3D r[0].start;
> + r[1].start =3D np->intrs[0].line;
> + r[1].end =3D np->intrs[0].line;
> + r[1].flags =3D IORESOURCE_IRQ;
> +
> + model =3D get_property(np, "model", NULL);
> + ucc_num =3D *((u32 *) get_property(np, "device-id",
NULL));
> + if ((strstr(model, "UCC") =3D=3D NULL) ||
> + (ucc_num < 1) || (ucc_num > 8)) {
> + ret =3D -ENODEV;
> + goto err;
> + }
> + =09
> + ugeth_dev =3D
> + platform_device_register_simple("ucc_geth", ucc_num
- 1,
> + &r[0], np->n_intrs + 1);
> +
> + if (IS_ERR(ugeth_dev)) {
> + ret =3D PTR_ERR(ugeth_dev);
> + goto err;
> + }
> +
> + mac_addr =3D get_property(np, "mac-address", NULL);
> + =09
> + memcpy(ugeth_data.mac_addr, mac_addr, 6);
> +
> + ugeth_data.rx_clock =3D *((u32 *) get_property(np,
"rx-clock",
> + NULL));
> + ugeth_data.tx_clock =3D *((u32 *) get_property(np,
"tx-clock",
> + NULL));
> +
> + ph =3D (phandle *) get_property(np, "phy-handle", NULL);
> + phy =3D of_find_node_by_phandle(*ph);
> +
> + if (phy =3D=3D NULL) {
> + ret =3D -ENODEV;
> + goto unreg;
> + }
> +
> + mdio =3D of_get_parent(phy);
> +
> + id =3D (u32 *) get_property(phy, "reg", NULL);
> + ret =3D of_address_to_resource(mdio, 0, &res);
> + if (ret) {
> + of_node_put(phy);
> + of_node_put(mdio);
> + goto unreg;
> + }
> + =09
> + ugeth_data.phy_id =3D *id;
> + ugeth_data.phy_interrupt =3D phy->intrs[0].line;
> + ugeth_data.phy_interface =3D *((u32 *) get_property(phy,
> + "interface", NULL));
> +
> + /* FIXME: Work around for early chip rev.
*/
> + /* There's a bug in initial chip rev(s) in the RGMII ac
*/
> + /* timing.
*/
> + /* The following compensates by writing to the reserved
*/
> + /* QE Port Output Hold Registers (CPOH1?).
*/=09
> + if ((ugeth_data.phy_interface =3D=3D ENET_1000_RGMII) ||
> + (ugeth_data.phy_interface =3D=3D
ENET_100_RGMII) ||
> + (ugeth_data.phy_interface =3D=3D
ENET_10_RGMII)) {
> + u32 *tmp_reg =3D (u32 *) ioremap(get_immrbase()
> + + 0x14A8, 0x4);
> + u32 tmp_val =3D in_be32(tmp_reg);
> + if (ucc_num =3D=3D 1)
> + out_be32(tmp_reg, tmp_val | 0x00003000);
> + else if (ucc_num =3D=3D 2)
> + out_be32(tmp_reg, tmp_val | 0x0c000000);
> + iounmap(tmp_reg);
> + }
> + =09
> + if (phy->intrs[0].line !=3D 0)
> + ugeth_data.board_flags |=3D
FSL_UGETH_BRD_HAS_PHY_INTR;
> +
> + of_node_put(phy);
> + of_node_put(mdio);
> +
> + ret =3D
> + platform_device_add_data(ugeth_dev, &ugeth_data,
> + sizeof(struct
> +
ucc_geth_platform_data));
> + if (ret)
> + goto unreg;
> + }
> +
> + return 0;
> +
> +unreg:
> + platform_device_unregister(ugeth_dev);
> +err:
> + return ret;
> +}
> +
> +arch_initcall(ucc_geth_of_init);
> diff --git a/arch/powerpc/sysdev/qe_lib/qe_common.c b/arch/powerpc/=20
> sysdev/qe_lib/qe_common.c
> new file mode 100644
> index 0000000..cd0aca9
> --- /dev/null
> +++ b/arch/powerpc/sysdev/qe_lib/qe_common.c
> @@ -0,0 +1,401 @@
> +/*
> + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights =20
> reserved.
> + *
> + * Author: Shlomi Gridish <gridish@freescale.com>
> + *
> + * Description:
> + * General Purpose functions for the global management of the
> + * QUICC Engine (QE).
> + *
> + * Changelog:
> + * Jun 28, 2006 Li Yang <LeoLi@freescale.com>
> + * - Reorganized as qe_lib
> + * - Merged to powerpc arch; add device tree support
> + * - Style fixes
> + *
> + * This program is free software; you can redistribute it and/or =20
> modify it
> + * under the terms of the GNU General Public License as =20
> published by the
> + * Free Software Foundation; either version 2 of the License, or =20
> (at your
> + * option) any later version.
> + */
> +#undef USE_RHEAP
> +#include <linux/errno.h>
> +#include <linux/sched.h>
> +#include <linux/kernel.h>
> +#include <linux/param.h>
> +#include <linux/string.h>
> +#include <linux/mm.h>
> +#include <linux/interrupt.h>
> +#include <linux/bootmem.h>
> +#include <linux/module.h>
> +#include <linux/delay.h>
> +#include <asm/irq.h>
> +#include <asm/page.h>
> +#include <asm/pgtable.h>
> +#include <asm/immap_qe.h>
> +#include <asm/qe.h>
> +#include <asm/prom.h>
> +#ifdef USE_RHEAP
> +#include <asm/rheap.h>
> +#else
> +#include "mm.h"
> +#endif /* USE_RHEAP */
> +
> +/* QE snum state
> +*/
> +typedef enum qe_snum_state {
> + QE_SNUM_STATE_USED, /* used */
> + QE_SNUM_STATE_FREE /* free */
> +} qe_snum_state_e;
> +
> +/* QE snum
> +*/
> +typedef struct qe_snum {
> + u8 num; /* snum */
> + qe_snum_state_e state; /* state */
> +} qe_snum_t;
> +
> +/* We allocate this here because it is used almost exclusively for
> + * the communication processor devices.
> + */
> +EXPORT_SYMBOL(qe_immr);
> +qe_map_t *qe_immr =3D NULL;
> +static qe_snum_t snums[QE_NUM_OF_SNUM]; /* Dynamically allocated
> SNUMs */
> +
> +static void qe_snums_init(void);
> +static void qe_muram_init(void);
> +static int qe_sdma_init(void);
> +
> +void qe_reset(void)
> +{
> + if (qe_immr =3D=3D NULL)
> + qe_immr =3D (qe_map_t *) ioremap(get_qe_base(),
QE_IMMAP_SIZE);
> +
> + qe_snums_init();
> +
> + qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
> + (u8) QE_CR_PROTOCOL_UNSPECIFIED, 0);
> +
> + /* Reclaim the MURAM memory for our use. */
> + qe_muram_init();
> +
> +#ifdef USE_RHEAP
> + if (qe_sdma_init())
> + panic("sdma init failed!");
> +#endif /* USE_RHEAP */
> +}
> +
> +EXPORT_SYMBOL(qe_issue_cmd);
> +int qe_issue_cmd(uint cmd, uint device, u8 mcn_protocol, u32 =20
> cmd_input)
> +{
> + unsigned long flags;
> + u32 cecr;
> + u8 mcn_shift =3D 0, dev_shift =3D 0;
> +
> + local_irq_save(flags);
> + if (cmd =3D=3D QE_RESET) {
> + out_be32(&qe_immr->cp.cecr, (u32) (cmd | QE_CR_FLG));
> + } else {
> + if (cmd =3D=3D QE_ASSIGN_PAGE) {
> + /* Here device is the SNUM, not sub-block */
> + dev_shift =3D QE_CR_SNUM_SHIFT;
> + } else if (cmd =3D=3D QE_ASSIGN_RISC) {
> + /* Here device is the SNUM, and mcnProtocol is
> + * e_QeCmdRiscAssignment value */
> + dev_shift =3D QE_CR_SNUM_SHIFT;
> + mcn_shift =3D QE_CR_MCN_RISC_ASSIGN_SHIFT;
> + } else {
> + if (device =3D=3D QE_CR_SUBBLOCK_USB)
> + mcn_shift =3D QE_CR_MCN_USB_SHIFT;
> + else
> + mcn_shift =3D QE_CR_MCN_NORMAL_SHIFT;
> + }
> +
> + out_be32(&qe_immr->cp.cecdr,
> + immrbar_virt_to_phys((void *)cmd_input));
> + out_be32(&qe_immr->cp.cecr,
> + (cmd | QE_CR_FLG | ((u32) device << dev_shift)
| (u32)
> + mcn_protocol << mcn_shift));
> + }
> +
> + /* wait for the QE_CR_FLG to clear */
> + do {
> + cecr =3D in_be32(&qe_immr->cp.cecr);
> + } while (cecr & QE_CR_FLG);
> + local_irq_restore(flags);
> +
> + return 0;
> +}
> +
> +/* Set a baud rate generator. This needs lots of work. There are
> + * 16 BRGs, which can be connected to the QE channels or output
> + * as clocks. The BRGs are in two different block of internal
> + * memory mapped space.
> + * The baud rate clock is the system clock divided by something.
> + * It was set up long ago during the initial boot phase and is
> + * is given to us.
> + * Baud rate clocks are zero-based in the driver code (as that maps
> + * to port numbers). Documentation uses 1-based numbering.
> + */
> +static unsigned int brg_clk =3D 0;
> +
> +unsigned int get_brg_clk(void)
> +{
> + struct device_node *qe;
> + if (brg_clk)
> + return brg_clk;
> +
> + qe =3D of_find_node_by_type(NULL, "qe");
> + if (qe) {
> + unsigned int size;
> + u32 *prop =3D (u32 *) get_property(qe, "brg-frequency",
&size);
> + brg_clk =3D *prop;
> + of_node_put(qe);
> + };
> + return brg_clk;
> +}
> +
> +/* This function is used by UARTS, or anything else that uses a 16x
> + * oversampled clock.
> + */
> +void qe_setbrg(uint brg, uint rate)
> +{
> + volatile uint *bp;
> + u32 divisor;
> + int div16 =3D 0;
> +
> + bp =3D (uint *) & qe_immr->brg.brgc1;
> + bp +=3D brg;
> +
> + divisor =3D (get_brg_clk() / rate);
> + if (divisor > QE_BRGC_DIVISOR_MAX + 1) {
> + div16 =3D 1;
> + divisor /=3D 16;
> + }
> +
> + *bp =3D ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE;
> + if (div16)
> + *bp |=3D QE_BRGC_DIV16;
> +}
> +
> +static void qe_snums_init(void)
> +{
> + int i;
> +
> + /* Initialize the SNUMs array. */
> + for (i =3D 0; i < QE_NUM_OF_SNUM; i++)
> + snums[i].state =3D QE_SNUM_STATE_FREE;
> +
> + /* Initialize SNUMs (thread serial numbers) according to QE
> + * spec chapter 4, SNUM table */
> + i =3D 0;
> + snums[i++].num =3D 0x04;
> + snums[i++].num =3D 0x05;
> + snums[i++].num =3D 0x0C;
> + snums[i++].num =3D 0x0D;
> + snums[i++].num =3D 0x14;
> + snums[i++].num =3D 0x15;
> + snums[i++].num =3D 0x1C;
> + snums[i++].num =3D 0x1D;
> + snums[i++].num =3D 0x24;
> + snums[i++].num =3D 0x25;
> + snums[i++].num =3D 0x2C;
> + snums[i++].num =3D 0x2D;
> + snums[i++].num =3D 0x34;
> + snums[i++].num =3D 0x35;
> + snums[i++].num =3D 0x88;
> + snums[i++].num =3D 0x89;
> + snums[i++].num =3D 0x98;
> + snums[i++].num =3D 0x99;
> + snums[i++].num =3D 0xA8;
> + snums[i++].num =3D 0xA9;
> + snums[i++].num =3D 0xB8;
> + snums[i++].num =3D 0xB9;
> + snums[i++].num =3D 0xC8;
> + snums[i++].num =3D 0xC9;
> + snums[i++].num =3D 0xD8;
> + snums[i++].num =3D 0xD9;
> + snums[i++].num =3D 0xE8;
> + snums[i++].num =3D 0xE9;
> +}
> +
> +int qe_get_snum(void)
> +{
> + unsigned long flags;
> + int snum =3D -EBUSY;
> + int i;
> +
> + local_irq_save(flags);
> + for (i =3D 0; i < QE_NUM_OF_SNUM; i++) {
> + if (snums[i].state =3D=3D QE_SNUM_STATE_FREE) {
> + snums[i].state =3D QE_SNUM_STATE_USED;
> + snum =3D snums[i].num;
> + break;
> + }
> + }
> + local_irq_restore(flags);
> +
> + return snum;
> +}
> +
> +EXPORT_SYMBOL(qe_get_snum);
> +
> +void qe_put_snum(u8 snum)
> +{
> + int i;
> +
> + for (i =3D 0; i < QE_NUM_OF_SNUM; i++) {
> + if (snums[i].num =3D=3D snum) {
> + snums[i].state =3D QE_SNUM_STATE_FREE;
> + break;
> + }
> + }
> +}
> +
> +EXPORT_SYMBOL(qe_put_snum);
> +
> +static int qe_sdma_init(void)
> +{
> + sdma_t *sdma =3D &qe_immr->sdma;
> + uint sdma_buf_offset;
> +
> + if (!sdma)
> + return -ENODEV;
> +
> + /* allocate 2 internal temporary buffers (512 bytes size each)
for
> + * the SDMA */
> + sdma_buf_offset =3D qe_muram_alloc(512 * 2, 64);
> + if (IS_MURAM_ERR(sdma_buf_offset))
> + return -ENOMEM;
> +
> + out_be32(&sdma->sdebcr, sdma_buf_offset & QE_SDEBCR_BA_MASK);
> + out_be32(&sdma->sdmr, (QE_SDMR_GLB_1_MSK | (0x1 >>
> + QE_SDMR_CEN_SHIFT)));
> +
> + return 0;
> +}
> +
> +/*
> + * muram_alloc / muram_free bits.
> + */
> +static spinlock_t qe_muram_lock;
> +#ifdef USE_RHEAP
> +/* 16 blocks should be enough to satisfy all requests
> + * until the memory subsystem goes up... */
> +static rh_block_t qe_boot_muram_rh_block[16];
> +static rh_info_t qe_muram_info;
> +#else
> +static void *mm =3D NULL;
> +#endif /* USE_RHEAP */
> +
> +static void qe_muram_init(void)
> +{
> + spin_lock_init(&qe_muram_lock);
> +
> +#ifdef USE_RHEAP
> + /* initialize the info header */
> + rh_init(&qe_muram_info, 1,
> + sizeof(qe_boot_muram_rh_block) /
> + sizeof(qe_boot_muram_rh_block[0]),
qe_boot_muram_rh_block);
> +
> + /* Attach the usable muram area */
> + /* XXX: This is actually crap. QE_DATAONLY_BASE and
> + * QE_DATAONLY_SIZE is only a subset of the available muram. It
> + * varies with the processor and the microcode patches
activated.
> + * But the following should be at least safe.
> + */
> + rh_attach_region(&qe_muram_info,
> + (void *)QE_MURAM_DATAONLY_BASE,
> + QE_MURAM_DATAONLY_SIZE);
> +#else
> +#endif /* USE_RHEAP */
> +}
> +
> +/* This function returns an index into the MURAM area.
> + */
> +uint qe_muram_alloc(uint size, uint align)
> +{
> + void *start;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&qe_muram_lock, flags);
> +#ifdef USE_RHEAP
> + qe_muram_info.alignment =3D align;
> + start =3D rh_alloc(&qe_muram_info, size, "QE");
> +#else
> + if (!mm) {
> + mm_init(&mm, (u32)
qe_muram_addr(QE_MURAM_DATAONLY_BASE),
> + QE_MURAM_DATAONLY_SIZE);
> + if (qe_sdma_init())
> + panic("sdma init failed!");
> +
> + }
> + start =3D mm_get(mm, (u32) size, (int)align, "QE");
> + if (!IS_MURAM_ERR((u32) start))
> + start =3D (void *)((u32) start - (u32) qe_immr->muram);
> +#endif /* USE_RHEAP */
> + spin_unlock_irqrestore(&qe_muram_lock, flags);
> +
> + return (uint) start;
> +}
> +
> +EXPORT_SYMBOL(qe_muram_alloc);
> +
> +int qe_muram_free(uint offset)
> +{
> + int ret;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&qe_muram_lock, flags);
> +#ifdef USE_RHEAP
> + ret =3D rh_free(&qe_muram_info, (void *)offset);
> +#else
> + ret =3D mm_put(mm, (u32) qe_muram_addr(offset));
> +#endif /* USE_RHEAP */
> + spin_unlock_irqrestore(&qe_muram_lock, flags);
> +
> + return ret;
> +}
> +
> +EXPORT_SYMBOL(qe_muram_free);
> +
> +/* not sure if this is ever needed */
> +uint qe_muram_alloc_fixed(uint offset, uint size, uint align)
> +{
> + void *start;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&qe_muram_lock, flags);
> +#ifdef USE_RHEAP
> + qe_muram_info.alignment =3D align;
> + start =3D
> + rh_alloc_fixed(&qe_muram_info, (void *)offset, size, =20
> "commproc");
> +#else
> + start =3D mm_get_force(mm, (u32) offset, (u32) size, "QE");
> + if (!IS_MURAM_ERR((u32) start))
> + start =3D (void *)((u32) start - (u32) qe_immr->muram);
> +#endif /* USE_RHEAP */
> + spin_unlock_irqrestore(&qe_muram_lock, flags);
> +
> + return (uint) start;
> +}
> +
> +EXPORT_SYMBOL(qe_muram_alloc_fixed);
> +
> +void qe_muram_dump(void)
> +{
> +#ifdef USE_RHEAP
> + rh_dump(&qe_muram_info);
> +#else
> + mm_dump(mm);
> +#endif /* USE_RHEAP */
> +}
> +
> +EXPORT_SYMBOL(qe_muram_dump);
> +
> +void *qe_muram_addr(uint offset)
> +{
> + return (void *)&qe_immr->muram[offset];
> +}
> +
> +EXPORT_SYMBOL(qe_muram_addr);
> diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/=20
> sysdev/qe_lib/qe_ic.c
> new file mode 100644
> index 0000000..465630e
> --- /dev/null
> +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c
> @@ -0,0 +1,487 @@
> +/*
> + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights =20
> reserved.
> + *
> + * Author: Shlomi Gridish <gridish@freescale.com>
> + *
> + * Description:
> + * QE Interrupt Controller routines implementations.
> + *
> + * Changelog:
> + * Jun 28, 2006 Li Yang <LeoLi@freescale.com>
> + * - Reorganized as qe_lib
> + * - Merged to powerpc arch; add device tree support
> + * - Style fixes
> + *
> + * This program is free software; you can redistribute it and/or =20
> modify it
> + * under the terms of the GNU General Public License as =20
> published by the
> + * Free Software Foundation; either version 2 of the License, or =20
> (at your
> + * option) any later version.
> + */
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/errno.h>
> +#include <linux/reboot.h>
> +#include <linux/slab.h>
> +#include <linux/stddef.h>
> +#include <linux/sched.h>
> +#include <linux/signal.h>
> +#include <linux/sysdev.h>
> +#include <linux/interrupt.h>
> +
> +#include <asm/irq.h>
> +#include <asm/io.h>
> +#include <asm/qe_ic.h>
> +
> +#include "qe_ic.h"
> +
> +static struct qe_ic_private p_qe_ic;
> +static struct qe_ic_private *primary_qe_ic;
> +
> +static struct qe_ic_info qe_ic_info[] =3D {
> + [1] =3D {
> + .mask =3D 0x00008000,
> + .qimr =3D 1,
> + .pri_code =3D 0},
> + [2] =3D {
> + .mask =3D 0x00004000,
> + .qimr =3D 1,
> + .pri_code =3D 1},
> + [3] =3D {
> + .mask =3D 0x00002000,
> + .qimr =3D 1,
> + .pri_code =3D 2},
> + [10] =3D {
> + .mask =3D 0x00000040,
> + .qimr =3D 1,
> + .pri_code =3D 1},
> + [11] =3D {
> + .mask =3D 0x00000020,
> + .qimr =3D 1,
> + .pri_code =3D 2},
> + [12] =3D {
> + .mask =3D 0x00000010,
> + .qimr =3D 1,
> + .pri_code =3D 3},
> + [13] =3D {
> + .mask =3D 0x00000008,
> + .qimr =3D 1,
> + .pri_code =3D 4},
> + [14] =3D {
> + .mask =3D 0x00000004,
> + .qimr =3D 1,
> + .pri_code =3D 5},
> + [15] =3D {
> + .mask =3D 0x00000002,
> + .qimr =3D 1,
> + .pri_code =3D 6},
> + [20] =3D {
> + .mask =3D 0x10000000,
> + .qimr =3D 0,
> + .pri_code =3D 3},
> + [25] =3D {
> + .mask =3D 0x00800000,
> + .qimr =3D 0,
> + .pri_code =3D 0},
> + [26] =3D {
> + .mask =3D 0x00400000,
> + .qimr =3D 0,
> + .pri_code =3D 1},
> + [27] =3D {
> + .mask =3D 0x00200000,
> + .qimr =3D 0,
> + .pri_code =3D 2},
> + [28] =3D {
> + .mask =3D 0x00100000,
> + .qimr =3D 0,
> + .pri_code =3D 3},
> + [32] =3D {
> + .mask =3D 0x80000000,
> + .qimr =3D 1,
> + .pri_code =3D 0},
> + [33] =3D {
> + .mask =3D 0x40000000,
> + .qimr =3D 1,
> + .pri_code =3D 1},
> + [34] =3D {
> + .mask =3D 0x20000000,
> + .qimr =3D 1,
> + .pri_code =3D 2},
> + [35] =3D {
> + .mask =3D 0x10000000,
> + .qimr =3D 1,
> + .pri_code =3D 3},
> + [36] =3D {
> + .mask =3D 0x08000000,
> + .qimr =3D 1,
> + .pri_code =3D 4},
> + [40] =3D {
> + .mask =3D 0x00800000,
> + .qimr =3D 1,
> + .pri_code =3D 0},
> + [41] =3D {
> + .mask =3D 0x00400000,
> + .qimr =3D 1,
> + .pri_code =3D 1},
> + [42] =3D {
> + .mask =3D 0x00200000,
> + .qimr =3D 1,
> + .pri_code =3D 2},
> + [43] =3D {
> + .mask =3D 0x00100000,
> + .qimr =3D 1,
> + .pri_code =3D 3},
> +};
> +
> +struct hw_interrupt_type qe_ic =3D {
> + .typename =3D "QE IC",
> + .enable =3D qe_ic_enable_irq,
> + .disable =3D qe_ic_disable_irq,
> + .ack =3D qe_ic_disable_irq_and_ack,
> + .end =3D qe_ic_end_irq,
> +};
> +
> +static int qe_ic_get_low_irq(struct pt_regs *regs)
> +{
> + struct qe_ic_private *p_qe_ic =3D primary_qe_ic;
> + int irq =3D -1;
> +
> + /* get the low byte of SIVEC to get the interrupt source vector.
*/
> + irq =3D (in_be32(&p_qe_ic->regs->qivec) >> 24) >> 2;
> +
> + if (irq =3D=3D 0) /* 0 --> no irq is pending */
> + return -1;
> +
> + return irq + p_qe_ic->irq_offset;
> +}
> +
> +static int qe_ic_get_high_irq(struct pt_regs *regs)
> +{
> + struct qe_ic_private *p_qe_ic =3D primary_qe_ic;
> + int irq =3D -1;
> +
> + /* get the high byte of SIVEC to get the interrupt source
vector. */
> + irq =3D (in_be32(&p_qe_ic->regs->qhivec) >> 24) >> 2;
> +
> + if (irq =3D=3D 0) /* 0 --> no irq is pending */
> + return -1;
> +
> + return irq + p_qe_ic->irq_offset;
> +}
> +
> +static irqreturn_t qe_ic_cascade_low(int irq, void *dev_id,
> + struct pt_regs *regs)
> +{
> + while ((irq =3D qe_ic_get_low_irq(regs)) >=3D 0)
> + __do_IRQ(irq, regs);
> + return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t qe_ic_cascade_high(int irq, void *dev_id,
> + struct pt_regs *regs)
> +{
> + while ((irq =3D qe_ic_get_high_irq(regs)) >=3D 0)
> + __do_IRQ(irq, regs);
> + return IRQ_HANDLED;
> +}
> +
> +static struct irqaction qe_ic_low_irqaction =3D {
> + .handler =3D qe_ic_cascade_low,
> + .flags =3D SA_INTERRUPT,
> + .mask =3D CPU_MASK_NONE,
> + .name =3D "qe_ic_cascade_low",
> +};
> +
> +static struct irqaction qe_ic_high_irqaction =3D {
> + .handler =3D qe_ic_cascade_high,
> + .flags =3D SA_INTERRUPT,
> + .mask =3D CPU_MASK_NONE,
> + .name =3D "qe_ic_cascade_high",
> +};
> +
> +int qe_ic_init(phys_addr_t phys_addr,
> + unsigned int flags, unsigned int irq_offset)
> +{
> + struct qe_ic_map *regs;
> + u8 grp, pri, shift =3D 0;
> + u32 tmp_qicr =3D 0, tmp_qricr =3D 0, tmp_qicnr =3D 0, tmp_mask;
> + int i, high_hctive =3D 0;
> + const u32 high_signal =3D 2;
> +
> + primary_qe_ic =3D &p_qe_ic;
> + memset(primary_qe_ic, 0, sizeof(struct qe_ic_private));
> +
> + /* initialize QE interrupt controller registers */
> + primary_qe_ic->regs =3D regs =3D
> + (struct qe_ic_map *)ioremap(phys_addr, QE_IC_SIZE);
> + primary_qe_ic->irq_offset =3D irq_offset;
> +
> + /* default priority scheme is grouped. If spread mode is */
> + /* required, configure sicr accordingly. */
> + if (flags & QE_IC_SPREADMODE_GRP_W)
> + tmp_qicr |=3D QICR_GWCC;
> + if (flags & QE_IC_SPREADMODE_GRP_X)
> + tmp_qicr |=3D QICR_GXCC;
> + if (flags & QE_IC_SPREADMODE_GRP_Y)
> + tmp_qicr |=3D QICR_GYCC;
> + if (flags & QE_IC_SPREADMODE_GRP_Z)
> + tmp_qicr |=3D QICR_GZCC;
> + if (flags & QE_IC_SPREADMODE_GRP_RISCA)
> + tmp_qicr |=3D QICR_GRTA;
> + if (flags & QE_IC_SPREADMODE_GRP_RISCB)
> + tmp_qicr |=3D QICR_GRTB;
> +
> + /* choose destination signal for highest priority interrupt */
> + if (flags & QE_IC_HIGH_SIGNAL) {
> + tmp_qicr |=3D (high_signal << QICR_HPIT_SHIFT);
> + high_hctive =3D 1;
> + }
> +
> + out_be32(®s->qicr, tmp_qicr);
> +
> + tmp_mask =3D (1 << QE_IC_GRP_W_DEST_SIGNAL_SHIFT);
> + /* choose destination signal for highest priority interrupt in
each
> + * group */
> + for (grp =3D 0; grp < NUM_OF_QE_IC_GROUPS; grp++) {
> + /* the first 2 priorities in each group have a choice of
> + * destination signal */
> + for (pri =3D 0; pri <=3D 1; pri++) {
> + if (flags & ((tmp_mask << (grp << 1)) << pri)) {
> + /* indicate whether QE High signal is
> + * required */
> + if (!high_hctive)
> + high_hctive =3D 1;
> +
> + /* The location of the bits relevant to
> + * priority 0 in the */
> + /* registers is always 2 bits left
comparing
> + * to priority 1. */
> + if (pri =3D=3D 0)
> + shift =3D 2;
> +
> + switch (grp) {
> + case (QE_IC_GRP_W):
> + shift +=3D QICNR_WCC1T_SHIFT;
> + tmp_qicnr |=3D high_signal <<
shift;
> + break;
> + case (QE_IC_GRP_X):
> + shift +=3D QICNR_XCC1T_SHIFT;
> + tmp_qicnr |=3D high_signal <<
shift;
> + break;
> + case (QE_IC_GRP_Y):
> + shift +=3D QICNR_YCC1T_SHIFT;
> + tmp_qicnr |=3D high_signal <<
shift;
> + break;
> + case (QE_IC_GRP_Z):
> + shift +=3D QICNR_ZCC1T_SHIFT;
> + tmp_qicnr |=3D high_signal <<
shift;
> + break;
> + case (QE_IC_GRP_RISCA):
> + shift +=3D QRICR_RTA1T_SHIFT;
> + tmp_qricr |=3D high_signal <<
shift;
> + break;
> + case (QE_IC_GRP_RISCB):
> + shift +=3D QRICR_RTB1T_SHIFT;
> + tmp_qricr |=3D high_signal <<
shift;
> + break;
> + default:
> + break;
> + }
> + }
> + }
> + }
> +
> + if (tmp_qicnr)
> + out_be32(®s->qicnr, tmp_qicnr);
> + if (tmp_qricr)
> + out_be32(®s->qricr, tmp_qricr);
> +
> + for (i =3D primary_qe_ic->irq_offset;
> + i < (NR_QE_IC_INTS + primary_qe_ic->irq_offset); i++) {
> + irq_desc[i].handler =3D &qe_ic;
> + irq_desc[i].status =3D IRQ_LEVEL;
> + }
> +
> + /* register QE_IC interrupt controller in the a higher hirarchy
> + * controller */
> + setup_irq(IRQ_QE_LOW, &qe_ic_low_irqaction);
> +
> + if (high_hctive)
> + /* register QE_IC high interrupt source in the higher
> + * hirarchy controller */
> + setup_irq(IRQ_QE_HIGH, &qe_ic_high_irqaction);
> +
> + printk("QE IC (%d IRQ sources) at %p\n", NR_QE_IC_INTS,
> + primary_qe_ic->regs);
> + return 0;
> +}
> +
> +void qe_ic_free(void)
> +{
> +}
> +
> +void qe_ic_enable_irq(unsigned int irq)
> +{
> + struct qe_ic_private *p_qe_ic =3D primary_qe_ic;
> + unsigned int src =3D irq - p_qe_ic->irq_offset;
> + u32 qimr;
> +
> + if (qe_ic_info[src].qimr) {
> + qimr =3D in_be32(&((struct qe_ic_private
*)p_qe_ic)->regs->qimr);
> + out_be32(&((struct qe_ic_private *)p_qe_ic)->regs->qimr,
> + qimr | (qe_ic_info[src].mask));
> + } else {
> + qimr =3D in_be32(&((struct qe_ic_private
*)p_qe_ic)->regs->qrimr);
> + out_be32(&((struct qe_ic_private
*)p_qe_ic)->regs->qrimr,
> + qimr | (qe_ic_info[src].mask));
> + }
> +}
> +
> +void qe_ic_disable_irq(unsigned int irq)
> +{
> + struct qe_ic_private *p_qe_ic =3D primary_qe_ic;
> + unsigned int src =3D irq - p_qe_ic->irq_offset;
> + u32 qimr;
> +
> + if (qe_ic_info[src].qimr) {
> + qimr =3D in_be32(&((struct qe_ic_private
*)p_qe_ic)->regs->qimr);
> + out_be32(&((struct qe_ic_private *)p_qe_ic)->regs->qimr,
> + qimr & ~(qe_ic_info[src].mask));
> + } else {
> + qimr =3D in_be32(&((struct qe_ic_private
*)p_qe_ic)->regs->qrimr);
> + out_be32(&((struct qe_ic_private
*)p_qe_ic)->regs->qrimr,
> + qimr & ~(qe_ic_info[src].mask));
> + }
> +}
> +
> +void qe_ic_disable_irq_and_ack(unsigned int irq)
> +{
> + qe_ic_disable_irq(irq);
> +}
> +
> +void qe_ic_end_irq(unsigned int irq)
> +{
> +
> + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))
> + && irq_desc[irq].action)
> + qe_ic_enable_irq(irq);
> +}
> +
> +void qe_ic_modify_highest_priority(unsigned int irq)
> +{
> + struct qe_ic_private *p_qe_ic =3D primary_qe_ic;
> + unsigned int src =3D irq - p_qe_ic->irq_offset;
> + u32 tmp_qicr =3D 0;
> +
> + tmp_qicr =3D in_be32(&p_qe_ic->regs->qicr);
> + out_be32(&p_qe_ic->regs->qicr, (u32) (tmp_qicr | ((u8) src <<
24)));
> +}
> +
> +void qe_ic_modify_priority(enum qe_ic_grp_id grp,
> + unsigned int pri0,
> + unsigned int pri1,
> + unsigned int pri2,
> + unsigned int pri3,
> + unsigned int pri4,
> + unsigned int pri5,
> + unsigned int pri6, unsigned int pri7)
> +{
> + struct qe_ic_private *p_qe_ic =3D primary_qe_ic;
> + volatile u32 *p_qip =3D 0;
> + u32 tmp_qip =3D 0;
> + u8 tmp_array[8] =3D { 0, 0, 0, 0, 0, 0, 0, 0 };
> + signed char code_array[8], i =3D 0, j =3D 0;
> +
> + code_array[0] =3D (signed char)(pri0 ? qe_ic_info[pri0].pri_code :
> -1);
> + code_array[1] =3D (signed char)(pri1 ? qe_ic_info[pri1].pri_code :
> -1);
> + code_array[2] =3D (signed char)(pri2 ? qe_ic_info[pri2].pri_code :
> -1);
> + code_array[3] =3D (signed char)(pri3 ? qe_ic_info[pri3].pri_code :
> -1);
> + code_array[4] =3D (signed char)(pri4 ? qe_ic_info[pri4].pri_code :
> -1);
> + code_array[5] =3D (signed char)(pri5 ? qe_ic_info[pri5].pri_code :
> -1);
> + code_array[6] =3D (signed char)(pri6 ? qe_ic_info[pri6].pri_code :
> -1);
> + code_array[7] =3D (signed char)(pri7 ? qe_ic_info[pri7].pri_code :
> -1);
> +
> + for (i =3D 0; i < 8; i++) {
> + if (code_array[i] =3D=3D -1)
> + break;
> + tmp_array[code_array[i]] =3D 1;
> + }
> +
> + for (; i < 8; i++) {
> + while (tmp_array[j] && j < 8)
> + j++;
> + code_array[i] =3D j;
> + tmp_array[j] =3D 1;
> + }
> +
> + tmp_qip =3D (u32) (code_array[0] << QIPCC_SHIFT_PRI0 |
> + code_array[1] << QIPCC_SHIFT_PRI1 |
> + code_array[2] << QIPCC_SHIFT_PRI2 |
> + code_array[3] << QIPCC_SHIFT_PRI3 |
> + code_array[4] << QIPCC_SHIFT_PRI4 |
> + code_array[5] << QIPCC_SHIFT_PRI5 |
> + code_array[6] << QIPCC_SHIFT_PRI6 |
> + code_array[7] << QIPCC_SHIFT_PRI7);
> +
> + switch (grp) {
> + case (QE_IC_GRP_W):
> + p_qip =3D &(p_qe_ic->regs->qipwcc);
> + break;
> + case (QE_IC_GRP_X):
> + p_qip =3D &(p_qe_ic->regs->qipxcc);
> + break;
> + case (QE_IC_GRP_Y):
> + p_qip =3D &(p_qe_ic->regs->qipycc);
> + break;
> + case (QE_IC_GRP_Z):
> + p_qip =3D &(p_qe_ic->regs->qipzcc);
> + break;
> + case (QE_IC_GRP_RISCA):
> + p_qip =3D &(p_qe_ic->regs->qiprta);
> + break;
> + case (QE_IC_GRP_RISCB):
> + p_qip =3D &(p_qe_ic->regs->qiprtb);
> + break;
> + default:
> + break;
> + }
> +
> + out_be32(p_qip, tmp_qip);
> +}
> +
> +void qe_ic_dump_regs(void)
> +{
> + struct qe_ic_private *p_qe_ic =3D primary_qe_ic;
> +
> + printk(KERN_INFO "QE IC registars:\n");
> + printk(KERN_INFO "Base address: 0x%08x\n", (u32) p_qe_ic->regs);
> + printk(KERN_INFO "qicr : addr - 0x%08x, val - 0x%08x\n",
> + (u32) & p_qe_ic->regs->qicr,
in_be32(&p_qe_ic->regs->qicr));
> + printk(KERN_INFO "qivec : addr - 0x%08x, val - 0x%08x\n",
> + (u32) & p_qe_ic->regs->qivec, in_be32(&p_qe_ic->regs-=20
> >qivec));
> + printk(KERN_INFO "qripnr: addr - 0x%08x, val - 0x%08x\n",
> + (u32) & p_qe_ic->regs->qripnr, in_be32(&p_qe_ic->regs-=20
> >qripnr));
> + printk(KERN_INFO "qipnr : addr - 0x%08x, val - 0x%08x\n",
> + (u32) & p_qe_ic->regs->qipnr, in_be32(&p_qe_ic->regs-=20
> >qipnr));
> + printk(KERN_INFO "qipxcc: addr - 0x%08x, val - 0x%08x\n",
> + (u32) & p_qe_ic->regs->qipxcc, in_be32(&p_qe_ic->regs-=20
> >qipxcc));
> + printk(KERN_INFO "qipycc: addr - 0x%08x, val - 0x%08x\n",
> + (u32) & p_qe_ic->regs->qipycc, in_be32(&p_qe_ic->regs-=20
> >qipycc));
> + printk(KERN_INFO "qipwcc: addr - 0x%08x, val - 0x%08x\n",
> + (u32) & p_qe_ic->regs->qipwcc, in_be32(&p_qe_ic->regs-=20
> >qipwcc));
> + printk(KERN_INFO "qipzcc: addr - 0x%08x, val - 0x%08x\n",
> + (u32) & p_qe_ic->regs->qipzcc, in_be32(&p_qe_ic->regs-=20
> >qipzcc));
> + printk(KERN_INFO "qimr : addr - 0x%08x, val - 0x%08x\n",
> + (u32) & p_qe_ic->regs->qimr,
in_be32(&p_qe_ic->regs->qimr));
> + printk(KERN_INFO "qrimr : addr - 0x%08x, val - 0x%08x\n",
> + (u32) & p_qe_ic->regs->qrimr, in_be32(&p_qe_ic->regs-=20
> >qrimr));
> + printk(KERN_INFO "qicnr : addr - 0x%08x, val - 0x%08x\n",
> + (u32) & p_qe_ic->regs->qicnr, in_be32(&p_qe_ic->regs-=20
> >qicnr));
> + printk(KERN_INFO "qiprta: addr - 0x%08x, val - 0x%08x\n",
> + (u32) & p_qe_ic->regs->qiprta, in_be32(&p_qe_ic->regs-=20
> >qiprta));
> + printk(KERN_INFO "qiprtb: addr - 0x%08x, val - 0x%08x\n",
> + (u32) & p_qe_ic->regs->qiprtb, in_be32(&p_qe_ic->regs-=20
> >qiprtb));
> + printk(KERN_INFO "qricr : addr - 0x%08x, val - 0x%08x\n",
> + (u32) & p_qe_ic->regs->qricr, in_be32(&p_qe_ic->regs-=20
> >qricr));
> + printk(KERN_INFO "qhivec: addr - 0x%08x, val - 0x%08x\n",
> + (u32) & p_qe_ic->regs->qhivec, in_be32(&p_qe_ic->regs-=20
> >qhivec));
> +}
> diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.h b/arch/powerpc/=20
> sysdev/qe_lib/qe_ic.h
> new file mode 100644
> index 0000000..6662ad2
> --- /dev/null
> +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.h
> @@ -0,0 +1,83 @@
> +/*
> + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights =20
> reserved.
> + *
> + * Author: Shlomi Gridish <gridish@freescale.com>
> + *
> + * Description:
> + * QE IC private definitions and structure.
> + *
> + * Changelog:
> + * Jun 21, 2006 Li Yang <LeoLi@freescale.com>
> + * - Style fix; port to powerpc arch
> + *
> + * This program is free software; you can redistribute it and/or =20
> modify it
> + * under the terms of the GNU General Public License as =20
> published by the
> + * Free Software Foundation; either version 2 of the License, or =20
> (at your
> + * option) any later version.
> + */
> +#ifndef __QE_IC_H__
> +#define __QE_IC_H__
> +
> +typedef struct qe_ic_map {
> + volatile u32 qicr;
> + volatile u32 qivec;
> + volatile u32 qripnr;
> + volatile u32 qipnr;
> + volatile u32 qipxcc;
> + volatile u32 qipycc;
> + volatile u32 qipwcc;
> + volatile u32 qipzcc;
> + volatile u32 qimr;
> + volatile u32 qrimr;
> + volatile u32 qicnr;
> + volatile u8 res0[0x4];
> + volatile u32 qiprta;
> + volatile u32 qiprtb;
> + volatile u8 res1[0x4];
> + volatile u32 qricr;
> + volatile u8 res2[0x20];
> + volatile u32 qhivec;
> + volatile u8 res3[0x1C];
> +} __attribute__ ((packed)) qe_ic_map_t;
> +
> +
> +#define QE_IC_SIZE sizeof(struct qe_ic_map)
> +
> +/* Interrupt priority registers */
> +#define QIPCC_SHIFT_PRI0 29
> +#define QIPCC_SHIFT_PRI1 26
> +#define QIPCC_SHIFT_PRI2 23
> +#define QIPCC_SHIFT_PRI3 20
> +#define QIPCC_SHIFT_PRI4 13
> +#define QIPCC_SHIFT_PRI5 10
> +#define QIPCC_SHIFT_PRI6 7
> +#define QIPCC_SHIFT_PRI7 4
> +
> +/* QICR priority modes */
> +#define QICR_GWCC 0x00040000
> +#define QICR_GXCC 0x00020000
> +#define QICR_GYCC 0x00010000
> +#define QICR_GZCC 0x00080000
> +#define QICR_GRTA 0x00200000
> +#define QICR_GRTB 0x00400000
> +#define QICR_HPIT_SHIFT 8
> +
> +/* QICNR */
> +#define QICNR_WCC1T_SHIFT 20
> +#define QICNR_ZCC1T_SHIFT 28
> +#define QICNR_YCC1T_SHIFT 12
> +#define QICNR_XCC1T_SHIFT 4
> +
> +/* QRICR */
> +#define QRICR_RTA1T_SHIFT 20
> +#define QRICR_RTB1T_SHIFT 28
> +
> +struct qe_ic_private {
> + struct qe_ic_map *regs;
> + unsigned int irq_offset;
> +} qe_ic_private_t;
> +
> +extern struct hw_interrupt_type qe_ic;
> +extern int qe_ic_get_irq(struct pt_regs *regs);
> +
> +#endif /* __QE_IC_H__ */
> diff --git a/arch/powerpc/sysdev/qe_lib/qe_io.c b/arch/powerpc/=20
> sysdev/qe_lib/qe_io.c
> new file mode 100644
> index 0000000..a943c27
> --- /dev/null
> +++ b/arch/powerpc/sysdev/qe_lib/qe_io.c
> @@ -0,0 +1,275 @@
> +/*
> + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights =20
> reserved.
> + *
> + * Author: Li Yang <LeoLi@freescale.com>
> + *
> + * Description:
> + * QE Parallel I/O ports configuration routines. Based on code from
> + * Shlomi Gridish <gridish@freescale.com>
> + *
> + * Changelog:
> + * Jun 21, 2006 Initial version
> + *
> + * This program is free software; you can redistribute it and/or =20
> modify it
> + * under the terms of the GNU General Public License as =20
> published by the
> + * Free Software Foundation; either version 2 of the License, or =20
> (at your
> + * option) any later version.
> + */
> +
> +#include <linux/config.h>
> +#include <linux/stddef.h>
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/errno.h>
> +#include <linux/module.h>
> +
> +#include <asm/io.h>
> +#include <asm/prom.h>
> +#include <sysdev/fsl_soc.h>
> +#undef DEBUG
> +
> +#define NUM_OF_PINS 32
> +#define NUM_OF_PAR_IOS 7
> +
> +typedef struct par_io {
> + struct {
> + u32 cpodr; /* Open drain register */
> + u32 cpdata; /* Data register */
> + u32 cpdir1; /* Direction register */
> + u32 cpdir2; /* Direction register */
> + u32 cppar1; /* Pin assignment register */
> + u32 cppar2; /* Pin assignment register */
> + } io_regs[NUM_OF_PAR_IOS];
> +} par_io_t;
> +
> +typedef struct qe_par_io {
> + u8 res[0xc];
> + u32 cepier; /* QE ports interrupt event register */
> + u32 cepimr; /* QE ports mask event register */
> + u32 cepicr; /* QE ports control event register */
> +} qe_par_io_t;
> +
> +static int qe_irq_ports[NUM_OF_PAR_IOS][NUM_OF_PINS] =3D {
> + /* 0-7 */ /* 8-15 */ /* 16 - 23 */ /* 24 - 31
*/
> + {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,1, 1,0,0,0,0,0,0,0, =20
> 0,0,0,0,0,1,1,0},
> + {0,0,0,1,0,1,0,0, 0,0,0,0,1,1,0,0, 0,0,0,0,0,0,0,0, =20
> 0,0,1,1,0,0,0,0},
> + {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, =20
> 0,0,0,1,1,1,0,0},
> + {0,0,0,0,0,0,0,0, 0,0,0,0,1,1,0,0, 1,1,0,0,0,0,0,0, =20
> 0,0,1,1,0,0,0,0},
> + {0,0,0,0,0,0,0,0, 0,0,0,0,1,1,0,0, 0,0,0,0,0,0,0,0, =20
> 1,1,1,1,0,0,0,1},
> + {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,1,0,0,0, =20
> 0,0,0,0,0,0,0,0},
> + {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,1}
> +};
> +
> +
> +static u8 get_irq_num(u8 port, u8 pin)
> +{
> + int i, j;
> + u8 num =3D 0;
> +
> + if (qe_irq_ports[port][pin] =3D=3D 0)
> + return -1;
> + for (j =3D 0; j <=3D port; j++)
> + for (i =3D 0; i < pin; i++)
> + if (qe_irq_ports[j][i])
> + num++;
> + return num;
> +}
> +
> +static par_io_t *par_io =3D NULL;
> +static qe_par_io_t *qe_par_io =3D NULL;
> +
> +int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain,
> + int assignment, int has_irq)
> +{
> + u32 pinMask1bit, pinMask2bits, newMask2bits, tmp_val;
> +
> + if (!par_io) {
> + par_io =3D (par_io_t *) ioremap(get_immrbase() + 0x1400,
> + sizeof(par_io_t));
> + qe_par_io =3D (qe_par_io_t *) ioremap(get_immrbase() +
0xC00,
> +
sizeof(qe_par_io_t));
> +
> + /* clear event bits in the event register of the QE
ports */
> + out_be32(&qe_par_io->cepier, 0xFFFFFFFF);
> + }
> +
> + /* calculate pin location for single and 2 bits information */
> + pinMask1bit =3D (u32) (1 << (NUM_OF_PINS - (pin + 1)));
> +
> + /* Set open drain, if required */
> + tmp_val =3D in_be32(&par_io->io_regs[port].cpodr);
> + if (open_drain)
> + out_be32(&par_io->io_regs[port].cpodr, pinMask1bit |
tmp_val);
> + else
> + out_be32(&par_io->io_regs[port].cpodr, ~pinMask1bit &
tmp_val);
> +
> + /* define direction */
> + tmp_val =3D (pin > (NUM_OF_PINS / 2) - 1) ?
> + in_be32(&par_io->io_regs[port].cpdir2) :
> + in_be32(&par_io->io_regs[port].cpdir1);
> +
> + /* get all bits mask for 2 bit per port */
> + pinMask2bits =3D (u32) (0x3 <<
> + (NUM_OF_PINS -
> + (pin % (NUM_OF_PINS / 2) + 1) * 2));
> +
> + /* Get the final mask we need for the right definition */
> + newMask2bits =3D (u32) (dir <<
> + (NUM_OF_PINS -
> + (pin % (NUM_OF_PINS / 2) + 1) * 2));
> +
> + /* clear and set 2 bits mask */
> + if (pin > (NUM_OF_PINS / 2) - 1) {
> + out_be32(&par_io->io_regs[port].cpdir2,
> + ~pinMask2bits & tmp_val);
> + tmp_val &=3D ~pinMask2bits;
> + out_be32(&par_io->io_regs[port].cpdir2, newMask2bits |
tmp_val);
> + } else {
> + out_be32(&par_io->io_regs[port].cpdir1,
> + ~pinMask2bits & tmp_val);
> + tmp_val &=3D ~pinMask2bits;
> + out_be32(&par_io->io_regs[port].cpdir1, newMask2bits |
tmp_val);
> + }
> + /* define pin assignment */
> + tmp_val =3D (pin > (NUM_OF_PINS / 2) - 1) ?
> + in_be32(&par_io->io_regs[port].cppar2) :
> + in_be32(&par_io->io_regs[port].cppar1);
> +
> + newMask2bits =3D (u32) (assignment << (NUM_OF_PINS -
> + (pin % (NUM_OF_PINS / 2) + 1) * 2));
> + /* clear and set 2 bits mask */
> + if (pin > (NUM_OF_PINS / 2) - 1) {
> + out_be32(&par_io->io_regs[port].cppar2,
> + ~pinMask2bits & tmp_val);
> + tmp_val &=3D ~pinMask2bits;
> + out_be32(&par_io->io_regs[port].cppar2, newMask2bits |
tmp_val);
> + } else {
> + out_be32(&par_io->io_regs[port].cppar1,
> + ~pinMask2bits & tmp_val);
> + tmp_val &=3D ~pinMask2bits;
> + out_be32(&par_io->io_regs[port].cppar1, newMask2bits |
tmp_val);
> + }
> +
> + /* Set interrupt mask if the pin generates interrupt */
> + if (has_irq) {
> + int irq =3D get_irq_num(port, pin);
> + u32 mask =3D 0;
> +
> + if (irq =3D=3D -1) {
> + printk(KERN_WARNING "Port %d, pin %d is can't be
"
> + "interrupt\n", port, pin);
> + return -EINVAL;
> + }
> + mask =3D 0x80000000 >> irq;
> +
> + tmp_val =3D in_be32(&qe_par_io->cepimr);
> + out_be32(&qe_par_io->cepimr, mask | tmp_val);
> + }
> +
> + return 0;
> +}
> +
> +EXPORT_SYMBOL(par_io_config_pin);
> +
> +int par_io_data_set(u8 port, u8 pin, u8 val)
> +{
> + u32 pin_mask, tmp_val;
> +
> + if (port >=3D NUM_OF_PAR_IOS)
> + return -EINVAL;
> + if (pin >=3D NUM_OF_PINS)
> + return -EINVAL;
> + /* calculate pin location */
> + pin_mask =3D (u32) (1 << (NUM_OF_PINS - 1 - pin));
> +
> + tmp_val =3D in_be32(&par_io->io_regs[port].cpdata);
> +
> + if (val =3D=3D 0) /* clear */
> + out_be32(&par_io->io_regs[port].cpdata, ~pin_mask &
tmp_val);
> + else /* set */
> + out_be32(&par_io->io_regs[port].cpdata, pin_mask |
tmp_val);
> +
> + return 0;
> +}
> +
> +EXPORT_SYMBOL(par_io_data_set);
> +
> +int par_io_of_config(struct device_node *np)
> +{
> + struct device_node *pio;
> + phandle *ph;
> + int pio_map_len;
> + unsigned int *pio_map;
> +=09
> + ph =3D (phandle *) get_property(np, "pio-handle", NULL);
> + if (ph =3D=3D 0) {
> + printk(KERN_ERR "pio-handle not available \n");
> + return -1;
> + }
> + =09
> + pio =3D of_find_node_by_phandle(*ph);
> +
> + pio_map =3D (unsigned int *)
> + get_property(pio, "pio-map", &pio_map_len);
> + if (pio_map =3D=3D NULL) {
> + printk(KERN_ERR "pio-map is not set! \n");
> + return -1;
> + }
> + pio_map_len /=3D sizeof(unsigned int);
> + if ((pio_map_len % 6) !=3D 0) {
> + printk(KERN_ERR "pio-map format wrong! \n");
> + return -1;
> + }
> +
> + while (pio_map_len > 0) {
> + par_io_config_pin((u8) pio_map[0], (u8) pio_map[1],
> + (int) pio_map[2], (int) pio_map[3],
> + (int) pio_map[4], (int) pio_map[5]);
> + pio_map +=3D 6;
> + pio_map_len -=3D 6;
> + }
> + of_node_put(pio);
> + return 0;
> +}
> +EXPORT_SYMBOL(par_io_of_config);
> +
> +#ifdef DEBUG
> +static void dump_par_io(void)
> +{
> + int i;
> +
> + printk(KERN_INFO "PAR IO registars:\n");
> + printk(KERN_INFO "Base address: 0x%08x\n", (u32) par_io);
> + for (i =3D 0; i < NUM_OF_PAR_IOS; i++) {
> + printk(KERN_INFO "cpodr[%d] : addr - 0x%08x, val -
0x%08x\n",
> + i, (u32) & par_io->io_regs[i].cpodr,
> + in_be32(&par_io->io_regs[i].cpodr));
> + printk(KERN_INFO "cpdata[%d]: addr - 0x%08x, val -
0x%08x\n",
> + i, (u32) & par_io->io_regs[i].cpdata,
> + in_be32(&par_io->io_regs[i].cpdata));
> + printk(KERN_INFO "cpdir1[%d]: addr - 0x%08x, val -
0x%08x\n",
> + i, (u32) & par_io->io_regs[i].cpdir1,
> + in_be32(&par_io->io_regs[i].cpdir1));
> + printk(KERN_INFO "cpdir2[%d]: addr - 0x%08x, val -
0x%08x\n",
> + i, (u32) & par_io->io_regs[i].cpdir2,
> + in_be32(&par_io->io_regs[i].cpdir2));
> + printk(KERN_INFO "cppar1[%d]: addr - 0x%08x, val -
0x%08x\n",
> + i, (u32) & par_io->io_regs[i].cppar1,
> + in_be32(&par_io->io_regs[i].cppar1));
> + printk(KERN_INFO "cppar2[%d]: addr - 0x%08x, val -
0x%08x\n",
> + i, (u32) & par_io->io_regs[i].cppar2,
> + in_be32(&par_io->io_regs[i].cppar2));
> + }
> +
> + printk(KERN_INFO "QE PAR IO registars:\n");
> + printk(KERN_INFO "Base address: 0x%08x\n", (u32) qe_par_io);
> + printk(KERN_INFO "cepier : addr - 0x%08x, val - 0x%08x\n",
> + (u32) & qe_par_io->cepier, in_be32(&qe_par_io->cepier));
> + printk(KERN_INFO "cepimr : addr - 0x%08x, val - 0x%08x\n",
> + (u32) & qe_par_io->cepimr, in_be32(&qe_par_io->cepimr));
> + printk(KERN_INFO "cepicr : addr - 0x%08x, val - 0x%08x\n",
> + (u32) & qe_par_io->cepicr, in_be32(&qe_par_io->cepicr));
> +}
> +
> +EXPORT_SYMBOL(dump_par_io);
> +#endif
> -
> To unsubscribe from this list: send the line "unsubscribe linux-=20
> kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
^ permalink raw reply
* Re: [PATCH 3/7] powerpc: Add QE library qe_lib--common files
From: Kumar Gala @ 2006-06-29 16:33 UTC (permalink / raw)
To: Gridish Shlomi-RM96313
Cc: Phillips Kim-R1AAHA, linux-kernel, linuxppc-dev, Paul Mackerras,
Chu hanjin-r52514
In-Reply-To: <75B28D1B75754E4BAEAF634C9498EC9009904D@zil05exm11.fsl.freescale.net>
On Jun 29, 2006, at 11:06 AM, Gridish Shlomi-RM96313 wrote:
> Hi all,
>
> The reason why I chose to work with MM and not with RHEAP is that,
> apparently, there is a BUG in the RHEAP module,
> it is not allocating correctly blocks that require alignments grater
> than 8.
> The usage of MM is only a temporary solution till RHEAP is fixed.
>
> Regards,
> Shlomi
Will fix rheap than. We aren't going to merge in QE support with a
new memory allocator.
- kumar
> -----Original Message-----
> From: Kumar Gala [mailto:galak@kernel.crashing.org]
> Sent: Wednesday, June 28, 2006 22:20
> To: Li Yang-r58472
> Cc: 'Paul Mackerras'; linuxppc-dev@ozlabs.org;
> 'linux-kernel@vger.kernel.org'; Chu hanjin-r52514; Gridish
> Shlomi-RM96313; Phillips Kim-R1AAHA
> Subject: Re: [PATCH 3/7] powerpc: Add QE library qe_lib--common files
>
> Nack, remove the mm allocation code and just use rheap.
>
> - k
>
> On Jun 28, 2006, at 9:23 AM, Li Yang-r58472 wrote:
>
>>
>> Signed-off-by: Shlomi Gridish <gridish@freescale.com>
>> Signed-off-by: Li Yang <leoli@freescale.com>
>> Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
>>
>> ---
>> arch/powerpc/Kconfig | 12
>> arch/powerpc/sysdev/Makefile | 1
>> arch/powerpc/sysdev/ipic.c | 2
>> arch/powerpc/sysdev/qe_lib/Kconfig | 315 +++++++++++++
>> arch/powerpc/sysdev/qe_lib/Makefile | 8
>> arch/powerpc/sysdev/qe_lib/mm.c | 770 +++++++++++++++++++++
>> +++++++++++
>> arch/powerpc/sysdev/qe_lib/mm.h | 6
>> arch/powerpc/sysdev/qe_lib/qe.c | 181 ++++++++
>> arch/powerpc/sysdev/qe_lib/qe_common.c | 401 +++++++++++++++++
>> arch/powerpc/sysdev/qe_lib/qe_ic.c | 487 ++++++++++++++++++++
>> arch/powerpc/sysdev/qe_lib/qe_ic.h | 83 +++
>> arch/powerpc/sysdev/qe_lib/qe_io.c | 275 +++++++++++
>> 12 files changed, 2541 insertions(+), 0 deletions(-)
>>
>> diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
>> index 6729c98..6d4fc0b 100644
>> --- a/arch/powerpc/Kconfig
>> +++ b/arch/powerpc/Kconfig
>> @@ -334,6 +334,16 @@ config APUS
>> <http://linux-apus.sourceforge.net/>.
>> endchoice
>>
>> +config QUICC_ENGINE
>> + bool
>> + depends on MPC836x
>> + default y
>> + help
>> + The QE(QUICC Engine) is a new generation of coprocessor on
>> + Freescale embedded CPUs(like CPM in older chips). Selecting
>> + this option means that you wish to build a kernel for a
> machine
>> + with QE coprocessor on it.
>> +
>> config PPC_PSERIES
>> depends on PPC_MULTIPLATFORM && PPC64
>> bool " IBM pSeries & new (POWER5-based) iSeries"
>> @@ -993,6 +1003,8 @@ # XXX source "arch/ppc/8xx_io/Kconfig"
>>
>> # XXX source "arch/ppc/8260_io/Kconfig"
>>
>> +source "arch/powerpc/sysdev/qe_lib/Kconfig"
>> +
>> source "arch/powerpc/platforms/iseries/Kconfig"
>>
>> source "lib/Kconfig"
>> diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/
>> Makefile
>> index 4c2b356..cd1d5cc 100644
>> --- a/arch/powerpc/sysdev/Makefile
>> +++ b/arch/powerpc/sysdev/Makefile
>> @@ -8,3 +8,4 @@ obj-$(CONFIG_U3_DART) += dart_iommu.o
>> obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o
>> obj-$(CONFIG_PPC_83xx) += ipic.o
>> obj-$(CONFIG_FSL_SOC) += fsl_soc.o
>> +obj-$(CONFIG_QUICC_ENGINE) += qe_lib/
>> diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c
>> index 8f01e0f..dbeccba 100644
>> --- a/arch/powerpc/sysdev/ipic.c
>> +++ b/arch/powerpc/sysdev/ipic.c
>> @@ -537,12 +537,14 @@ void ipic_set_highest_priority(unsigned
>>
>> void ipic_set_default_priority(void)
>> {
>> +#ifdef CONFIG_MPC834x
>> ipic_set_priority(MPC83xx_IRQ_TSEC1_TX, 0);
>> ipic_set_priority(MPC83xx_IRQ_TSEC1_RX, 1);
>> ipic_set_priority(MPC83xx_IRQ_TSEC1_ERROR, 2);
>> ipic_set_priority(MPC83xx_IRQ_TSEC2_TX, 3);
>> ipic_set_priority(MPC83xx_IRQ_TSEC2_RX, 4);
>> ipic_set_priority(MPC83xx_IRQ_TSEC2_ERROR, 5);
>> +#endif
>> ipic_set_priority(MPC83xx_IRQ_USB2_DR, 6);
>> ipic_set_priority(MPC83xx_IRQ_USB2_MPH, 7);
>>
>> diff --git a/arch/powerpc/sysdev/qe_lib/Kconfig b/arch/powerpc/
>> sysdev/qe_lib/Kconfig
>> new file mode 100644
>> index 0000000..6105237
>> --- /dev/null
>> +++ b/arch/powerpc/sysdev/qe_lib/Kconfig
>> @@ -0,0 +1,315 @@
>> +#
>> +# QE Communication options
>> +#
>> +
>> +menu "QE Options"
>> + depends on QUICC_ENGINE
>> +
>> +config UCC1
>> + bool "Enable QE UCC1"
>> +
>> +choice
>> + prompt "UCC1 speed selection"
>> + depends on UCC1
>> + default UCC1_SLOW
>> +
>> + config UCC1_SLOW
>> + bool "UCC1 is slow"
>> + config UCC1_FAST
>> + bool "UCC1 is fast"
>> +endchoice
>> +
>> +menu "UCC1 Protocols options"
>> + depends on UCC1
>> +
>> + choice
>> + prompt "UCC1 Slow Protocols selection"
>> + depends on UCC1_SLOW
>> + default UCC1_UART
>> +
>> + config UCC1_UART
>> + bool "UCC1 is UART"
>> + endchoice
>> +
>> + choice
>> + prompt "UCC1 Fast Protocols selection"
>> + depends on UCC1_FAST
>> + default UCC1_GETH
>> +
>> + config UCC1_GETH
>> + bool "UCC1 is GETH"
>> + endchoice
>> +endmenu
>> +
>> +config UCC2
>> + bool "Enable QE UCC2"
>> +
>> +choice
>> + prompt "UCC2 speed selection"
>> + depends on UCC2
>> + default UCC2_SLOW
>> +
>> + config UCC2_SLOW
>> + bool "UCC2 is slow"
>> + config UCC2_FAST
>> + bool "UCC2 is fast"
>> +endchoice
>> +
>> +menu "UCC2 Protocols options"
>> + depends on UCC2
>> +
>> + choice
>> + prompt "UCC2 Slow Protocols selection"
>> + depends on UCC2_SLOW
>> + default UCC2_UART
>> +
>> + config UCC2_UART
>> + bool "UCC2 is UART"
>> + endchoice
>> +
>> + choice
>> + prompt "UCC2 Fast Protocols selection"
>> + depends on UCC2_FAST
>> + default UCC2_GETH
>> +
>> + config UCC2_GETH
>> + bool "UCC2 is GETH"
>> + endchoice
>> +endmenu
>> +
>> +config UCC3
>> + bool "Enable QE UCC3"
>> +
>> +choice
>> + prompt "UCC3 speed selection"
>> + depends on UCC3
>> + default UCC3_SLOW
>> +
>> + config UCC3_SLOW
>> + bool "UCC3 is slow"
>> + config UCC3_FAST
>> + bool "UCC3 is fast"
>> +endchoice
>> +
>> +menu "UCC3 Protocols options"
>> + depends on UCC3
>> +
>> + choice
>> + prompt "UCC3 Slow Protocols selection"
>> + depends on UCC3_SLOW
>> + default UCC3_UART
>> +
>> + config UCC3_UART
>> + bool "UCC3 is UART"
>> + endchoice
>> +
>> + config UCC3_GETH
>> + depends on UCC3_FAST
>> + bool "UCC3 is GETH"
>> +
>> + config UCC3_ATM
>> + depends on UCC3_FAST && !UCC3_GETH
>> + tristate "UCC3 is ATM"
>> +endmenu
>> +
>> +config UCC4
>> + bool "Enable QE UCC4"
>> +
>> +choice
>> + prompt "UCC4 speed selection"
>> + depends on UCC4
>> + default UCC4_SLOW
>> +
>> + config UCC4_SLOW
>> + bool "UCC4 is slow"
>> + config UCC4_FAST
>> + bool "UCC4 is fast"
>> +endchoice
>> +
>> +menu "UCC4 Protocols options"
>> + depends on UCC4
>> +
>> + choice
>> + prompt "UCC4 Slow Protocols selection"
>> + depends on UCC4_SLOW
>> + default UCC4_UART
>> +
>> + config UCC4_UART
>> + bool "UCC4 is UART"
>> + endchoice
>> +
>> + choice
>> + prompt "UCC4 Fast Protocols selection"
>> + depends on UCC4_FAST
>> + default UCC4_GETH
>> +
>> + config UCC4_GETH
>> + bool "UCC4 is GETH"
>> + endchoice
>> +endmenu
>> +
>> +config UCC5
>> + bool "Enable QE UCC5"
>> +
>> +choice
>> + prompt "UCC5 speed selection"
>> + depends on UCC5
>> + default UCC5_SLOW
>> +
>> + config UCC5_SLOW
>> + bool "UCC5 is slow"
>> + config UCC5_FAST
>> + bool "UCC5 is fast"
>> +endchoice
>> +
>> +menu "UCC5 Protocols options"
>> + depends on UCC5
>> +
>> + choice
>> + prompt "UCC5 Slow Protocols selection"
>> + depends on UCC5_SLOW
>> + default UCC5_UART
>> +
>> + config UCC5_UART
>> + bool "UCC5 is UART"
>> + endchoice
>> +
>> + choice
>> + prompt "UCC5 Fast Protocols selection"
>> + depends on UCC5_FAST
>> + default UCC5_GETH
>> +
>> + config UCC5_GETH
>> + bool "UCC5 is GETH"
>> + endchoice
>> +endmenu
>> +
>> +config UCC6
>> + bool "Enable QE UCC6"
>> +
>> +choice
>> + prompt "UCC6 speed selection"
>> + depends on UCC6
>> + default UCC6_SLOW
>> +
>> + config UCC6_SLOW
>> + bool "UCC6 is slow"
>> + config UCC6_FAST
>> + bool "UCC6 is fast"
>> +endchoice
>> +
>> +menu "UCC6 Protocols options"
>> + depends on UCC6
>> +
>> + choice
>> + prompt "UCC6 Slow Protocols selection"
>> + depends on UCC6_SLOW
>> + default UCC6_UART
>> +
>> + config UCC6_UART
>> + bool "UCC6 is UART"
>> + endchoice
>> +
>> + choice
>> + prompt "UCC6 Fast Protocols selection"
>> + depends on UCC6_FAST
>> + default UCC6_GETH
>> +
>> + config UCC6_GETH
>> + bool "UCC6 is GETH"
>> + endchoice
>> +endmenu
>> +
>> +config UCC7
>> + bool "Enable QE UCC7"
>> +
>> +choice
>> + prompt "UCC7 speed selection"
>> + depends on UCC7
>> + default UCC7_SLOW
>> +
>> + config UCC7_SLOW
>> + bool "UCC7 is slow"
>> + config UCC7_FAST
>> + bool "UCC7 is fast"
>> +endchoice
>> +
>> +menu "UCC7 Protocols options"
>> + depends on UCC7
>> +
>> + choice
>> + prompt "UCC7 Slow Protocols selection"
>> + depends on UCC7_SLOW
>> + default UCC7_UART
>> +
>> + config UCC7_UART
>> + bool "UCC7 is UART"
>> + endchoice
>> +
>> + choice
>> + prompt "UCC7 Fast Protocols selection"
>> + depends on UCC7_FAST
>> + default UCC7_GETH
>> +
>> + config UCC7_GETH
>> + bool "UCC7 is GETH"
>> + endchoice
>> +endmenu
>> +
>> +config UCC8
>> + bool "Enable QE UCC8"
>> +
>> +choice
>> + prompt "UCC8 speed selection"
>> + depends on UCC8
>> + default UCC8_SLOW
>> +
>> + config UCC8_SLOW
>> + bool "UCC8 is slow"
>> + config UCC8_FAST
>> + bool "UCC8 is fast"
>> +endchoice
>> +
>> +menu "UCC8 Protocols options"
>> + depends on UCC8
>> +
>> + choice
>> + prompt "UCC8 Slow Protocols selection"
>> + depends on UCC8_SLOW
>> + default UCC8_UART
>> +
>> + config UCC8_UART
>> + bool "UCC8 is UART"
>> + endchoice
>> +
>> + choice
>> + prompt "UCC8 Fast Protocols selection"
>> + depends on UCC8_FAST
>> + default UCC8_GETH
>> +
>> + config UCC8_GETH
>> + bool "UCC8 is GETH"
>> + endchoice
>> +endmenu
>> +
>> +config UCC
>> + depends on UCC1 || UCC2 || UCC3 || UCC4 || UCC5 || UCC6 || UCC7
>
>> || UCC8
>> + default y
>> + bool
>> +
>> +config UCC_SLOW
>> + depends on UCC1_SLOW || UCC2_SLOW || UCC3_SLOW || UCC4_SLOW ||
>> UCC5_SLOW || UCC6_SLOW || UCC7_SLOW || UCC8_SLOW
>> + default y
>> + bool
>> +
>> +config UCC_FAST
>> + depends on UCC1_FAST || UCC2_FAST || UCC3_FAST || UCC4_FAST ||
>> UCC5_FAST || UCC6_FAST || UCC7_FAST || UCC8_FAST
>> + default y
>> + bool
>> +
>> +config UCC_GETH_CONF
>> + depends on UCC1_GETH || UCC2_GETH || UCC3_GETH || UCC4_GETH ||
>> UCC5_GETH || UCC6_GETH || UCC7_GETH || UCC8_GETH
>> + default y
>> + bool
>> +endmenu
>> +
>> diff --git a/arch/powerpc/sysdev/qe_lib/Makefile b/arch/powerpc/
>> sysdev/qe_lib/Makefile
>> new file mode 100644
>> index 0000000..c04a70c
>> --- /dev/null
>> +++ b/arch/powerpc/sysdev/qe_lib/Makefile
>> @@ -0,0 +1,8 @@
>> +#
>> +# Makefile for the linux ppc-specific parts of QE
>> +#
>> +obj-$(CONFIG_QUICC_ENGINE)+= qe_common.o mm.o qe.o qe_ic.o qe_io.o
>> +
>> +obj-$(CONFIG_UCC) += ucc.o
>> +obj-$(CONFIG_UCC_SLOW) += ucc_slow.o
>> +obj-$(CONFIG_UCC_FAST) += ucc_fast.o ucc_slow.o
>> diff --git a/arch/powerpc/sysdev/qe_lib/mm.c b/arch/powerpc/sysdev/
>> qe_lib/mm.c
>> new file mode 100644
>> index 0000000..58984ba
>> --- /dev/null
>> +++ b/arch/powerpc/sysdev/qe_lib/mm.c
>> @@ -0,0 +1,770 @@
>> +/*
>> + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights
>> reserved.
>> + *
>> + * Author: Shlomi Gridish <gridish@freescale.com>
>> + *
>> + * Description:
>> + * QE Memory Manager.
>> + *
>> + * Changelog:
>> + * Jun 28, 2006 Li Yang <LeoLi@freescale.com>
>> + * - Reorganized as qe_lib
>> + * - Merged to powerpc arch; add device tree support
>> + * - Style fixes
>> + *
>> + * This program is free software; you can redistribute it and/or
>> modify it
>> + * under the terms of the GNU General Public License as
>> published by the
>> + * Free Software Foundation; either version 2 of the License, or
>> (at your
>> + * option) any later version.
>> + */
>> +#include <linux/errno.h>
>> +#include <linux/sched.h>
>> +#include <linux/kernel.h>
>> +#include <linux/param.h>
>> +#include <linux/string.h>
>> +#include <linux/mm.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/bootmem.h>
>> +#include <linux/module.h>
>> +#include <asm/irq.h>
>> +#include <asm/page.h>
>> +#include <asm/pgtable.h>
>> +
>> +#include "mm.h"
>> +
>> +#define MAX_ALIGNMENT 20
>> +#define MAX_NAME_LEN 50
>> +
>> +#define MAKE_ALIGNED(adr, align) ( ((u32)adr + (align - 1)) & (~
>> (align - 1)) )
>> +
>> +/* mem_block_t data stucutre defines parameters of the Memory
>> Block */
>> +typedef struct mem_block {
>> + struct mem_block *next; /* Pointer to the next memory block */
>> +
>> + u32 base; /* base address of the memory block */
>> + u32 end; /* end address of the memory block */
>> +} mem_block_t;
>> +
>> +/* free_block_t data stucutre defines parameters of the Free
>> Block */
>> +typedef struct free_block {
>> + struct free_block *next; /* Pointer to the next free
> block */
>> +
>> + u32 base; /* base address of the block */
>> + u32 end; /* end address of the block */
>> +} free_block_t;
>> +
>> +/* busy_block_t data stucutre defines parameters of the Busy
>> Block */
>> +typedef struct busy_block {
>> + struct busy_block *next; /* Pointer to the next free
> block */
>> +
>> + u32 base; /* base address of the block */
>> + u32 end; /* end address of the block */
>> + char name[MAX_NAME_LEN];
>> +} busy_block_t;
>> +
>> +/* mm_t data structure defines parameters of the MM object */
>> +typedef struct mm {
>> + mem_block_t *mem_blocks; /* List of memory blocks (Memory
>> list) */
>> + busy_block_t *busy_blocks; /* List of busy blocks (Busy
> list) */
>> + free_block_t *free_blocks[MAX_ALIGNMENT + 1];/* align lists of
> free
>> + blocks (Free
> lists) */
>> +} mm_t;
>> +
>> +/
>> *********************************************************************
>> *
>> + * MM internal routines
>> set *
>> +
>> *********************************************************************
>> *
>
>> /
>> +
>> +/****************************************************************
>> + * Routine: mem_block_init
>> + *
>> + * Description:
>> + * Initializes a new memory block of "size" bytes and started
>> + * from "base" address.
>> + *
>> + * Arguments:
>> + * mem_blk- handle to the mem_blk object
>> + * base - base address of the memory block
>> + * size - size of the memory block
>> + *
>> + * Return value:
>> + * 0 is returned on success. E_NOMEMORY is returned
>> + * if can't allocate memory for mem_blk object.
>> + ****************************************************************/
>> +static int mem_block_init(void **mem_blk, u32 base, u32 size)
>> +{
>> + mem_block_t *p_mem_blk;
>> +
>> + p_mem_blk = (mem_block_t *) kmalloc(sizeof(mem_block_t),
>> GFP_KERNEL);
>> + if (!p_mem_blk)
>> + return -ENOMEM;
>> +
>> + p_mem_blk->base = base;
>> + p_mem_blk->end = base + size;
>> + p_mem_blk->next = 0;
>> +
>> + *mem_blk = p_mem_blk;
>> +
>> + return (0);
>> +}
>> +
>> +/****************************************************************
>> + * Routine: free_block_init
>> + *
>> + * Description:
>> + * Initializes a new free block of of "size" bytes and
>> + * started from "base" address.
>> + *
>> + * Arguments:
>> + * FreeBlock - handle to the FreeBlock object
>> + * base - base address of the free block
>> + * size - size of the free block
>> + *
>> + * Return value:
>> + * 0 is returned on success. E_NOMEMORY is returned
>> + * if can't allocate memory for a free block.
>> + ****************************************************************/
>> +static int free_block_init(void **FreeBlock, u32 base, u32 size)
>> +{
>> + free_block_t *p_free_blk;
>> +
>> + p_free_blk = (free_block_t *) kmalloc(sizeof(free_block_t),
>> GFP_KERNEL);
>> + if (!p_free_blk)
>> + return -ENOMEM;
>> +
>> + p_free_blk->base = base;
>> + p_free_blk->end = base + size;
>> + p_free_blk->next = 0;
>> +
>> + *FreeBlock = p_free_blk;
>> +
>> + return (0);
>> +}
>> +
>> +/****************************************************************
>> + * Routine: busy_block_init
>> + *
>> + * Description:
>> + * Initializes a new busy block of "size" bytes and started
>> + * rom "base" address. Each busy block has a name that
>> + * specified the purpose of the memory allocation.
>> + *
>> + * Arguments:
>> + * BusyBlock - handle to the BusyBlock object
>> + * base - base address of the busy block
>> + * size - size of the busy block
>> + * name - name that specified the busy block
>> + *
>> + * Return value:
>> + * 0 is returned on success. E_NOMEMORY is returned
>> + * if can't allocate memory for busy block.
>> + ****************************************************************/
>> +static int busy_block_init(void **BusyBlock, u32 base, u32 size,
>> char *name)
>> +{
>> + busy_block_t *p_busy_blk;
>> + int n, NameLen;
>> +
>> + p_busy_blk = (busy_block_t *) kmalloc(sizeof(busy_block_t),
>> GFP_KERNEL);
>> + if (!p_busy_blk)
>> + return -ENOMEM;
>> +
>> + p_busy_blk->base = base;
>> + p_busy_blk->end = base + size;
>> + NameLen = (int)strlen(name);
>> + n = (NameLen > MAX_NAME_LEN - 1) ? MAX_NAME_LEN - 1 : NameLen;
>> + strncpy(p_busy_blk->name, name, (u32) n);
>> + p_busy_blk->name[n] = '\0';
>> + p_busy_blk->next = 0;
>> +
>> + *BusyBlock = p_busy_blk;
>> +
>> + return (0);
>> +}
>> +
>> +/****************************************************************
>> + * Routine: add_free
>> + *
>> + * Description:
>> + * Adds a new free block to the free lists. It updates each
>> + * free list to include a new free block.
>> + * Note, that all free block in each free list are ordered
>> + * by their base address.
>> + *
>> + * Arguments:
>> + * p_mm - pointer to the MM object
>> + * base - base address of a given free block
>> + * end - end address of a given free block
>> + *
>> + * Return value:
>> + *
>> + *
>> + ****************************************************************/
>> +static int add_free(mm_t * p_mm, u32 base, u32 end)
>> +{
>> + free_block_t *p_prev_blk, *p_curr_blk, *p_new_blk;
>> + u32 align;
>> + int i;
>> + u32 align_base;
>> +
>> + /* Updates free lists to include a just released block */
>> + for (i = 0; i <= MAX_ALIGNMENT; i++) {
>> + p_prev_blk = p_new_blk = 0;
>> + p_curr_blk = p_mm->free_blocks[i];
>> +
>> + align = (u32) (0x1 << i);
>> + align_base = MAKE_ALIGNED(base, align);
>> +
>> + /* Goes to the next free list if there is no block to
> free */
>> + if (align_base >= end)
>> + continue;
>> +
>> + /* Looks for a free block that should be updated */
>> + while (p_curr_blk) {
>> + if (align_base <= p_curr_blk->end) {
>> + if (end > p_curr_blk->end) {
>> + free_block_t *p_NextB;
>> + while (p_curr_blk->next
>> + && end >
> p_curr_blk->next->end) {
>> + p_NextB =
> p_curr_blk->next;
>> + p_curr_blk->next =
>> +
> p_curr_blk->next->next;
>> + kfree(p_NextB);
>> + }
>> +
>> + p_NextB = p_curr_blk->next;
>> + if (!p_NextB
>> + || (p_NextB
>> + && end < p_NextB->base))
> {
>> + p_curr_blk->end = end;
>> + } else {
>> + p_curr_blk->end =
> p_NextB->end;
>> + p_curr_blk->next =
>> + p_NextB->next;
>> + kfree(p_NextB);
>> + }
>> + } else if (end < p_curr_blk->base
>> + && ((end - align_base) >=
> align)) {
>> + if (free_block_init
>> + ((void *)&p_new_blk,
> align_base,
>> + end - align_base) != 0)
>> + return -ENOMEM;
>> + p_new_blk->next = p_curr_blk;
>> + if (p_prev_blk)
>> + p_prev_blk->next =
> p_new_blk;
>> + else
>> + p_mm->free_blocks[i] =
>> + p_new_blk;
>> + break;
>> + }
>> +
>> + if (align_base < p_curr_blk->base
>> + && end >= p_curr_blk->base)
>> + p_curr_blk->base = align_base;
>> +
>> + /* if size of the free block is less
> then
>> + * alignment deletes that free block
> from
>> + * the free list. */
>> + if ((p_curr_blk->end - p_curr_blk->base)
> <
>> + align) {
>> + if (p_prev_blk)
>> + p_prev_blk->next =
>> + p_curr_blk->next;
>> + else
>> + p_mm->free_blocks[i] =
>> + p_curr_blk->next;
>> + kfree(p_curr_blk);
>> + }
>> + break;
>> + } else {
>> + p_prev_blk = p_curr_blk;
>> + p_curr_blk = p_curr_blk->next;
>> + }
>> + }
>> +
>> + /* If no free block found to be updated, insert a new
> free block
>> + * to the end of the free list. */
>> + if (!p_curr_blk && ((end - base) % align == 0)) {
>> + if (free_block_init
>> + ((void *)&p_new_blk, align_base, end - base)
> != 0)
>> + return -ENOMEM;
>> + if (p_prev_blk)
>> + p_prev_blk->next = p_new_blk;
>> + else
>> + p_mm->free_blocks[i] = p_new_blk;
>> + }
>> +
>> + /* Update boundaries of the new free block */
>> + if (align == 1 && !p_new_blk) {
>> + if (p_curr_blk && base > p_curr_blk->base)
>> + base = p_curr_blk->base;
>> + if (p_curr_blk && end < p_curr_blk->end)
>> + end = p_curr_blk->end;
>> + }
>> + }
>> +
>> + return (0);
>> +}
>> +
>> +/****************************************************************
>> + * Routine: cut_free
>> + *
>> + * Description:
>> + * Cuts a free block from hold_base to hold_end from the free
>> lists.
>> + * That is, it updates all free lists of the MM object do
>> + * not include a block of memory from hold_base to hold_end.
>> + * For each free lists it seek for a free block that holds
>> + * either hold_base or hold_end. If such block is found it
>> updates it.
>> + *
>> + * Arguments:
>> + * p_mm - pointer to the MM object
>> + * hold_base - base address of the allocated block
>> + * hold_end - end address of the allocated block
>> + *
>> + * Return value:
>> + * 0 is returned on success,
>> + * otherwise returns an error code.
>> + *
>> + ****************************************************************/
>> +static int cut_free(mm_t * p_mm, u32 hold_base, u32 hold_end)
>> +{
>> + free_block_t *p_prev_blk, *p_curr_blk, *p_new_blk;
>> + u32 align_base, base, end, align;
>> + int i;
>> +
>> + for (i = 0; i <= MAX_ALIGNMENT; i++) {
>> + p_prev_blk = p_new_blk = 0;
>> + p_curr_blk = p_mm->free_blocks[i];
>> +
>> + align = (u32) 0x1 << i;
>> + align_base = MAKE_ALIGNED(hold_end, align);
>> +
>> + while (p_curr_blk) {
>> + base = p_curr_blk->base;
>> + end = p_curr_blk->end;
>> +
>> + if (hold_base <= base && hold_end <= end
>> + && hold_end > base) {
>> + if (align_base >= end
>> + || (align_base < end
>> + && (end - align_base) < align))
> {
>> + if (p_prev_blk)
>> + p_prev_blk->next =
>> + p_curr_blk->next;
>> + else
>> + p_mm->free_blocks[i] =
>> + p_curr_blk->next;
>> + kfree(p_curr_blk);
>> + } else {
>> + p_curr_blk->base = align_base;
>> + }
>> + break;
>> + } else if (hold_base > base && hold_end <= end)
> {
>> + if ((hold_base - base) >= align) {
>> + if (align_base < end
>> + && (end - align_base) >=
> align) {
>> + if (free_block_init
>> + ((void *)&p_new_blk,
>> + align_base,
>> + (end - align_base))
> != 0)
>> + return -ENOMEM;
>> + p_new_blk->next =
>> + p_curr_blk->next;
>> + p_curr_blk->next =
> p_new_blk;
>> + }
>> + p_curr_blk->end = hold_base;
>> + } else if (align_base < end
>> + && (end - align_base) >=
> align) {
>> + p_curr_blk->base = align_base;
>> + } else {
>> + if (p_prev_blk)
>> + p_prev_blk->next =
>> + p_curr_blk->next;
>> + else
>> + p_mm->free_blocks[i] =
>> + p_curr_blk->next;
>> + kfree(p_curr_blk);
>> + }
>> + break;
>> + } else {
>> + p_prev_blk = p_curr_blk;
>> + p_curr_blk = p_curr_blk->next;
>> + }
>> + }
>> + }
>> +
>> + return (0);
>> +}
>> +
>> +/****************************************************************
>> + * Routine: add_busy
>> + *
>> + * Description:
>> + * Adds a new busy block to the list of busy blocks. Note,
>> + * that all busy blocks are ordered by their base address in
>> + * the busy list.
>> + *
>> + * Arguments:
>> + * MM - handler to the MM object
>> + * p_new_busy_blk - pointer to the a busy block
>> + *
>> + * Return value:
>> + * None.
>> + *
>> + ****************************************************************/
>> +static void add_busy(mm_t * p_mm, busy_block_t * p_new_busy_blk)
>> +{
>> + busy_block_t *p_cur_busy_blk, *p_prev_busy_blk;
>> +
>> + /* finds a place of a new busy block in the list of busy blocks
> */
>> + p_prev_busy_blk = 0;
>> + p_cur_busy_blk = p_mm->busy_blocks;
>> +
>> + while (p_cur_busy_blk && p_new_busy_blk->base > p_cur_busy_blk-
>>> base) {
>> + p_prev_busy_blk = p_cur_busy_blk;
>> + p_cur_busy_blk = p_cur_busy_blk->next;
>> + }
>> +
>> + /* insert the new busy block into the list of busy blocks */
>> + if (p_cur_busy_blk)
>> + p_new_busy_blk->next = p_cur_busy_blk;
>> + if (p_prev_busy_blk)
>> + p_prev_busy_blk->next = p_new_busy_blk;
>> + else
>> + p_mm->busy_blocks = p_new_busy_blk;
>> +
>> +}
>> +
>> +/****************************************************************
>> + * Routine: get_greater_align
>> + *
>> + * Description:
>> + * Allocates a block of memory according to the given size
>> + * and the alignment. That routine is called from the mm_get
>> + * routine if the required alignment is grater then
>> MAX_ALIGNMENT.
>> + * In that case, it goes over free blocks of 64 byte align list
>> + * and checks if it has the required size of bytes of the
>> required
>> + * alignment. If no blocks found returns ILLEGAL_BASE.
>> + * After the block is found and data is allocated, it calls
>> + * the internal cut_free routine to update all free lists
>> + * do not include a just allocated block. Of course, each
>> + * free list contains a free blocks with the same alignment.
>> + * It is also creates a busy block that holds
>> + * information about an allocated block.
>> + *
>> + * Arguments:
>> + * MM - handle to the MM object
>> + * size - size of the MM
>> + * align - index as a power of two defines
>> + * a required alignment that is grater then
>> 64.
>> + * name - the name that specifies an allocated
>> block.
>> + *
>> + * Return value:
>> + * base address of an allocated block.
>> + * ILLEGAL_BASE if can't allocate a block
>> + *
>> + ****************************************************************/
>> +static int get_greater_align(void *MM, u32 size, int align, char
>> *name)
>> +{
>> + mm_t *p_mm = (mm_t *) MM;
>> + free_block_t *p_free_blk;
>> + busy_block_t *p_new_busy_blk;
>> + u32 hold_base, hold_end, align_base = 0;
>> + u32 ret;
>> +
>> + /* goes over free blocks of the 64 byte alignment list
>> + * and look for a block of the suitable size and
>> + * base address according to the alignment.
>> + */
>> + p_free_blk = p_mm->free_blocks[MAX_ALIGNMENT];
>> +
>> + while (p_free_blk) {
>> + align_base = MAKE_ALIGNED(p_free_blk->base, align);
>> +
>> + /* the block is found if the aligned base inside the
> block
>> + * and has the anough size.
>> + */
>> + if (align_base >= p_free_blk->base &&
>> + align_base < p_free_blk->end &&
>> + size <= (p_free_blk->end - align_base))
>> + break;
>> + else
>> + p_free_blk = p_free_blk->next;
>> + }
>> +
>> + /* If such block isn't found */
>> + if (!p_free_blk)
>> + return -EBUSY;
>> +
>> + hold_base = align_base;
>> + hold_end = align_base + size;
>> +
>> + /* init a new busy block */
>> + if ((ret =
>> + busy_block_init((void *)&p_new_busy_blk, hold_base, size,
>> + name)) != 0)
>> + return ret;
>> +
>> + /* calls Update routine to update a lists of free blocks */
>> + if ((ret = cut_free(MM, hold_base, hold_end)) != 0)
>> + return ret;
>> +
>> + /* insert the new busy block into the list of busy blocks */
>> + add_busy(p_mm, p_new_busy_blk);
>> +
>> + return (hold_base);
>> +}
>> +
>> +/
>> *********************************************************************
>> *
>> + * MM API routines
>> set *
>> +
>> *********************************************************************
>> *
>
>> /
>> +int mm_init(void **MM, u32 base, u32 size)
>> +{
>> + mm_t *p_mm;
>> + int i;
>> + u32 new_base, new_size;
>> +
>> + /* Initializes a new MM object */
>> + p_mm = (mm_t *) kmalloc(sizeof(mm_t), GFP_KERNEL);
>> + if (p_mm == 0)
>> + return -ENOMEM;
>> +
>> + /* initializes a new memory block */
>> + if (mem_block_init((void *)&p_mm->mem_blocks, base, size) != 0)
>> + return -ENOMEM;
>> +
>> + /* A busy list is empty */
>> + p_mm->busy_blocks = 0;
>> +
>> + /*Initializes a new free block for each free list */
>> + for (i = 0; i <= MAX_ALIGNMENT; i++) {
>> + new_base = MAKE_ALIGNED(base, (0x1 << i));
>> + new_size = size - (new_base - base);
>> + if (free_block_init((void *)&p_mm->free_blocks[i],
>> + new_base, new_size) != 0)
>> + return -ENOMEM;
>> + }
>> +
>> + *MM = p_mm;
>> +
>> + return (0);
>> +}
>> +
>> +EXPORT_SYMBOL(mm_init);
>> +
>> +void mm_free(void *MM)
>> +{
>> + mm_t *p_mm = (mm_t *) MM;
>> + mem_block_t *p_mem_blk;
>> + busy_block_t *p_busy_blk;
>> + free_block_t *p_free_blk;
>> + void *p_blk;
>> + int i;
>> +
>> + if (!p_mm)
>> + return;
>> +
>> + /* release memory allocated for busy blocks */
>> + p_busy_blk = p_mm->busy_blocks;
>> + while (p_busy_blk) {
>> + p_blk = p_busy_blk;
>> + p_busy_blk = p_busy_blk->next;
>> + kfree(p_blk);
>> + }
>> +
>> + /* release memory allocated for free blocks */
>> + for (i = 0; i <= MAX_ALIGNMENT; i++) {
>> + p_free_blk = p_mm->free_blocks[i];
>> + while (p_free_blk) {
>> + p_blk = p_free_blk;
>> + p_free_blk = p_free_blk->next;
>> + kfree(p_blk);
>> + }
>> + }
>> +
>> + /* release memory allocated for memory blocks */
>> + p_mem_blk = p_mm->mem_blocks;
>> + while (p_mem_blk) {
>> + p_blk = p_mem_blk;
>> + p_mem_blk = p_mem_blk->next;
>> + kfree(p_blk);
>> + }
>> +
>> + /* release memory allocated for MM object itself */
>> + kfree(p_mm);
>> +}
>> +
>> +EXPORT_SYMBOL(mm_free);
>> +
>> +void *mm_get(void *MM, u32 size, int align, char *name)
>> +{
>> + mm_t *p_mm = (mm_t *) MM;
>> + free_block_t *p_free_blk;
>> + busy_block_t *p_new_busy_blk;
>> + u32 hold_base, hold_end;
>> + u32 i = 0, j = (u32) align;
>> + u32 ret;
>> +
>> + if (!p_mm)
>> + return ERR_PTR(-EINVAL);
>> +
>> + /* checks that align value is grater then zero */
>> + if (align == 0)
>> + return ERR_PTR(-EINVAL);
>> +
>> + /* checks if alignment is a power of two,
>> + * if it correct and if the required size
>> + * is multiple of the given alignment.
>> + */
>> + while ((j & 0x1) == 0) {
>> + i++;
>> + j = j >> 1;
>> + }
>> +
>> + /* if the given alignment isn't power of two, returns an error
> */
>> + if (j != 1)
>> + return ERR_PTR(-EINVAL);
>> +
>> + if (i > MAX_ALIGNMENT)
>> + return ERR_PTR(get_greater_align(MM, size, align,
> name));
>> +
>> + /* look for a block of the size grater or equal to the
>> + * required size.
>> + */
>> + p_free_blk = p_mm->free_blocks[i];
>> + while (p_free_blk && (p_free_blk->end - p_free_blk->base) <
> size)
>> + p_free_blk = p_free_blk->next;
>> +
>> + /* If such block is found */
>> + if (!p_free_blk)
>> + return ERR_PTR(-ENOMEM);
>> +
>> + hold_base = p_free_blk->base;
>> + hold_end = hold_base + size;
>> +
>> + /* init a new busy block */
>> + if ((ret =
>> + busy_block_init((void *)&p_new_busy_blk, hold_base, size,
>> + name)) != 0)
>> + return ERR_PTR(ret);
>> +
>> + /* calls Update routine to update a lists of free blocks */
>> + if ((ret = cut_free(MM, hold_base, hold_end)) != 0)
>> + return ERR_PTR(ret);
>> +
>> + /* insert the new busy block into the list of busy blocks */
>> + add_busy(p_mm, p_new_busy_blk);
>> +
>> + return (void *)(hold_base);
>> +}
>> +
>> +EXPORT_SYMBOL(mm_get);
>> +
>> +void *mm_get_force(void *MM, u32 base, u32 size, char *name)
>> +{
>> + mm_t *p_mm = (mm_t *) MM;
>> + free_block_t *p_free_blk;
>> + busy_block_t *p_new_busy_blk;
>> + int blk_is_free = 0;
>> + u32 ret;
>> +
>> + p_free_blk = p_mm->free_blocks[0];/* The biggest free blocks are
> in
>> + the free list with
> alignment 1 */
>> + while (p_free_blk) {
>> + if (base >= p_free_blk->base
>> + && (base + size) <= p_free_blk->end) {
>> + blk_is_free = 1;
>> + break;
>> + } else
>> + p_free_blk = p_free_blk->next;
>> + }
>> +
>> + if (!blk_is_free)
>> + return ERR_PTR(-ENOMEM);
>> +
>> + /* init a new busy block */
>> + if ((ret =
>> + busy_block_init((void *)&p_new_busy_blk, base, size, name))
> !
>> = 0)
>> + return ERR_PTR(ret);
>> +
>> + /* calls Update routine to update a lists of free blocks */
>> + if ((ret = cut_free(MM, base, base + size)) != 0)
>> + return ERR_PTR(ret);
>> +
>> + /* insert the new busy block into the list of busy blocks */
>> + add_busy(p_mm, p_new_busy_blk);
>> + return (void *)(base);
>> +}
>> +
>> +EXPORT_SYMBOL(mm_get_force);
>> +
>> +int mm_put(void *MM, u32 base)
>> +{
>> + mm_t *p_mm = (mm_t *) MM;
>> + busy_block_t *p_busy_blk, *p_prev_busy_blk;
>> + u32 size;
>> + u32 ret;
>> +
>> + if (!p_mm)
>> + return -EINVAL;
>> +
>> + /* Look for a busy block that have the given base value.
>> + * That block will be returned back to the memory.
>> + */
>> + p_prev_busy_blk = 0;
>> + p_busy_blk = p_mm->busy_blocks;
>> + while (p_busy_blk && base != p_busy_blk->base) {
>> + p_prev_busy_blk = p_busy_blk;
>> + p_busy_blk = p_busy_blk->next;
>> + }
>> +
>> + if (!p_busy_blk)
>> + return -EINVAL;
>> +
>> + if ((ret = add_free(p_mm, p_busy_blk->base, p_busy_blk->end)) !=
> 0)
>> + return ret;
>> +
>> + /* removes a busy block form the list of busy blocks */
>> + if (p_prev_busy_blk)
>> + p_prev_busy_blk->next = p_busy_blk->next;
>> + else
>> + p_mm->busy_blocks = p_busy_blk->next;
>> +
>> + size = p_busy_blk->end - p_busy_blk->base;
>> +
>> + kfree(p_busy_blk);
>> +
>> + return (0);
>> +}
>> +
>> +EXPORT_SYMBOL(mm_put);
>> +
>> +void mm_dump(void *MM)
>> +{
>> + mm_t *p_mm = (mm_t *) MM;
>> + free_block_t *p_free_blk;
>> + busy_block_t *p_busy_blk;
>> + int i;
>> +
>> + p_busy_blk = p_mm->busy_blocks;
>> + printk(KERN_INFO "List of busy blocks:\n");
>> + while (p_busy_blk) {
>> + printk(KERN_INFO "\t0x%08x: (%s: b=0x%08x, e=0x%08x)\n",
>> + (u32) p_busy_blk, p_busy_blk->name,
> p_busy_blk->base,
>> + p_busy_blk->end);
>> + p_busy_blk = p_busy_blk->next;
>> + }
>> +
>> + printk(KERN_INFO "Lists of free blocks according to
> alignment:\n");
>> + for (i = 0; i <= MAX_ALIGNMENT; i++) {
>> + printk(KERN_INFO "%d alignment:\n", (0x1 << i));
>> + p_free_blk = p_mm->free_blocks[i];
>> + while (p_free_blk) {
>> + printk(KERN_INFO "\t0x%08x: (b=0x%08x,
> e=0x%08x)\n",
>> + (u32) p_free_blk, p_free_blk->base,
>> + p_free_blk->end);
>> + p_free_blk = p_free_blk->next;
>> + }
>> + printk(KERN_INFO "\n");
>> + }
>> +}
>> +
>> +EXPORT_SYMBOL(mm_dump);
>> diff --git a/arch/powerpc/sysdev/qe_lib/mm.h b/arch/powerpc/sysdev/
>> qe_lib/mm.h
>> new file mode 100644
>> index 0000000..ab30080
>> --- /dev/null
>> +++ b/arch/powerpc/sysdev/qe_lib/mm.h
>> @@ -0,0 +1,6 @@
>> +int mm_init ( void **MM, u32 base, u32 size );
>> +void mm_free (void * MM);
>> +void *mm_get ( void * MM, u32 size, int align, char* name );
>> +void *mm_get_force ( void * MM, u32 base, u32 size, char* name );
>> +int mm_put ( void * MM, u32 base );
>> +void mm_dump ( void * MM );
>> diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/
>> qe_lib/qe.c
>> new file mode 100644
>> index 0000000..0fbb54c
>> --- /dev/null
>> +++ b/arch/powerpc/sysdev/qe_lib/qe.c
>> @@ -0,0 +1,181 @@
>> +/*
>> + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights
>> reserved.
>> + *
>> + * Author: Li Yang <LeoLi@freescale.com>
>> + *
>> + * Description:
>> + * FSL QE SOC setup.
>> + *
>> + * Changelog:
>> + * Jun 21, 2006 Initial version
>> + *
>> + * This program is free software; you can redistribute it and/or
>> modify it
>> + * under the terms of the GNU General Public License as
>> published by the
>> + * Free Software Foundation; either version 2 of the License, or
>> (at your
>> + * option) any later version.
>> + */
>> +
>> +#include <linux/config.h>
>> +#include <linux/stddef.h>
>> +#include <linux/kernel.h>
>> +#include <linux/init.h>
>> +#include <linux/errno.h>
>> +#include <linux/major.h>
>> +#include <linux/delay.h>
>> +#include <linux/irq.h>
>> +#include <linux/module.h>
>> +#include <linux/device.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/fsl_devices.h>
>> +
>> +#include <asm/system.h>
>> +#include <asm/atomic.h>
>> +#include <asm/io.h>
>> +#include <asm/irq.h>
>> +#include <asm/prom.h>
>> +#include <sysdev/fsl_soc.h>
>> +#include <mm/mmu_decl.h>
>> +
>> +static phys_addr_t qebase = -1;
>> +
>> +phys_addr_t get_qe_base(void)
>> +{
>> + struct device_node *qe;
>> +
>> + if (qebase != -1)
>> + return qebase;
>> +
>> + qe = of_find_node_by_type(NULL, "qe");
>> + if (qe) {
>> + unsigned int size;
>> + void *prop = get_property(qe, "reg", &size);
>> + qebase = of_translate_address(qe, prop);
>> + of_node_put(qe);
>> + };
>> +
>> + return qebase;
>> +}
>> +
>> +EXPORT_SYMBOL(get_qe_base);
>> +
>> +static int __init ucc_geth_of_init(void)
>> +{
>> + struct device_node *np;
>> + unsigned int i, ucc_num;
>> + struct platform_device *ugeth_dev;
>> + struct resource res;
>> + int ret;
>> +
>> + for (np = NULL, i = 0;
>> + (np = of_find_compatible_node(np, "network", "ucc_geth"))
> !=
>> NULL;
>> + i++) {
>> + struct resource r[2];
>> + struct device_node *phy, *mdio;
>> + struct ucc_geth_platform_data ugeth_data;
>> + unsigned int *id;
>> + char *model;
>> + void *mac_addr;
>> + phandle *ph;
>> +
>> + memset(r, 0, sizeof(r));
>> + memset(&ugeth_data, 0, sizeof(ugeth_data));
>> +
>> + ret = of_address_to_resource(np, 0, &r[0]);
>> + if (ret)
>> + goto err;
>> +
>> + ugeth_data.phy_reg_addr = r[0].start;
>> + r[1].start = np->intrs[0].line;
>> + r[1].end = np->intrs[0].line;
>> + r[1].flags = IORESOURCE_IRQ;
>> +
>> + model = get_property(np, "model", NULL);
>> + ucc_num = *((u32 *) get_property(np, "device-id",
> NULL));
>> + if ((strstr(model, "UCC") == NULL) ||
>> + (ucc_num < 1) || (ucc_num > 8)) {
>> + ret = -ENODEV;
>> + goto err;
>> + }
>> +
>> + ugeth_dev =
>> + platform_device_register_simple("ucc_geth", ucc_num
> - 1,
>> + &r[0], np->n_intrs + 1);
>> +
>> + if (IS_ERR(ugeth_dev)) {
>> + ret = PTR_ERR(ugeth_dev);
>> + goto err;
>> + }
>> +
>> + mac_addr = get_property(np, "mac-address", NULL);
>> +
>> + memcpy(ugeth_data.mac_addr, mac_addr, 6);
>> +
>> + ugeth_data.rx_clock = *((u32 *) get_property(np,
> "rx-clock",
>> + NULL));
>> + ugeth_data.tx_clock = *((u32 *) get_property(np,
> "tx-clock",
>> + NULL));
>> +
>> + ph = (phandle *) get_property(np, "phy-handle", NULL);
>> + phy = of_find_node_by_phandle(*ph);
>> +
>> + if (phy == NULL) {
>> + ret = -ENODEV;
>> + goto unreg;
>> + }
>> +
>> + mdio = of_get_parent(phy);
>> +
>> + id = (u32 *) get_property(phy, "reg", NULL);
>> + ret = of_address_to_resource(mdio, 0, &res);
>> + if (ret) {
>> + of_node_put(phy);
>> + of_node_put(mdio);
>> + goto unreg;
>> + }
>> +
>> + ugeth_data.phy_id = *id;
>> + ugeth_data.phy_interrupt = phy->intrs[0].line;
>> + ugeth_data.phy_interface = *((u32 *) get_property(phy,
>> + "interface", NULL));
>> +
>> + /* FIXME: Work around for early chip rev.
> */
>> + /* There's a bug in initial chip rev(s) in the RGMII ac
> */
>> + /* timing.
> */
>> + /* The following compensates by writing to the reserved
> */
>> + /* QE Port Output Hold Registers (CPOH1?).
> */
>> + if ((ugeth_data.phy_interface == ENET_1000_RGMII) ||
>> + (ugeth_data.phy_interface ==
> ENET_100_RGMII) ||
>> + (ugeth_data.phy_interface ==
> ENET_10_RGMII)) {
>> + u32 *tmp_reg = (u32 *) ioremap(get_immrbase()
>> + + 0x14A8, 0x4);
>> + u32 tmp_val = in_be32(tmp_reg);
>> + if (ucc_num == 1)
>> + out_be32(tmp_reg, tmp_val | 0x00003000);
>> + else if (ucc_num == 2)
>> + out_be32(tmp_reg, tmp_val | 0x0c000000);
>> + iounmap(tmp_reg);
>> + }
>> +
>> + if (phy->intrs[0].line != 0)
>> + ugeth_data.board_flags |=
> FSL_UGETH_BRD_HAS_PHY_INTR;
>> +
>> + of_node_put(phy);
>> + of_node_put(mdio);
>> +
>> + ret =
>> + platform_device_add_data(ugeth_dev, &ugeth_data,
>> + sizeof(struct
>> +
> ucc_geth_platform_data));
>> + if (ret)
>> + goto unreg;
>> + }
>> +
>> + return 0;
>> +
>> +unreg:
>> + platform_device_unregister(ugeth_dev);
>> +err:
>> + return ret;
>> +}
>> +
>> +arch_initcall(ucc_geth_of_init);
>> diff --git a/arch/powerpc/sysdev/qe_lib/qe_common.c b/arch/powerpc/
>> sysdev/qe_lib/qe_common.c
>> new file mode 100644
>> index 0000000..cd0aca9
>> --- /dev/null
>> +++ b/arch/powerpc/sysdev/qe_lib/qe_common.c
>> @@ -0,0 +1,401 @@
>> +/*
>> + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights
>> reserved.
>> + *
>> + * Author: Shlomi Gridish <gridish@freescale.com>
>> + *
>> + * Description:
>> + * General Purpose functions for the global management of the
>> + * QUICC Engine (QE).
>> + *
>> + * Changelog:
>> + * Jun 28, 2006 Li Yang <LeoLi@freescale.com>
>> + * - Reorganized as qe_lib
>> + * - Merged to powerpc arch; add device tree support
>> + * - Style fixes
>> + *
>> + * This program is free software; you can redistribute it and/or
>> modify it
>> + * under the terms of the GNU General Public License as
>> published by the
>> + * Free Software Foundation; either version 2 of the License, or
>> (at your
>> + * option) any later version.
>> + */
>> +#undef USE_RHEAP
>> +#include <linux/errno.h>
>> +#include <linux/sched.h>
>> +#include <linux/kernel.h>
>> +#include <linux/param.h>
>> +#include <linux/string.h>
>> +#include <linux/mm.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/bootmem.h>
>> +#include <linux/module.h>
>> +#include <linux/delay.h>
>> +#include <asm/irq.h>
>> +#include <asm/page.h>
>> +#include <asm/pgtable.h>
>> +#include <asm/immap_qe.h>
>> +#include <asm/qe.h>
>> +#include <asm/prom.h>
>> +#ifdef USE_RHEAP
>> +#include <asm/rheap.h>
>> +#else
>> +#include "mm.h"
>> +#endif /* USE_RHEAP */
>> +
>> +/* QE snum state
>> +*/
>> +typedef enum qe_snum_state {
>> + QE_SNUM_STATE_USED, /* used */
>> + QE_SNUM_STATE_FREE /* free */
>> +} qe_snum_state_e;
>> +
>> +/* QE snum
>> +*/
>> +typedef struct qe_snum {
>> + u8 num; /* snum */
>> + qe_snum_state_e state; /* state */
>> +} qe_snum_t;
>> +
>> +/* We allocate this here because it is used almost exclusively for
>> + * the communication processor devices.
>> + */
>> +EXPORT_SYMBOL(qe_immr);
>> +qe_map_t *qe_immr = NULL;
>> +static qe_snum_t snums[QE_NUM_OF_SNUM]; /* Dynamically allocated
>
>> SNUMs */
>> +
>> +static void qe_snums_init(void);
>> +static void qe_muram_init(void);
>> +static int qe_sdma_init(void);
>> +
>> +void qe_reset(void)
>> +{
>> + if (qe_immr == NULL)
>> + qe_immr = (qe_map_t *) ioremap(get_qe_base(),
> QE_IMMAP_SIZE);
>> +
>> + qe_snums_init();
>> +
>> + qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
>> + (u8) QE_CR_PROTOCOL_UNSPECIFIED, 0);
>> +
>> + /* Reclaim the MURAM memory for our use. */
>> + qe_muram_init();
>> +
>> +#ifdef USE_RHEAP
>> + if (qe_sdma_init())
>> + panic("sdma init failed!");
>> +#endif /* USE_RHEAP */
>> +}
>> +
>> +EXPORT_SYMBOL(qe_issue_cmd);
>> +int qe_issue_cmd(uint cmd, uint device, u8 mcn_protocol, u32
>> cmd_input)
>> +{
>> + unsigned long flags;
>> + u32 cecr;
>> + u8 mcn_shift = 0, dev_shift = 0;
>> +
>> + local_irq_save(flags);
>> + if (cmd == QE_RESET) {
>> + out_be32(&qe_immr->cp.cecr, (u32) (cmd | QE_CR_FLG));
>> + } else {
>> + if (cmd == QE_ASSIGN_PAGE) {
>> + /* Here device is the SNUM, not sub-block */
>> + dev_shift = QE_CR_SNUM_SHIFT;
>> + } else if (cmd == QE_ASSIGN_RISC) {
>> + /* Here device is the SNUM, and mcnProtocol is
>> + * e_QeCmdRiscAssignment value */
>> + dev_shift = QE_CR_SNUM_SHIFT;
>> + mcn_shift = QE_CR_MCN_RISC_ASSIGN_SHIFT;
>> + } else {
>> + if (device == QE_CR_SUBBLOCK_USB)
>> + mcn_shift = QE_CR_MCN_USB_SHIFT;
>> + else
>> + mcn_shift = QE_CR_MCN_NORMAL_SHIFT;
>> + }
>> +
>> + out_be32(&qe_immr->cp.cecdr,
>> + immrbar_virt_to_phys((void *)cmd_input));
>> + out_be32(&qe_immr->cp.cecr,
>> + (cmd | QE_CR_FLG | ((u32) device << dev_shift)
> | (u32)
>> + mcn_protocol << mcn_shift));
>> + }
>> +
>> + /* wait for the QE_CR_FLG to clear */
>> + do {
>> + cecr = in_be32(&qe_immr->cp.cecr);
>> + } while (cecr & QE_CR_FLG);
>> + local_irq_restore(flags);
>> +
>> + return 0;
>> +}
>> +
>> +/* Set a baud rate generator. This needs lots of work. There are
>> + * 16 BRGs, which can be connected to the QE channels or output
>> + * as clocks. The BRGs are in two different block of internal
>> + * memory mapped space.
>> + * The baud rate clock is the system clock divided by something.
>> + * It was set up long ago during the initial boot phase and is
>> + * is given to us.
>> + * Baud rate clocks are zero-based in the driver code (as that maps
>> + * to port numbers). Documentation uses 1-based numbering.
>> + */
>> +static unsigned int brg_clk = 0;
>> +
>> +unsigned int get_brg_clk(void)
>> +{
>> + struct device_node *qe;
>> + if (brg_clk)
>> + return brg_clk;
>> +
>> + qe = of_find_node_by_type(NULL, "qe");
>> + if (qe) {
>> + unsigned int size;
>> + u32 *prop = (u32 *) get_property(qe, "brg-frequency",
> &size);
>> + brg_clk = *prop;
>> + of_node_put(qe);
>> + };
>> + return brg_clk;
>> +}
>> +
>> +/* This function is used by UARTS, or anything else that uses a 16x
>> + * oversampled clock.
>> + */
>> +void qe_setbrg(uint brg, uint rate)
>> +{
>> + volatile uint *bp;
>> + u32 divisor;
>> + int div16 = 0;
>> +
>> + bp = (uint *) & qe_immr->brg.brgc1;
>> + bp += brg;
>> +
>> + divisor = (get_brg_clk() / rate);
>> + if (divisor > QE_BRGC_DIVISOR_MAX + 1) {
>> + div16 = 1;
>> + divisor /= 16;
>> + }
>> +
>> + *bp = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE;
>> + if (div16)
>> + *bp |= QE_BRGC_DIV16;
>> +}
>> +
>> +static void qe_snums_init(void)
>> +{
>> + int i;
>> +
>> + /* Initialize the SNUMs array. */
>> + for (i = 0; i < QE_NUM_OF_SNUM; i++)
>> + snums[i].state = QE_SNUM_STATE_FREE;
>> +
>> + /* Initialize SNUMs (thread serial numbers) according to QE
>> + * spec chapter 4, SNUM table */
>> + i = 0;
>> + snums[i++].num = 0x04;
>> + snums[i++].num = 0x05;
>> + snums[i++].num = 0x0C;
>> + snums[i++].num = 0x0D;
>> + snums[i++].num = 0x14;
>> + snums[i++].num = 0x15;
>> + snums[i++].num = 0x1C;
>> + snums[i++].num = 0x1D;
>> + snums[i++].num = 0x24;
>> + snums[i++].num = 0x25;
>> + snums[i++].num = 0x2C;
>> + snums[i++].num = 0x2D;
>> + snums[i++].num = 0x34;
>> + snums[i++].num = 0x35;
>> + snums[i++].num = 0x88;
>> + snums[i++].num = 0x89;
>> + snums[i++].num = 0x98;
>> + snums[i++].num = 0x99;
>> + snums[i++].num = 0xA8;
>> + snums[i++].num = 0xA9;
>> + snums[i++].num = 0xB8;
>> + snums[i++].num = 0xB9;
>> + snums[i++].num = 0xC8;
>> + snums[i++].num = 0xC9;
>> + snums[i++].num = 0xD8;
>> + snums[i++].num = 0xD9;
>> + snums[i++].num = 0xE8;
>> + snums[i++].num = 0xE9;
>> +}
>> +
>> +int qe_get_snum(void)
>> +{
>> + unsigned long flags;
>> + int snum = -EBUSY;
>> + int i;
>> +
>> + local_irq_save(flags);
>> + for (i = 0; i < QE_NUM_OF_SNUM; i++) {
>> + if (snums[i].state == QE_SNUM_STATE_FREE) {
>> + snums[i].state = QE_SNUM_STATE_USED;
>> + snum = snums[i].num;
>> + break;
>> + }
>> + }
>> + local_irq_restore(flags);
>> +
>> + return snum;
>> +}
>> +
>> +EXPORT_SYMBOL(qe_get_snum);
>> +
>> +void qe_put_snum(u8 snum)
>> +{
>> + int i;
>> +
>> + for (i = 0; i < QE_NUM_OF_SNUM; i++) {
>> + if (snums[i].num == snum) {
>> + snums[i].state = QE_SNUM_STATE_FREE;
>> + break;
>> + }
>> + }
>> +}
>> +
>> +EXPORT_SYMBOL(qe_put_snum);
>> +
>> +static int qe_sdma_init(void)
>> +{
>> + sdma_t *sdma = &qe_immr->sdma;
>> + uint sdma_buf_offset;
>> +
>> + if (!sdma)
>> + return -ENODEV;
>> +
>> + /* allocate 2 internal temporary buffers (512 bytes size each)
> for
>> + * the SDMA */
>> + sdma_buf_offset = qe_muram_alloc(512 * 2, 64);
>> + if (IS_MURAM_ERR(sdma_buf_offset))
>> + return -ENOMEM;
>> +
>> + out_be32(&sdma->sdebcr, sdma_buf_offset & QE_SDEBCR_BA_MASK);
>> + out_be32(&sdma->sdmr, (QE_SDMR_GLB_1_MSK | (0x1 >>
>> + QE_SDMR_CEN_SHIFT)));
>> +
>> + return 0;
>> +}
>> +
>> +/*
>> + * muram_alloc / muram_free bits.
>> + */
>> +static spinlock_t qe_muram_lock;
>> +#ifdef USE_RHEAP
>> +/* 16 blocks should be enough to satisfy all requests
>> + * until the memory subsystem goes up... */
>> +static rh_block_t qe_boot_muram_rh_block[16];
>> +static rh_info_t qe_muram_info;
>> +#else
>> +static void *mm = NULL;
>> +#endif /* USE_RHEAP */
>> +
>> +static void qe_muram_init(void)
>> +{
>> + spin_lock_init(&qe_muram_lock);
>> +
>> +#ifdef USE_RHEAP
>> + /* initialize the info header */
>> + rh_init(&qe_muram_info, 1,
>> + sizeof(qe_boot_muram_rh_block) /
>> + sizeof(qe_boot_muram_rh_block[0]),
> qe_boot_muram_rh_block);
>> +
>> + /* Attach the usable muram area */
>> + /* XXX: This is actually crap. QE_DATAONLY_BASE and
>> + * QE_DATAONLY_SIZE is only a subset of the available muram. It
>> + * varies with the processor and the microcode patches
> activated.
>> + * But the following should be at least safe.
>> + */
>> + rh_attach_region(&qe_muram_info,
>> + (void *)QE_MURAM_DATAONLY_BASE,
>> + QE_MURAM_DATAONLY_SIZE);
>> +#else
>> +#endif /* USE_RHEAP */
>> +}
>> +
>> +/* This function returns an index into the MURAM area.
>> + */
>> +uint qe_muram_alloc(uint size, uint align)
>> +{
>> + void *start;
>> + unsigned long flags;
>> +
>> + spin_lock_irqsave(&qe_muram_lock, flags);
>> +#ifdef USE_RHEAP
>> + qe_muram_info.alignment = align;
>> + start = rh_alloc(&qe_muram_info, size, "QE");
>> +#else
>> + if (!mm) {
>> + mm_init(&mm, (u32)
> qe_muram_addr(QE_MURAM_DATAONLY_BASE),
>> + QE_MURAM_DATAONLY_SIZE);
>> + if (qe_sdma_init())
>> + panic("sdma init failed!");
>> +
>> + }
>> + start = mm_get(mm, (u32) size, (int)align, "QE");
>> + if (!IS_MURAM_ERR((u32) start))
>> + start = (void *)((u32) start - (u32) qe_immr->muram);
>> +#endif /* USE_RHEAP */
>> + spin_unlock_irqrestore(&qe_muram_lock, flags);
>> +
>> + return (uint) start;
>> +}
>> +
>> +EXPORT_SYMBOL(qe_muram_alloc);
>> +
>> +int qe_muram_free(uint offset)
>> +{
>> + int ret;
>> + unsigned long flags;
>> +
>> + spin_lock_irqsave(&qe_muram_lock, flags);
>> +#ifdef USE_RHEAP
>> + ret = rh_free(&qe_muram_info, (void *)offset);
>> +#else
>> + ret = mm_put(mm, (u32) qe_muram_addr(offset));
>> +#endif /* USE_RHEAP */
>> + spin_unlock_irqrestore(&qe_muram_lock, flags);
>> +
>> + return ret;
>> +}
>> +
>> +EXPORT_SYMBOL(qe_muram_free);
>> +
>> +/* not sure if this is ever needed */
>> +uint qe_muram_alloc_fixed(uint offset, uint size, uint align)
>> +{
>> + void *start;
>> + unsigned long flags;
>> +
>> + spin_lock_irqsave(&qe_muram_lock, flags);
>> +#ifdef USE_RHEAP
>> + qe_muram_info.alignment = align;
>> + start =
>> + rh_alloc_fixed(&qe_muram_info, (void *)offset, size,
>> "commproc");
>> +#else
>> + start = mm_get_force(mm, (u32) offset, (u32) size, "QE");
>> + if (!IS_MURAM_ERR((u32) start))
>> + start = (void *)((u32) start - (u32) qe_immr->muram);
>> +#endif /* USE_RHEAP */
>> + spin_unlock_irqrestore(&qe_muram_lock, flags);
>> +
>> + return (uint) start;
>> +}
>> +
>> +EXPORT_SYMBOL(qe_muram_alloc_fixed);
>> +
>> +void qe_muram_dump(void)
>> +{
>> +#ifdef USE_RHEAP
>> + rh_dump(&qe_muram_info);
>> +#else
>> + mm_dump(mm);
>> +#endif /* USE_RHEAP */
>> +}
>> +
>> +EXPORT_SYMBOL(qe_muram_dump);
>> +
>> +void *qe_muram_addr(uint offset)
>> +{
>> + return (void *)&qe_immr->muram[offset];
>> +}
>> +
>> +EXPORT_SYMBOL(qe_muram_addr);
>> diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/
>> sysdev/qe_lib/qe_ic.c
>> new file mode 100644
>> index 0000000..465630e
>> --- /dev/null
>> +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c
>> @@ -0,0 +1,487 @@
>> +/*
>> + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights
>> reserved.
>> + *
>> + * Author: Shlomi Gridish <gridish@freescale.com>
>> + *
>> + * Description:
>> + * QE Interrupt Controller routines implementations.
>> + *
>> + * Changelog:
>> + * Jun 28, 2006 Li Yang <LeoLi@freescale.com>
>> + * - Reorganized as qe_lib
>> + * - Merged to powerpc arch; add device tree support
>> + * - Style fixes
>> + *
>> + * This program is free software; you can redistribute it and/or
>> modify it
>> + * under the terms of the GNU General Public License as
>> published by the
>> + * Free Software Foundation; either version 2 of the License, or
>> (at your
>> + * option) any later version.
>> + */
>> +#include <linux/kernel.h>
>> +#include <linux/init.h>
>> +#include <linux/errno.h>
>> +#include <linux/reboot.h>
>> +#include <linux/slab.h>
>> +#include <linux/stddef.h>
>> +#include <linux/sched.h>
>> +#include <linux/signal.h>
>> +#include <linux/sysdev.h>
>> +#include <linux/interrupt.h>
>> +
>> +#include <asm/irq.h>
>> +#include <asm/io.h>
>> +#include <asm/qe_ic.h>
>> +
>> +#include "qe_ic.h"
>> +
>> +static struct qe_ic_private p_qe_ic;
>> +static struct qe_ic_private *primary_qe_ic;
>> +
>> +static struct qe_ic_info qe_ic_info[] = {
>> + [1] = {
>> + .mask = 0x00008000,
>> + .qimr = 1,
>> + .pri_code = 0},
>> + [2] = {
>> + .mask = 0x00004000,
>> + .qimr = 1,
>> + .pri_code = 1},
>> + [3] = {
>> + .mask = 0x00002000,
>> + .qimr = 1,
>> + .pri_code = 2},
>> + [10] = {
>> + .mask = 0x00000040,
>> + .qimr = 1,
>> + .pri_code = 1},
>> + [11] = {
>> + .mask = 0x00000020,
>> + .qimr = 1,
>> + .pri_code = 2},
>> + [12] = {
>> + .mask = 0x00000010,
>> + .qimr = 1,
>> + .pri_code = 3},
>> + [13] = {
>> + .mask = 0x00000008,
>> + .qimr = 1,
>> + .pri_code = 4},
>> + [14] = {
>> + .mask = 0x00000004,
>> + .qimr = 1,
>> + .pri_code = 5},
>> + [15] = {
>> + .mask = 0x00000002,
>> + .qimr = 1,
>> + .pri_code = 6},
>> + [20] = {
>> + .mask = 0x10000000,
>> + .qimr = 0,
>> + .pri_code = 3},
>> + [25] = {
>> + .mask = 0x00800000,
>> + .qimr = 0,
>> + .pri_code = 0},
>> + [26] = {
>> + .mask = 0x00400000,
>> + .qimr = 0,
>> + .pri_code = 1},
>> + [27] = {
>> + .mask = 0x00200000,
>> + .qimr = 0,
>> + .pri_code = 2},
>> + [28] = {
>> + .mask = 0x00100000,
>> + .qimr = 0,
>> + .pri_code = 3},
>> + [32] = {
>> + .mask = 0x80000000,
>> + .qimr = 1,
>> + .pri_code = 0},
>> + [33] = {
>> + .mask = 0x40000000,
>> + .qimr = 1,
>> + .pri_code = 1},
>> + [34] = {
>> + .mask = 0x20000000,
>> + .qimr = 1,
>> + .pri_code = 2},
>> + [35] = {
>> + .mask = 0x10000000,
>> + .qimr = 1,
>> + .pri_code = 3},
>> + [36] = {
>> + .mask = 0x08000000,
>> + .qimr = 1,
>> + .pri_code = 4},
>> + [40] = {
>> + .mask = 0x00800000,
>> + .qimr = 1,
>> + .pri_code = 0},
>> + [41] = {
>> + .mask = 0x00400000,
>> + .qimr = 1,
>> + .pri_code = 1},
>> + [42] = {
>> + .mask = 0x00200000,
>> + .qimr = 1,
>> + .pri_code = 2},
>> + [43] = {
>> + .mask = 0x00100000,
>> + .qimr = 1,
>> + .pri_code = 3},
>> +};
>> +
>> +struct hw_interrupt_type qe_ic = {
>> + .typename = "QE IC",
>> + .enable = qe_ic_enable_irq,
>> + .disable = qe_ic_disable_irq,
>> + .ack = qe_ic_disable_irq_and_ack,
>> + .end = qe_ic_end_irq,
>> +};
>> +
>> +static int qe_ic_get_low_irq(struct pt_regs *regs)
>> +{
>> + struct qe_ic_private *p_qe_ic = primary_qe_ic;
>> + int irq = -1;
>> +
>> + /* get the low byte of SIVEC to get the interrupt source vector.
> */
>> + irq = (in_be32(&p_qe_ic->regs->qivec) >> 24) >> 2;
>> +
>> + if (irq == 0) /* 0 --> no irq is pending */
>> + return -1;
>> +
>> + return irq + p_qe_ic->irq_offset;
>> +}
>> +
>> +static int qe_ic_get_high_irq(struct pt_regs *regs)
>> +{
>> + struct qe_ic_private *p_qe_ic = primary_qe_ic;
>> + int irq = -1;
>> +
>> + /* get the high byte of SIVEC to get the interrupt source
> vector. */
>> + irq = (in_be32(&p_qe_ic->regs->qhivec) >> 24) >> 2;
>> +
>> + if (irq == 0) /* 0 --> no irq is pending */
>> + return -1;
>> +
>> + return irq + p_qe_ic->irq_offset;
>> +}
>> +
>> +static irqreturn_t qe_ic_cascade_low(int irq, void *dev_id,
>> + struct pt_regs *regs)
>> +{
>> + while ((irq = qe_ic_get_low_irq(regs)) >= 0)
>> + __do_IRQ(irq, regs);
>> + return IRQ_HANDLED;
>> +}
>> +
>> +static irqreturn_t qe_ic_cascade_high(int irq, void *dev_id,
>> + struct pt_regs *regs)
>> +{
>> + while ((irq = qe_ic_get_high_irq(regs)) >= 0)
>> + __do_IRQ(irq, regs);
>> + return IRQ_HANDLED;
>> +}
>> +
>> +static struct irqaction qe_ic_low_irqaction = {
>> + .handler = qe_ic_cascade_low,
>> + .flags = SA_INTERRUPT,
>> + .mask = CPU_MASK_NONE,
>> + .name = "qe_ic_cascade_low",
>> +};
>> +
>> +static struct irqaction qe_ic_high_irqaction = {
>> + .handler = qe_ic_cascade_high,
>> + .flags = SA_INTERRUPT,
>> + .mask = CPU_MASK_NONE,
>> + .name = "qe_ic_cascade_high",
>> +};
>> +
>> +int qe_ic_init(phys_addr_t phys_addr,
>> + unsigned int flags, unsigned int irq_offset)
>> +{
>> + struct qe_ic_map *regs;
>> + u8 grp, pri, shift = 0;
>> + u32 tmp_qicr = 0, tmp_qricr = 0, tmp_qicnr = 0, tmp_mask;
>> + int i, high_hctive = 0;
>> + const u32 high_signal = 2;
>> +
>> + primary_qe_ic = &p_qe_ic;
>> + memset(primary_qe_ic, 0, sizeof(struct qe_ic_private));
>> +
>> + /* initialize QE interrupt controller registers */
>> + primary_qe_ic->regs = regs =
>> + (struct qe_ic_map *)ioremap(phys_addr, QE_IC_SIZE);
>> + primary_qe_ic->irq_offset = irq_offset;
>> +
>> + /* default priority scheme is grouped. If spread mode is */
>> + /* required, configure sicr accordingly. */
>> + if (flags & QE_IC_SPREADMODE_GRP_W)
>> + tmp_qicr |= QICR_GWCC;
>> + if (flags & QE_IC_SPREADMODE_GRP_X)
>> + tmp_qicr |= QICR_GXCC;
>> + if (flags & QE_IC_SPREADMODE_GRP_Y)
>> + tmp_qicr |= QICR_GYCC;
>> + if (flags & QE_IC_SPREADMODE_GRP_Z)
>> + tmp_qicr |= QICR_GZCC;
>> + if (flags & QE_IC_SPREADMODE_GRP_RISCA)
>> + tmp_qicr |= QICR_GRTA;
>> + if (flags & QE_IC_SPREADMODE_GRP_RISCB)
>> + tmp_qicr |= QICR_GRTB;
>> +
>> + /* choose destination signal for highest priority interrupt */
>> + if (flags & QE_IC_HIGH_SIGNAL) {
>> + tmp_qicr |= (high_signal << QICR_HPIT_SHIFT);
>> + high_hctive = 1;
>> + }
>> +
>> + out_be32(®s->qicr, tmp_qicr);
>> +
>> + tmp_mask = (1 << QE_IC_GRP_W_DEST_SIGNAL_SHIFT);
>> + /* choose destination signal for highest priority interrupt in
> each
>> + * group */
>> + for (grp = 0; grp < NUM_OF_QE_IC_GROUPS; grp++) {
>> + /* the first 2 priorities in each group have a choice of
>> + * destination signal */
>> + for (pri = 0; pri <= 1; pri++) {
>> + if (flags & ((tmp_mask << (grp << 1)) << pri)) {
>> + /* indicate whether QE High signal is
>> + * required */
>> + if (!high_hctive)
>> + high_hctive = 1;
>> +
>> + /* The location of the bits relevant to
>> + * priority 0 in the */
>> + /* registers is always 2 bits left
> comparing
>> + * to priority 1. */
>> + if (pri == 0)
>> + shift = 2;
>> +
>> + switch (grp) {
>> + case (QE_IC_GRP_W):
>> + shift += QICNR_WCC1T_SHIFT;
>> + tmp_qicnr |= high_signal <<
> shift;
>> + break;
>> + case (QE_IC_GRP_X):
>> + shift += QICNR_XCC1T_SHIFT;
>> + tmp_qicnr |= high_signal <<
> shift;
>> + break;
>> + case (QE_IC_GRP_Y):
>> + shift += QICNR_YCC1T_SHIFT;
>> + tmp_qicnr |= high_signal <<
> shift;
>> + break;
>> + case (QE_IC_GRP_Z):
>> + shift += QICNR_ZCC1T_SHIFT;
>> + tmp_qicnr |= high_signal <<
> shift;
>> + break;
>> + case (QE_IC_GRP_RISCA):
>> + shift += QRICR_RTA1T_SHIFT;
>> + tmp_qricr |= high_signal <<
> shift;
>> + break;
>> + case (QE_IC_GRP_RISCB):
>> + shift += QRICR_RTB1T_SHIFT;
>> + tmp_qricr |= high_signal <<
> shift;
>> + break;
>> + default:
>> + break;
>> + }
>> + }
>> + }
>> + }
>> +
>> + if (tmp_qicnr)
>> + out_be32(®s->qicnr, tmp_qicnr);
>> + if (tmp_qricr)
>> + out_be32(®s->qricr, tmp_qricr);
>> +
>> + for (i = primary_qe_ic->irq_offset;
>> + i < (NR_QE_IC_INTS + primary_qe_ic->irq_offset); i++) {
>> + irq_desc[i].handler = &qe_ic;
>> + irq_desc[i].status = IRQ_LEVEL;
>> + }
>> +
>> + /* register QE_IC interrupt controller in the a higher hirarchy
>> + * controller */
>> + setup_irq(IRQ_QE_LOW, &qe_ic_low_irqaction);
>> +
>> + if (high_hctive)
>> + /* register QE_IC high interrupt source in the higher
>> + * hirarchy controller */
>> + setup_irq(IRQ_QE_HIGH, &qe_ic_high_irqaction);
>> +
>> + printk("QE IC (%d IRQ sources) at %p\n", NR_QE_IC_INTS,
>> + primary_qe_ic->regs);
>> + return 0;
>> +}
>> +
>> +void qe_ic_free(void)
>> +{
>> +}
>> +
>> +void qe_ic_enable_irq(unsigned int irq)
>> +{
>> + struct qe_ic_private *p_qe_ic = primary_qe_ic;
>> + unsigned int src = irq - p_qe_ic->irq_offset;
>> + u32 qimr;
>> +
>> + if (qe_ic_info[src].qimr) {
>> + qimr = in_be32(&((struct qe_ic_private
> *)p_qe_ic)->regs->qimr);
>> + out_be32(&((struct qe_ic_private *)p_qe_ic)->regs->qimr,
>> + qimr | (qe_ic_info[src].mask));
>> + } else {
>> + qimr = in_be32(&((struct qe_ic_private
> *)p_qe_ic)->regs->qrimr);
>> + out_be32(&((struct qe_ic_private
> *)p_qe_ic)->regs->qrimr,
>> + qimr | (qe_ic_info[src].mask));
>> + }
>> +}
>> +
>> +void qe_ic_disable_irq(unsigned int irq)
>> +{
>> + struct qe_ic_private *p_qe_ic = primary_qe_ic;
>> + unsigned int src = irq - p_qe_ic->irq_offset;
>> + u32 qimr;
>> +
>> + if (qe_ic_info[src].qimr) {
>> + qimr = in_be32(&((struct qe_ic_private
> *)p_qe_ic)->regs->qimr);
>> + out_be32(&((struct qe_ic_private *)p_qe_ic)->regs->qimr,
>> + qimr & ~(qe_ic_info[src].mask));
>> + } else {
>> + qimr = in_be32(&((struct qe_ic_private
> *)p_qe_ic)->regs->qrimr);
>> + out_be32(&((struct qe_ic_private
> *)p_qe_ic)->regs->qrimr,
>> + qimr & ~(qe_ic_info[src].mask));
>> + }
>> +}
>> +
>> +void qe_ic_disable_irq_and_ack(unsigned int irq)
>> +{
>> + qe_ic_disable_irq(irq);
>> +}
>> +
>> +void qe_ic_end_irq(unsigned int irq)
>> +{
>> +
>> + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))
>> + && irq_desc[irq].action)
>> + qe_ic_enable_irq(irq);
>> +}
>> +
>> +void qe_ic_modify_highest_priority(unsigned int irq)
>> +{
>> + struct qe_ic_private *p_qe_ic = primary_qe_ic;
>> + unsigned int src = irq - p_qe_ic->irq_offset;
>> + u32 tmp_qicr = 0;
>> +
>> + tmp_qicr = in_be32(&p_qe_ic->regs->qicr);
>> + out_be32(&p_qe_ic->regs->qicr, (u32) (tmp_qicr | ((u8) src <<
> 24)));
>> +}
>> +
>> +void qe_ic_modify_priority(enum qe_ic_grp_id grp,
>> + unsigned int pri0,
>> + unsigned int pri1,
>> + unsigned int pri2,
>> + unsigned int pri3,
>> + unsigned int pri4,
>> + unsigned int pri5,
>> + unsigned int pri6, unsigned int pri7)
>> +{
>> + struct qe_ic_private *p_qe_ic = primary_qe_ic;
>> + volatile u32 *p_qip = 0;
>> + u32 tmp_qip = 0;
>> + u8 tmp_array[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
>> + signed char code_array[8], i = 0, j = 0;
>> +
>> + code_array[0] = (signed char)(pri0 ? qe_ic_info[pri0].pri_code :
>
>> -1);
>> + code_array[1] = (signed char)(pri1 ? qe_ic_info[pri1].pri_code :
>
>> -1);
>> + code_array[2] = (signed char)(pri2 ? qe_ic_info[pri2].pri_code :
>
>> -1);
>> + code_array[3] = (signed char)(pri3 ? qe_ic_info[pri3].pri_code :
>
>> -1);
>> + code_array[4] = (signed char)(pri4 ? qe_ic_info[pri4].pri_code :
>
>> -1);
>> + code_array[5] = (signed char)(pri5 ? qe_ic_info[pri5].pri_code :
>
>> -1);
>> + code_array[6] = (signed char)(pri6 ? qe_ic_info[pri6].pri_code :
>
>> -1);
>> + code_array[7] = (signed char)(pri7 ? qe_ic_info[pri7].pri_code :
>
>> -1);
>> +
>> + for (i = 0; i < 8; i++) {
>> + if (code_array[i] == -1)
>> + break;
>> + tmp_array[code_array[i]] = 1;
>> + }
>> +
>> + for (; i < 8; i++) {
>> + while (tmp_array[j] && j < 8)
>> + j++;
>> + code_array[i] = j;
>> + tmp_array[j] = 1;
>> + }
>> +
>> + tmp_qip = (u32) (code_array[0] << QIPCC_SHIFT_PRI0 |
>> + code_array[1] << QIPCC_SHIFT_PRI1 |
>> + code_array[2] << QIPCC_SHIFT_PRI2 |
>> + code_array[3] << QIPCC_SHIFT_PRI3 |
>> + code_array[4] << QIPCC_SHIFT_PRI4 |
>> + code_array[5] << QIPCC_SHIFT_PRI5 |
>> + code_array[6] << QIPCC_SHIFT_PRI6 |
>> + code_array[7] << QIPCC_SHIFT_PRI7);
>> +
>> + switch (grp) {
>> + case (QE_IC_GRP_W):
>> + p_qip = &(p_qe_ic->regs->qipwcc);
>> + break;
>> + case (QE_IC_GRP_X):
>> + p_qip = &(p_qe_ic->regs->qipxcc);
>> + break;
>> + case (QE_IC_GRP_Y):
>> + p_qip = &(p_qe_ic->regs->qipycc);
>> + break;
>> + case (QE_IC_GRP_Z):
>> + p_qip = &(p_qe_ic->regs->qipzcc);
>> + break;
>> + case (QE_IC_GRP_RISCA):
>> + p_qip = &(p_qe_ic->regs->qiprta);
>> + break;
>> + case (QE_IC_GRP_RISCB):
>> + p_qip = &(p_qe_ic->regs->qiprtb);
>> + break;
>> + default:
>> + break;
>> + }
>> +
>> + out_be32(p_qip, tmp_qip);
>> +}
>> +
>> +void qe_ic_dump_regs(void)
>> +{
>> + struct qe_ic_private *p_qe_ic = primary_qe_ic;
>> +
>> + printk(KERN_INFO "QE IC registars:\n");
>> + printk(KERN_INFO "Base address: 0x%08x\n", (u32) p_qe_ic->regs);
>> + printk(KERN_INFO "qicr : addr - 0x%08x, val - 0x%08x\n",
>> + (u32) & p_qe_ic->regs->qicr,
> in_be32(&p_qe_ic->regs->qicr));
>> + printk(KERN_INFO "qivec : addr - 0x%08x, val - 0x%08x\n",
>> + (u32) & p_qe_ic->regs->qivec, in_be32(&p_qe_ic->regs-
>>> qivec));
>> + printk(KERN_INFO "qripnr: addr - 0x%08x, val - 0x%08x\n",
>> + (u32) & p_qe_ic->regs->qripnr, in_be32(&p_qe_ic->regs-
>>> qripnr));
>> + printk(KERN_INFO "qipnr : addr - 0x%08x, val - 0x%08x\n",
>> + (u32) & p_qe_ic->regs->qipnr, in_be32(&p_qe_ic->regs-
>>> qipnr));
>> + printk(KERN_INFO "qipxcc: addr - 0x%08x, val - 0x%08x\n",
>> + (u32) & p_qe_ic->regs->qipxcc, in_be32(&p_qe_ic->regs-
>>> qipxcc));
>> + printk(KERN_INFO "qipycc: addr - 0x%08x, val - 0x%08x\n",
>> + (u32) & p_qe_ic->regs->qipycc, in_be32(&p_qe_ic->regs-
>>> qipycc));
>> + printk(KERN_INFO "qipwcc: addr - 0x%08x, val - 0x%08x\n",
>> + (u32) & p_qe_ic->regs->qipwcc, in_be32(&p_qe_ic->regs-
>>> qipwcc));
>> + printk(KERN_INFO "qipzcc: addr - 0x%08x, val - 0x%08x\n",
>> + (u32) & p_qe_ic->regs->qipzcc, in_be32(&p_qe_ic->regs-
>>> qipzcc));
>> + printk(KERN_INFO "qimr : addr - 0x%08x, val - 0x%08x\n",
>> + (u32) & p_qe_ic->regs->qimr,
> in_be32(&p_qe_ic->regs->qimr));
>> + printk(KERN_INFO "qrimr : addr - 0x%08x, val - 0x%08x\n",
>> + (u32) & p_qe_ic->regs->qrimr, in_be32(&p_qe_ic->regs-
>>> qrimr));
>> + printk(KERN_INFO "qicnr : addr - 0x%08x, val - 0x%08x\n",
>> + (u32) & p_qe_ic->regs->qicnr, in_be32(&p_qe_ic->regs-
>>> qicnr));
>> + printk(KERN_INFO "qiprta: addr - 0x%08x, val - 0x%08x\n",
>> + (u32) & p_qe_ic->regs->qiprta, in_be32(&p_qe_ic->regs-
>>> qiprta));
>> + printk(KERN_INFO "qiprtb: addr - 0x%08x, val - 0x%08x\n",
>> + (u32) & p_qe_ic->regs->qiprtb, in_be32(&p_qe_ic->regs-
>>> qiprtb));
>> + printk(KERN_INFO "qricr : addr - 0x%08x, val - 0x%08x\n",
>> + (u32) & p_qe_ic->regs->qricr, in_be32(&p_qe_ic->regs-
>>> qricr));
>> + printk(KERN_INFO "qhivec: addr - 0x%08x, val - 0x%08x\n",
>> + (u32) & p_qe_ic->regs->qhivec, in_be32(&p_qe_ic->regs-
>>> qhivec));
>> +}
>> diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.h b/arch/powerpc/
>> sysdev/qe_lib/qe_ic.h
>> new file mode 100644
>> index 0000000..6662ad2
>> --- /dev/null
>> +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.h
>> @@ -0,0 +1,83 @@
>> +/*
>> + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights
>> reserved.
>> + *
>> + * Author: Shlomi Gridish <gridish@freescale.com>
>> + *
>> + * Description:
>> + * QE IC private definitions and structure.
>> + *
>> + * Changelog:
>> + * Jun 21, 2006 Li Yang <LeoLi@freescale.com>
>> + * - Style fix; port to powerpc arch
>> + *
>> + * This program is free software; you can redistribute it and/or
>> modify it
>> + * under the terms of the GNU General Public License as
>> published by the
>> + * Free Software Foundation; either version 2 of the License, or
>> (at your
>> + * option) any later version.
>> + */
>> +#ifndef __QE_IC_H__
>> +#define __QE_IC_H__
>> +
>> +typedef struct qe_ic_map {
>> + volatile u32 qicr;
>> + volatile u32 qivec;
>> + volatile u32 qripnr;
>> + volatile u32 qipnr;
>> + volatile u32 qipxcc;
>> + volatile u32 qipycc;
>> + volatile u32 qipwcc;
>> + volatile u32 qipzcc;
>> + volatile u32 qimr;
>> + volatile u32 qrimr;
>> + volatile u32 qicnr;
>> + volatile u8 res0[0x4];
>> + volatile u32 qiprta;
>> + volatile u32 qiprtb;
>> + volatile u8 res1[0x4];
>> + volatile u32 qricr;
>> + volatile u8 res2[0x20];
>> + volatile u32 qhivec;
>> + volatile u8 res3[0x1C];
>> +} __attribute__ ((packed)) qe_ic_map_t;
>> +
>> +
>> +#define QE_IC_SIZE sizeof(struct qe_ic_map)
>> +
>> +/* Interrupt priority registers */
>> +#define QIPCC_SHIFT_PRI0 29
>> +#define QIPCC_SHIFT_PRI1 26
>> +#define QIPCC_SHIFT_PRI2 23
>> +#define QIPCC_SHIFT_PRI3 20
>> +#define QIPCC_SHIFT_PRI4 13
>> +#define QIPCC_SHIFT_PRI5 10
>> +#define QIPCC_SHIFT_PRI6 7
>> +#define QIPCC_SHIFT_PRI7 4
>> +
>> +/* QICR priority modes */
>> +#define QICR_GWCC 0x00040000
>> +#define QICR_GXCC 0x00020000
>> +#define QICR_GYCC 0x00010000
>> +#define QICR_GZCC 0x00080000
>> +#define QICR_GRTA 0x00200000
>> +#define QICR_GRTB 0x00400000
>> +#define QICR_HPIT_SHIFT 8
>> +
>> +/* QICNR */
>> +#define QICNR_WCC1T_SHIFT 20
>> +#define QICNR_ZCC1T_SHIFT 28
>> +#define QICNR_YCC1T_SHIFT 12
>> +#define QICNR_XCC1T_SHIFT 4
>> +
>> +/* QRICR */
>> +#define QRICR_RTA1T_SHIFT 20
>> +#define QRICR_RTB1T_SHIFT 28
>> +
>> +struct qe_ic_private {
>> + struct qe_ic_map *regs;
>> + unsigned int irq_offset;
>> +} qe_ic_private_t;
>> +
>> +extern struct hw_interrupt_type qe_ic;
>> +extern int qe_ic_get_irq(struct pt_regs *regs);
>> +
>> +#endif /* __QE_IC_H__ */
>> diff --git a/arch/powerpc/sysdev/qe_lib/qe_io.c b/arch/powerpc/
>> sysdev/qe_lib/qe_io.c
>> new file mode 100644
>> index 0000000..a943c27
>> --- /dev/null
>> +++ b/arch/powerpc/sysdev/qe_lib/qe_io.c
>> @@ -0,0 +1,275 @@
>> +/*
>> + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights
>> reserved.
>> + *
>> + * Author: Li Yang <LeoLi@freescale.com>
>> + *
>> + * Description:
>> + * QE Parallel I/O ports configuration routines. Based on code from
>> + * Shlomi Gridish <gridish@freescale.com>
>> + *
>> + * Changelog:
>> + * Jun 21, 2006 Initial version
>> + *
>> + * This program is free software; you can redistribute it and/or
>> modify it
>> + * under the terms of the GNU General Public License as
>> published by the
>> + * Free Software Foundation; either version 2 of the License, or
>> (at your
>> + * option) any later version.
>> + */
>> +
>> +#include <linux/config.h>
>> +#include <linux/stddef.h>
>> +#include <linux/kernel.h>
>> +#include <linux/init.h>
>> +#include <linux/errno.h>
>> +#include <linux/module.h>
>> +
>> +#include <asm/io.h>
>> +#include <asm/prom.h>
>> +#include <sysdev/fsl_soc.h>
>> +#undef DEBUG
>> +
>> +#define NUM_OF_PINS 32
>> +#define NUM_OF_PAR_IOS 7
>> +
>> +typedef struct par_io {
>> + struct {
>> + u32 cpodr; /* Open drain register */
>> + u32 cpdata; /* Data register */
>> + u32 cpdir1; /* Direction register */
>> + u32 cpdir2; /* Direction register */
>> + u32 cppar1; /* Pin assignment register */
>> + u32 cppar2; /* Pin assignment register */
>> + } io_regs[NUM_OF_PAR_IOS];
>> +} par_io_t;
>> +
>> +typedef struct qe_par_io {
>> + u8 res[0xc];
>> + u32 cepier; /* QE ports interrupt event register */
>> + u32 cepimr; /* QE ports mask event register */
>> + u32 cepicr; /* QE ports control event register */
>> +} qe_par_io_t;
>> +
>> +static int qe_irq_ports[NUM_OF_PAR_IOS][NUM_OF_PINS] = {
>> + /* 0-7 */ /* 8-15 */ /* 16 - 23 */ /* 24 - 31
> */
>> + {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,1, 1,0,0,0,0,0,0,0,
>> 0,0,0,0,0,1,1,0},
>> + {0,0,0,1,0,1,0,0, 0,0,0,0,1,1,0,0, 0,0,0,0,0,0,0,0,
>> 0,0,1,1,0,0,0,0},
>> + {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
>> 0,0,0,1,1,1,0,0},
>> + {0,0,0,0,0,0,0,0, 0,0,0,0,1,1,0,0, 1,1,0,0,0,0,0,0,
>> 0,0,1,1,0,0,0,0},
>> + {0,0,0,0,0,0,0,0, 0,0,0,0,1,1,0,0, 0,0,0,0,0,0,0,0,
>> 1,1,1,1,0,0,0,1},
>> + {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,1,0,0,0,
>> 0,0,0,0,0,0,0,0},
>> + {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
> 0,0,0,0,0,0,0,1}
>> +};
>> +
>> +
>> +static u8 get_irq_num(u8 port, u8 pin)
>> +{
>> + int i, j;
>> + u8 num = 0;
>> +
>> + if (qe_irq_ports[port][pin] == 0)
>> + return -1;
>> + for (j = 0; j <= port; j++)
>> + for (i = 0; i < pin; i++)
>> + if (qe_irq_ports[j][i])
>> + num++;
>> + return num;
>> +}
>> +
>> +static par_io_t *par_io = NULL;
>> +static qe_par_io_t *qe_par_io = NULL;
>> +
>> +int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain,
>> + int assignment, int has_irq)
>> +{
>> + u32 pinMask1bit, pinMask2bits, newMask2bits, tmp_val;
>> +
>> + if (!par_io) {
>> + par_io = (par_io_t *) ioremap(get_immrbase() + 0x1400,
>> + sizeof(par_io_t));
>> + qe_par_io = (qe_par_io_t *) ioremap(get_immrbase() +
> 0xC00,
>> +
> sizeof(qe_par_io_t));
>> +
>> + /* clear event bits in the event register of the QE
> ports */
>> + out_be32(&qe_par_io->cepier, 0xFFFFFFFF);
>> + }
>> +
>> + /* calculate pin location for single and 2 bits information */
>> + pinMask1bit = (u32) (1 << (NUM_OF_PINS - (pin + 1)));
>> +
>> + /* Set open drain, if required */
>> + tmp_val = in_be32(&par_io->io_regs[port].cpodr);
>> + if (open_drain)
>> + out_be32(&par_io->io_regs[port].cpodr, pinMask1bit |
> tmp_val);
>> + else
>> + out_be32(&par_io->io_regs[port].cpodr, ~pinMask1bit &
> tmp_val);
>> +
>> + /* define direction */
>> + tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ?
>> + in_be32(&par_io->io_regs[port].cpdir2) :
>> + in_be32(&par_io->io_regs[port].cpdir1);
>> +
>> + /* get all bits mask for 2 bit per port */
>> + pinMask2bits = (u32) (0x3 <<
>> + (NUM_OF_PINS -
>> + (pin % (NUM_OF_PINS / 2) + 1) * 2));
>> +
>> + /* Get the final mask we need for the right definition */
>> + newMask2bits = (u32) (dir <<
>> + (NUM_OF_PINS -
>> + (pin % (NUM_OF_PINS / 2) + 1) * 2));
>> +
>> + /* clear and set 2 bits mask */
>> + if (pin > (NUM_OF_PINS / 2) - 1) {
>> + out_be32(&par_io->io_regs[port].cpdir2,
>> + ~pinMask2bits & tmp_val);
>> + tmp_val &= ~pinMask2bits;
>> + out_be32(&par_io->io_regs[port].cpdir2, newMask2bits |
> tmp_val);
>> + } else {
>> + out_be32(&par_io->io_regs[port].cpdir1,
>> + ~pinMask2bits & tmp_val);
>> + tmp_val &= ~pinMask2bits;
>> + out_be32(&par_io->io_regs[port].cpdir1, newMask2bits |
> tmp_val);
>> + }
>> + /* define pin assignment */
>> + tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ?
>> + in_be32(&par_io->io_regs[port].cppar2) :
>> + in_be32(&par_io->io_regs[port].cppar1);
>> +
>> + newMask2bits = (u32) (assignment << (NUM_OF_PINS -
>> + (pin % (NUM_OF_PINS / 2) + 1) * 2));
>> + /* clear and set 2 bits mask */
>> + if (pin > (NUM_OF_PINS / 2) - 1) {
>> + out_be32(&par_io->io_regs[port].cppar2,
>> + ~pinMask2bits & tmp_val);
>> + tmp_val &= ~pinMask2bits;
>> + out_be32(&par_io->io_regs[port].cppar2, newMask2bits |
> tmp_val);
>> + } else {
>> + out_be32(&par_io->io_regs[port].cppar1,
>> + ~pinMask2bits & tmp_val);
>> + tmp_val &= ~pinMask2bits;
>> + out_be32(&par_io->io_regs[port].cppar1, newMask2bits |
> tmp_val);
>> + }
>> +
>> + /* Set interrupt mask if the pin generates interrupt */
>> + if (has_irq) {
>> + int irq = get_irq_num(port, pin);
>> + u32 mask = 0;
>> +
>> + if (irq == -1) {
>> + printk(KERN_WARNING "Port %d, pin %d is can't be
> "
>> + "interrupt\n", port, pin);
>> + return -EINVAL;
>> + }
>> + mask = 0x80000000 >> irq;
>> +
>> + tmp_val = in_be32(&qe_par_io->cepimr);
>> + out_be32(&qe_par_io->cepimr, mask | tmp_val);
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +EXPORT_SYMBOL(par_io_config_pin);
>> +
>> +int par_io_data_set(u8 port, u8 pin, u8 val)
>> +{
>> + u32 pin_mask, tmp_val;
>> +
>> + if (port >= NUM_OF_PAR_IOS)
>> + return -EINVAL;
>> + if (pin >= NUM_OF_PINS)
>> + return -EINVAL;
>> + /* calculate pin location */
>> + pin_mask = (u32) (1 << (NUM_OF_PINS - 1 - pin));
>> +
>> + tmp_val = in_be32(&par_io->io_regs[port].cpdata);
>> +
>> + if (val == 0) /* clear */
>> + out_be32(&par_io->io_regs[port].cpdata, ~pin_mask &
> tmp_val);
>> + else /* set */
>> + out_be32(&par_io->io_regs[port].cpdata, pin_mask |
> tmp_val);
>> +
>> + return 0;
>> +}
>> +
>> +EXPORT_SYMBOL(par_io_data_set);
>> +
>> +int par_io_of_config(struct device_node *np)
>> +{
>> + struct device_node *pio;
>> + phandle *ph;
>> + int pio_map_len;
>> + unsigned int *pio_map;
>> +
>> + ph = (phandle *) get_property(np, "pio-handle", NULL);
>> + if (ph == 0) {
>> + printk(KERN_ERR "pio-handle not available \n");
>> + return -1;
>> + }
>> +
>> + pio = of_find_node_by_phandle(*ph);
>> +
>> + pio_map = (unsigned int *)
>> + get_property(pio, "pio-map", &pio_map_len);
>> + if (pio_map == NULL) {
>> + printk(KERN_ERR "pio-map is not set! \n");
>> + return -1;
>> + }
>> + pio_map_len /= sizeof(unsigned int);
>> + if ((pio_map_len % 6) != 0) {
>> + printk(KERN_ERR "pio-map format wrong! \n");
>> + return -1;
>> + }
>> +
>> + while (pio_map_len > 0) {
>> + par_io_config_pin((u8) pio_map[0], (u8) pio_map[1],
>> + (int) pio_map[2], (int) pio_map[3],
>> + (int) pio_map[4], (int) pio_map[5]);
>> + pio_map += 6;
>> + pio_map_len -= 6;
>> + }
>> + of_node_put(pio);
>> + return 0;
>> +}
>> +EXPORT_SYMBOL(par_io_of_config);
>> +
>> +#ifdef DEBUG
>> +static void dump_par_io(void)
>> +{
>> + int i;
>> +
>> + printk(KERN_INFO "PAR IO registars:\n");
>> + printk(KERN_INFO "Base address: 0x%08x\n", (u32) par_io);
>> + for (i = 0; i < NUM_OF_PAR_IOS; i++) {
>> + printk(KERN_INFO "cpodr[%d] : addr - 0x%08x, val -
> 0x%08x\n",
>> + i, (u32) & par_io->io_regs[i].cpodr,
>> + in_be32(&par_io->io_regs[i].cpodr));
>> + printk(KERN_INFO "cpdata[%d]: addr - 0x%08x, val -
> 0x%08x\n",
>> + i, (u32) & par_io->io_regs[i].cpdata,
>> + in_be32(&par_io->io_regs[i].cpdata));
>> + printk(KERN_INFO "cpdir1[%d]: addr - 0x%08x, val -
> 0x%08x\n",
>> + i, (u32) & par_io->io_regs[i].cpdir1,
>> + in_be32(&par_io->io_regs[i].cpdir1));
>> + printk(KERN_INFO "cpdir2[%d]: addr - 0x%08x, val -
> 0x%08x\n",
>> + i, (u32) & par_io->io_regs[i].cpdir2,
>> + in_be32(&par_io->io_regs[i].cpdir2));
>> + printk(KERN_INFO "cppar1[%d]: addr - 0x%08x, val -
> 0x%08x\n",
>> + i, (u32) & par_io->io_regs[i].cppar1,
>> + in_be32(&par_io->io_regs[i].cppar1));
>> + printk(KERN_INFO "cppar2[%d]: addr - 0x%08x, val -
> 0x%08x\n",
>> + i, (u32) & par_io->io_regs[i].cppar2,
>> + in_be32(&par_io->io_regs[i].cppar2));
>> + }
>> +
>> + printk(KERN_INFO "QE PAR IO registars:\n");
>> + printk(KERN_INFO "Base address: 0x%08x\n", (u32) qe_par_io);
>> + printk(KERN_INFO "cepier : addr - 0x%08x, val - 0x%08x\n",
>> + (u32) & qe_par_io->cepier, in_be32(&qe_par_io->cepier));
>> + printk(KERN_INFO "cepimr : addr - 0x%08x, val - 0x%08x\n",
>> + (u32) & qe_par_io->cepimr, in_be32(&qe_par_io->cepimr));
>> + printk(KERN_INFO "cepicr : addr - 0x%08x, val - 0x%08x\n",
>> + (u32) & qe_par_io->cepicr, in_be32(&qe_par_io->cepicr));
>> +}
>> +
>> +EXPORT_SYMBOL(dump_par_io);
>> +#endif
>> -
>> To unsubscribe from this list: send the line "unsubscribe linux-
>> kernel" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>> Please read the FAQ at http://www.tux.org/lkml/
>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox