* Re: [PATCH 2/4] mpc8313erdb: Add NAND to device tree, and call of_platform_bus_probe().
From: Olof Johansson @ 2007-12-13 21:40 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev
In-Reply-To: <20071213171714.GA4510@loki.buserror.net>
On Thu, Dec 13, 2007 at 11:17:14AM -0600, Scott Wood wrote:
> Signed-off-by: Scott Wood <scottwood@freescale.com>
> diff --git a/arch/powerpc/platforms/83xx/mpc8313_rdb.c b/arch/powerpc/platforms/83xx/mpc8313_rdb.c
> index 6fb8299..3ad482a 100644
> --- a/arch/powerpc/platforms/83xx/mpc8313_rdb.c
> +++ b/arch/powerpc/platforms/83xx/mpc8313_rdb.c
> @@ -14,6 +14,7 @@
> */
>
> #include <linux/pci.h>
> +#include <linux/of_platform.h>
>
> #include <asm/time.h>
> #include <asm/ipic.h>
> @@ -75,6 +76,22 @@ static int __init mpc8313_rdb_probe(void)
> return of_flat_dt_is_compatible(root, "MPC8313ERDB");
> }
>
> +static struct of_device_id __initdata of_bus_ids[] = {
> + { .name = "soc8313", },
> + { .name = "localbus", },
Please probe based on compatible instead of name properties.
Thanks,
Olof
^ permalink raw reply
* RE: [ofa-general] Re: [ewg] Re: [PATCH] IB/ehca: Serialize HCA-related hCalls on POWER5
From: Caitlin Bestler @ 2007-12-13 21:08 UTC (permalink / raw)
To: Joachim Fenkes
Cc: Arnd Bergmann, Roland Dreier, LKML, Or Gerlitz, linuxppc-dev,
OF-General, Stefan Roscher
In-Reply-To: <OFD5B7D5E6.3538DC2A-ONC12573B0.0072D42A-C12573B0.00735730@de.ibm.com>
> -----Original Message-----
> From: Joachim Fenkes [mailto:FENKES@de.ibm.com]
> Sent: Thursday, December 13, 2007 1:00 PM
> To: Caitlin Bestler
> Cc: Arnd Bergmann; caitlin.bestler@gmail.com; OF-General; LKML;
> linuxppc-dev@ozlabs.org; Or Gerlitz; Roland Dreier; Stefan Roscher
> Subject: Re: [ofa-general] Re: [ewg] Re: [PATCH] IB/ehca: Serialize
> HCA-related hCalls on POWER5
>=20
> caitlin.bestler@gmail.com wrote on 13.12.2007 20:22:49:
>=20
> > On Dec 13, 2007 12:30 AM, Or Gerlitz <ogerlitz@voltaire.com> wrote:
> > > The current implementation of the open iscsi initiator makes sure
> to
> > > issue commands in thread (sleepable) context, see iscsi_xmitworker
> and
> > > references to it in drivers/scsi/libiscsi.c , so this keeps ehca
> users
> > > safe for the time being.
>=20
> > I agree, *some* form of FMR support is important for iSER (and
> probably
> > for NFS over RDMA as well). Rather than adding a crippled NO FMR
> > mode it would make more sense to add support for FMR Work Requests.
> > I'm not certain what, if any, impact that would have on the Power5
> problem,
> > but that's certainly a cleaner path for iWARP.
>=20
> Well, FMR WRs wouldn't change the eHCA issue -- the driver would have
> to
> make an hCall in any case, and the architecture says that the hCalls
> used
> in this scenario might return H_LONG_BUSY, causing the driver to
sleep.
> No
> way around that. Because of this, eHCA's FMRs are actually standard
MRs
> with a different API.
>=20
> If, as Or said, the iSCSI initiator issues commands in sleepable
> context
> anyway, nothing would be lost by using standard MRs as a fallback
> solution
> if FMRs aren't available, would it?
>=20
To clarify, an FMR Work Request is simply posted to the SendQ like
any other Work Request (of course the QP has to be privileged, or
it will complete in error). An SQ Post should never block.
But yes, if the current iSCSI initiator always does all call-based
FMRs in a sleepable context then I would agree then any changes can
wait for the first vendor that wants to support FMR Work Requests.
FMR Work Requests can be pipelined, so anyone with hardware that
supported them would have strong motivation to enable the open
iSCSI initiator to take advantage of this.
^ permalink raw reply
* Re: [PATCH 19/20] [POWERPC] pci32: 4xx embedded platforms want to reassign all PCI resources
From: Josh Boyer @ 2007-12-13 21:11 UTC (permalink / raw)
To: benh; +Cc: linuxppc-dev
In-Reply-To: <1197579177.15741.169.camel@pasglop>
On Fri, 14 Dec 2007 07:52:57 +1100
Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:
>
> On Thu, 2007-12-13 at 14:40 -0600, Josh Boyer wrote:
> >
> > > > This one is slightly broken in my opinion. You've added
> > > > the ppc_pci_flags to all of these platforms, which is fine for
> > your
> > > > intended goal. But now all of these platforms _have_ to compile
> > with
> > > > PCI enabled or they'll break with:
> > > >
> > > > arch/powerpc/platforms/built-in.o: In function `walnut_probe':
> > > > walnut.c:(.init.text+0x9a): undefined reference to `ppc_pci_flags'
> > > > walnut.c:(.init.text+0xa6): undefined reference to `ppc_pci_flags'
> > > > make[1]: *** [.tmp_vmlinux1] Error 1
> > > >
> > > > So to do it correctly we need to either select CONFIG_PCI for all
> > of
> > > > them, wrap the ppc_pci_flags assignment in #ifdef CONFIG_PCI, or
> > move
> > > > the ppc_pci_flags variable declaration into something that always
> > gets
> > > > compiled.
> > >
> > > Hrm... PCI is user selectable ? Forgot about that ...
> > >
> > > All those platforms have PCI slots, so we may as well select it in
> > > Kconfig... I'd rather avoid #ifdef's
> >
> > What about people that don't have PCI on their boards, or don't really
> > care about it?
>
> Then those boards wouldn't be a walnut, ep405, ... right ?
>
> That's why I put the flags in the BSP. If your board has no PCI, don't
> muck around with the PCI flags.
Well, there is physical PCI hardware on the boards, yes. But what if
people have no intention of using it? E.g. they have no devices, etc.
Now we're requiring PCI support to be built into the kernel.
I'm just being pedantic about keeping embedded tiny.
josh
^ permalink raw reply
* Re: [ofa-general] Re: [ewg] Re: [PATCH] IB/ehca: Serialize HCA-related hCalls on POWER5
From: Joachim Fenkes @ 2007-12-13 20:59 UTC (permalink / raw)
To: Caitlin Bestler
Cc: Arnd Bergmann, Roland Dreier, LKML, Or Gerlitz, linuxppc-dev,
caitlin.bestler, OF-General, Stefan Roscher
In-Reply-To: <469958e00712131122s661dd970ud359389e1c6637d4@mail.gmail.com>
caitlin.bestler@gmail.com wrote on 13.12.2007 20:22:49:
> On Dec 13, 2007 12:30 AM, Or Gerlitz <ogerlitz@voltaire.com> wrote:
> > The current implementation of the open iscsi initiator makes sure to
> > issue commands in thread (sleepable) context, see iscsi_xmitworker and
> > references to it in drivers/scsi/libiscsi.c , so this keeps ehca users
> > safe for the time being.
> I agree, *some* form of FMR support is important for iSER (and probably
> for NFS over RDMA as well). Rather than adding a crippled NO FMR
> mode it would make more sense to add support for FMR Work Requests.
> I'm not certain what, if any, impact that would have on the Power5
problem,
> but that's certainly a cleaner path for iWARP.
Well, FMR WRs wouldn't change the eHCA issue -- the driver would have to
make an hCall in any case, and the architecture says that the hCalls used
in this scenario might return H_LONG_BUSY, causing the driver to sleep. No
way around that. Because of this, eHCA's FMRs are actually standard MRs
with a different API.
If, as Or said, the iSCSI initiator issues commands in sleepable context
anyway, nothing would be lost by using standard MRs as a fallback solution
if FMRs aren't available, would it?
J.
^ permalink raw reply
* Re: [PATCH 19/20] [POWERPC] pci32: 4xx embedded platforms want to reassign all PCI resources
From: Benjamin Herrenschmidt @ 2007-12-13 20:52 UTC (permalink / raw)
To: Josh Boyer; +Cc: linuxppc-dev
In-Reply-To: <20071213144056.1a46b7a3@weaponx>
On Thu, 2007-12-13 at 14:40 -0600, Josh Boyer wrote:
>
> > > This one is slightly broken in my opinion. You've added
> > > the ppc_pci_flags to all of these platforms, which is fine for
> your
> > > intended goal. But now all of these platforms _have_ to compile
> with
> > > PCI enabled or they'll break with:
> > >
> > > arch/powerpc/platforms/built-in.o: In function `walnut_probe':
> > > walnut.c:(.init.text+0x9a): undefined reference to `ppc_pci_flags'
> > > walnut.c:(.init.text+0xa6): undefined reference to `ppc_pci_flags'
> > > make[1]: *** [.tmp_vmlinux1] Error 1
> > >
> > > So to do it correctly we need to either select CONFIG_PCI for all
> of
> > > them, wrap the ppc_pci_flags assignment in #ifdef CONFIG_PCI, or
> move
> > > the ppc_pci_flags variable declaration into something that always
> gets
> > > compiled.
> >
> > Hrm... PCI is user selectable ? Forgot about that ...
> >
> > All those platforms have PCI slots, so we may as well select it in
> > Kconfig... I'd rather avoid #ifdef's
>
> What about people that don't have PCI on their boards, or don't really
> care about it?
Then those boards wouldn't be a walnut, ep405, ... right ?
That's why I put the flags in the BSP. If your board has no PCI, don't
muck around with the PCI flags.
Ben.
^ permalink raw reply
* Re: [PATCH 1/20] [POWERPC] Reworking machine check handling and Fix 440/440A
From: Benjamin Herrenschmidt @ 2007-12-13 20:38 UTC (permalink / raw)
To: Josh Boyer; +Cc: linuxppc-dev
In-Reply-To: <20071213135317.0cffbfb8@weaponx>
> This breaks non-44x based arch/ppc platforms. For example ep405 in
> arch/ppc fails with:
>
> /home/jwboyer/src/linux-2.6/arch/ppc/kernel/traps.c: In function ‘machine_check_440A’:
> /home/jwboyer/src/linux-2.6/arch/ppc/kernel/traps.c:260: error: ‘MCSR_IB’ undeclared (first use in this function)
> /home/jwboyer/src/linux-2.6/arch/ppc/kernel/traps.c:260: error: (Each undeclared identifier is reported only once
> /home/jwboyer/src/linux-2.6/arch/ppc/kernel/traps.c:260: error: for each function it appears in.)
> /home/jwboyer/src/linux-2.6/arch/ppc/kernel/traps.c:262: error: ‘MCSR_DRB’ undeclared (first use in this function)
> /home/jwboyer/src/linux-2.6/arch/ppc/kernel/traps.c:264: error: ‘MCSR_DWB’ undeclared (first use in this function)
> /home/jwboyer/src/linux-2.6/arch/ppc/kernel/traps.c:266: error: ‘MCSR_TLBP’ undeclared (first use in this function)
> /home/jwboyer/src/linux-2.6/arch/ppc/kernel/traps.c:268: error: ‘MCSR_ICP’ undeclared (first use in this function)
> /home/jwboyer/src/linux-2.6/arch/ppc/kernel/traps.c:272: error: ‘MCSR_DCSP’ undeclared (first use in this function)
> /home/jwboyer/src/linux-2.6/arch/ppc/kernel/traps.c:274: error: ‘MCSR_DCFP’ undeclared (first use in this function)
> /home/jwboyer/src/linux-2.6/arch/ppc/kernel/traps.c:276: error: ‘MCSR_IMPE’ undeclared (first use in this function)
> make[2]: *** [arch/ppc/kernel/traps.o] Error 1
>
> The same is true for other platforms as well. Getting closer...
True, I intended to use 4xx not 44x for the ifdef... very easy typo to
make.
Ben.
^ permalink raw reply
* Re: [PATCH 19/20] [POWERPC] pci32: 4xx embedded platforms want to reassign all PCI resources
From: Josh Boyer @ 2007-12-13 20:40 UTC (permalink / raw)
To: benh; +Cc: linuxppc-dev
In-Reply-To: <1197578243.15741.150.camel@pasglop>
On Fri, 14 Dec 2007 07:37:23 +1100
Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:
>
> > This one is slightly broken in my opinion. You've added
> > the ppc_pci_flags to all of these platforms, which is fine for your
> > intended goal. But now all of these platforms _have_ to compile with
> > PCI enabled or they'll break with:
> >
> > arch/powerpc/platforms/built-in.o: In function `walnut_probe':
> > walnut.c:(.init.text+0x9a): undefined reference to `ppc_pci_flags'
> > walnut.c:(.init.text+0xa6): undefined reference to `ppc_pci_flags'
> > make[1]: *** [.tmp_vmlinux1] Error 1
> >
> > So to do it correctly we need to either select CONFIG_PCI for all of
> > them, wrap the ppc_pci_flags assignment in #ifdef CONFIG_PCI, or move
> > the ppc_pci_flags variable declaration into something that always gets
> > compiled.
>
> Hrm... PCI is user selectable ? Forgot about that ...
>
> All those platforms have PCI slots, so we may as well select it in
> Kconfig... I'd rather avoid #ifdef's
What about people that don't have PCI on their boards, or don't really
care about it?
josh
^ permalink raw reply
* Re: [PATCH 19/20] [POWERPC] pci32: 4xx embedded platforms want to reassign all PCI resources
From: Benjamin Herrenschmidt @ 2007-12-13 20:37 UTC (permalink / raw)
To: Josh Boyer; +Cc: linuxppc-dev
In-Reply-To: <20071213130547.728d873d@weaponx>
On Thu, 2007-12-13 at 13:05 -0600, Josh Boyer wrote:
> On Thu, 13 Dec 2007 18:38:46 +1100
> Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:
>
> > This makes 4xx embedded platforms re-assign all PCI resources as we
> > pretty much never care about what the various firmwares have done on
> > these, it's generally not compatible with the way the kernel will map
> > the bridges.
> >
> > We still need to also enable bus renumbering on some of them, but I
> > will do that from a separate patch after I've fixed 4xx PCIe to handle
> > all bus numbers.
> >
> > Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
>
> [snip]
>
> > Index: linux-work/arch/powerpc/platforms/44x/sequoia.c
> > ===================================================================
> > --- linux-work.orig/arch/powerpc/platforms/44x/sequoia.c 2007-12-10 16:51:42.000000000 +1100
> > +++ linux-work/arch/powerpc/platforms/44x/sequoia.c 2007-12-10 16:55:06.000000000 +1100
> > @@ -21,7 +21,8 @@
> > #include <asm/udbg.h>
> > #include <asm/time.h>
> > #include <asm/uic.h>
> > -#include "44x.h"
> > +#include <asm/pci-bridge.h>
> > +
>
> Oh, and you also broke the Sequoia build with this change because you
> removed the 44x.h include :).
Ok.
Ben.
^ permalink raw reply
* Re: [PATCH 19/20] [POWERPC] pci32: 4xx embedded platforms want to reassign all PCI resources
From: Benjamin Herrenschmidt @ 2007-12-13 20:37 UTC (permalink / raw)
To: Josh Boyer; +Cc: linuxppc-dev
In-Reply-To: <20071213130113.59342c40@weaponx>
> This one is slightly broken in my opinion. You've added
> the ppc_pci_flags to all of these platforms, which is fine for your
> intended goal. But now all of these platforms _have_ to compile with
> PCI enabled or they'll break with:
>
> arch/powerpc/platforms/built-in.o: In function `walnut_probe':
> walnut.c:(.init.text+0x9a): undefined reference to `ppc_pci_flags'
> walnut.c:(.init.text+0xa6): undefined reference to `ppc_pci_flags'
> make[1]: *** [.tmp_vmlinux1] Error 1
>
> So to do it correctly we need to either select CONFIG_PCI for all of
> them, wrap the ppc_pci_flags assignment in #ifdef CONFIG_PCI, or move
> the ppc_pci_flags variable declaration into something that always gets
> compiled.
Hrm... PCI is user selectable ? Forgot about that ...
All those platforms have PCI slots, so we may as well select it in
Kconfig... I'd rather avoid #ifdef's
Ben.
^ permalink raw reply
* Re: apm_emulation regression
From: Benjamin Herrenschmidt @ 2007-12-13 20:31 UTC (permalink / raw)
To: Johannes Berg; +Cc: Rafael J. Wysocki, linuxppc-dev list, linux-pm, ralf
In-Reply-To: <1197546020.6558.247.camel@johannes.berg>
On Thu, 2007-12-13 at 12:40 +0100, Johannes Berg wrote:
> > > That basically means X will break. That's why X broke on the latest
> > > ubuntu until I whacked some new scripts in them to force console
> > > switching, among other things. Possibly other apps that relied
> > > on /dev/apm_bios to be notified of system suspend/resume broke as well.
> >
> > Ah. I guess I never noticed because I had the scripts to do console
> > switching all along.
>
> Actually, it just occurred to me that the *kernel* does a console switch
> when we use /sys/power/state, so maybe that is why I never had a problem
> rather than userspace doing a console switch (which it only started
> doing very recently)
The kernel console switching can be disabled and -is- by some distros.
For example, the problem I was having was when testing Gutsy before it
was final, the script to console switch wasn't in the right place for
powermac and didn't work. X wouldn't be suspended properly and the
machine would lockup.
In general, we should try to fix that, as other things might rely
on /dev/apm_bios doing the right thing.
Ben.
^ permalink raw reply
* Re: [PATCH/RFC] CPM1: implement GPIO API
From: Arnd Bergmann @ 2007-12-13 20:31 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <20071213165530.GB4347@loki.buserror.net>
On Thursday 13 December 2007, Scott Wood wrote:
> > +}
> > +EXPORT_SYMBOL_GPL(gpio_request);
>
> This is an API, not internals; can we stick with plain EXPORT_SYMBOL()?
The architecture independent API posted by David Brownell uses _GPL,
see http://lkml.org/lkml/2007/11/9/141.
I'd vote for _GPL on all new interfaces anyway, but I guess this one
is really David's decision since he came up with the API.
Arnd <><
^ permalink raw reply
* Re: [PATCH 1/20] [POWERPC] Reworking machine check handling and Fix 440/440A
From: Josh Boyer @ 2007-12-13 19:53 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev
In-Reply-To: <20071213073836.A25EDDDF80@ozlabs.org>
On Thu, 13 Dec 2007 18:38:31 +1100
Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:
> This adds a cputable function pointer for the CPU-side machine
> check handling. The semantic is still the same as the old one,
> the one in ppc_md. overrides the one in cputable, though
> ultimately we'll want to change that so the CPU gets first.
>=20
> This removes CONFIG_440A which was a problem for multiplatform
> kernels and instead fixes up the IVOR at runtime from a setup_cpu
> function. The "A" version of the machine check also tweaks the
> regs->trap value to differenciate the 2 versions at the C level.
[snip]
> Index: linux-merge/include/asm-ppc/reg_booke.h
> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
> --- linux-merge.orig/include/asm-ppc/reg_booke.h 2007-12-11 16:21:38.0000=
00000 +1100
> +++ linux-merge/include/asm-ppc/reg_booke.h 2007-12-11 16:23:21.000000000=
+1100
> @@ -207,7 +207,7 @@
> #define CCR1_TCS 0x00000080 /* Timer Clock Select */
>=20
> /* Bit definitions for the MCSR. */
> -#ifdef CONFIG_440A
> +#ifdef CONFIG_44x
> #define MCSR_MCS 0x80000000 /* Machine Check Summary */
> #define MCSR_IB 0x40000000 /* Instruction PLB Error */
> #define MCSR_DRB 0x20000000 /* Data Read PLB Error */
This breaks non-44x based arch/ppc platforms. For example ep405 in
arch/ppc fails with:
/home/jwboyer/src/linux-2.6/arch/ppc/kernel/traps.c: In function =E2=80=98m=
achine_check_440A=E2=80=99:
/home/jwboyer/src/linux-2.6/arch/ppc/kernel/traps.c:260: error: =E2=80=98MC=
SR_IB=E2=80=99 undeclared (first use in this function)
/home/jwboyer/src/linux-2.6/arch/ppc/kernel/traps.c:260: error: (Each undec=
lared identifier is reported only once
/home/jwboyer/src/linux-2.6/arch/ppc/kernel/traps.c:260: error: for each fu=
nction it appears in.)
/home/jwboyer/src/linux-2.6/arch/ppc/kernel/traps.c:262: error: =E2=80=98MC=
SR_DRB=E2=80=99 undeclared (first use in this function)
/home/jwboyer/src/linux-2.6/arch/ppc/kernel/traps.c:264: error: =E2=80=98MC=
SR_DWB=E2=80=99 undeclared (first use in this function)
/home/jwboyer/src/linux-2.6/arch/ppc/kernel/traps.c:266: error: =E2=80=98MC=
SR_TLBP=E2=80=99 undeclared (first use in this function)
/home/jwboyer/src/linux-2.6/arch/ppc/kernel/traps.c:268: error: =E2=80=98MC=
SR_ICP=E2=80=99 undeclared (first use in this function)
/home/jwboyer/src/linux-2.6/arch/ppc/kernel/traps.c:272: error: =E2=80=98MC=
SR_DCSP=E2=80=99 undeclared (first use in this function)
/home/jwboyer/src/linux-2.6/arch/ppc/kernel/traps.c:274: error: =E2=80=98MC=
SR_DCFP=E2=80=99 undeclared (first use in this function)
/home/jwboyer/src/linux-2.6/arch/ppc/kernel/traps.c:276: error: =E2=80=98MC=
SR_IMPE=E2=80=99 undeclared (first use in this function)
make[2]: *** [arch/ppc/kernel/traps.o] Error 1
The same is true for other platforms as well. Getting closer...
josh
^ permalink raw reply
* Re: [ofa-general] Re: [ewg] Re: [PATCH] IB/ehca: Serialize HCA-related hCalls on POWER5
From: Caitlin Bestler @ 2007-12-13 19:22 UTC (permalink / raw)
To: Or Gerlitz
Cc: Arnd Bergmann, Roland Dreier, Joachim Fenkes, LKML, linuxppc-dev,
OF-General, Stefan Roscher
In-Reply-To: <4760EDC0.5020703@voltaire.com>
On Dec 13, 2007 12:30 AM, Or Gerlitz <ogerlitz@voltaire.com> wrote:
> Roland Dreier wrote:
> > I think the right fix for iSER would be to make iSER work even for
> > devices that don't support FMRs. For example cxgb3 doesn't implement
> > FMRs so if anyone ever updates iSER to work on iWARP and not just IB,
> > then this is something that has to be tackled anyway. Then ehca could
> > just get rid of the FMR support it has.
>
> OK, The iSER design took into account the case of many initiators
> running on strong/modern machines talking to possibly lightweight
> embedded target for which the processing cost per I/O at the target side
> should be minimized, that is at most --one-- RDMA operation should be
> issued by the target to serve an I/O request.
>
> For that end, iSER works with one descriptor (called stag in iWARP and
> rkey in IB) per I/O direction sent from the initiator to the target and
> hence can't work without some sort of FMR implementation.
>
> The current implementation of the open iscsi initiator makes sure to
> issue commands in thread (sleepable) context, see iscsi_xmitworker and
> references to it in drivers/scsi/libiscsi.c , so this keeps ehca users
> safe for the time being.
>
> Or.
>
I agree, *some* form of FMR support is important for iSER (and probably
for NFS over RDMA as well). Rather than adding a crippled NO FMR
mode it would make more sense to add support for FMR Work Requests.
I'm not certain what, if any, impact that would have on the Power5 problem,
but that's certainly a cleaner path for iWARP.
^ permalink raw reply
* Re: [PATCH 19/20] [POWERPC] pci32: 4xx embedded platforms want to reassign all PCI resources
From: Josh Boyer @ 2007-12-13 19:05 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev
In-Reply-To: <20071213073851.C321FDDFC9@ozlabs.org>
On Thu, 13 Dec 2007 18:38:46 +1100
Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:
> This makes 4xx embedded platforms re-assign all PCI resources as we
> pretty much never care about what the various firmwares have done on
> these, it's generally not compatible with the way the kernel will map
> the bridges.
>
> We still need to also enable bus renumbering on some of them, but I
> will do that from a separate patch after I've fixed 4xx PCIe to handle
> all bus numbers.
>
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
[snip]
> Index: linux-work/arch/powerpc/platforms/44x/sequoia.c
> ===================================================================
> --- linux-work.orig/arch/powerpc/platforms/44x/sequoia.c 2007-12-10 16:51:42.000000000 +1100
> +++ linux-work/arch/powerpc/platforms/44x/sequoia.c 2007-12-10 16:55:06.000000000 +1100
> @@ -21,7 +21,8 @@
> #include <asm/udbg.h>
> #include <asm/time.h>
> #include <asm/uic.h>
> -#include "44x.h"
> +#include <asm/pci-bridge.h>
> +
Oh, and you also broke the Sequoia build with this change because you
removed the 44x.h include :).
josh
^ permalink raw reply
* Re: [PATCH 19/20] [POWERPC] pci32: 4xx embedded platforms want to reassign all PCI resources
From: Josh Boyer @ 2007-12-13 19:01 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev
In-Reply-To: <20071213073851.C321FDDFC9@ozlabs.org>
On Thu, 13 Dec 2007 18:38:46 +1100
Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:
> This makes 4xx embedded platforms re-assign all PCI resources as we
> pretty much never care about what the various firmwares have done on
> these, it's generally not compatible with the way the kernel will map
> the bridges.
>
> We still need to also enable bus renumbering on some of them, but I
> will do that from a separate patch after I've fixed 4xx PCIe to handle
> all bus numbers.
This one is slightly broken in my opinion. You've added
the ppc_pci_flags to all of these platforms, which is fine for your
intended goal. But now all of these platforms _have_ to compile with
PCI enabled or they'll break with:
arch/powerpc/platforms/built-in.o: In function `walnut_probe':
walnut.c:(.init.text+0x9a): undefined reference to `ppc_pci_flags'
walnut.c:(.init.text+0xa6): undefined reference to `ppc_pci_flags'
make[1]: *** [.tmp_vmlinux1] Error 1
So to do it correctly we need to either select CONFIG_PCI for all of
them, wrap the ppc_pci_flags assignment in #ifdef CONFIG_PCI, or move
the ppc_pci_flags variable declaration into something that always gets
compiled.
josh
^ permalink raw reply
* Re: [PATCH/RFC] CPM1: implement GPIO API
From: Scott Wood @ 2007-12-13 16:48 UTC (permalink / raw)
To: Anton Vorontsov; +Cc: linuxppc-dev, Arnd Bergmann
In-Reply-To: <20071213005345.GA1577@zarina>
On Thu, Dec 13, 2007 at 03:53:45AM +0300, Anton Vorontsov wrote:
> No. This is how gpio api is working currently. With gpiolib[1], most of
> these functions will be controller-specific. IIRC, gpiolib is still in
> early development stage, so, for now, we have to limit us to one gpio
> chip controller.
>
> This works great for us: CPM, CPM2 and QE shouldn't appear on the single
> crystal.
But at least the latter two should be able to co-exist in a single kernel
image... Oh well, all we can do is hope the saner API makes it in soon. :-)
-Scott
^ permalink raw reply
* Re: [PATCH] IB/ehca: Fix lock flag location, bump version number
From: Roland Dreier @ 2007-12-13 17:39 UTC (permalink / raw)
To: Joachim Fenkes
Cc: LKML, OF-EWG, LinuxPPC-Dev, Christoph Raisch, Marcus Eder,
OF-General, Stefan Roscher
In-Reply-To: <200712131335.58136.fenkes@de.ibm.com>
applied, thanks
^ permalink raw reply
* RE: Xilinx devicetrees
From: Stephen Neuendorffer @ 2007-12-13 17:36 UTC (permalink / raw)
To: Koss, Mike (Mission Systems), David H. Lynch Jr., Grant Likely,
linuxppc-embedded
In-Reply-To: <EDAE140DF1B2FC42B5867C22CA0B333F0A590F@XMBIL132.northgrum.com>
=20
> -----Original Message-----
> From: Koss, Mike (Mission Systems) [mailto:mike.koss@ngc.com]=20
> Sent: Thursday, December 13, 2007 5:49 AM
> To: Stephen Neuendorffer; David H. Lynch Jr.; Grant Likely;=20
> linuxppc-embedded
> Subject: RE: Xilinx devicetrees
>=20
> SN> Interesting idea.. I've been trying to figure out how to=20
> architect this=20
> SN> better, but it requires some information passing within=20
> EDK that isnot=20
> SN> today supported. I don't see at all how to synchronize this with=20
> SN> patches to the kernel, tho. My approach is to describe=20
> the hardware=20
> SN> as completely and faithfully as we can (given the=20
> information in EDK),=20
> SN> and let the drivers do whatever with it that they want to.
>=20
> You'll have to correct if I'm wrong here, but from what I've=20
> been reading up about EDK and its built-in Tcl interface, one=20
> can load their system.xmp with corresponding mhs and then use=20
> Tcl to traverse the device information to create the same=20
> information as found using the generated BSP. This would=20
> allow for a Tcl system that could be setup such that a main=20
> (unchanging, or slowly changing) Tcl script that would start=20
> the EDK definition traversal and upon finding a new device it=20
> would use a registered 'handler' Tcl function. These handlers=20
> could be stored as seperate script/files and would be=20
> registered at the start of the main script either via a=20
> config file or by searching a directory and looking for tags=20
> stored at the top of the Tcl files in comments. These driver=20
> handlers would be passed the handle to the system definition=20
> and then know how to gather the information they need to=20
> create their entry in the device tree. This approach gets=20
> around the issue of losing defaults found in the mhs file.
This seems like alot of work, for relatively little benefit. :)
Instead, I think it is safer to just describe the IP as completely as we
can up front. Everything else should be done by the Linux driver. Now
today there is a problem, which is that there isn't a standard way of
having a device describe itself, in the format of a device tree. This
is something that we'll likely have to add hooks for in the future.
> I originally looked at trying to perform the same thing using=20
> just device drivers in EDK, but I think I found some pitfall.=20
> Oh, I think it was that I would have to choose the OS for=20
> the processor and EDK wants to build the library, but there=20
> isn't anything to compile for Linux (or I wasn't compiling=20
> anything for the linux BSP) and that was adding extra time to=20
> the download.bit generation and that is already a long build process.
I can't imagine that generating this file is the bottleneck in getting
to a bitstream (or at least, I really hope it isn't!)=20
Steve
^ permalink raw reply
* [PATCH 4/4] MPC8313 enhanced Local Bus Controller NAND support.
From: Scott Wood @ 2007-12-13 17:15 UTC (permalink / raw)
To: dwmw2; +Cc: linuxppc-dev, linux-mtd
In-Reply-To: <20071213171528.GA4440@loki.buserror.net>
Signed-off-by: Nick Spence <nick.spence@freescale.com>
Signed-off-by: Scott Wood <scottwood@freescale.com>
---
drivers/mtd/nand/Kconfig | 9 +
drivers/mtd/nand/Makefile | 1 +
drivers/mtd/nand/fsl_elbc_nand.c | 1281 ++++++++++++++++++++++++++++++++++++++
3 files changed, 1291 insertions(+), 0 deletions(-)
create mode 100644 drivers/mtd/nand/fsl_elbc_nand.c
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 246d451..05d976c 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -306,4 +306,13 @@ config MTD_ALAUDA
These two (and possibly other) Alauda-based cardreaders for
SmartMedia and xD allow raw flash access.
+config MTD_NAND_FSL_ELBC
+ tristate "NAND support for Freescale eLBC controllers"
+ depends on MTD_NAND && PPC_OF
+ help
+ Various Freescale chips, including the 8313, include a NAND Flash
+ Controller Module with built-in hardware ECC capabilities.
+ Enabling this option will enable you to use this to control
+ external NAND devices.
+
endif # MTD_NAND
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 3ad6c01..d0d4de2 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -29,5 +29,6 @@ obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o
obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o
obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o
obj-$(CONFIG_MTD_ALAUDA) += alauda.o
+obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o
nand-objs := nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
new file mode 100644
index 0000000..ce8b0bf
--- /dev/null
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -0,0 +1,1281 @@
+/* Freescale Enhanced Local Bus Controller NAND driver
+ *
+ * Copyright (c) 2006-2007 Freescale Semiconductor
+ *
+ * Authors: Nick Spence <nick.spence@freescale.com>,
+ * Scott Wood <scottwood@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+
+
+//#define ELBC_NAND_DEBUG_LVL 6
+
+#ifdef ELBC_NAND_DEBUG_LVL
+static int fcm_debug_level = ELBC_NAND_DEBUG_LVL;
+#define FCM_DEBUG(n, args...) \
+ do { \
+ if (n <= fcm_debug_level) \
+ pr_dbg(args); \
+ } while(0)
+#else
+#define FCM_DEBUG(n, dev, args...) do { } while(0)
+#endif
+
+#define MAX_BANKS 8
+#define ERR_BYTE 0xFF /* Value returned for read bytes when read failed */
+#define FCM_TIMEOUT_MSECS 500 /* Maximum number of mSecs to wait for FCM */
+
+struct elbc_bank {
+ u32 br; /**< Base Register */
+#define BR_BA 0xFFFF8000
+#define BR_BA_SHIFT 15
+#define BR_PS 0x00001800
+#define BR_PS_SHIFT 11
+#define BR_PS_8 0x00000800 /* Port Size 8 bit */
+#define BR_PS_16 0x00001000 /* Port Size 16 bit */
+#define BR_PS_32 0x00001800 /* Port Size 32 bit */
+#define BR_DECC 0x00000600
+#define BR_DECC_SHIFT 9
+#define BR_DECC_OFF 0x00000000 /* HW ECC checking and generation off */
+#define BR_DECC_CHK 0x00000200 /* HW ECC checking on, generation off */
+#define BR_DECC_CHK_GEN 0x00000400 /* HW ECC checking and generation on */
+#define BR_WP 0x00000100
+#define BR_WP_SHIFT 8
+#define BR_MSEL 0x000000E0
+#define BR_MSEL_SHIFT 5
+#define BR_MS_GPCM 0x00000000 /* GPCM */
+#define BR_MS_FCM 0x00000020 /* FCM */
+#define BR_MS_SDRAM 0x00000060 /* SDRAM */
+#define BR_MS_UPMA 0x00000080 /* UPMA */
+#define BR_MS_UPMB 0x000000A0 /* UPMB */
+#define BR_MS_UPMC 0x000000C0 /* UPMC */
+#define BR_V 0x00000001
+#define BR_V_SHIFT 0
+#define BR_RES ~(BR_BA|BR_PS|BR_DECC|BR_WP|BR_MSEL|BR_V)
+
+ u32 or; /**< Base Register */
+#define OR0 0x5004
+#define OR1 0x500C
+#define OR2 0x5014
+#define OR3 0x501C
+#define OR4 0x5024
+#define OR5 0x502C
+#define OR6 0x5034
+#define OR7 0x503C
+
+#define OR_GPCM_AM 0xFFFF8000
+#define OR_GPCM_AM_SHIFT 15
+#define OR_GPCM_BCTLD 0x00001000
+#define OR_GPCM_BCTLD_SHIFT 12
+#define OR_GPCM_CSNT 0x00000800
+#define OR_GPCM_CSNT_SHIFT 11
+#define OR_GPCM_ACS 0x00000600
+#define OR_GPCM_ACS_SHIFT 9
+#define OR_GPCM_ACS_0b10 0x00000400
+#define OR_GPCM_ACS_0b11 0x00000600
+#define OR_GPCM_XACS 0x00000100
+#define OR_GPCM_XACS_SHIFT 8
+#define OR_GPCM_SCY 0x000000F0
+#define OR_GPCM_SCY_SHIFT 4
+#define OR_GPCM_SCY_1 0x00000010
+#define OR_GPCM_SCY_2 0x00000020
+#define OR_GPCM_SCY_3 0x00000030
+#define OR_GPCM_SCY_4 0x00000040
+#define OR_GPCM_SCY_5 0x00000050
+#define OR_GPCM_SCY_6 0x00000060
+#define OR_GPCM_SCY_7 0x00000070
+#define OR_GPCM_SCY_8 0x00000080
+#define OR_GPCM_SCY_9 0x00000090
+#define OR_GPCM_SCY_10 0x000000a0
+#define OR_GPCM_SCY_11 0x000000b0
+#define OR_GPCM_SCY_12 0x000000c0
+#define OR_GPCM_SCY_13 0x000000d0
+#define OR_GPCM_SCY_14 0x000000e0
+#define OR_GPCM_SCY_15 0x000000f0
+#define OR_GPCM_SETA 0x00000008
+#define OR_GPCM_SETA_SHIFT 3
+#define OR_GPCM_TRLX 0x00000004
+#define OR_GPCM_TRLX_SHIFT 2
+#define OR_GPCM_EHTR 0x00000002
+#define OR_GPCM_EHTR_SHIFT 1
+#define OR_GPCM_EAD 0x00000001
+#define OR_GPCM_EAD_SHIFT 0
+
+#define OR_UPM_AM 0xFFFF8000
+#define OR_UPM_AM_SHIFT 15
+#define OR_UPM_XAM 0x00006000
+#define OR_UPM_XAM_SHIFT 13
+#define OR_UPM_BCTLD 0x00001000
+#define OR_UPM_BCTLD_SHIFT 12
+#define OR_UPM_BI 0x00000100
+#define OR_UPM_BI_SHIFT 8
+#define OR_UPM_TRLX 0x00000004
+#define OR_UPM_TRLX_SHIFT 2
+#define OR_UPM_EHTR 0x00000002
+#define OR_UPM_EHTR_SHIFT 1
+#define OR_UPM_EAD 0x00000001
+#define OR_UPM_EAD_SHIFT 0
+
+#define OR_SDRAM_AM 0xFFFF8000
+#define OR_SDRAM_AM_SHIFT 15
+#define OR_SDRAM_XAM 0x00006000
+#define OR_SDRAM_XAM_SHIFT 13
+#define OR_SDRAM_COLS 0x00001C00
+#define OR_SDRAM_COLS_SHIFT 10
+#define OR_SDRAM_ROWS 0x000001C0
+#define OR_SDRAM_ROWS_SHIFT 6
+#define OR_SDRAM_PMSEL 0x00000020
+#define OR_SDRAM_PMSEL_SHIFT 5
+#define OR_SDRAM_EAD 0x00000001
+#define OR_SDRAM_EAD_SHIFT 0
+
+#define OR_FCM_AM 0xFFFF8000
+#define OR_FCM_AM_SHIFT 15
+#define OR_FCM_BCTLD 0x00001000
+#define OR_FCM_BCTLD_SHIFT 12
+#define OR_FCM_PGS 0x00000400
+#define OR_FCM_PGS_SHIFT 10
+#define OR_FCM_CSCT 0x00000200
+#define OR_FCM_CSCT_SHIFT 9
+#define OR_FCM_CST 0x00000100
+#define OR_FCM_CST_SHIFT 8
+#define OR_FCM_CHT 0x00000080
+#define OR_FCM_CHT_SHIFT 7
+#define OR_FCM_SCY 0x00000070
+#define OR_FCM_SCY_SHIFT 4
+#define OR_FCM_SCY_1 0x00000010
+#define OR_FCM_SCY_2 0x00000020
+#define OR_FCM_SCY_3 0x00000030
+#define OR_FCM_SCY_4 0x00000040
+#define OR_FCM_SCY_5 0x00000050
+#define OR_FCM_SCY_6 0x00000060
+#define OR_FCM_SCY_7 0x00000070
+#define OR_FCM_RST 0x00000008
+#define OR_FCM_RST_SHIFT 3
+#define OR_FCM_TRLX 0x00000004
+#define OR_FCM_TRLX_SHIFT 2
+#define OR_FCM_EHTR 0x00000002
+#define OR_FCM_EHTR_SHIFT 1
+};
+
+struct elbc_regs {
+ struct elbc_bank bank[8];
+ u8 res0[0x28];
+ u32 mar; /**< UPM Address Register */
+ u8 res1[0x4];
+ u32 mamr; /**< UPMA Mode Register */
+ u32 mbmr; /**< UPMB Mode Register */
+ u32 mcmr; /**< UPMC Mode Register */
+ u8 res2[0x8];
+ u32 mrtpr; /**< Memory Refresh Timer Prescaler Register */
+ u32 mdr; /**< UPM Data Register */
+ u8 res3[0x4];
+ u32 lsor; /**< Special Operation Initiation Register */
+ u32 lsdmr; /**< SDRAM Mode Register */
+ u8 res4[0x8];
+ u32 lurt; /**< UPM Refresh Timer */
+ u32 lsrt; /**< SDRAM Refresh Timer */
+ u8 res5[0x8];
+ u32 ltesr; /**< Transfer Error Status Register */
+#define LTESR_BM 0x80000000
+#define LTESR_FCT 0x40000000
+#define LTESR_PAR 0x20000000
+#define LTESR_WP 0x04000000
+#define LTESR_ATMW 0x00800000
+#define LTESR_ATMR 0x00400000
+#define LTESR_CS 0x00080000
+#define LTESR_CC 0x00000001
+#define LTESR_NAND_MASK (LTESR_FCT | LTESR_PAR | LTESR_CC)
+ u32 ltedr; /**< Transfer Error Disable Register */
+ u32 lteir; /**< Transfer Error Interrupt Register */
+ u32 lteatr; /**< Transfer Error Attributes Register */
+ u32 ltear; /**< Transfer Error Address Register */
+ u8 res6[0xC];
+ u32 lbcr; /**< Configuration Register */
+#define LBCR_LDIS 0x80000000
+#define LBCR_LDIS_SHIFT 31
+#define LBCR_BCTLC 0x00C00000
+#define LBCR_BCTLC_SHIFT 22
+#define LBCR_AHD 0x00200000
+#define LBCR_LPBSE 0x00020000
+#define LBCR_LPBSE_SHIFT 17
+#define LBCR_EPAR 0x00010000
+#define LBCR_EPAR_SHIFT 16
+#define LBCR_BMT 0x0000FF00
+#define LBCR_BMT_SHIFT 8
+#define LBCR_INIT 0x00040000
+ u32 lcrr; /**< Clock Ratio Register */
+#define LCRR_DBYP 0x80000000
+#define LCRR_DBYP_SHIFT 31
+#define LCRR_BUFCMDC 0x30000000
+#define LCRR_BUFCMDC_SHIFT 28
+#define LCRR_ECL 0x03000000
+#define LCRR_ECL_SHIFT 24
+#define LCRR_EADC 0x00030000
+#define LCRR_EADC_SHIFT 16
+#define LCRR_CLKDIV 0x0000000F
+#define LCRR_CLKDIV_SHIFT 0
+ u8 res7[0x8];
+ u32 fmr; /**< Flash Mode Register */
+#define FMR_CWTO 0x0000F000
+#define FMR_CWTO_SHIFT 12
+#define FMR_BOOT 0x00000800
+#define FMR_ECCM 0x00000100
+#define FMR_AL 0x00000030
+#define FMR_AL_SHIFT 4
+#define FMR_OP 0x00000003
+#define FMR_OP_SHIFT 0
+ u32 fir; /**< Flash Instruction Register */
+#define FIR_OP0 0xF0000000
+#define FIR_OP0_SHIFT 28
+#define FIR_OP1 0x0F000000
+#define FIR_OP1_SHIFT 24
+#define FIR_OP2 0x00F00000
+#define FIR_OP2_SHIFT 20
+#define FIR_OP3 0x000F0000
+#define FIR_OP3_SHIFT 16
+#define FIR_OP4 0x0000F000
+#define FIR_OP4_SHIFT 12
+#define FIR_OP5 0x00000F00
+#define FIR_OP5_SHIFT 8
+#define FIR_OP6 0x000000F0
+#define FIR_OP6_SHIFT 4
+#define FIR_OP7 0x0000000F
+#define FIR_OP7_SHIFT 0
+#define FIR_OP_NOP 0x0 /* No operation and end of sequence */
+#define FIR_OP_CA 0x1 /* Issue current column address */
+#define FIR_OP_PA 0x2 /* Issue current block+page address */
+#define FIR_OP_UA 0x3 /* Issue user defined address */
+#define FIR_OP_CM0 0x4 /* Issue command from FCR[CMD0] */
+#define FIR_OP_CM1 0x5 /* Issue command from FCR[CMD1] */
+#define FIR_OP_CM2 0x6 /* Issue command from FCR[CMD2] */
+#define FIR_OP_CM3 0x7 /* Issue command from FCR[CMD3] */
+#define FIR_OP_WB 0x8 /* Write FBCR bytes from FCM buffer */
+#define FIR_OP_WS 0x9 /* Write 1 or 2 bytes from MDR[AS] */
+#define FIR_OP_RB 0xA /* Read FBCR bytes to FCM buffer */
+#define FIR_OP_RS 0xB /* Read 1 or 2 bytes to MDR[AS] */
+#define FIR_OP_CW0 0xC /* Wait then issue FCR[CMD0] */
+#define FIR_OP_CW1 0xD /* Wait then issue FCR[CMD1] */
+#define FIR_OP_RBW 0xE /* Wait then read FBCR bytes */
+#define FIR_OP_RSW 0xE /* Wait then read 1 or 2 bytes */
+ u32 fcr; /**< Flash Command Register */
+#define FCR_CMD0 0xFF000000
+#define FCR_CMD0_SHIFT 24
+#define FCR_CMD1 0x00FF0000
+#define FCR_CMD1_SHIFT 16
+#define FCR_CMD2 0x0000FF00
+#define FCR_CMD2_SHIFT 8
+#define FCR_CMD3 0x000000FF
+#define FCR_CMD3_SHIFT 0
+ u32 fbar; /**< Flash Block Address Register */
+#define FBAR_BLK 0x00FFFFFF
+ u32 fpar; /**< Flash Page Address Register */
+#define FPAR_SP_PI 0x00007C00
+#define FPAR_SP_PI_SHIFT 10
+#define FPAR_SP_MS 0x00000200
+#define FPAR_SP_CI 0x000001FF
+#define FPAR_SP_CI_SHIFT 0
+#define FPAR_LP_PI 0x0003F000
+#define FPAR_LP_PI_SHIFT 12
+#define FPAR_LP_MS 0x00000800
+#define FPAR_LP_CI 0x000007FF
+#define FPAR_LP_CI_SHIFT 0
+ u32 fbcr; /**< Flash Byte Count Register */
+#define FBCR_BC 0x00000FFF
+ u8 res11[0x8];
+ u8 res8[0xF00];
+};
+
+struct fsl_elbc_ctrl;
+
+/* mtd information per set */
+
+struct fsl_elbc_mtd {
+ struct mtd_info mtd;
+ struct nand_chip chip;
+ struct fsl_elbc_ctrl *ctrl;
+
+ struct device *dev;
+ int bank; /* Chip select bank number */
+ u8 __iomem *vbase; /* Chip select base virtual address */
+ int page_size; /* NAND page size (0=512, 1=2048) */
+ unsigned int fmr; /* FCM Flash Mode Register value */
+};
+
+/* overview of the fsl elbc controller */
+
+struct fsl_elbc_ctrl {
+ struct nand_hw_control controller;
+ struct fsl_elbc_mtd *chips[MAX_BANKS];
+
+ /* device info */
+ struct device *dev;
+ struct elbc_regs __iomem *regs;
+ int irq;
+ wait_queue_head_t irq_wait;
+ unsigned int irq_status; /* status read from LTESR by irq handler */
+ u8 __iomem *addr; /* Address of assigned FCM buffer */
+ unsigned int page; /* Last page written to / read from */
+ unsigned int read_bytes; /* Number of bytes read during command */
+ unsigned int column; /* Saved column from SEQIN */
+ unsigned int index; /* Pointer to next byte to 'read' */
+ unsigned int status; /* status read from LTESR after last op */
+ unsigned int mdr; /* UPM/FCM Data Register value */
+ unsigned int use_mdr; /* Non zero if the MDR is to be set */
+ unsigned int oob; /* Non zero if operating on OOB data */
+ char *oob_poi; /* Place to write ECC after read back */
+};
+
+/* These map to the positions used by the FCM hardware ECC generator */
+
+/* Small Page FLASH with FMR[ECCM] = 0 */
+static struct nand_ecclayout fsl_elbc_oob_sp_eccm0 = {
+ .eccbytes = 3,
+ .eccpos = {6, 7, 8},
+ .oobfree = { {0, 5}, {9, 7} },
+ .oobavail = 12,
+};
+
+/* Small Page FLASH with FMR[ECCM] = 1 */
+static struct nand_ecclayout fsl_elbc_oob_sp_eccm1 = {
+ .eccbytes = 3,
+ .eccpos = {8, 9, 10},
+ .oobfree = { {0, 5}, {6, 2}, {11, 5} },
+ .oobavail = 12,
+};
+
+/* Large Page FLASH with FMR[ECCM] = 0 */
+static struct nand_ecclayout fsl_elbc_oob_lp_eccm0 = {
+ .eccbytes = 12,
+ .eccpos = {6, 7, 8, 22, 23, 24, 38, 39, 40, 54, 55, 56},
+ .oobfree = { {1, 5}, {9, 13}, {25, 13}, {41, 13}, {57, 7} },
+ .oobavail = 48,
+};
+
+/* Large Page FLASH with FMR[ECCM] = 1 */
+static struct nand_ecclayout fsl_elbc_oob_lp_eccm1 = {
+ .eccbytes = 12,
+ .eccpos = {8, 9, 10, 24, 25, 26, 40, 41, 42, 56, 57, 58},
+ .oobfree = { {1, 7}, {11, 13}, {27, 13}, {43, 13}, {59, 5} },
+ .oobavail = 48,
+};
+
+/*=================================*/
+
+/*
+ * Set up the FCM hardware block and page address fields, and the fcm
+ * structure addr field to point to the correct FCM buffer in memory
+ */
+static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct fsl_elbc_mtd *priv = chip->priv;
+ struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ struct elbc_regs __iomem *lbc = ctrl->regs;
+ int buf_num;
+
+ ctrl->page = page_addr;
+
+ out_be32(&lbc->fbar,
+ page_addr >> (chip->phys_erase_shift - chip->page_shift));
+
+ if (priv->page_size) {
+ out_be32(&lbc->fpar,
+ ((page_addr << FPAR_LP_PI_SHIFT) & FPAR_LP_PI) |
+ (oob ? FPAR_LP_MS : 0) | column);
+ buf_num = (page_addr & 1) << 2;
+ } else {
+ out_be32(&lbc->fpar,
+ ((page_addr << FPAR_SP_PI_SHIFT) & FPAR_SP_PI) |
+ (oob ? FPAR_SP_MS : 0) | column);
+ buf_num = page_addr & 7;
+ }
+
+ ctrl->addr = priv->vbase + buf_num * 1024;
+ ctrl->index = column;
+
+ /* for OOB data point to the second half of the buffer */
+ if (oob)
+ ctrl->index += priv->page_size ? 2048 : 512;
+
+ FCM_DEBUG(2, "set_addr: bank=%d, ctrl->addr=0x%p (0x%p), index %x, pes %d ps %d\n", buf_num, ctrl->addr, priv->vbase, ctrl->index,
+ chip->phys_erase_shift, chip->page_shift);
+}
+
+/*
+ * execute FCM command and wait for it to complete
+ */
+static int fsl_elbc_run_command(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct fsl_elbc_mtd *priv = chip->priv;
+ struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ struct elbc_regs __iomem *lbc = ctrl->regs;
+
+ /* Setup the FMR[OP] to execute without write protection */
+ out_be32(&lbc->fmr, priv->fmr | 3);
+ if (ctrl->use_mdr)
+ out_be32(&lbc->mdr, ctrl->mdr);
+
+ FCM_DEBUG(5, "fsl_elbc_run_command: fmr= %08X fir= %08X fcr= %08X\n",
+ lbc->fmr, lbc->fir, lbc->fcr);
+ FCM_DEBUG(5, "fsl_elbc_run_command: fbar=%08X fpar=%08X fbcr=%08X bank=%d\n",
+ lbc->fbar, lbc->fpar, lbc->fbcr, priv->bank);
+
+ /* execute special operation */
+ out_be32(&lbc->lsor, priv->bank);
+
+ /* wait for FCM complete flag or timeout */
+ ctrl->irq_status = 0;
+ wait_event_timeout(ctrl->irq_wait, ctrl->irq_status,
+ FCM_TIMEOUT_MSECS * HZ/1000);
+ ctrl->status = ctrl->irq_status;
+
+ /* store mdr value in case it was needed */
+ if (ctrl->use_mdr)
+ ctrl->mdr = in_be32(&lbc->mdr);
+
+ ctrl->use_mdr = 0;
+
+ FCM_DEBUG(5, "fsl_elbc_run_command: stat=%08X mdr= %08X fmr= %08X\n",
+ ctrl->status, ctrl->mdr, lbc->fmr);
+
+ /* returns 0 on success otherwise non-zero) */
+ return ctrl->status == LTESR_CC ? 0 : -EIO;
+}
+
+static void fsl_elbc_do_read(struct nand_chip *chip, int oob)
+{
+ struct fsl_elbc_mtd *priv = chip->priv;
+ struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ struct elbc_regs __iomem *lbc = ctrl->regs;
+
+ if (priv->page_size) {
+ out_be32(&lbc->fir,
+ (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+ (FIR_OP_CA << FIR_OP1_SHIFT) |
+ (FIR_OP_PA << FIR_OP2_SHIFT) |
+ (FIR_OP_CW1 << FIR_OP3_SHIFT) |
+ (FIR_OP_RBW << FIR_OP4_SHIFT));
+
+ out_be32(&lbc->fcr, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) |
+ (NAND_CMD_READSTART << FCR_CMD1_SHIFT));
+ } else {
+ out_be32(&lbc->fir,
+ (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+ (FIR_OP_CA << FIR_OP1_SHIFT) |
+ (FIR_OP_PA << FIR_OP2_SHIFT) |
+ (FIR_OP_RBW << FIR_OP3_SHIFT));
+
+ if (oob)
+ out_be32(&lbc->fcr, NAND_CMD_READOOB << FCR_CMD0_SHIFT);
+ else
+ out_be32(&lbc->fcr, NAND_CMD_READ0 << FCR_CMD0_SHIFT);
+ }
+}
+
+/* cmdfunc send commands to the FCM */
+static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
+ int column, int page_addr)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct fsl_elbc_mtd *priv = chip->priv;
+ struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ struct elbc_regs __iomem *lbc = ctrl->regs;
+
+ ctrl->use_mdr = 0;
+
+ /* clear the read buffer */
+ ctrl->read_bytes = 0;
+ if (command != NAND_CMD_PAGEPROG)
+ ctrl->index = 0;
+
+ switch (command) {
+ /* READ0 and READ1 read the entire buffer to use hardware ECC. */
+ case NAND_CMD_READ1:
+ column += 256;
+
+ /* fall-through */
+ case NAND_CMD_READ0:
+ FCM_DEBUG(2, "fsl_elbc_cmdfunc: NAND_CMD_READ0, page_addr:"
+ " 0x%x, column: 0x%x.\n", page_addr, column);
+
+
+ out_be32(&lbc->fbcr, 0); /* read entire page to enable ECC */
+
+ set_addr(mtd, 0, page_addr, 0);
+
+ ctrl->read_bytes = mtd->writesize + mtd->oobsize;
+ ctrl->index += column;
+
+ fsl_elbc_do_read(chip, 0);
+ fsl_elbc_run_command(mtd);
+ return;
+
+ /* READOOB reads only the OOB because no ECC is performed. */
+ case NAND_CMD_READOOB:
+ FCM_DEBUG(2, "fsl_elbc_cmdfunc: NAND_CMD_READOOB, page_addr:"
+ " 0x%x, column: 0x%x.\n", page_addr, column);
+
+ out_be32(&lbc->fbcr, mtd->oobsize - column);
+ set_addr(mtd, column, page_addr, 1);
+
+ ctrl->read_bytes = mtd->writesize + mtd->oobsize;
+
+ fsl_elbc_do_read(chip, 1);
+ fsl_elbc_run_command(mtd);
+ return;
+
+ /* READID must read all 5 possible bytes while CEB is active */
+ case NAND_CMD_READID:
+ FCM_DEBUG(2, "fsl_elbc_cmdfunc: NAND_CMD_READID.\n");
+
+ out_be32(&lbc->fir, (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+ (FIR_OP_UA << FIR_OP1_SHIFT) |
+ (FIR_OP_RBW << FIR_OP2_SHIFT));
+ out_be32(&lbc->fcr, NAND_CMD_READID << FCR_CMD0_SHIFT);
+ /* 5 bytes for manuf, device and exts */
+ out_be32(&lbc->fbcr, 5);
+ ctrl->read_bytes = 5;
+ ctrl->use_mdr = 1;
+ ctrl->mdr = 0;
+
+ set_addr(mtd, 0, 0, 0);
+ fsl_elbc_run_command(mtd);
+ return;
+
+ /* ERASE1 stores the block and page address */
+ case NAND_CMD_ERASE1:
+ FCM_DEBUG(2, "fsl_elbc_cmdfunc: NAND_CMD_ERASE1, page_addr:"
+ " 0x%x.\n", page_addr);
+ set_addr(mtd, 0, page_addr, 0);
+ return;
+
+ /* ERASE2 uses the block and page address from ERASE1 */
+ case NAND_CMD_ERASE2:
+ FCM_DEBUG(2, "fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n");
+
+ out_be32(&lbc->fir,
+ (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+ (FIR_OP_PA << FIR_OP1_SHIFT) |
+ (FIR_OP_CM1 << FIR_OP2_SHIFT));
+
+ out_be32(&lbc->fcr,
+ (NAND_CMD_ERASE1 << FCR_CMD0_SHIFT) |
+ (NAND_CMD_ERASE2 << FCR_CMD1_SHIFT));
+
+ out_be32(&lbc->fbcr, 0);
+ ctrl->read_bytes = 0;
+
+ fsl_elbc_run_command(mtd);
+ return;
+
+ /* SEQIN sets up the addr buffer and all registers except the length */
+ case NAND_CMD_SEQIN: {
+ u32 fcr;
+ FCM_DEBUG(2, "fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, page_addr:"
+ " 0x%x, column: 0x%x.\n", page_addr, column);
+
+ ctrl->column = column;
+ ctrl->oob = 0;
+
+ fcr = (NAND_CMD_PAGEPROG << FCR_CMD1_SHIFT) |
+ (NAND_CMD_SEQIN << FCR_CMD2_SHIFT);
+
+ if (priv->page_size) {
+ out_be32(&lbc->fir,
+ (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+ (FIR_OP_CA << FIR_OP1_SHIFT) |
+ (FIR_OP_PA << FIR_OP2_SHIFT) |
+ (FIR_OP_WB << FIR_OP3_SHIFT) |
+ (FIR_OP_CW1 << FIR_OP4_SHIFT));
+
+ fcr |= NAND_CMD_READ0 << FCR_CMD0_SHIFT;
+ } else {
+ out_be32(&lbc->fir,
+ (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+ (FIR_OP_CM2 << FIR_OP1_SHIFT) |
+ (FIR_OP_CA << FIR_OP2_SHIFT) |
+ (FIR_OP_PA << FIR_OP3_SHIFT) |
+ (FIR_OP_WB << FIR_OP4_SHIFT) |
+ (FIR_OP_CW1 << FIR_OP5_SHIFT));
+
+ if (column >= mtd->writesize) {
+ /* OOB area --> READOOB */
+ column -= mtd->writesize;
+ fcr |= NAND_CMD_READOOB << FCR_CMD0_SHIFT;
+ ctrl->oob = 1;
+ } else if (column < 256) {
+ /* First 256 bytes --> READ0 */
+ fcr |= NAND_CMD_READ0 << FCR_CMD0_SHIFT;
+ } else {
+ /* Second 256 bytes --> READ1 */
+ fcr |= NAND_CMD_READ1 << FCR_CMD0_SHIFT;
+ }
+ }
+
+ out_be32(&lbc->fcr, fcr);
+ set_addr(mtd, column, page_addr, ctrl->oob);
+ return;
+ }
+
+ /* PAGEPROG reuses all of the setup from SEQIN and adds the length */
+ case NAND_CMD_PAGEPROG: {
+ int full_page;
+ FCM_DEBUG(2, "fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG"
+ " writing %d bytes.\n",ctrl->index);
+
+ /* if the write did not start at 0 or is not a full page
+ * then set the exact length, otherwise use a full page
+ * write so the HW generates the ECC.
+ */
+ if (ctrl->oob || ctrl->column != 0 ||
+ ctrl->index != mtd->writesize + mtd->oobsize) {
+ out_be32(&lbc->fbcr, ctrl->index);
+ full_page = 0;
+ } else {
+ out_be32(&lbc->fbcr, 0);
+ full_page = 1;
+ }
+
+ fsl_elbc_run_command(mtd);
+
+ /* Read back the page in order to fill in the ECC for the caller.
+ * Is this really needed?
+ */
+ if (full_page && ctrl->oob_poi) {
+ out_be32(&lbc->fbcr, 3);
+ set_addr(mtd, 6, page_addr, 1);
+
+ ctrl->read_bytes = mtd->writesize + 9;
+
+ fsl_elbc_do_read(chip, 1);
+ fsl_elbc_run_command(mtd);
+
+ memcpy_fromio(ctrl->oob_poi + 6, &ctrl->addr[ctrl->index], 3);
+ ctrl->index += 3;
+ }
+
+ ctrl->oob_poi = NULL;
+ return;
+ }
+
+ /* CMD_STATUS must read the status byte while CEB is active */
+ /* Note - it does not wait for the ready line */
+ case NAND_CMD_STATUS:
+ out_be32(&lbc->fir,
+ (FIR_OP_CM0 << FIR_OP0_SHIFT) |
+ (FIR_OP_RBW << FIR_OP1_SHIFT));
+ out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT);
+ out_be32(&lbc->fbcr, 1);
+ set_addr(mtd, 0, 0, 0);
+ ctrl->read_bytes = 1;
+
+ fsl_elbc_run_command(mtd);
+
+ // The chip always seems to report that it is write-protected,
+ // even when it is not.
+ setbits8(ctrl->addr, NAND_STATUS_WP);
+ return;
+
+ /* RESET without waiting for the ready line */
+ case NAND_CMD_RESET:
+ FCM_DEBUG(2, "fsl_elbc_cmdfunc: NAND_CMD_RESET.\n");
+ out_be32(&lbc->fir, FIR_OP_CM0 << FIR_OP0_SHIFT);
+ out_be32(&lbc->fcr, NAND_CMD_RESET << FCR_CMD0_SHIFT);
+ fsl_elbc_run_command(mtd);
+ return;
+
+ default:
+ printk("fsl_elbc_cmdfunc: error, unsupported command 0x%x.\n",
+ command);
+ }
+}
+
+static void fsl_elbc_select_chip(struct mtd_info *mtd, int chip)
+{
+ /* The hardware does not seem to support multiple
+ * chips per bank.
+ */
+}
+
+/*
+ * Write buf to the FCM Controller Data Buffer
+ */
+static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct fsl_elbc_mtd *priv = chip->priv;
+ struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ unsigned int bufsize = mtd->writesize + mtd->oobsize;
+
+ if (len < 0) {
+ dev_err(ctrl->dev, "write_buf of %d bytes", len);
+ ctrl->status = 0;
+ return;
+ }
+
+ if ((unsigned int)len > bufsize - ctrl->index) {
+ dev_err(ctrl->dev,
+ "write_buf beyond end of buffer "
+ "(%d requested, %u available)\n",
+ len, bufsize - ctrl->index);
+ printk("index %x\n", ctrl->index);
+ BUG();
+
+ len = bufsize - ctrl->index;
+ }
+
+ memcpy_toio(&ctrl->addr[ctrl->index], buf, len);
+ ctrl->index += len;
+}
+
+/*
+ * read a byte from either the FCM hardware buffer if it has any data left
+ * otherwise issue a command to read a single byte.
+ */
+static u8 fsl_elbc_read_byte(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct fsl_elbc_mtd *priv = chip->priv;
+ struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+
+ /* If there are still bytes in the FCM, then use the next byte. */
+ if (ctrl->index < ctrl->read_bytes)
+ return ctrl->addr[ctrl->index++];
+
+ dev_err(ctrl->dev, "read_byte beyond end of buffer\n");
+ return ERR_BYTE;
+}
+
+/*
+ * Read from the FCM Controller Data Buffer
+ */
+static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct fsl_elbc_mtd *priv = chip->priv;
+ struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ int avail;
+
+ if (len < 0)
+ return;
+
+ avail = min((unsigned int)len, ctrl->read_bytes - ctrl->index);
+ memcpy_fromio(buf, &ctrl->addr[ctrl->index], avail);
+ ctrl->index += avail;
+
+ if (len > avail)
+ dev_err(ctrl->dev,
+ "read_buf beyond end of buffer "
+ "(%d requested, %d available)\n",
+ len, avail);
+}
+
+/*
+ * Verify buffer against the FCM Controller Data Buffer
+ */
+static int fsl_elbc_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct fsl_elbc_mtd *priv = chip->priv;
+ struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ int i;
+
+ if (len < 0) {
+ dev_err(ctrl->dev, "write_buf of %d bytes", len);
+ return -EINVAL;
+ }
+
+ if ((unsigned int)len > ctrl->read_bytes - ctrl->index) {
+ dev_err(ctrl->dev,
+ "verify_buf beyond end of buffer "
+ "(%d requested, %u available)\n",
+ len, ctrl->read_bytes - ctrl->index);
+
+ ctrl->index = ctrl->read_bytes;
+ return -EINVAL;
+ }
+
+ for (i = 0; i < len; i++)
+ if (in_8(&ctrl->addr[ctrl->index + i]) != buf[i])
+ break;
+
+ ctrl->index += len;
+ return i == len && ctrl->status == LTESR_CC ? 0 : -EIO;
+}
+
+/* This function is called after Program and Erase Operations to
+ * check for success or failure.
+ */
+static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
+{
+ struct fsl_elbc_mtd *priv = chip->priv;
+ struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ struct elbc_regs __iomem *lbc = ctrl->regs;
+
+ if (ctrl->status != LTESR_CC)
+ return NAND_STATUS_FAIL;
+
+ /* Use READ_STATUS command, but wait for the device to be ready */
+ ctrl->use_mdr = 0;
+ out_be32(&lbc->fir,
+ (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+ (FIR_OP_RBW << FIR_OP1_SHIFT));
+ out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT);
+ out_be32(&lbc->fbcr, 1);
+ set_addr(mtd, 0, 0, 0);
+ ctrl->read_bytes = 1;
+
+ fsl_elbc_run_command(mtd);
+
+ if (ctrl->status != LTESR_CC)
+ return NAND_STATUS_FAIL;
+
+ // The chip always seems to report that it is write-protected,
+ // even when it is not.
+ setbits8(ctrl->addr, NAND_STATUS_WP);
+ return fsl_elbc_read_byte(mtd);
+}
+
+static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct fsl_elbc_mtd *priv = chip->priv;
+ struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ struct elbc_regs __iomem *lbc = ctrl->regs;
+ unsigned int al;
+
+ /* calculate FMR Address Length field */
+ al = 0;
+ if (chip->pagemask & 0xffff0000)
+ al++;
+ if (chip->pagemask & 0xff000000)
+ al++;
+
+ /* add to ECCM mode set in fsl_elbc_init */
+ priv->fmr |= (12 << FMR_CWTO_SHIFT) | /* Timeout > 12 ms */
+ (al << FMR_AL_SHIFT);
+
+ FCM_DEBUG(1, "fsl_elbc_init: nand->numchips = %10d\n", chip->numchips);
+ FCM_DEBUG(1, "fsl_elbc_init: nand->chipsize = %10ld\n", chip->chipsize);
+ FCM_DEBUG(1, "fsl_elbc_init: nand->pagemask = %10X\n", chip->pagemask);
+ FCM_DEBUG(1, "fsl_elbc_init: nand->chip_delay = %8d\n", chip->chip_delay);
+ FCM_DEBUG(1, "fsl_elbc_init: nand->badblockpos = %7d\n", chip->badblockpos);
+ FCM_DEBUG(1, "fsl_elbc_init: nand->chip_shift = %8d\n", chip->chip_shift);
+ FCM_DEBUG(1, "fsl_elbc_init: nand->page_shift = %8d\n", chip->page_shift);
+ FCM_DEBUG(1, "fsl_elbc_init: nand->phys_erase_shift = %2d\n",
+ chip->phys_erase_shift);
+ FCM_DEBUG(1, "fsl_elbc_init: nand->ecclayout= %10p\n", chip->ecclayout);
+ FCM_DEBUG(1, "fsl_elbc_init: nand->eccmode = %10d\n", chip->ecc.mode );
+ FCM_DEBUG(1, "fsl_elbc_init: nand->eccsteps = %10d\n", chip->ecc.steps);
+ FCM_DEBUG(1, "fsl_elbc_init: nand->eccbytes = %10d\n", chip->ecc.bytes);
+ FCM_DEBUG(1, "fsl_elbc_init: nand->ecctotal = %10d\n", chip->ecc.total);
+ FCM_DEBUG(1, "fsl_elbc_init: nand->ecclayout= %10p\n", chip->ecc.layout);
+ FCM_DEBUG(1, "fsl_elbc_init: mtd->flags = %08X\n", mtd->flags);
+ FCM_DEBUG(1, "fsl_elbc_init: mtd->size = %10d\n", mtd->size);
+ FCM_DEBUG(1, "fsl_elbc_init: mtd->erasesize = %10d\n", mtd->erasesize);
+ FCM_DEBUG(1, "fsl_elbc_init: mtd->writesize = %10d\n", mtd->writesize);
+ FCM_DEBUG(1, "fsl_elbc_init: mtd->oobsize = %10d\n", mtd->oobsize);
+
+ /* adjust Option Register and ECC to match Flash page size */
+ if (mtd->writesize == 512) {
+ priv->page_size = 0;
+ clrbits32(&lbc->bank[priv->bank].or, ~OR_FCM_PGS);
+ } else if (mtd->writesize == 2048) {
+ priv->page_size = 1;
+ setbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS);
+ /* adjust ecc setup if needed */
+ if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) ==
+ BR_DECC_CHK_GEN) {
+ chip->ecc.size = 512;
+ chip->ecc.layout = (priv->fmr & FMR_ECCM) ?
+ &fsl_elbc_oob_lp_eccm1 :
+ &fsl_elbc_oob_lp_eccm0;
+ mtd->ecclayout = chip->ecc.layout;
+ mtd->oobavail = chip->ecc.layout->oobavail;
+ }
+ } else {
+ printk("fsl_elbc_init: page size %d is not supported\n",
+ mtd->writesize);
+ return -1;
+ }
+
+ /* The default u-boot configuration on MPC8313ERDB causes errors;
+ * more delay is needed. This should be safe for other boards
+ * as well.
+ */
+ setbits32(&lbc->bank[priv->bank].or, 0x70);
+ return 0;
+}
+
+static int fsl_elbc_read_page(struct mtd_info *mtd,
+ struct nand_chip *chip,
+ uint8_t *buf)
+{
+ fsl_elbc_read_buf(mtd, buf, mtd->writesize);
+ fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+ if (fsl_elbc_wait(mtd, chip) & NAND_STATUS_FAIL)
+ mtd->ecc_stats.failed++;
+
+ return 0;
+}
+
+/* ECC will be calculated automatically, and errors will be detected in
+ * waitfunc.
+ */
+static void fsl_elbc_write_page(struct mtd_info *mtd,
+ struct nand_chip *chip,
+ const uint8_t *buf)
+{
+ struct fsl_elbc_mtd *priv = chip->priv;
+ struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+
+ fsl_elbc_write_buf(mtd, buf, mtd->writesize);
+ fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+ ctrl->oob_poi = chip->oob_poi;
+}
+
+static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
+{
+ struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ struct elbc_regs __iomem *lbc = ctrl->regs;
+ struct nand_chip *chip = &priv->chip;
+
+ dev_dbg(priv->dev, "eLBC Set Information for bank %d\n", priv->bank);
+
+ /* Fill in fsl_elbc_mtd structure */
+ priv->mtd.priv = chip;
+ priv->mtd.owner = THIS_MODULE;
+ priv->fmr = 0; /* rest filled in later */
+
+ /* fill in nand_chip structure */
+ /* set up function call table */
+ chip->read_byte = fsl_elbc_read_byte;
+ chip->write_buf = fsl_elbc_write_buf;
+ chip->read_buf = fsl_elbc_read_buf;
+ chip->verify_buf = fsl_elbc_verify_buf;
+ chip->select_chip = fsl_elbc_select_chip;
+ chip->cmdfunc = fsl_elbc_cmdfunc;
+ chip->waitfunc = fsl_elbc_wait;
+ chip->late_init = fsl_elbc_chip_init_tail;
+
+ /* set up nand options */
+ chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR;// | NAND_SKIP_BBTSCAN;
+
+ chip->controller = &ctrl->controller;
+ chip->priv = priv;
+
+ chip->ecc.read_page = fsl_elbc_read_page;
+ chip->ecc.write_page = fsl_elbc_write_page;
+
+ /* If CS Base Register selects full hardware ECC then use it */
+ if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) ==
+ BR_DECC_CHK_GEN) {
+ chip->ecc.mode = NAND_ECC_HW;
+ /* put in small page settings and adjust later if needed */
+ chip->ecc.layout = (priv->fmr & FMR_ECCM) ?
+ &fsl_elbc_oob_sp_eccm1 : &fsl_elbc_oob_sp_eccm0;
+ chip->ecc.size = 512;
+ chip->ecc.bytes = 3;
+ } else {
+ /* otherwise fall back to default software ECC */
+ chip->ecc.mode = NAND_ECC_SOFT;
+ }
+
+ return 0;
+}
+
+static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv)
+{
+ struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+
+ nand_release(&priv->mtd);
+
+ if (priv->vbase)
+ iounmap(priv->vbase);
+
+ ctrl->chips[priv->bank] = NULL;
+ kfree(priv);
+
+ return 0;
+}
+
+static int fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl,
+ struct device_node *node)
+{
+ struct elbc_regs __iomem *lbc = ctrl->regs;
+ struct fsl_elbc_mtd *priv;
+ struct resource res;
+#ifdef CONFIG_MTD_PARTITIONS
+ static const char *part_probe_types[]
+ = { "cmdlinepart", "RedBoot", NULL };
+ struct mtd_partition *parts;
+#endif
+ int ret;
+ int bank;
+
+ /* get, allocate and map the memory resource */
+ ret = of_address_to_resource(node, 0, &res);
+ if (ret) {
+ dev_err(ctrl->dev, "failed to get resource\n");
+ return ret;
+ }
+
+ /* find which chip select it is connected to */
+ for (bank = 0; bank < MAX_BANKS; bank++)
+ if ((in_be32(&lbc->bank[bank].br) & BR_V) &&
+ (in_be32(&lbc->bank[bank].br) & BR_MSEL) == BR_MS_FCM &&
+ (in_be32(&lbc->bank[bank].br) & lbc->bank[bank].or & BR_BA)
+ == res.start)
+ break;
+
+ if (bank >= MAX_BANKS) {
+ dev_err(ctrl->dev, "address did not match any chip selects\n");
+ WARN_ON(1);
+ return -ENODEV;
+ }
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ ctrl->chips[bank] = priv;
+ priv->bank = bank;
+ priv->ctrl = ctrl;
+ priv->dev = ctrl->dev;
+
+ priv->vbase = ioremap(res.start, res.end - res.start + 1);
+ if (!priv->vbase) {
+ dev_err(ctrl->dev, "failed to map chip region\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ret = fsl_elbc_chip_init(priv);
+ if (ret)
+ goto err;
+
+ ret = nand_scan(&priv->mtd, 1);
+ if (ret)
+ goto err;
+
+#ifdef CONFIG_MTD_PARTITIONS
+ /* First look for RedBoot table or partitions on the command
+ * line, these take precedence over device tree information */
+ ret = parse_mtd_partitions(&priv->mtd, part_probe_types, &parts, 0);
+ if (ret < 0)
+ goto err;
+
+#ifdef CONFIG_MTD_OF_PARTS
+ if (ret == 0) {
+ ret = of_mtd_parse_partitions(priv->dev, &priv->mtd,
+ node, &parts);
+ if (ret < 0)
+ goto err;
+ }
+#endif
+
+ if (ret > 0)
+ add_mtd_partitions(&priv->mtd, parts, ret);
+ else
+#endif
+ add_mtd_device(&priv->mtd);
+
+ printk(KERN_INFO "eLBC NAND device at 0x%zx, bank %d\n",
+ res.start, priv->bank);
+ return 0;
+
+err:
+ fsl_elbc_chip_remove(priv);
+ return ret;
+}
+
+static int __devinit fsl_elbc_ctrl_init(struct fsl_elbc_ctrl *ctrl)
+{
+ struct elbc_regs __iomem *lbc = ctrl->regs;
+
+ /* clear event registers */
+ setbits32(&lbc->ltesr, LTESR_NAND_MASK);
+ out_be32(&lbc->lteatr, 0);
+
+ /* Enable interrupts for any detected events */
+ out_be32(&lbc->lteir, LTESR_NAND_MASK);
+
+ ctrl->read_bytes = 0;
+ ctrl->index = 0;
+ ctrl->addr = NULL;
+
+ return 0;
+}
+
+static int __devexit fsl_elbc_ctrl_remove(struct of_device *ofdev)
+{
+ struct fsl_elbc_ctrl *ctrl = dev_get_drvdata(&ofdev->dev);
+ int i;
+
+ for (i = 0; i < MAX_BANKS; i++)
+ if (ctrl->chips[i])
+ fsl_elbc_chip_remove(ctrl->chips[i]);
+
+ if (ctrl->irq)
+ free_irq(ctrl->irq, ctrl);
+
+ if (ctrl->regs)
+ iounmap(ctrl->regs);
+
+ dev_set_drvdata(&ofdev->dev, NULL);
+ kfree(ctrl);
+ return 0;
+}
+
+/* interrupt handler code */
+
+static irqreturn_t fsl_elbc_ctrl_irq(int irqno, void *data)
+{
+ struct fsl_elbc_ctrl *ctrl = data;
+ struct elbc_regs __iomem *lbc = ctrl->regs;
+ u32 status = in_be32(&lbc->ltesr) & LTESR_NAND_MASK;
+
+ if (status) {
+ out_be32(&lbc->ltesr, status);
+ out_be32(&lbc->lteatr, 0);
+
+ ctrl->irq_status = status;
+ smp_wmb();
+ wake_up(&ctrl->irq_wait);
+
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+/* fsl_elbc_ctrl_probe
+ *
+ * called by device layer when it finds a device matching
+ * one our driver can handled. This code allocates all of
+ * the resources needed for the controller only. The
+ * resources for the NAND banks themselves are allocated
+ * in the chip probe function.
+*/
+
+static int __devinit fsl_elbc_ctrl_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct device_node *child;
+ struct fsl_elbc_ctrl *ctrl;
+ int ret;
+
+ ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
+ if (!ctrl)
+ return -ENOMEM;
+
+ dev_set_drvdata(&ofdev->dev, ctrl);
+
+ spin_lock_init(&ctrl->controller.lock);
+ init_waitqueue_head(&ctrl->controller.wq);
+ init_waitqueue_head(&ctrl->irq_wait);
+
+ ctrl->regs = of_iomap(ofdev->node, 0);
+ if (!ctrl->regs) {
+ dev_err(&ofdev->dev, "failed to get memory region\n");
+ ret = -ENODEV;
+ goto err;
+ }
+
+ ctrl->irq = of_irq_to_resource(ofdev->node, 0, NULL);
+ if (ctrl->irq == NO_IRQ) {
+ dev_err(&ofdev->dev, "failed to get irq resource\n");
+ ret = -ENODEV;
+ goto err;
+ }
+
+ ctrl->dev = &ofdev->dev;
+
+ ret = fsl_elbc_ctrl_init(ctrl);
+ if (ret < 0)
+ goto err;
+
+ ret = request_irq(ctrl->irq, fsl_elbc_ctrl_irq, 0, "fsl-elbc", ctrl);
+ if (ret != 0) {
+ dev_err(&ofdev->dev, "failed to install irq (%d)\n",
+ ctrl->irq);
+ ret = ctrl->irq;
+ goto err;
+ }
+
+ child = NULL;
+ while ((child = of_get_next_child(ofdev->node, child)))
+ if (of_device_is_compatible(child, "fsl,elbc-fcm-nand"))
+ fsl_elbc_chip_probe(ctrl, child);
+
+ return 0;
+
+err:
+ fsl_elbc_ctrl_remove(ofdev);
+ return ret;
+}
+
+static struct of_device_id fsl_elbc_match[] = {
+ {
+ .compatible = "fsl,elbc",
+ },
+ {}
+};
+
+static struct of_platform_driver fsl_elbc_ctrl_driver = {
+ .name = "fsl-elbc",
+ .match_table = fsl_elbc_match,
+ .probe = fsl_elbc_ctrl_probe,
+ .remove = __devexit_p(fsl_elbc_ctrl_remove),
+};
+
+static int __init fsl_elbc_init(void)
+{
+ return of_register_platform_driver(&fsl_elbc_ctrl_driver);
+}
+
+static void __exit fsl_elbc_exit(void)
+{
+ of_unregister_platform_driver(&fsl_elbc_ctrl_driver);
+}
+
+module_init(fsl_elbc_init);
+module_exit(fsl_elbc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Freescale");
+MODULE_DESCRIPTION("Freescale Enhanced Local Bus Controller MTD NAND driver");
--
1.5.3.7
^ permalink raw reply related
* [PATCH 3/4] mtd: Factor out OF partition support from the NOR driver.
From: Scott Wood @ 2007-12-13 17:15 UTC (permalink / raw)
To: dwmw2; +Cc: linuxppc-dev, linux-mtd
In-Reply-To: <20071213171528.GA4440@loki.buserror.net>
Signed-off-by: Scott Wood <scottwood@freescale.com>
---
drivers/mtd/Kconfig | 8 ++++
drivers/mtd/Makefile | 1 +
drivers/mtd/maps/physmap_of.c | 88 ++++++++++++---------------------------
drivers/mtd/ofpart.c | 68 +++++++++++++++++++++++++++++++
include/linux/mtd/partitions.h | 9 ++++-
5 files changed, 112 insertions(+), 62 deletions(-)
create mode 100644 drivers/mtd/ofpart.c
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index 8848e8a..b729410 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -150,6 +150,14 @@ config MTD_AFS_PARTS
for your particular device. It won't happen automatically. The
'armflash' map driver (CONFIG_MTD_ARMFLASH) does this, for example.
+config MTD_OF_PARTS
+ tristate "Flash partition map based on OF description"
+ depends on PPC_OF && MTD_PARTITIONS
+ help
+ This provides a partition parsing function which derives
+ the partition map from the children of the flash node,
+ as described in Documentation/powerpc/booting-without-of.txt.
+
comment "User Modules And Translation Layers"
config MTD_CHAR
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 7f0b04b..538e33d 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o
obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
+obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o
# 'Users' - code which presents functionality to userspace.
obj-$(CONFIG_MTD_CHAR) += mtdchar.o
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c
index aeed9ea..49acd41 100644
--- a/drivers/mtd/maps/physmap_of.c
+++ b/drivers/mtd/maps/physmap_of.c
@@ -80,64 +80,6 @@ static int parse_obsolete_partitions(struct of_device *dev,
return nr_parts;
}
-
-static int __devinit parse_partitions(struct of_flash *info,
- struct of_device *dev)
-{
- const char *partname;
- static const char *part_probe_types[]
- = { "cmdlinepart", "RedBoot", NULL };
- struct device_node *dp = dev->node, *pp;
- int nr_parts, i;
-
- /* First look for RedBoot table or partitions on the command
- * line, these take precedence over device tree information */
- nr_parts = parse_mtd_partitions(info->mtd, part_probe_types,
- &info->parts, 0);
- if (nr_parts > 0) {
- add_mtd_partitions(info->mtd, info->parts, nr_parts);
- return 0;
- }
-
- /* First count the subnodes */
- nr_parts = 0;
- for (pp = dp->child; pp; pp = pp->sibling)
- nr_parts++;
-
- if (nr_parts == 0)
- return parse_obsolete_partitions(dev, info, dp);
-
- info->parts = kzalloc(nr_parts * sizeof(*info->parts),
- GFP_KERNEL);
- if (!info->parts)
- return -ENOMEM;
-
- for (pp = dp->child, i = 0; pp; pp = pp->sibling, i++) {
- const u32 *reg;
- int len;
-
- reg = of_get_property(pp, "reg", &len);
- if (!reg || (len != 2*sizeof(u32))) {
- dev_err(&dev->dev, "Invalid 'reg' on %s\n",
- dp->full_name);
- kfree(info->parts);
- info->parts = NULL;
- return -EINVAL;
- }
- info->parts[i].offset = reg[0];
- info->parts[i].size = reg[1];
-
- partname = of_get_property(pp, "label", &len);
- if (!partname)
- partname = of_get_property(pp, "name", &len);
- info->parts[i].name = (char *)partname;
-
- if (of_get_property(pp, "read-only", &len))
- info->parts[i].mask_flags = MTD_WRITEABLE;
- }
-
- return nr_parts;
-}
#else /* MTD_PARTITIONS */
#define OF_FLASH_PARTS(info) (0)
#define parse_partitions(info, dev) (0)
@@ -212,6 +154,10 @@ static struct mtd_info * __devinit obsolete_probe(struct of_device *dev,
static int __devinit of_flash_probe(struct of_device *dev,
const struct of_device_id *match)
{
+#ifdef CONFIG_MTD_PARTITIONS
+ static const char *part_probe_types[]
+ = { "cmdlinepart", "RedBoot", NULL };
+#endif
struct device_node *dp = dev->node;
struct resource res;
struct of_flash *info;
@@ -274,13 +220,33 @@ static int __devinit of_flash_probe(struct of_device *dev,
}
info->mtd->owner = THIS_MODULE;
- err = parse_partitions(info, dev);
+#ifdef CONFIG_MTD_PARTITIONS
+ /* First look for RedBoot table or partitions on the command
+ * line, these take precedence over device tree information */
+ err = parse_mtd_partitions(info->mtd, part_probe_types,
+ &info->parts, 0);
if (err < 0)
- goto err_out;
+ return err;
+
+#ifdef CONFIG_MTD_OF_PARTS
+ if (err == 0) {
+ err = of_mtd_parse_partitions(&dev->dev, info->mtd,
+ dp, &info->parts);
+ if (err < 0)
+ return err;
+ }
+#endif
+
+ if (err == 0) {
+ err = parse_obsolete_partitions(dev, info, dp);
+ if (err < 0)
+ return err;
+ }
if (err > 0)
- add_mtd_partitions(info->mtd, OF_FLASH_PARTS(info), err);
+ add_mtd_partitions(info->mtd, info->parts, err);
else
+#endif
add_mtd_device(info->mtd);
return 0;
diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
new file mode 100644
index 0000000..6a36cb9
--- /dev/null
+++ b/drivers/mtd/ofpart.c
@@ -0,0 +1,68 @@
+/*
+ * Flash partitions described by the OF (or flattened) device tree
+ *
+ * Copyright (C) 2006 MontaVista Software Inc.
+ * Author: Vitaly Wool <vwool@ru.mvista.com>
+ *
+ * Revised to handle newer style flash binding by:
+ * Copyright (C) 2007 David Gibson, 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+int __devinit of_mtd_parse_partitions(struct device *dev,
+ struct mtd_info *mtd,
+ struct device_node *node,
+ struct mtd_partition **pparts)
+{
+ const char *partname;
+ struct device_node *pp;
+ int nr_parts, i;
+
+ /* First count the subnodes */
+ nr_parts = 0;
+ for (pp = node->child; pp; pp = pp->sibling)
+ nr_parts++;
+
+ if (nr_parts == 0)
+ return 0;
+
+ *pparts = kzalloc(nr_parts * sizeof(**pparts), GFP_KERNEL);
+ if (!*pparts)
+ return -ENOMEM;
+
+ for (pp = node->child, i = 0; pp; pp = pp->sibling, i++) {
+ const u32 *reg;
+ int len;
+
+ reg = of_get_property(pp, "reg", &len);
+ if (!reg || (len != 2*sizeof(u32))) {
+ dev_err(dev, "Invalid 'reg' on %s\n", node->full_name);
+ kfree(*pparts);
+ *pparts = NULL;
+ return -EINVAL;
+ }
+ (*pparts)[i].offset = reg[0];
+ (*pparts)[i].size = reg[1];
+
+ partname = of_get_property(pp, "label", &len);
+ if (!partname)
+ partname = of_get_property(pp, "name", &len);
+ (*pparts)[i].name = (char *)partname;
+
+ if (of_get_property(pp, "read-only", &len))
+ (*pparts)[i].mask_flags = MTD_WRITEABLE;
+ }
+
+ return nr_parts;
+}
+EXPORT_SYMBOL(of_mtd_parse_partitions);
diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h
index da6b3d6..7c37d7e 100644
--- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h
@@ -71,5 +71,12 @@ extern int parse_mtd_partitions(struct mtd_info *master, const char **types,
#define put_partition_parser(p) do { module_put((p)->owner); } while(0)
-#endif
+struct device;
+struct device_node;
+
+int __devinit of_mtd_parse_partitions(struct device *dev,
+ struct mtd_info *mtd,
+ struct device_node *node,
+ struct mtd_partition **pparts);
+#endif
--
1.5.3.7
^ permalink raw reply related
* [PATCH 2/4] nand base: Give drivers a chance to do late initialization.
From: Scott Wood @ 2007-12-13 17:15 UTC (permalink / raw)
To: dwmw2; +Cc: linuxppc-dev, linux-mtd
In-Reply-To: <20071213171528.GA4440@loki.buserror.net>
Some nand controllers, such as the Freescale enhanced local bus controller,
need to do late initialization based on details of the chip that has been
probed, such as chip size, large/small pages, etc. A late_init() callback
method is added to allow this.
Signed-off-by: Scott Wood <scottwood@freescale.com>
---
drivers/mtd/nand/nand_base.c | 12 ++++++++++++
include/linux/mtd/nand.h | 2 ++
2 files changed, 14 insertions(+), 0 deletions(-)
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 85a7283..119a6f7 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -2593,6 +2593,18 @@ int nand_scan_tail(struct mtd_info *mtd)
/* propagate ecc.layout to mtd_info */
mtd->ecclayout = chip->ecc.layout;
+ /* Give the driver a chance to do any remaining setup
+ * based on the chip details.
+ */
+ if (chip->late_init) {
+ int ret = chip->late_init(mtd);
+
+ if (ret) {
+ kfree(chip->buffers);
+ return ret;
+ }
+ }
+
/* Check, if we should skip the bad block table scan */
if (chip->options & NAND_SKIP_BBTSCAN)
return 0;
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index c42bc7f..27bc879 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -360,6 +360,7 @@ struct nand_buffers {
* @errstat: [OPTIONAL] hardware specific function to perform additional error status checks
* (determine if errors are correctable)
* @write_page: [REPLACEABLE] High-level page write function
+ * @late_init: [OPTIONAL] initialization callback after identification
*/
struct nand_chip {
@@ -384,6 +385,7 @@ struct nand_chip {
int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page);
int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int page, int cached, int raw);
+ int (*late_init)(struct mtd_info *mtd);
int chip_delay;
unsigned int options;
--
1.5.3.7
^ permalink raw reply related
* [PATCH] mpc834x_mds: Fix whitespace and call of_platform_bus_probe().
From: Scott Wood @ 2007-12-13 17:19 UTC (permalink / raw)
To: galak; +Cc: linuxppc-dev
Signed-off-by: Scott Wood <scottwood@freescale.com>
---
arch/powerpc/platforms/83xx/mpc834x_mds.c | 21 +++++++++++++++++++--
1 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/platforms/83xx/mpc834x_mds.c b/arch/powerpc/platforms/83xx/mpc834x_mds.c
index a81bb3c..459fb72 100644
--- a/arch/powerpc/platforms/83xx/mpc834x_mds.c
+++ b/arch/powerpc/platforms/83xx/mpc834x_mds.c
@@ -23,6 +23,7 @@
#include <linux/delay.h>
#include <linux/seq_file.h>
#include <linux/root_dev.h>
+#include <linux/of_platform.h>
#include <asm/system.h>
#include <asm/atomic.h>
@@ -106,14 +107,30 @@ static void __init mpc834x_mds_init_IRQ(void)
ipic_set_default_priority();
}
+static struct of_device_id mpc834x_ids[] = {
+ { .type = "soc", },
+ { .compatible = "soc", },
+ {},
+};
+
+static int __init mpc834x_declare_of_platform_devices(void)
+{
+ if (!machine_is(mpc834x_mds))
+ return 0;
+
+ of_platform_bus_probe(NULL, mpc834x_ids, NULL);
+ return 0;
+}
+device_initcall(mpc834x_declare_of_platform_devices);
+
/*
* Called very early, MMU is off, device-tree isn't unflattened
*/
static int __init mpc834x_mds_probe(void)
{
- unsigned long root = of_get_flat_dt_root();
+ unsigned long root = of_get_flat_dt_root();
- return of_flat_dt_is_compatible(root, "MPC834xMDS");
+ return of_flat_dt_is_compatible(root, "MPC834xMDS");
}
define_machine(mpc834x_mds) {
--
1.5.3.7
^ permalink raw reply related
* [PATCH 2/4] mpc8313erdb: Add NAND to device tree, and call of_platform_bus_probe().
From: Scott Wood @ 2007-12-13 17:17 UTC (permalink / raw)
To: galak; +Cc: linuxppc-dev
In-Reply-To: <20071213171632.GA4491@loki.buserror.net>
Signed-off-by: Scott Wood <scottwood@freescale.com>
---
arch/powerpc/boot/dts/mpc8313erdb.dts | 37 +++++++++++++++++++++++++++++
arch/powerpc/platforms/83xx/mpc8313_rdb.c | 17 +++++++++++++
2 files changed, 54 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/boot/dts/mpc8313erdb.dts b/arch/powerpc/boot/dts/mpc8313erdb.dts
index 9e7eba9..86e851a 100644
--- a/arch/powerpc/boot/dts/mpc8313erdb.dts
+++ b/arch/powerpc/boot/dts/mpc8313erdb.dts
@@ -37,6 +37,43 @@
reg = <00000000 08000000>; // 128MB at 0
};
+ localbus {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ compatible = "fsl,mpc8313-elbc", "fsl,elbc";
+ reg = <e0005000 1000>;
+ interrupts = <d#77 8>;
+ interrupt-parent = <&ipic>;
+
+ // CS0 and CS1 are swapped when
+ // booting from nand, but the
+ // addresses are the same.
+ ranges = <0 0 fe000000 00800000
+ 1 0 e2800000 00008000
+ 2 0 f0000000 00020000
+ 3 0 fa000000 00008000>;
+
+ nand@1,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,mpc8313-fcm-nand", "fsl,elbc-fcm-nand";
+ reg = <1 0 2000>;
+
+ u-boot@0 {
+ reg = <0 100000>;
+ read-only;
+ };
+
+ kernel@100000 {
+ reg = <100000 300000>;
+ };
+
+ fs@400000 {
+ reg = <400000 1c00000>;
+ };
+ };
+ };
+
soc8313@e0000000 {
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/powerpc/platforms/83xx/mpc8313_rdb.c b/arch/powerpc/platforms/83xx/mpc8313_rdb.c
index 6fb8299..3ad482a 100644
--- a/arch/powerpc/platforms/83xx/mpc8313_rdb.c
+++ b/arch/powerpc/platforms/83xx/mpc8313_rdb.c
@@ -14,6 +14,7 @@
*/
#include <linux/pci.h>
+#include <linux/of_platform.h>
#include <asm/time.h>
#include <asm/ipic.h>
@@ -75,6 +76,22 @@ static int __init mpc8313_rdb_probe(void)
return of_flat_dt_is_compatible(root, "MPC8313ERDB");
}
+static struct of_device_id __initdata of_bus_ids[] = {
+ { .name = "soc8313", },
+ { .name = "localbus", },
+ {},
+};
+
+static int __init declare_of_platform_devices(void)
+{
+ if (!machine_is(mpc8313_rdb))
+ return 0;
+
+ of_platform_bus_probe(NULL, of_bus_ids, NULL);
+ return 0;
+}
+device_initcall(declare_of_platform_devices);
+
define_machine(mpc8313_rdb) {
.name = "MPC8313 RDB",
.probe = mpc8313_rdb_probe,
--
1.5.3.7
^ permalink raw reply related
* [PATCH 3/4] mpc8313erdb: Add NOR flash to the device tree.
From: Scott Wood @ 2007-12-13 17:17 UTC (permalink / raw)
To: galak; +Cc: linuxppc-dev
In-Reply-To: <20071213171632.GA4491@loki.buserror.net>
Signed-off-by: Scott Wood <scottwood@freescale.com>
---
arch/powerpc/boot/dts/mpc8313erdb.dts | 9 +++++++++
1 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/boot/dts/mpc8313erdb.dts b/arch/powerpc/boot/dts/mpc8313erdb.dts
index 86e851a..8c7b645 100644
--- a/arch/powerpc/boot/dts/mpc8313erdb.dts
+++ b/arch/powerpc/boot/dts/mpc8313erdb.dts
@@ -53,6 +53,15 @@
2 0 f0000000 00020000
3 0 fa000000 00008000>;
+ flash@0,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "cfi-flash";
+ reg = <0 0 800000>;
+ bank-width = <2>;
+ device-width = <1>;
+ };
+
nand@1,0 {
#address-cells = <1>;
#size-cells = <1>;
--
1.5.3.7
^ permalink raw reply related
* [PATCH 4/4] mpc8313erdb: Update defconfig with NOR flash, NAND flash, and JFFS enabled.
From: Scott Wood @ 2007-12-13 17:17 UTC (permalink / raw)
To: galak; +Cc: linuxppc-dev
In-Reply-To: <20071213171632.GA4491@loki.buserror.net>
Signed-off-by: Scott Wood <scottwood@freescale.com>
---
arch/powerpc/configs/mpc8313_rdb_defconfig | 45 ++++++++++++++++++++-------
1 files changed, 33 insertions(+), 12 deletions(-)
diff --git a/arch/powerpc/configs/mpc8313_rdb_defconfig b/arch/powerpc/configs/mpc8313_rdb_defconfig
index c9af905..6942568 100644
--- a/arch/powerpc/configs/mpc8313_rdb_defconfig
+++ b/arch/powerpc/configs/mpc8313_rdb_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.24-rc4
-# Thu Dec 6 16:48:31 2007
+# Wed Dec 12 17:01:53 2007
#
# CONFIG_PPC64 is not set
@@ -336,15 +336,17 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
CONFIG_MTD=y
# CONFIG_MTD_DEBUG is not set
# CONFIG_MTD_CONCAT is not set
-# CONFIG_MTD_PARTITIONS is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+CONFIG_MTD_OF_PARTS=y
#
# User Modules And Translation Layers
#
CONFIG_MTD_CHAR=y
-# CONFIG_MTD_BLKDEVS is not set
-# CONFIG_MTD_BLOCK is not set
-# CONFIG_MTD_BLOCK_RO is not set
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
# CONFIG_FTL is not set
# CONFIG_NFTL is not set
# CONFIG_INFTL is not set
@@ -381,11 +383,8 @@ CONFIG_MTD_CFI_UTIL=y
# Mapping drivers for chip access
#
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
-CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_PHYSMAP_START=0xfe000000
-CONFIG_MTD_PHYSMAP_LEN=0x1000000
-CONFIG_MTD_PHYSMAP_BANKWIDTH=2
-# CONFIG_MTD_PHYSMAP_OF is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_PHYSMAP_OF=y
# CONFIG_MTD_INTEL_VR_NOR is not set
# CONFIG_MTD_PLATRAM is not set
@@ -406,7 +405,17 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
# CONFIG_MTD_DOC2000 is not set
# CONFIG_MTD_DOC2001 is not set
# CONFIG_MTD_DOC2001PLUS is not set
-# CONFIG_MTD_NAND is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_CAFE is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+CONFIG_MTD_NAND_FSL_ELBC=y
# CONFIG_MTD_ONENAND is not set
#
@@ -1178,7 +1187,17 @@ CONFIG_TMPFS=y
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
-# CONFIG_JFFS2_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
# CONFIG_CRAMFS is not set
# CONFIG_VXFS_FS is not set
# CONFIG_HPFS_FS is not set
@@ -1242,6 +1261,8 @@ CONFIG_BITREVERSE=y
CONFIG_CRC32=y
# CONFIG_CRC7 is not set
# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
CONFIG_PLIST=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
--
1.5.3.7
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox