* Re: [PATCH/RFC 1/2] 5200: improve i2c bus error recovery
From: Grant Likely @ 2010-02-16 19:31 UTC (permalink / raw)
To: Albrecht Dreß
Cc: Linux PPC Development, Devicetree Discussions,
Ben Dooks (embedded platforms)
In-Reply-To: <1264191475.2224.1@antares>
Hi Albrecht,
Comments below.
On Fri, Jan 22, 2010 at 1:17 PM, Albrecht Dre=DF <albrecht.dress@arcor.de> =
wrote:
> Improve the recovery of the MPC5200B's I2C bus from errors like bus
> hangs.
>
> Signed-off-by: Albrecht Dre=DF <albrecht.dress@arcor.de>
>
> ---
>
> This patch introduces several improvements to the MPC5200B's I2C driver
> as to improve the recovery from error conditions I encountered when
> testing a custom board with several I2C devices attached (eeprom, io
> expander, rtc, sensors). =A0The error conditions included cases where the
> bus if logic of one slave apparently went south, blocking the bus
> completely.
>
> My fixes include:
> 1. make the bus timeout configurable in fsl_i2c_probe(); the default of
> =A0 one second is *way* too long for my use case;
> 2. if a timeout condition occurs in mpc_xfer(), mpc_i2c_fixup() the bus
> =A0 if *any* of the CF, BB and RXAK flags in the MSR is 1. =A0I actually
> =A0 saw different combinations with hangs, not only all three set;
> 3. improve the fixup procedure by calculating the timing needed from the
> =A0 real (configured) bus clock, calculated in mpc_i2c_setclock_52xx().
> =A0 Furthermore, I issue 9 instead of one cycle, as I experienced cases
> =A0 where the single one is not enough (found this tip in a forum). =A0As=
a
> =A0 side effect, the new scheme needs only 81us @375kHz bus clock instead
> =A0 of 150us. =A0I recorded waveforms for 18.4kHz, 85.9kHz and 375kHz, al=
l
> =A0 looking fine, which I can provide if anyone is interested.
These are three separate fixes. Ideally you should submit them in
separate patches to make it easy on poor old reviewers like me. And,
as Ben mentions, this descriptions should be above the '---' line so
it appears in the commit text.
>
> Open questions:
> - is the approach correct at all, in particular the interpretation of
> =A0the flags (#2)?
> - could this code also be used on non-5200 processors?
>
> --- linux-2.6.32-orig/drivers/i2c/busses/i2c-mpc.c =A0 =A0 =A02009-12-03 =
04:51:21.000000000 +0100
> +++ linux-2.6.32/drivers/i2c/busses/i2c-mpc.c =A0 2010-01-22 16:05:13.000=
000000 +0100
> @@ -59,6 +59,7 @@ struct mpc_i2c {
> =A0 =A0 =A0 =A0wait_queue_head_t queue;
> =A0 =A0 =A0 =A0struct i2c_adapter adap;
> =A0 =A0 =A0 =A0int irq;
> + =A0 =A0 =A0 u32 real_clk;
> =A0};
>
> =A0struct mpc_i2c_divider {
> @@ -97,16 +98,32 @@ static irqreturn_t mpc_i2c_isr(int irq,
> =A0*/
> =A0static void mpc_i2c_fixup(struct mpc_i2c *i2c)
> =A0{
> - =A0 =A0 =A0 writeccr(i2c, 0);
> - =A0 =A0 =A0 udelay(30);
> - =A0 =A0 =A0 writeccr(i2c, CCR_MEN);
> - =A0 =A0 =A0 udelay(30);
> - =A0 =A0 =A0 writeccr(i2c, CCR_MSTA | CCR_MTX);
> - =A0 =A0 =A0 udelay(30);
> - =A0 =A0 =A0 writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN);
> - =A0 =A0 =A0 udelay(30);
> - =A0 =A0 =A0 writeccr(i2c, CCR_MEN);
> - =A0 =A0 =A0 udelay(30);
> + =A0 =A0 =A0 if (i2c->real_clk =3D=3D 0) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 writeccr(i2c, 0);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(30);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 writeccr(i2c, CCR_MEN);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(30);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 writeccr(i2c, CCR_MSTA | CCR_MTX);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(30);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN)=
;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(30);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 writeccr(i2c, CCR_MEN);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(30);
> + =A0 =A0 =A0 } else {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 int k;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 u32 delay_val =3D 1000000 / i2c->real_clk +=
1;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (delay_val < 2)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 delay_val =3D 2;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 for (k =3D 9; k; k--) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 writeccr(i2c, 0);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 writeccr(i2c, CCR_MSTA | CC=
R_MTX | CCR_MEN);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(delay_val);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 writeccr(i2c, CCR_MEN);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(delay_val << 1);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 }
This doesn't look right. Why is the old code being preserved? Isn't
it not as reliable? It looks to me that the new block should be the
only path, with delay_val getting hard set to a sane value if real_clk
=3D=3D 0. This approach looks to add complexity to the driver without a
reason other than fear it *might* breaking something.
If the new code is better, then be strong, stand tall, and say in a
loud voice, "this old code is crap. The new stuff is much better."
g.
> =A0}
>
> =A0static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing=
)
> @@ -186,15 +203,18 @@ static const struct mpc_i2c_divider mpc_
> =A0 =A0 =A0 =A0{10240, 0x9d}, {12288, 0x9e}, {15360, 0x9f}
> =A0};
>
> -int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock, int presca=
ler)
> +int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock, int presca=
ler,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0u32 *real_clk)
> =A0{
> =A0 =A0 =A0 =A0const struct mpc_i2c_divider *div =3D NULL;
> =A0 =A0 =A0 =A0unsigned int pvr =3D mfspr(SPRN_PVR);
> =A0 =A0 =A0 =A0u32 divider;
> =A0 =A0 =A0 =A0int i;
>
> - =A0 =A0 =A0 if (!clock)
> + =A0 =A0 =A0 if (!clock) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 *real_clk =3D 0;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return -EINVAL;
> + =A0 =A0 =A0 }
>
> =A0 =A0 =A0 =A0/* Determine divider value */
> =A0 =A0 =A0 =A0divider =3D mpc5xxx_get_bus_frequency(node) / clock;
> @@ -212,7 +232,8 @@ int mpc_i2c_get_fdr_52xx(struct device_n
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;
> =A0 =A0 =A0 =A0}
>
> - =A0 =A0 =A0 return div ? (int)div->fdr : -EINVAL;
> + =A0 =A0 =A0 *real_clk =3D mpc5xxx_get_bus_frequency(node) / div->divide=
r;
> + =A0 =A0 =A0 return (int)div->fdr;
> =A0}
>
> =A0static void mpc_i2c_setclock_52xx(struct device_node *node,
> @@ -221,13 +242,14 @@ static void mpc_i2c_setclock_52xx(struct
> =A0{
> =A0 =A0 =A0 =A0int ret, fdr;
>
> - =A0 =A0 =A0 ret =3D mpc_i2c_get_fdr_52xx(node, clock, prescaler);
> + =A0 =A0 =A0 ret =3D mpc_i2c_get_fdr_52xx(node, clock, prescaler, &i2c->=
real_clk);
> =A0 =A0 =A0 =A0fdr =3D (ret >=3D 0) ? ret : 0x3f; /* backward compatibili=
ty */
>
> =A0 =A0 =A0 =A0writeb(fdr & 0xff, i2c->base + MPC_I2C_FDR);
>
> =A0 =A0 =A0 =A0if (ret >=3D 0)
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_info(i2c->dev, "clock %d Hz (fdr=3D%d)\=
n", clock, fdr);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_info(i2c->dev, "clock %u Hz (fdr=3D%d)\=
n", i2c->real_clk,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0fdr);
> =A0}
> =A0#else /* !CONFIG_PPC_MPC52xx */
> =A0static void mpc_i2c_setclock_52xx(struct device_node *node,
> @@ -446,10 +468,14 @@ static int mpc_xfer(struct i2c_adapter *
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return -EINTR;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (time_after(jiffies, orig_jiffies + HZ)=
) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 u8 status =3D readb(i2c->ba=
se + MPC_I2C_SR);
> +
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dev_dbg(i2c->dev, "timeout=
\n");
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (readb(i2c->base + MPC_I=
2C_SR) =3D=3D
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (CSR_MCF | CSR_MBB =
| CSR_RXAK))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if ((status & (CSR_MCF | CS=
R_MBB | CSR_RXAK)) !=3D 0) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 writeb(stat=
us & ~CSR_MAL,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0i2c->base + MPC_I2C_SR);
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0mpc_i2c_fi=
xup(i2c);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return -EIO;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0schedule();
> @@ -540,6 +566,14 @@ static int __devinit fsl_i2c_probe(struc
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
> =A0 =A0 =A0 =A0}
>
> + =A0 =A0 =A0 prop =3D of_get_property(op->node, "timeout", &plen);
> + =A0 =A0 =A0 if (prop && plen =3D=3D sizeof(u32)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mpc_ops.timeout =3D *prop * HZ / 1000000;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (mpc_ops.timeout < 5)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 mpc_ops.timeout =3D 5;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 dev_info(i2c->dev, "timeout %u us\n", mpc_ops.timeout * 100=
0000 / HZ);
> +
> =A0 =A0 =A0 =A0dev_set_drvdata(&op->dev, i2c);
>
> =A0 =A0 =A0 =A0i2c->adap =3D mpc_ops;
>
> _______________________________________________
> devicetree-discuss mailing list
> devicetree-discuss@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/devicetree-discuss
>
--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* [PATCH] powerpc: mpc5121: correct DIU compatible property
From: Anatolij Gustschin @ 2010-02-16 19:32 UTC (permalink / raw)
To: linuxppc-dev; +Cc: wd, dzu, Anatolij Gustschin, kosmo
In-Reply-To: <fa686aa41002161011r29f5323clcbb1d89a9df6614@mail.gmail.com>
The DIU driver should bind against "fsl,mpc5121-diu"
directly. Add this compatible property to the match
table and fix DTS and platform code accordingly.
Signed-off-by: Anatolij Gustschin <agust@denx.de>
---
arch/powerpc/boot/dts/mpc5121ads.dts | 2 +-
arch/powerpc/platforms/512x/mpc512x_shared.c | 2 +-
drivers/video/fsl-diu-fb.c | 5 +++++
3 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/boot/dts/mpc5121ads.dts b/arch/powerpc/boot/dts/mpc5121ads.dts
index d2b2db7..c9ef6bb 100644
--- a/arch/powerpc/boot/dts/mpc5121ads.dts
+++ b/arch/powerpc/boot/dts/mpc5121ads.dts
@@ -255,7 +255,7 @@
};
display@2100 {
- compatible = "fsl,mpc5121-diu", "fsl,diu";
+ compatible = "fsl,mpc5121-diu";
reg = <0x2100 0x100>;
interrupts = <64 0x8>;
interrupt-parent = < &ipic >;
diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c
index 1751c0d..3a5ff75 100644
--- a/arch/powerpc/platforms/512x/mpc512x_shared.c
+++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
@@ -250,7 +250,7 @@ void __init mpc512x_init_diu(void)
unsigned long mode, pix_fmt, res, bpp;
unsigned long dst;
- np = of_find_compatible_node(NULL, NULL, "fsl,diu");
+ np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-diu");
if (!np) {
pr_err("No DIU node\n");
return;
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index 29c7f31..5db701b 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -1663,6 +1663,11 @@ static int __init fsl_diu_setup(char *options)
#endif
static struct of_device_id fsl_diu_match[] = {
+#ifdef CONFIG_PPC_MPC512x
+ {
+ .compatible = "fsl,mpc5121-diu",
+ },
+#endif
{
.compatible = "fsl,diu",
},
--
1.6.3.3
^ permalink raw reply related
* Re: [PATCH/RFC 2/2] 5200: improve i2c bus error recovery
From: Grant Likely @ 2010-02-16 19:33 UTC (permalink / raw)
To: Albrecht Dreß
Cc: Linux PPC Development, Devicetree Discussions,
Ben Dooks (embedded platforms)
In-Reply-To: <1264191502.2224.2@antares>
On Fri, Jan 22, 2010 at 1:18 PM, Albrecht Dre=DF <albrecht.dress@arcor.de> =
wrote:
> Make the I2C adapter timeout configurable through a Device Tree property
> which gives the timeout in microseconds.
>
> Signed-off-by: Albrecht Dre=DF <albrecht.dress@arcor.de>
>
> ---
>
> --- linux-2.6.32-orig/Documentation/powerpc/dts-bindings/fsl/i2c.txt =A0 =
=A02009-12-03 04:51:21.000000000 +0100
> +++ linux-2.6.32/Documentation/powerpc/dts-bindings/fsl/i2c.txt 2010-01-2=
2 16:04:56.000000000 +0100
> @@ -21,6 +21,7 @@
> =A0- fsl,preserve-clocking : boolean; if defined, the clock settings
> =A0 =A0from the bootloader are preserved (not touched).
> =A0- clock-frequency : desired I2C bus clock frequency in Hz.
> + - timeout : I2C timeout in microseconds.
fsl,timeout to avoid namespace collisions please (ie. if a common i2c
'timeout' property is ever defined for all i2c busses)
g.
^ permalink raw reply
* Re: [PATCH] pata_mpc52xx: optimizing code size by change of ATA timing data types
From: Grant Likely @ 2010-02-16 19:41 UTC (permalink / raw)
To: Roman Fietze
Cc: linux-ide, linuxppc-dev, Linux Kernel Mailing List, Jeff Garzik
In-Reply-To: <200912161429.14968.roman.fietze@telemotive.de>
[cc'd linux-kernel, linux-ide and Jeff Garzik]
Hi Roman.
you should use ./scripts/get_maintainer.pl to make sure you're cc'ing
the right people when posting patches. You should repost so that Jeff
has a copy of the patch to pick up (and add my acked-by when you do).
On Wed, Dec 16, 2009 at 6:29 AM, Roman Fietze
<roman.fietze@telemotive.de> wrote:
> Hello Everybody,
>
> A totally simple patch that reduces the text size as of the
> ppc_6xx-size command of pata_mpc52xx by more than 10%, by reducing the
> rodata size from 0x4a4 to 0x17e bytes. This is simply done by changing
> the data types of the ATA timing constants.
Acked-by: Grant Likely <grant.likely@secretlab>
>
> If you are interested at all, and it's worth the trouble, here the
> details:
>
> ppc_6xx-size:
> =A0 =A0 text data bss =A0dec =A0hex filename
> old: 6532 1068 =A0 0 7600 1db0 pata_mpc52xx.o
> new: 5718 1068 =A0 0 6786 1a82 pata_mpc52xx.o
>
> The (assembler) code itself doesn't really change very much. I double
> checked the final results inside mpc52xx_ata_apply_timings() and they
> match.
>
> BTW: Should I break lines at col 72 or 80?
>
>
> From: Roman Fietze <roman.fietze@telemotive.de>
> Date: Wed, 16 Dec 2009 13:10:31 +0100
> Subject: [PATCH] pata_mpc52xx: reduce code size by simple change of const=
ant data types
>
> Signed-off-by: Roman Fietze <roman.fietze@telemotive.de>
> ---
> =A0drivers/ata/pata_mpc52xx.c | =A0 78 ++++++++++++++++++++++------------=
----------
> =A01 files changed, 39 insertions(+), 39 deletions(-)
>
> diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c
> index 2bc2dbe..e4e5e82 100644
> --- a/drivers/ata/pata_mpc52xx.c
> +++ b/drivers/ata/pata_mpc52xx.c
> @@ -64,13 +64,13 @@ struct mpc52xx_ata_priv {
>
>
> =A0/* ATAPI-4 PIO specs (in ns) */
> -static const int ataspec_t0[5] =A0 =A0=3D {600, 383, 240, 180, 120};
> -static const int ataspec_t1[5] =A0 =A0=3D { 70, =A050, =A030, =A030, =A0=
25};
> -static const int ataspec_t2_8[5] =A0=3D {290, 290, 290, =A080, =A070};
> -static const int ataspec_t2_16[5] =3D {165, 125, 100, =A080, =A070};
> -static const int ataspec_t2i[5] =A0 =3D { =A00, =A0 0, =A0 0, =A070, =A0=
25};
> -static const int ataspec_t4[5] =A0 =A0=3D { 30, =A020, =A015, =A010, =A0=
10};
> -static const int ataspec_ta[5] =A0 =A0=3D { 35, =A035, =A035, =A035, =A0=
35};
> +static const u16 ataspec_t0[5] =A0 =A0 =A0 =A0 =3D {600, 383, 240, 180, =
120};
> +static const u16 ataspec_t1[5] =A0 =A0 =A0 =A0 =3D { 70, =A050, =A030, =
=A030, =A025};
> +static const u16 ataspec_t2_8[5] =A0 =A0 =A0 =3D {290, 290, 290, =A080, =
=A070};
> +static const u16 ataspec_t2_16[5] =A0 =A0 =A0=3D {165, 125, 100, =A080, =
=A070};
> +static const u16 ataspec_t2i[5] =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=3D { =A0=
0, =A0 0, =A0 0, =A070, =A025};
> +static const u16 ataspec_t4[5] =A0 =A0 =A0 =A0 =3D { 30, =A020, =A015, =
=A010, =A010};
> +static const u16 ataspec_ta[5] =A0 =A0 =A0 =A0 =3D { 35, =A035, =A035, =
=A035, =A035};
>
> =A0#define CALC_CLKCYC(c,v) ((((v)+(c)-1)/(c)))
>
> @@ -78,13 +78,13 @@ static const int ataspec_ta[5] =A0 =A0=3D { 35, =A035=
, =A035, =A035, =A035};
>
> =A0/* ATAPI-4 MDMA specs (in clocks) */
> =A0struct mdmaspec {
> - =A0 =A0 =A0 u32 t0M;
> - =A0 =A0 =A0 u32 td;
> - =A0 =A0 =A0 u32 th;
> - =A0 =A0 =A0 u32 tj;
> - =A0 =A0 =A0 u32 tkw;
> - =A0 =A0 =A0 u32 tm;
> - =A0 =A0 =A0 u32 tn;
> + =A0 =A0 =A0 u8 t0M;
> + =A0 =A0 =A0 u8 td;
> + =A0 =A0 =A0 u8 th;
> + =A0 =A0 =A0 u8 tj;
> + =A0 =A0 =A0 u8 tkw;
> + =A0 =A0 =A0 u8 tm;
> + =A0 =A0 =A0 u8 tn;
> =A0};
>
> =A0static const struct mdmaspec mdmaspec66[3] =3D {
> @@ -101,23 +101,23 @@ static const struct mdmaspec mdmaspec132[3] =3D {
>
> =A0/* ATAPI-4 UDMA specs (in clocks) */
> =A0struct udmaspec {
> - =A0 =A0 =A0 u32 tcyc;
> - =A0 =A0 =A0 u32 t2cyc;
> - =A0 =A0 =A0 u32 tds;
> - =A0 =A0 =A0 u32 tdh;
> - =A0 =A0 =A0 u32 tdvs;
> - =A0 =A0 =A0 u32 tdvh;
> - =A0 =A0 =A0 u32 tfs;
> - =A0 =A0 =A0 u32 tli;
> - =A0 =A0 =A0 u32 tmli;
> - =A0 =A0 =A0 u32 taz;
> - =A0 =A0 =A0 u32 tzah;
> - =A0 =A0 =A0 u32 tenv;
> - =A0 =A0 =A0 u32 tsr;
> - =A0 =A0 =A0 u32 trfs;
> - =A0 =A0 =A0 u32 trp;
> - =A0 =A0 =A0 u32 tack;
> - =A0 =A0 =A0 u32 tss;
> + =A0 =A0 =A0 u8 tcyc;
> + =A0 =A0 =A0 u8 t2cyc;
> + =A0 =A0 =A0 u8 tds;
> + =A0 =A0 =A0 u8 tdh;
> + =A0 =A0 =A0 u8 tdvs;
> + =A0 =A0 =A0 u8 tdvh;
> + =A0 =A0 =A0 u8 tfs;
> + =A0 =A0 =A0 u8 tli;
> + =A0 =A0 =A0 u8 tmli;
> + =A0 =A0 =A0 u8 taz;
> + =A0 =A0 =A0 u8 tzah;
> + =A0 =A0 =A0 u8 tenv;
> + =A0 =A0 =A0 u8 tsr;
> + =A0 =A0 =A0 u8 trfs;
> + =A0 =A0 =A0 u8 trp;
> + =A0 =A0 =A0 u8 tack;
> + =A0 =A0 =A0 u8 tss;
> =A0};
>
> =A0static const struct udmaspec udmaspec66[6] =3D {
> @@ -270,7 +270,7 @@ mpc52xx_ata_compute_pio_timings(struct mpc52xx_ata_pr=
iv *priv, int dev, int pio)
> =A0{
> =A0 =A0 =A0 =A0struct mpc52xx_ata_timings *timing =3D &priv->timings[dev]=
;
> =A0 =A0 =A0 =A0unsigned int ipb_period =3D priv->ipb_period;
> - =A0 =A0 =A0 unsigned int t0, t1, t2_8, t2_16, t2i, t4, ta;
> + =A0 =A0 =A0 u32 t0, t1, t2_8, t2_16, t2i, t4, ta;
>
> =A0 =A0 =A0 =A0if ((pio < 0) || (pio > 4))
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return -EINVAL;
> @@ -299,8 +299,8 @@ mpc52xx_ata_compute_mdma_timings(struct mpc52xx_ata_p=
riv *priv, int dev,
> =A0 =A0 =A0 =A0if (speed < 0 || speed > 2)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return -EINVAL;
>
> - =A0 =A0 =A0 t->mdma1 =3D (s->t0M << 24) | (s->td << 16) | (s->tkw << 8)=
| (s->tm);
> - =A0 =A0 =A0 t->mdma2 =3D (s->th << 24) | (s->tj << 16) | (s->tn << 8);
> + =A0 =A0 =A0 t->mdma1 =3D ((u32)s->t0M << 24) | ((u32)s->td << 16) | ((u=
32)s->tkw << 8) | s->tm;
> + =A0 =A0 =A0 t->mdma2 =3D ((u32)s->th << 24) | ((u32)s->tj << 16) | ((u3=
2)s->tn << 8);
> =A0 =A0 =A0 =A0t->using_udma =3D 0;
>
> =A0 =A0 =A0 =A0return 0;
> @@ -316,11 +316,11 @@ mpc52xx_ata_compute_udma_timings(struct mpc52xx_ata=
_priv *priv, int dev,
> =A0 =A0 =A0 =A0if (speed < 0 || speed > 2)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return -EINVAL;
>
> - =A0 =A0 =A0 t->udma1 =3D (s->t2cyc << 24) | (s->tcyc << 16) | (s->tds <=
< 8) | s->tdh;
> - =A0 =A0 =A0 t->udma2 =3D (s->tdvs << 24) | (s->tdvh << 16) | (s->tfs <<=
8) | s->tli;
> - =A0 =A0 =A0 t->udma3 =3D (s->tmli << 24) | (s->taz << 16) | (s->tenv <<=
8) | s->tsr;
> - =A0 =A0 =A0 t->udma4 =3D (s->tss << 24) | (s->trfs << 16) | (s->trp << =
8) | s->tack;
> - =A0 =A0 =A0 t->udma5 =3D (s->tzah << 24);
> + =A0 =A0 =A0 t->udma1 =3D ((u32)s->t2cyc << 24) | ((u32)s->tcyc << 16) |=
((u32)s->tds << 8) | s->tdh;
> + =A0 =A0 =A0 t->udma2 =3D ((u32)s->tdvs << 24) | ((u32)s->tdvh << 16) | =
((u32)s->tfs << 8) | s->tli;
> + =A0 =A0 =A0 t->udma3 =3D ((u32)s->tmli << 24) | ((u32)s->taz << 16) | (=
(u32)s->tenv << 8) | s->tsr;
> + =A0 =A0 =A0 t->udma4 =3D ((u32)s->tss << 24) | ((u32)s->trfs << 16) | (=
(u32)s->trp << 8) | s->tack;
> + =A0 =A0 =A0 t->udma5 =3D (u32)s->tzah << 24;
> =A0 =A0 =A0 =A0t->using_udma =3D 1;
>
> =A0 =A0 =A0 =A0return 0;
> --
> 1.6.5.3
>
>
> Roman
>
> --
> Roman Fietze =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0Telemotive AG B=FCro M=FChlha=
usen
> Breitwiesen =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A073=
347 M=FChlhausen
> Tel.: +49(0)7335/18493-45 =A0 =A0 =A0 =A0http://www.telemotive.de
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
>
--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [PATCH/RFC 1/2] 5200: improve i2c bus error recovery
From: Ira W. Snyder @ 2010-02-16 19:49 UTC (permalink / raw)
To: Albrecht Dreß
Cc: Linux PPC Development, Devicetree Discussions,
Ben Dooks (embedded platforms)
In-Reply-To: <1264191475.2224.1@antares>
On Fri, Jan 22, 2010 at 09:17:55PM +0100, Albrecht Dreß wrote:
> Improve the recovery of the MPC5200B's I2C bus from errors like bus
> hangs.
>
> Signed-off-by: Albrecht Dreß <albrecht.dress@arcor.de>
>
> ---
>
> This patch introduces several improvements to the MPC5200B's I2C driver
> as to improve the recovery from error conditions I encountered when
> testing a custom board with several I2C devices attached (eeprom, io
> expander, rtc, sensors). The error conditions included cases where the
> bus if logic of one slave apparently went south, blocking the bus
> completely.
>
> My fixes include:
> 1. make the bus timeout configurable in fsl_i2c_probe(); the default of
> one second is *way* too long for my use case;
> 2. if a timeout condition occurs in mpc_xfer(), mpc_i2c_fixup() the bus
> if *any* of the CF, BB and RXAK flags in the MSR is 1. I actually
> saw different combinations with hangs, not only all three set;
Hello Albrecht,
I see this exact hang on a MPC8349EA board. I poll my i2c sensors every
500ms, and it takes around 12 hours to produce a hang. The usual hang
has (CF | BB) set, however I have seen a hang with just BB (only once so
far in about 2 weeks).
I think the fixup should be run on 8349 as well, if not all processors.
I'm happy to test patches. I have a way to reliably trigger a lockup,
using another master on the i2c bus.
> 3. improve the fixup procedure by calculating the timing needed from the
> real (configured) bus clock, calculated in mpc_i2c_setclock_52xx().
> Furthermore, I issue 9 instead of one cycle, as I experienced cases
> where the single one is not enough (found this tip in a forum). As a
> side effect, the new scheme needs only 81us @375kHz bus clock instead
> of 150us. I recorded waveforms for 18.4kHz, 85.9kHz and 375kHz, all
> looking fine, which I can provide if anyone is interested.
>
> Open questions:
> - is the approach correct at all, in particular the interpretation of
> the flags (#2)?
> - could this code also be used on non-5200 processors?
>
> --- linux-2.6.32-orig/drivers/i2c/busses/i2c-mpc.c 2009-12-03 04:51:21.000000000 +0100
> +++ linux-2.6.32/drivers/i2c/busses/i2c-mpc.c 2010-01-22 16:05:13.000000000 +0100
> @@ -59,6 +59,7 @@ struct mpc_i2c {
> wait_queue_head_t queue;
> struct i2c_adapter adap;
> int irq;
> + u32 real_clk;
> };
>
> struct mpc_i2c_divider {
> @@ -97,16 +98,32 @@ static irqreturn_t mpc_i2c_isr(int irq,
> */
> static void mpc_i2c_fixup(struct mpc_i2c *i2c)
> {
> - writeccr(i2c, 0);
> - udelay(30);
> - writeccr(i2c, CCR_MEN);
> - udelay(30);
> - writeccr(i2c, CCR_MSTA | CCR_MTX);
> - udelay(30);
> - writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN);
> - udelay(30);
> - writeccr(i2c, CCR_MEN);
> - udelay(30);
> + if (i2c->real_clk == 0) {
> + writeccr(i2c, 0);
> + udelay(30);
> + writeccr(i2c, CCR_MEN);
> + udelay(30);
> + writeccr(i2c, CCR_MSTA | CCR_MTX);
> + udelay(30);
> + writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN);
> + udelay(30);
> + writeccr(i2c, CCR_MEN);
> + udelay(30);
> + } else {
> + int k;
> + u32 delay_val = 1000000 / i2c->real_clk + 1;
> +
> + if (delay_val < 2)
> + delay_val = 2;
> +
> + for (k = 9; k; k--) {
> + writeccr(i2c, 0);
> + writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN);
> + udelay(delay_val);
> + writeccr(i2c, CCR_MEN);
> + udelay(delay_val << 1);
> + }
> + }
> }
>
The old sequence has always un-hung the bus for me. Yours might be
better. I'll try it next time the bus wedges up on me.
> static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
> @@ -186,15 +203,18 @@ static const struct mpc_i2c_divider mpc_
> {10240, 0x9d}, {12288, 0x9e}, {15360, 0x9f}
> };
>
> -int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock, int prescaler)
> +int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock, int prescaler,
> + u32 *real_clk)
> {
> const struct mpc_i2c_divider *div = NULL;
> unsigned int pvr = mfspr(SPRN_PVR);
> u32 divider;
> int i;
>
> - if (!clock)
> + if (!clock) {
> + *real_clk = 0;
> return -EINVAL;
> + }
>
> /* Determine divider value */
> divider = mpc5xxx_get_bus_frequency(node) / clock;
> @@ -212,7 +232,8 @@ int mpc_i2c_get_fdr_52xx(struct device_n
> break;
> }
>
> - return div ? (int)div->fdr : -EINVAL;
> + *real_clk = mpc5xxx_get_bus_frequency(node) / div->divider;
> + return (int)div->fdr;
> }
>
> static void mpc_i2c_setclock_52xx(struct device_node *node,
> @@ -221,13 +242,14 @@ static void mpc_i2c_setclock_52xx(struct
> {
> int ret, fdr;
>
> - ret = mpc_i2c_get_fdr_52xx(node, clock, prescaler);
> + ret = mpc_i2c_get_fdr_52xx(node, clock, prescaler, &i2c->real_clk);
> fdr = (ret >= 0) ? ret : 0x3f; /* backward compatibility */
>
> writeb(fdr & 0xff, i2c->base + MPC_I2C_FDR);
>
> if (ret >= 0)
> - dev_info(i2c->dev, "clock %d Hz (fdr=%d)\n", clock, fdr);
> + dev_info(i2c->dev, "clock %u Hz (fdr=%d)\n", i2c->real_clk,
> + fdr);
> }
> #else /* !CONFIG_PPC_MPC52xx */
> static void mpc_i2c_setclock_52xx(struct device_node *node,
> @@ -446,10 +468,14 @@ static int mpc_xfer(struct i2c_adapter *
> return -EINTR;
> }
> if (time_after(jiffies, orig_jiffies + HZ)) {
> + u8 status = readb(i2c->base + MPC_I2C_SR);
> +
> dev_dbg(i2c->dev, "timeout\n");
> - if (readb(i2c->base + MPC_I2C_SR) ==
> - (CSR_MCF | CSR_MBB | CSR_RXAK))
> + if ((status & (CSR_MCF | CSR_MBB | CSR_RXAK)) != 0) {
> + writeb(status & ~CSR_MAL,
> + i2c->base + MPC_I2C_SR);
> mpc_i2c_fixup(i2c);
> + }
> return -EIO;
> }
> schedule();
This hunk looks good to me. It is basically what I did, except I didn't
clear the MAL bit. Judging by the manual, it should be cleared.
> @@ -540,6 +566,14 @@ static int __devinit fsl_i2c_probe(struc
> }
> }
>
> + prop = of_get_property(op->node, "timeout", &plen);
> + if (prop && plen == sizeof(u32)) {
> + mpc_ops.timeout = *prop * HZ / 1000000;
> + if (mpc_ops.timeout < 5)
> + mpc_ops.timeout = 5;
> + }
> + dev_info(i2c->dev, "timeout %u us\n", mpc_ops.timeout * 1000000 / HZ);
> +
> dev_set_drvdata(&op->dev, i2c);
>
> i2c->adap = mpc_ops;
>
Ira
^ permalink raw reply
* Re: [PATCH] powerpc: mpc5121: correct DIU compatible property
From: Grant Likely @ 2010-02-16 19:51 UTC (permalink / raw)
To: Anatolij Gustschin; +Cc: linuxppc-dev, wd, dzu, kosmo
In-Reply-To: <1266348777-30665-1-git-send-email-agust@denx.de>
On Tue, Feb 16, 2010 at 12:32 PM, Anatolij Gustschin <agust@denx.de> wrote:
> The DIU driver should bind against "fsl,mpc5121-diu"
> directly. Add this compatible property to the match
> table and fix DTS and platform code accordingly.
>
> Signed-off-by: Anatolij Gustschin <agust@denx.de>
> ---
> =A0arch/powerpc/boot/dts/mpc5121ads.dts =A0 =A0 =A0 =A0 | =A0 =A02 +-
> =A0arch/powerpc/platforms/512x/mpc512x_shared.c | =A0 =A02 +-
> =A0drivers/video/fsl-diu-fb.c =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 | =A0 =
=A05 +++++
Merged, but only the dts and fsl-diu-fb.c hunks. I haven't merged the
mpc512x_shared.c changes because I haven't merged your diu patches yet
(as discussed in a previous email).
g.
^ permalink raw reply
* Re: [PATCH/RFC 1/2] 5200: improve i2c bus error recovery
From: Albrecht Dreß @ 2010-02-16 20:02 UTC (permalink / raw)
To: grant.likely, iws; +Cc: linuxppc-dev, devicetree-discuss, ben-linux
In-Reply-To: <fa686aa41002161131j7329a05cx16e66125f82fec39@mail.gmail.com>
Hi Grant & Ira:
Thanks a lot for reviewing the patch, and for the encouraging comments! I =
will re-submit a new version according according to them, hopefully tomorro=
w or on Thursday.
Best, Albrecht.
----- Original Nachricht ----
Von: Grant Likely <grant.likely@secretlab.ca>
An: Albrecht Dre=DF <albrecht.dress@arcor.de>
Datum: 16.02.2010 20:31
Betreff: Re: [PATCH/RFC 1/2] 5200: improve i2c bus error recovery
> Hi Albrecht,
>=20
> Comments below.
>=20
> On Fri, Jan 22, 2010 at 1:17 PM, Albrecht Dre=DF <albrecht.dress@arcor.de=
>
> wrote:
> > Improve the recovery of the MPC5200B's I2C bus from errors like bus
> > hangs.
> >
> > Signed-off-by: Albrecht Dre=DF <albrecht.dress@arcor.de>
> >
> > ---
> >
> > This patch introduces several improvements to the MPC5200B's I2C driver
> > as to improve the recovery from error conditions I encountered when
> > testing a custom board with several I2C devices attached (eeprom, io
> > expander, rtc, sensors). =A0The error conditions included cases where t=
he
> > bus if logic of one slave apparently went south, blocking the bus
> > completely.
> >
> > My fixes include:
> > 1. make the bus timeout configurable in fsl_i2c_probe(); the default of
> > =A0 one second is *way* too long for my use case;
> > 2. if a timeout condition occurs in mpc_xfer(), mpc_i2c_fixup() the bus
> > =A0 if *any* of the CF, BB and RXAK flags in the MSR is 1. =A0I actuall=
y
> > =A0 saw different combinations with hangs, not only all three set;
> > 3. improve the fixup procedure by calculating the timing needed from th=
e
> > =A0 real (configured) bus clock, calculated in mpc_i2c_setclock_52xx().
> > =A0 Furthermore, I issue 9 instead of one cycle, as I experienced cases
> > =A0 where the single one is not enough (found this tip in a forum). =A0=
As a
> > =A0 side effect, the new scheme needs only 81us @375kHz bus clock inste=
ad
> > =A0 of 150us. =A0I recorded waveforms for 18.4kHz, 85.9kHz and 375kHz, =
all
> > =A0 looking fine, which I can provide if anyone is interested.
>=20
> These are three separate fixes. Ideally you should submit them in
> separate patches to make it easy on poor old reviewers like me. And,
> as Ben mentions, this descriptions should be above the '---' line so
> it appears in the commit text.
OK, will do.
>=20
> >
> > Open questions:
> > - is the approach correct at all, in particular the interpretation of
> > =A0the flags (#2)?
> > - could this code also be used on non-5200 processors?
> >
> > --- linux-2.6.32-orig/drivers/i2c/busses/i2c-mpc.c =A0 =A0 =A02009-12-0=
3
> 04:51:21.000000000 +0100
> > +++ linux-2.6.32/drivers/i2c/busses/i2c-mpc.c =A0 2010-01-22
> 16:05:13.000000000 +0100
> > @@ -59,6 +59,7 @@ struct mpc_i2c {
> > =A0 =A0 =A0 =A0wait_queue_head_t queue;
> > =A0 =A0 =A0 =A0struct i2c_adapter adap;
> > =A0 =A0 =A0 =A0int irq;
> > + =A0 =A0 =A0 u32 real_clk;
> > =A0};
> >
> > =A0struct mpc_i2c_divider {
> > @@ -97,16 +98,32 @@ static irqreturn_t mpc_i2c_isr(int irq,
> > =A0*/
> > =A0static void mpc_i2c_fixup(struct mpc_i2c *i2c)
> > =A0{
> > - =A0 =A0 =A0 writeccr(i2c, 0);
> > - =A0 =A0 =A0 udelay(30);
> > - =A0 =A0 =A0 writeccr(i2c, CCR_MEN);
> > - =A0 =A0 =A0 udelay(30);
> > - =A0 =A0 =A0 writeccr(i2c, CCR_MSTA | CCR_MTX);
> > - =A0 =A0 =A0 udelay(30);
> > - =A0 =A0 =A0 writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN);
> > - =A0 =A0 =A0 udelay(30);
> > - =A0 =A0 =A0 writeccr(i2c, CCR_MEN);
> > - =A0 =A0 =A0 udelay(30);
> > + =A0 =A0 =A0 if (i2c->real_clk =3D=3D 0) {
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 writeccr(i2c, 0);
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(30);
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 writeccr(i2c, CCR_MEN);
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(30);
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 writeccr(i2c, CCR_MSTA | CCR_MTX);
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(30);
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_ME=
N);
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(30);
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 writeccr(i2c, CCR_MEN);
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(30);
> > + =A0 =A0 =A0 } else {
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 int k;
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 u32 delay_val =3D 1000000 / i2c->real_clk=
+ 1;
> > +
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (delay_val < 2)
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 delay_val =3D 2;
> > +
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 for (k =3D 9; k; k--) {
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 writeccr(i2c, 0);
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 writeccr(i2c, CCR_MSTA | =
CCR_MTX | CCR_MEN);
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(delay_val);
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 writeccr(i2c, CCR_MEN);
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(delay_val << 1);
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> > + =A0 =A0 =A0 }
>=20
> This doesn't look right. Why is the old code being preserved? Isn't
> it not as reliable? It looks to me that the new block should be the
> only path, with delay_val getting hard set to a sane value if real_clk
> =3D=3D 0. This approach looks to add complexity to the driver without a
> reason other than fear it *might* breaking something.
>=20
> If the new code is better, then be strong, stand tall, and say in a
> loud voice, "this old code is crap. The new stuff is much better."
:-) Ok...
>=20
> g.
>=20
> > =A0}
> >
> > =A0static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writi=
ng)
> > @@ -186,15 +203,18 @@ static const struct mpc_i2c_divider mpc_
> > =A0 =A0 =A0 =A0{10240, 0x9d}, {12288, 0x9e}, {15360, 0x9f}
> > =A0};
> >
> > -int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock, int
> prescaler)
> > +int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock, int
> prescaler,
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0u32 *real_clk)
> > =A0{
> > =A0 =A0 =A0 =A0const struct mpc_i2c_divider *div =3D NULL;
> > =A0 =A0 =A0 =A0unsigned int pvr =3D mfspr(SPRN_PVR);
> > =A0 =A0 =A0 =A0u32 divider;
> > =A0 =A0 =A0 =A0int i;
> >
> > - =A0 =A0 =A0 if (!clock)
> > + =A0 =A0 =A0 if (!clock) {
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 *real_clk =3D 0;
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return -EINVAL;
> > + =A0 =A0 =A0 }
> >
> > =A0 =A0 =A0 =A0/* Determine divider value */
> > =A0 =A0 =A0 =A0divider =3D mpc5xxx_get_bus_frequency(node) / clock;
> > @@ -212,7 +232,8 @@ int mpc_i2c_get_fdr_52xx(struct device_n
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;
> > =A0 =A0 =A0 =A0}
> >
> > - =A0 =A0 =A0 return div ? (int)div->fdr : -EINVAL;
> > + =A0 =A0 =A0 *real_clk =3D mpc5xxx_get_bus_frequency(node) / div->divi=
der;
> > + =A0 =A0 =A0 return (int)div->fdr;
> > =A0}
> >
> > =A0static void mpc_i2c_setclock_52xx(struct device_node *node,
> > @@ -221,13 +242,14 @@ static void mpc_i2c_setclock_52xx(struct
> > =A0{
> > =A0 =A0 =A0 =A0int ret, fdr;
> >
> > - =A0 =A0 =A0 ret =3D mpc_i2c_get_fdr_52xx(node, clock, prescaler);
> > + =A0 =A0 =A0 ret =3D mpc_i2c_get_fdr_52xx(node, clock, prescaler,
> &i2c->real_clk);
> > =A0 =A0 =A0 =A0fdr =3D (ret >=3D 0) ? ret : 0x3f; /* backward compatibi=
lity */
> >
> > =A0 =A0 =A0 =A0writeb(fdr & 0xff, i2c->base + MPC_I2C_FDR);
> >
> > =A0 =A0 =A0 =A0if (ret >=3D 0)
> > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_info(i2c->dev, "clock %d Hz (fdr=3D%d=
)\n", clock, fdr);
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_info(i2c->dev, "clock %u Hz (fdr=3D%d=
)\n",
> i2c->real_clk,
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0fdr);
> > =A0}
> > =A0#else /* !CONFIG_PPC_MPC52xx */
> > =A0static void mpc_i2c_setclock_52xx(struct device_node *node,
> > @@ -446,10 +468,14 @@ static int mpc_xfer(struct i2c_adapter *
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return -EINTR;
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (time_after(jiffies, orig_jiffies + H=
Z)) {
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 u8 status =3D readb(i2c->=
base + MPC_I2C_SR);
> > +
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dev_dbg(i2c->dev, "timeo=
ut\n");
> > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (readb(i2c->base + MPC=
_I2C_SR) =3D=3D
> > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (CSR_MCF | CSR_MB=
B | CSR_RXAK))
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if ((status & (CSR_MCF | =
CSR_MBB | CSR_RXAK)) !=3D
> 0) {
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 writeb(st=
atus & ~CSR_MAL,
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0i2c->base + MPC_I2C_SR);
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0mpc_i2c_=
fixup(i2c);
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return -EIO;
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0schedule();
> > @@ -540,6 +566,14 @@ static int __devinit fsl_i2c_probe(struc
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
> > =A0 =A0 =A0 =A0}
> >
> > + =A0 =A0 =A0 prop =3D of_get_property(op->node, "timeout", &plen);
> > + =A0 =A0 =A0 if (prop && plen =3D=3D sizeof(u32)) {
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mpc_ops.timeout =3D *prop * HZ / 1000000;
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (mpc_ops.timeout < 5)
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 mpc_ops.timeout =3D 5;
> > + =A0 =A0 =A0 }
> > + =A0 =A0 =A0 dev_info(i2c->dev, "timeout %u us\n", mpc_ops.timeout * 1=
000000 /
> HZ);
> > +
> > =A0 =A0 =A0 =A0dev_set_drvdata(&op->dev, i2c);
> >
> > =A0 =A0 =A0 =A0i2c->adap =3D mpc_ops;
> >
> > _______________________________________________
> > devicetree-discuss mailing list
> > devicetree-discuss@lists.ozlabs.org
> > https://lists.ozlabs.org/listinfo/devicetree-discuss
> >
>=20
>=20
>=20
> --=20
> Grant Likely, B.Sc., P.Eng.
> Secret Lab Technologies Ltd.
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
>=20
Immer auf dem Laufenden! Sport, Auto, Reise, Politik und Promis. Von uns f=
=FCr Sie: der neue Arcor.de-Newsletter!
Jetzt anmelden und einfach alles wissen: http://www.arcor.de/rd/footer.news=
letter
^ permalink raw reply
* Re: [PATCH/RFC 1/2] 5200: improve i2c bus error recovery
From: Albrecht Dreß @ 2010-02-16 20:14 UTC (permalink / raw)
To: iws; +Cc: linuxppc-dev, devicetree-discuss, ben-linux
In-Reply-To: <20100216194922.GA27811@ovro.caltech.edu>
Hi Ira:
[snip]
> I see this exact hang on a MPC8349EA board. I poll my i2c sensors every
> 500ms, and it takes around 12 hours to produce a hang. The usual hang
> has (CF | BB) set, however I have seen a hang with just BB (only once so
> far in about 2 weeks).
>=20
> I think the fixup should be run on 8349 as well, if not all processors.
> I'm happy to test patches. I have a way to reliably trigger a lockup,
> using another master on the i2c bus.
See my other post - hopefully a new patch is ready tomorrow/Thursday...
[snip]
> > static void mpc_i2c_fixup(struct mpc_i2c *i2c)
> > {
> > -=09writeccr(i2c, 0);
> > -=09udelay(30);
> > -=09writeccr(i2c, CCR_MEN);
> > -=09udelay(30);
> > -=09writeccr(i2c, CCR_MSTA | CCR_MTX);
> > -=09udelay(30);
> > -=09writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN);
> > -=09udelay(30);
> > -=09writeccr(i2c, CCR_MEN);
> > -=09udelay(30);
> > +=09if (i2c->real_clk =3D=3D 0) {
> > +=09=09writeccr(i2c, 0);
> > +=09=09udelay(30);
> > +=09=09writeccr(i2c, CCR_MEN);
> > +=09=09udelay(30);
> > +=09=09writeccr(i2c, CCR_MSTA | CCR_MTX);
> > +=09=09udelay(30);
> > +=09=09writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN);
> > +=09=09udelay(30);
> > +=09=09writeccr(i2c, CCR_MEN);
> > +=09=09udelay(30);
> > +=09} else {
> > +=09=09int k;
> > +=09=09u32 delay_val =3D 1000000 / i2c->real_clk + 1;
> > +
> > +=09=09if (delay_val < 2)
> > +=09=09=09delay_val =3D 2;
> > +
> > +=09=09for (k =3D 9; k; k--) {
> > +=09=09=09writeccr(i2c, 0);
> > +=09=09=09writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN);
> > +=09=09=09udelay(delay_val);
> > +=09=09=09writeccr(i2c, CCR_MEN);
> > +=09=09=09udelay(delay_val << 1);
> > +=09=09}
> > +=09}
> > }
> > =20
>=20
> The old sequence has always un-hung the bus for me. Yours might be
> better. I'll try it next time the bus wedges up on me.
The easiest way to verify the /waveforms/ is to simply call the function so=
mewhere else (e.g. in a i2c write call), and then record SCK and SDA with a=
scope. I saw *huge* unnecessary delays in the original code, and by some =
creative interpretation of the (not very clear) 5200 data sheet I came to t=
he write's and delays above. If you have a scope, you might want to repeat=
the test with your '8349.
Best, Albrecht.
Immer auf dem Laufenden! Sport, Auto, Reise, Politik und Promis. Von uns f=
=FCr Sie: der neue Arcor.de-Newsletter!
Jetzt anmelden und einfach alles wissen: http://www.arcor.de/rd/footer.news=
letter
^ permalink raw reply
* Re: [PATCH v7 1/4] i2c-mpc: use __devinit[data] for initialization functions and data
From: Wolfgang Grandegger @ 2010-02-16 20:49 UTC (permalink / raw)
To: Grant Likely
Cc: Ben Dooks, Devicetree-discuss, Linuxppc-dev, Linux-i2c,
Wolfgang Grandegger
In-Reply-To: <fa686aa41002161040kada217ds1f63d363157e08ab@mail.gmail.com>
Grant Likely wrote:
> On Wed, Feb 10, 2010 at 7:55 AM, Wolfgang Grandegger <wg@grandegger.com> wrote:
>> From: Wolfgang Grandegger <wg@denx.de>
>>
>> "__devinit[data]" has not yet been used for all initialization functions
>> and data. To avoid truncating lines, the struct "mpc_i2c_match_data" has
>> been renamed to "mpc_i2c_data", which is even the better name.
>>
>> Signed-off-by: Wolfgang Grandegger <wg@denx.de>
>> Tested-by: Wolfram Sang <w.sang@pengutronix.de>
>
> Between patch 1 & 2 is not bisectable. Functions still called
> *_setclock in this patch, but referenced as *_setup in the structure.
> Please respin.
Argh, sorry for the mess. I will fix it tomorrow.
> Also ...
>
>> +static struct mpc_i2c_data mpc_i2c_data_52xx __devinitdata = {
>> + .setup = mpc_i2c_setup_52xx,
>> +};
>> +
>> +static struct mpc_i2c_data mpc_i2c_data_8313 __devinitdata = {
>> + .setup = mpc_i2c_setup_8xxx,
>> +};
>> +
>> +static struct mpc_i2c_data mpc_i2c_data_8543 __devinitdata = {
>> + .setup = mpc_i2c_setup_8xxx,
>> + .prescaler = 2,
>> +};
>> +
>> +static struct mpc_i2c_data mpc_i2c_data_8544 __devinitdata = {
>> + .setup = mpc_i2c_setup_8xxx,
>> + .prescaler = 3,
>> +};
>> +
>> static const struct of_device_id mpc_i2c_of_match[] = {
>> - {.compatible = "mpc5200-i2c",
>> - .data = &(struct mpc_i2c_match_data) {
>> - .setclock = mpc_i2c_setclock_52xx,
>> - },
>> - },
>> - {.compatible = "fsl,mpc5200b-i2c",
>> - .data = &(struct mpc_i2c_match_data) {
>> - .setclock = mpc_i2c_setclock_52xx,
>> - },
>> - },
>> - {.compatible = "fsl,mpc5200-i2c",
>> - .data = &(struct mpc_i2c_match_data) {
>> - .setclock = mpc_i2c_setclock_52xx,
>> - },
>> - },
>> - {.compatible = "fsl,mpc8313-i2c",
>> - .data = &(struct mpc_i2c_match_data) {
>> - .setclock = mpc_i2c_setclock_8xxx,
>> - },
>> - },
>> - {.compatible = "fsl,mpc8543-i2c",
>> - .data = &(struct mpc_i2c_match_data) {
>> - .setclock = mpc_i2c_setclock_8xxx,
>> - .prescaler = 2,
>> - },
>> - },
>> - {.compatible = "fsl,mpc8544-i2c",
>> - .data = &(struct mpc_i2c_match_data) {
>> - .setclock = mpc_i2c_setclock_8xxx,
>> - .prescaler = 3,
>> - },
>> + {.compatible = "mpc5200-i2c", .data = &mpc_i2c_data_52xx, },
>> + {.compatible = "fsl,mpc5200b-i2c", .data = &mpc_i2c_data_52xx, },
>> + {.compatible = "fsl,mpc5200-i2c", .data = &mpc_i2c_data_52xx, },
>> + {.compatible = "fsl,mpc8313-i2c", .data = &mpc_i2c_data_8313, },
>> + {.compatible = "fsl,mpc8543-i2c", .data = &mpc_i2c_data_8543, },
>> + {.compatible = "fsl,mpc8544-i2c", .data = &mpc_i2c_data_8544, },
>
> ... what was wrong with the old format of declaring the .data
> structures inline with the match table?
It does not allow to use __devinitdata because the space reserved by the
compiler does belong to another section. In other words it was necessary
to get ride of section mismatches.
Wolfgang.
^ permalink raw reply
* patch-2.6.21-rt8 works for ppc arch?
From: Ryan @ 2010-02-17 7:42 UTC (permalink / raw)
To: ppcdev
Hi,
I'm trying to build a 2.6.21 kernel (ppc arch for a 74xx processor)
with the PREEMPT_RT patch "patch-2.6.21-rt8". But I'm having some
compilation errors in the very early stage. The errors are shown
below.
arch/ppc/kernel/asm-offsets.c: In function 'main':
arch/ppc/kernel/asm-offsets.c:148: error: 'struct vdso_data' has no
member named 'tb_orig_stamp'
arch/ppc/kernel/asm-offsets.c:149: error: 'struct vdso_data' has no
member named 'tb_ticks_per_sec'
arch/ppc/kernel/asm-offsets.c:150: error: 'struct vdso_data' has no
member named 'tb_to_xs'
arch/ppc/kernel/asm-offsets.c:151: error: 'struct vdso_data' has no
member named 'stamp_xsec'
arch/ppc/kernel/asm-offsets.c:152: error: 'struct vdso_data' has no
member named 'tb_update_count'
arch/ppc/kernel/asm-offsets.c:153: error: 'struct vdso_data' has no
member named 'tz_minuteswest'
arch/ppc/kernel/asm-offsets.c:154: error: 'struct vdso_data' has no
member named 'tz_dsttime'
arch/ppc/kernel/asm-offsets.c:156: error: 'struct vdso_data' has no
member named 'wtom_clock_sec'
arch/ppc/kernel/asm-offsets.c:157: error: 'struct vdso_data' has no
member named 'wtom_clock_nsec'
make[1]: *** [arch/ppc/kernel/asm-offsets.s] Error 1
I did dig a little deep to find why this error occurred. It turned out
these members are explicitly removed by patch-2.6.21-rt8. See below
exerted from this patch file. It makes me wondering if the PREEMPT_RT
patch ever worked for ppc arch.
Index: linux/include/asm-powerpc/vdso_datapage.h
===================================================================
--- linux.orig/include/asm-powerpc/vdso_datapage.h
+++ linux/include/asm-powerpc/vdso_datapage.h
@@ -74,11 +74,6 @@ struct vdso_data {
__u32 icache_size; /* L1 i-cache size 0x68 */
__u32 icache_line_size; /* L1 i-cache line size 0x6C */
- /* those additional ones don't have to be located anywhere
- * special as they were not part of the original systemcfg
- */
- __s32 wtom_clock_sec; /* Wall to monotonic clock */
- __s32 wtom_clock_nsec;
__u32 syscall_map_64[SYSCALL_MAP_SIZE]; /* map of syscalls */
__u32 syscall_map_32[SYSCALL_MAP_SIZE]; /* map of syscalls */
};
@@ -89,15 +84,6 @@ struct vdso_data {
* And here is the simpler 32 bits version
*/
struct vdso_data {
- __u64 tb_orig_stamp; /* Timebase at boot 0x30 */
- __u64 tb_ticks_per_sec; /* Timebase tics / sec 0x38 */
- __u64 tb_to_xs; /* Inverse of TB to 2^20 0x40 */
- __u64 stamp_xsec; /* 0x48 */
- __u32 tb_update_count; /* Timebase atomicity ctr 0x50 */
- __u32 tz_minuteswest; /* Minutes west of Greenwich 0x58 */
- __u32 tz_dsttime; /* Type of dst correction 0x5C */
- __s32 wtom_clock_sec; /* Wall to monotonic clock */
- __s32 wtom_clock_nsec;
__u32 syscall_map_32[SYSCALL_MAP_SIZE]; /* map of syscalls */
};
The kernel build also had some compilation warnings as follows.
CC arch/ppc/kernel/asm-offsets.s
In file included from arch/ppc/include/asm/hw_irq.h:110,
from include/asm/system.h:10,
from include/linux/list.h:9,
from include/linux/signal.h:8,
from arch/ppc/kernel/asm-offsets.c:11:
include/linux/irqflags.h:92:1: warning: "raw_local_irq_save" redefined
In file included from include/asm/system.h:10,
from include/linux/list.h:9,
from include/linux/signal.h:8,
from arch/ppc/kernel/asm-offsets.c:11:
arch/ppc/include/asm/hw_irq.h:103:1: warning: this is the location of
the previous definition
In file included from arch/ppc/include/asm/hw_irq.h:110,
from include/asm/system.h:10,
from include/linux/list.h:9,
from include/linux/signal.h:8,
from arch/ppc/kernel/asm-offsets.c:11:
include/linux/irqflags.h:97:1: warning: "raw_local_irq_restore" redefined
In file included from include/asm/system.h:10,
from include/linux/list.h:9,
from include/linux/signal.h:8,
from arch/ppc/kernel/asm-offsets.c:11:
arch/ppc/include/asm/hw_irq.h:62:1: warning: this is the location of
the previous definition
In file included from include/linux/time.h:7,
from include/linux/timex.h:57,
from include/linux/sched.h:51,
from arch/ppc/kernel/asm-offsets.c:12:
include/linux/seqlock.h: In function '__read_seqretry':
include/linux/seqlock.h:139: warning: implicit declaration of function
'local_irq_save'
include/linux/seqlock.h:140: warning: implicit declaration of function
'local_irq_restore'
All the failure makes me doubt the correctness of the PREEMPT_RT patch
in 2.6.21 for ppc arch. Has anyone made a RT patch work for ppc arch
in 2.6.21? In other words, is 2.6.21 a good candidate to test a
PREEMPT_RT patch for ppc arch? I understand that ppc arch will
eventually replaced by powerpc arch. Is there active work going on in
ppc arch to support the PREEMPT_RT?
Thanks a lot in advance for your help.
-Ryan.
^ permalink raw reply
* Re: [PATCH 1/6] powerpc: Use lwarx hint in spinlocks
From: Anton Blanchard @ 2010-02-17 9:37 UTC (permalink / raw)
To: Nick Piggin; +Cc: linuxppc-dev
In-Reply-To: <20100211065617.GA6735@laptop>
Hi Nick,
> Cool. How does it go when there are significant amount of instructions
> between the lock and the unlock? A real(ish) workload, like dbench on
> ramdisk (which should hit the dcache lock).
Good question, I'll see if we can see a difference on dbench.
Anton
^ permalink raw reply
* Re: [PATCH 6/6] powerpc: Use lwsync for acquire barrier if CPU supports it
From: Anton Blanchard @ 2010-02-17 9:43 UTC (permalink / raw)
To: Nick Piggin; +Cc: linuxppc-dev
In-Reply-To: <20100211070914.GB6735@laptop>
Hi Nick,
> Ah, good to see this one come back. I also tested tbench over localhost
> btw which actually did show some speedup on the G5.
>
> BTW. this was the last thing left:
> http://www.mail-archive.com/linuxppc-dev@lists.ozlabs.org/msg29738.html
>
> Don't know if you took a look at that again, but maybe it's worth
> looking at. Hmm, we do actually seem to be growing number of smp_mb*
> calls in core kernel too.
Interesting idea! I do worry we will get a late night visit from the
architecture police. From memory they want the complete larx, stcwx, bne,
isync sequence to guarantee an acquire barrier.
Anton
^ permalink raw reply
* [PATCH v8 0/4] i2c-mpc: add support for the Freescale MPC512x and other fixes
From: Wolfgang Grandegger @ 2010-02-17 10:19 UTC (permalink / raw)
To: Linux-i2c; +Cc: Devicetree-discuss, Linuxppc-dev
This patch series adds support for the MPC512x from Freescale to the
i2c-mpc driver. At that occasion, issues with __devinit[data] have
been fixed and the doc of the FSL I2C dts bindings updated. It has
been tested on a MPC5121ADS, TQM5200 and TQM8560 board
Changes since v1:
- use macro MPC_I2C_CLOCK_PRESERVE/SAFE for the special clock settings.
- document the special DTS node "fsl,mpc5121-i2c-ctrl".
- update and correct the Kconfig help.
- some other minor fixes as suggested by Wolfram.
Changes since v2:
- use __init[data] instead of __devinit[data] for this driver.
Changes since v3:
- switch back to __devinit[data] as pointed out by Ben.
Changes since v4:
- check MPC_I2C_CLOCK_SAFE instead of "!clock" as suggested by Wolfram.
- update MODULE_DESCRIPTION().
Changes since v5 (suggested by Grant Likely):
- various correctings for labling initialization functions and data
(this is tricky because section mismatches are not always obvious).
- add a separate patch for renaming the setclock into setup functions.
- correct the doc of the I2C bindings, e.g. don't mention the legacy
clock setting and remove obsolte parts.
Changes since v6:
- use __devinitconst for const data as suggested by Stephen Rothwell.
Changes since v7:
- fix non-bisectable patch 1 as pointed out by Grant Likely.
Wolfgang
Wolfgang Grandegger (4):
i2c-mpc: use __devinit[data] for initialization functions and data
i2c-mpc: rename "setclock" initialization functions to "setup"
i2c-mpc: add support for the MPC512x processors from Freescale
powerpc: doc/dts-bindings: update doc of FSL I2C bindings
Documentation/powerpc/dts-bindings/fsl/i2c.txt | 30 +++-
drivers/i2c/busses/Kconfig | 7 +-
drivers/i2c/busses/i2c-mpc.c | 194 +++++++++++++++---------
3 files changed, 146 insertions(+), 85 deletions(-)
^ permalink raw reply
* [PATCH v8 1/4] i2c-mpc: use __devinit[data] for initialization functions and data
From: Wolfgang Grandegger @ 2010-02-17 10:19 UTC (permalink / raw)
To: Linux-i2c; +Cc: Devicetree-discuss, Linuxppc-dev, Wolfgang Grandegger
In-Reply-To: <1266401960-19127-1-git-send-email-wg@grandegger.com>
From: Wolfgang Grandegger <wg@denx.de>
"__devinit[data]" has not yet been used for all initialization functions
and data. To avoid truncating lines, the struct "mpc_i2c_match_data" has
been renamed to "mpc_i2c_data", which is even the better name.
Signed-off-by: Wolfgang Grandegger <wg@denx.de>
Tested-by: Wolfram Sang <w.sang@pengutronix.de>
---
drivers/i2c/busses/i2c-mpc.c | 99 +++++++++++++++++++----------------------
1 files changed, 46 insertions(+), 53 deletions(-)
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index f627001..2f74d9b 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -66,7 +66,7 @@ struct mpc_i2c_divider {
u16 fdr; /* including dfsrr */
};
-struct mpc_i2c_match_data {
+struct mpc_i2c_data {
void (*setclock)(struct device_node *node,
struct mpc_i2c *i2c,
u32 clock, u32 prescaler);
@@ -165,7 +165,7 @@ static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
}
#ifdef CONFIG_PPC_MPC52xx
-static const struct mpc_i2c_divider mpc_i2c_dividers_52xx[] = {
+static const struct mpc_i2c_divider mpc_i2c_dividers_52xx[] __devinitconst = {
{20, 0x20}, {22, 0x21}, {24, 0x22}, {26, 0x23},
{28, 0x24}, {30, 0x01}, {32, 0x25}, {34, 0x02},
{36, 0x26}, {40, 0x27}, {44, 0x04}, {48, 0x28},
@@ -186,7 +186,8 @@ static const struct mpc_i2c_divider mpc_i2c_dividers_52xx[] = {
{10240, 0x9d}, {12288, 0x9e}, {15360, 0x9f}
};
-int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock, int prescaler)
+static int __devinit mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock,
+ int prescaler)
{
const struct mpc_i2c_divider *div = NULL;
unsigned int pvr = mfspr(SPRN_PVR);
@@ -215,9 +216,9 @@ int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock, int prescaler)
return div ? (int)div->fdr : -EINVAL;
}
-static void mpc_i2c_setclock_52xx(struct device_node *node,
- struct mpc_i2c *i2c,
- u32 clock, u32 prescaler)
+static void __devinit mpc_i2c_setclock_52xx(struct device_node *node,
+ struct mpc_i2c *i2c,
+ u32 clock, u32 prescaler)
{
int ret, fdr;
@@ -230,15 +231,15 @@ static void mpc_i2c_setclock_52xx(struct device_node *node,
dev_info(i2c->dev, "clock %d Hz (fdr=%d)\n", clock, fdr);
}
#else /* !CONFIG_PPC_MPC52xx */
-static void mpc_i2c_setclock_52xx(struct device_node *node,
- struct mpc_i2c *i2c,
- u32 clock, u32 prescaler)
+static void __devinit mpc_i2c_setclock_52xx(struct device_node *node,
+ struct mpc_i2c *i2c,
+ u32 clock, u32 prescaler)
{
}
#endif /* CONFIG_PPC_MPC52xx*/
#ifdef CONFIG_FSL_SOC
-static const struct mpc_i2c_divider mpc_i2c_dividers_8xxx[] = {
+static const struct mpc_i2c_divider mpc_i2c_dividers_8xxx[] __devinitconst = {
{160, 0x0120}, {192, 0x0121}, {224, 0x0122}, {256, 0x0123},
{288, 0x0100}, {320, 0x0101}, {352, 0x0601}, {384, 0x0102},
{416, 0x0602}, {448, 0x0126}, {480, 0x0103}, {512, 0x0127},
@@ -258,7 +259,7 @@ static const struct mpc_i2c_divider mpc_i2c_dividers_8xxx[] = {
{49152, 0x011e}, {61440, 0x011f}
};
-u32 mpc_i2c_get_sec_cfg_8xxx(void)
+static u32 __devinit mpc_i2c_get_sec_cfg_8xxx(void)
{
struct device_node *node = NULL;
u32 __iomem *reg;
@@ -287,7 +288,8 @@ u32 mpc_i2c_get_sec_cfg_8xxx(void)
return val;
}
-int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock, u32 prescaler)
+static int __devinit mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock,
+ u32 prescaler)
{
const struct mpc_i2c_divider *div = NULL;
u32 divider;
@@ -320,9 +322,9 @@ int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock, u32 prescaler)
return div ? (int)div->fdr : -EINVAL;
}
-static void mpc_i2c_setclock_8xxx(struct device_node *node,
- struct mpc_i2c *i2c,
- u32 clock, u32 prescaler)
+static void __devinit mpc_i2c_setclock_8xxx(struct device_node *node,
+ struct mpc_i2c *i2c,
+ u32 clock, u32 prescaler)
{
int ret, fdr;
@@ -338,9 +340,9 @@ static void mpc_i2c_setclock_8xxx(struct device_node *node,
}
#else /* !CONFIG_FSL_SOC */
-static void mpc_i2c_setclock_8xxx(struct device_node *node,
- struct mpc_i2c *i2c,
- u32 clock, u32 prescaler)
+static void __devinit mpc_i2c_setclock_8xxx(struct device_node *node,
+ struct mpc_i2c *i2c,
+ u32 clock, u32 prescaler)
{
}
#endif /* CONFIG_FSL_SOC */
@@ -529,8 +531,8 @@ static int __devinit fsl_i2c_probe(struct of_device *op,
clock = *prop;
if (match->data) {
- struct mpc_i2c_match_data *data =
- (struct mpc_i2c_match_data *)match->data;
+ struct mpc_i2c_data *data =
+ (struct mpc_i2c_data *)match->data;
data->setclock(op->node, i2c, clock, data->prescaler);
} else {
/* Backwards compatibility */
@@ -582,44 +584,35 @@ static int __devexit fsl_i2c_remove(struct of_device *op)
return 0;
};
+static struct mpc_i2c_data mpc_i2c_data_52xx __devinitdata = {
+ .setclock = mpc_i2c_setclock_52xx,
+};
+
+static struct mpc_i2c_data mpc_i2c_data_8313 __devinitdata = {
+ .setclock = mpc_i2c_setclock_8xxx,
+};
+
+static struct mpc_i2c_data mpc_i2c_data_8543 __devinitdata = {
+ .setclock = mpc_i2c_setclock_8xxx,
+ .prescaler = 2,
+};
+
+static struct mpc_i2c_data mpc_i2c_data_8544 __devinitdata = {
+ .setclock = mpc_i2c_setclock_8xxx,
+ .prescaler = 3,
+};
+
static const struct of_device_id mpc_i2c_of_match[] = {
- {.compatible = "mpc5200-i2c",
- .data = &(struct mpc_i2c_match_data) {
- .setclock = mpc_i2c_setclock_52xx,
- },
- },
- {.compatible = "fsl,mpc5200b-i2c",
- .data = &(struct mpc_i2c_match_data) {
- .setclock = mpc_i2c_setclock_52xx,
- },
- },
- {.compatible = "fsl,mpc5200-i2c",
- .data = &(struct mpc_i2c_match_data) {
- .setclock = mpc_i2c_setclock_52xx,
- },
- },
- {.compatible = "fsl,mpc8313-i2c",
- .data = &(struct mpc_i2c_match_data) {
- .setclock = mpc_i2c_setclock_8xxx,
- },
- },
- {.compatible = "fsl,mpc8543-i2c",
- .data = &(struct mpc_i2c_match_data) {
- .setclock = mpc_i2c_setclock_8xxx,
- .prescaler = 2,
- },
- },
- {.compatible = "fsl,mpc8544-i2c",
- .data = &(struct mpc_i2c_match_data) {
- .setclock = mpc_i2c_setclock_8xxx,
- .prescaler = 3,
- },
+ {.compatible = "mpc5200-i2c", .data = &mpc_i2c_data_52xx, },
+ {.compatible = "fsl,mpc5200b-i2c", .data = &mpc_i2c_data_52xx, },
+ {.compatible = "fsl,mpc5200-i2c", .data = &mpc_i2c_data_52xx, },
+ {.compatible = "fsl,mpc8313-i2c", .data = &mpc_i2c_data_8313, },
+ {.compatible = "fsl,mpc8543-i2c", .data = &mpc_i2c_data_8543, },
+ {.compatible = "fsl,mpc8544-i2c", .data = &mpc_i2c_data_8544, },
/* Backward compatibility */
- },
{.compatible = "fsl-i2c", },
{},
};
-
MODULE_DEVICE_TABLE(of, mpc_i2c_of_match);
--
1.6.2.5
^ permalink raw reply related
* [PATCH v8 2/4] i2c-mpc: rename "setclock" initialization functions to "setup"
From: Wolfgang Grandegger @ 2010-02-17 10:19 UTC (permalink / raw)
To: Linux-i2c; +Cc: Devicetree-discuss, Linuxppc-dev, Wolfgang Grandegger
In-Reply-To: <1266401960-19127-2-git-send-email-wg@grandegger.com>
From: Wolfgang Grandegger <wg@denx.de>
To prepare support for the MPC512x processors from Freescale the
"setclock" initialization functions have been renamed to "setup"
because I2C interrupts must be enabled for the MPC512x by this
function as well.
Signed-off-by: Wolfgang Grandegger <wg@denx.de>
Acked-by: Wolfram Sang <w.sang@pengutronix.de>
---
drivers/i2c/busses/i2c-mpc.c | 42 ++++++++++++++++++++----------------------
1 files changed, 20 insertions(+), 22 deletions(-)
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 2f74d9b..370c342 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -67,9 +67,8 @@ struct mpc_i2c_divider {
};
struct mpc_i2c_data {
- void (*setclock)(struct device_node *node,
- struct mpc_i2c *i2c,
- u32 clock, u32 prescaler);
+ void (*setup)(struct device_node *node, struct mpc_i2c *i2c,
+ u32 clock, u32 prescaler);
u32 prescaler;
};
@@ -216,9 +215,9 @@ static int __devinit mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock,
return div ? (int)div->fdr : -EINVAL;
}
-static void __devinit mpc_i2c_setclock_52xx(struct device_node *node,
- struct mpc_i2c *i2c,
- u32 clock, u32 prescaler)
+static void __devinit mpc_i2c_setup_52xx(struct device_node *node,
+ struct mpc_i2c *i2c,
+ u32 clock, u32 prescaler)
{
int ret, fdr;
@@ -231,9 +230,9 @@ static void __devinit mpc_i2c_setclock_52xx(struct device_node *node,
dev_info(i2c->dev, "clock %d Hz (fdr=%d)\n", clock, fdr);
}
#else /* !CONFIG_PPC_MPC52xx */
-static void __devinit mpc_i2c_setclock_52xx(struct device_node *node,
- struct mpc_i2c *i2c,
- u32 clock, u32 prescaler)
+static void __devinit mpc_i2c_setup_52xx(struct device_node *node,
+ struct mpc_i2c *i2c,
+ u32 clock, u32 prescaler)
{
}
#endif /* CONFIG_PPC_MPC52xx*/
@@ -322,9 +321,9 @@ static int __devinit mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock,
return div ? (int)div->fdr : -EINVAL;
}
-static void __devinit mpc_i2c_setclock_8xxx(struct device_node *node,
- struct mpc_i2c *i2c,
- u32 clock, u32 prescaler)
+static void __devinit mpc_i2c_setup_8xxx(struct device_node *node,
+ struct mpc_i2c *i2c,
+ u32 clock, u32 prescaler)
{
int ret, fdr;
@@ -340,9 +339,9 @@ static void __devinit mpc_i2c_setclock_8xxx(struct device_node *node,
}
#else /* !CONFIG_FSL_SOC */
-static void __devinit mpc_i2c_setclock_8xxx(struct device_node *node,
- struct mpc_i2c *i2c,
- u32 clock, u32 prescaler)
+static void __devinit mpc_i2c_setup_8xxx(struct device_node *node,
+ struct mpc_i2c *i2c,
+ u32 clock, u32 prescaler)
{
}
#endif /* CONFIG_FSL_SOC */
@@ -533,12 +532,11 @@ static int __devinit fsl_i2c_probe(struct of_device *op,
if (match->data) {
struct mpc_i2c_data *data =
(struct mpc_i2c_data *)match->data;
- data->setclock(op->node, i2c, clock, data->prescaler);
+ data->setup(op->node, i2c, clock, data->prescaler);
} else {
/* Backwards compatibility */
if (of_get_property(op->node, "dfsrr", NULL))
- mpc_i2c_setclock_8xxx(op->node, i2c,
- clock, 0);
+ mpc_i2c_setup_8xxx(op->node, i2c, clock, 0);
}
}
@@ -585,20 +583,20 @@ static int __devexit fsl_i2c_remove(struct of_device *op)
};
static struct mpc_i2c_data mpc_i2c_data_52xx __devinitdata = {
- .setclock = mpc_i2c_setclock_52xx,
+ .setup = mpc_i2c_setup_52xx,
};
static struct mpc_i2c_data mpc_i2c_data_8313 __devinitdata = {
- .setclock = mpc_i2c_setclock_8xxx,
+ .setup = mpc_i2c_setup_8xxx,
};
static struct mpc_i2c_data mpc_i2c_data_8543 __devinitdata = {
- .setclock = mpc_i2c_setclock_8xxx,
+ .setup = mpc_i2c_setup_8xxx,
.prescaler = 2,
};
static struct mpc_i2c_data mpc_i2c_data_8544 __devinitdata = {
- .setclock = mpc_i2c_setclock_8xxx,
+ .setup = mpc_i2c_setup_8xxx,
.prescaler = 3,
};
--
1.6.2.5
^ permalink raw reply related
* [PATCH v8 3/4] i2c-mpc: add support for the MPC512x processors from Freescale
From: Wolfgang Grandegger @ 2010-02-17 10:19 UTC (permalink / raw)
To: Linux-i2c; +Cc: Devicetree-discuss, Linuxppc-dev, Wolfgang Grandegger
In-Reply-To: <1266401960-19127-3-git-send-email-wg@grandegger.com>
From: Wolfgang Grandegger <wg@denx.de>
As I2C interrupts must be enabled for the MPC512x by the setup function
as well, "fsl,preserve-clocking" is handled in a slighly different way.
Also, the old settings are now reported calling dev_dbg(). For the
MPC512x the clock setup function of the MPC52xx can be re-used.
Furthermore, the Kconfig help has been updated and corrected.
Signed-off-by: Wolfgang Grandegger <wg@denx.de>
Reviewed-by: Wolfram Sang <w.sang@pengutronix.de>
---
drivers/i2c/busses/Kconfig | 7 +--
drivers/i2c/busses/i2c-mpc.c | 93 +++++++++++++++++++++++++++++++++--------
2 files changed, 78 insertions(+), 22 deletions(-)
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 5f318ce..5477e41 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -418,13 +418,12 @@ config I2C_IXP2000
instead.
config I2C_MPC
- tristate "MPC107/824x/85xx/52xx/86xx"
+ tristate "MPC107/824x/85xx/512x/52xx/83xx/86xx"
depends on PPC32
help
If you say yes to this option, support will be included for the
- built-in I2C interface on the MPC107/Tsi107/MPC8240/MPC8245 and
- MPC85xx/MPC8641 family processors. The driver may also work on 52xx
- family processors, though interrupts are known not to work.
+ built-in I2C interface on the MPC107, Tsi107, MPC512x, MPC52xx,
+ MPC8240, MPC8245, MPC83xx, MPC85xx and MPC8641 family processors.
This driver can also be built as a module. If so, the module
will be called i2c-mpc.
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 370c342..78a15af 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -31,6 +31,9 @@
#define DRV_NAME "mpc-i2c"
+#define MPC_I2C_CLOCK_LEGACY 0
+#define MPC_I2C_CLOCK_PRESERVE (~0U)
+
#define MPC_I2C_FDR 0x04
#define MPC_I2C_CR 0x08
#define MPC_I2C_SR 0x0c
@@ -163,7 +166,7 @@ static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
return 0;
}
-#ifdef CONFIG_PPC_MPC52xx
+#if defined(CONFIG_PPC_MPC52xx) || defined(CONFIG_PPC_MPC512x)
static const struct mpc_i2c_divider mpc_i2c_dividers_52xx[] __devinitconst = {
{20, 0x20}, {22, 0x21}, {24, 0x22}, {26, 0x23},
{28, 0x24}, {30, 0x01}, {32, 0x25}, {34, 0x02},
@@ -193,7 +196,7 @@ static int __devinit mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock,
u32 divider;
int i;
- if (!clock)
+ if (clock == MPC_I2C_CLOCK_LEGACY)
return -EINVAL;
/* Determine divider value */
@@ -221,6 +224,12 @@ static void __devinit mpc_i2c_setup_52xx(struct device_node *node,
{
int ret, fdr;
+ if (clock == MPC_I2C_CLOCK_PRESERVE) {
+ dev_dbg(i2c->dev, "using fdr %d\n",
+ readb(i2c->base + MPC_I2C_FDR));
+ return;
+ }
+
ret = mpc_i2c_get_fdr_52xx(node, clock, prescaler);
fdr = (ret >= 0) ? ret : 0x3f; /* backward compatibility */
@@ -229,13 +238,49 @@ static void __devinit mpc_i2c_setup_52xx(struct device_node *node,
if (ret >= 0)
dev_info(i2c->dev, "clock %d Hz (fdr=%d)\n", clock, fdr);
}
-#else /* !CONFIG_PPC_MPC52xx */
+#else /* !(CONFIG_PPC_MPC52xx || CONFIG_PPC_MPC512x) */
static void __devinit mpc_i2c_setup_52xx(struct device_node *node,
struct mpc_i2c *i2c,
u32 clock, u32 prescaler)
{
}
-#endif /* CONFIG_PPC_MPC52xx*/
+#endif /* CONFIG_PPC_MPC52xx || CONFIG_PPC_MPC512x */
+
+#ifdef CONFIG_PPC_MPC512x
+static void __devinit mpc_i2c_setup_512x(struct device_node *node,
+ struct mpc_i2c *i2c,
+ u32 clock, u32 prescaler)
+{
+ struct device_node *node_ctrl;
+ void __iomem *ctrl;
+ const u32 *pval;
+ u32 idx;
+
+ /* Enable I2C interrupts for mpc5121 */
+ node_ctrl = of_find_compatible_node(NULL, NULL,
+ "fsl,mpc5121-i2c-ctrl");
+ if (node_ctrl) {
+ ctrl = of_iomap(node_ctrl, 0);
+ if (ctrl) {
+ /* Interrupt enable bits for i2c-0/1/2: bit 24/26/28 */
+ pval = of_get_property(node, "reg", NULL);
+ idx = (*pval & 0xff) / 0x20;
+ setbits32(ctrl, 1 << (24 + idx * 2));
+ iounmap(ctrl);
+ }
+ of_node_put(node_ctrl);
+ }
+
+ /* The clock setup for the 52xx works also fine for the 512x */
+ mpc_i2c_setup_52xx(node, i2c, clock, prescaler);
+}
+#else /* CONFIG_PPC_MPC512x */
+static void __devinit mpc_i2c_setup_512x(struct device_node *node,
+ struct mpc_i2c *i2c,
+ u32 clock, u32 prescaler)
+{
+}
+#endif /* CONFIG_PPC_MPC512x */
#ifdef CONFIG_FSL_SOC
static const struct mpc_i2c_divider mpc_i2c_dividers_8xxx[] __devinitconst = {
@@ -294,7 +339,7 @@ static int __devinit mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock,
u32 divider;
int i;
- if (!clock)
+ if (clock == MPC_I2C_CLOCK_LEGACY)
return -EINVAL;
/* Determine proper divider value */
@@ -327,6 +372,13 @@ static void __devinit mpc_i2c_setup_8xxx(struct device_node *node,
{
int ret, fdr;
+ if (clock == MPC_I2C_CLOCK_PRESERVE) {
+ dev_dbg(i2c->dev, "using dfsrr %d, fdr %d\n",
+ readb(i2c->base + MPC_I2C_DFSRR),
+ readb(i2c->base + MPC_I2C_FDR));
+ return;
+ }
+
ret = mpc_i2c_get_fdr_8xxx(node, clock, prescaler);
fdr = (ret >= 0) ? ret : 0x1031; /* backward compatibility */
@@ -495,7 +547,7 @@ static int __devinit fsl_i2c_probe(struct of_device *op,
{
struct mpc_i2c *i2c;
const u32 *prop;
- u32 clock = 0;
+ u32 clock = MPC_I2C_CLOCK_LEGACY;
int result = 0;
int plen;
@@ -524,20 +576,21 @@ static int __devinit fsl_i2c_probe(struct of_device *op,
}
}
- if (!of_get_property(op->node, "fsl,preserve-clocking", NULL)) {
+ if (of_get_property(op->node, "fsl,preserve-clocking", NULL)) {
+ clock = MPC_I2C_CLOCK_PRESERVE;
+ } else {
prop = of_get_property(op->node, "clock-frequency", &plen);
if (prop && plen == sizeof(u32))
clock = *prop;
+ }
- if (match->data) {
- struct mpc_i2c_data *data =
- (struct mpc_i2c_data *)match->data;
- data->setup(op->node, i2c, clock, data->prescaler);
- } else {
- /* Backwards compatibility */
- if (of_get_property(op->node, "dfsrr", NULL))
- mpc_i2c_setup_8xxx(op->node, i2c, clock, 0);
- }
+ if (match->data) {
+ struct mpc_i2c_data *data = match->data;
+ data->setup(op->node, i2c, clock, data->prescaler);
+ } else {
+ /* Backwards compatibility */
+ if (of_get_property(op->node, "dfsrr", NULL))
+ mpc_i2c_setup_8xxx(op->node, i2c, clock, 0);
}
dev_set_drvdata(&op->dev, i2c);
@@ -582,6 +635,10 @@ static int __devexit fsl_i2c_remove(struct of_device *op)
return 0;
};
+static struct mpc_i2c_data mpc_i2c_data_512x __devinitdata = {
+ .setup = mpc_i2c_setup_512x,
+};
+
static struct mpc_i2c_data mpc_i2c_data_52xx __devinitdata = {
.setup = mpc_i2c_setup_52xx,
};
@@ -604,6 +661,7 @@ static const struct of_device_id mpc_i2c_of_match[] = {
{.compatible = "mpc5200-i2c", .data = &mpc_i2c_data_52xx, },
{.compatible = "fsl,mpc5200b-i2c", .data = &mpc_i2c_data_52xx, },
{.compatible = "fsl,mpc5200-i2c", .data = &mpc_i2c_data_52xx, },
+ {.compatible = "fsl,mpc5121-i2c", .data = &mpc_i2c_data_512x, },
{.compatible = "fsl,mpc8313-i2c", .data = &mpc_i2c_data_8313, },
{.compatible = "fsl,mpc8543-i2c", .data = &mpc_i2c_data_8543, },
{.compatible = "fsl,mpc8544-i2c", .data = &mpc_i2c_data_8544, },
@@ -613,7 +671,6 @@ static const struct of_device_id mpc_i2c_of_match[] = {
};
MODULE_DEVICE_TABLE(of, mpc_i2c_of_match);
-
/* Structure for a device driver */
static struct of_platform_driver mpc_i2c_driver = {
.match_table = mpc_i2c_of_match,
@@ -646,5 +703,5 @@ module_exit(fsl_i2c_exit);
MODULE_AUTHOR("Adrian Cox <adrian@humboldt.co.uk>");
MODULE_DESCRIPTION("I2C-Bus adapter for MPC107 bridge and "
- "MPC824x/85xx/52xx processors");
+ "MPC824x/83xx/85xx/86xx/512x/52xx processors");
MODULE_LICENSE("GPL");
--
1.6.2.5
^ permalink raw reply related
* [PATCH v8 4/4] powerpc: doc/dts-bindings: update doc of FSL I2C bindings
From: Wolfgang Grandegger @ 2010-02-17 10:19 UTC (permalink / raw)
To: Linux-i2c; +Cc: Devicetree-discuss, Linuxppc-dev, Wolfgang Grandegger
In-Reply-To: <1266401960-19127-4-git-send-email-wg@grandegger.com>
From: Wolfgang Grandegger <wg@denx.de>
This patch adds the MPC5121 to the list of supported devices,
enhances the doc of the "clock-frequency" property and removes
the obsolete "cell-index", "device_type" and "fsl-i2c" property.
Furthermore an example for the MPC5121 has been added.
Signed-off-by: Wolfgang Grandegger <wg@denx.de>
Reviewed-by: Wolfram Sang <w.sang@pengutronix.de>
---
Documentation/powerpc/dts-bindings/fsl/i2c.txt | 30 +++++++++++++++++------
1 files changed, 22 insertions(+), 8 deletions(-)
diff --git a/Documentation/powerpc/dts-bindings/fsl/i2c.txt b/Documentation/powerpc/dts-bindings/fsl/i2c.txt
index b6d2e21..50da203 100644
--- a/Documentation/powerpc/dts-bindings/fsl/i2c.txt
+++ b/Documentation/powerpc/dts-bindings/fsl/i2c.txt
@@ -2,15 +2,14 @@
Required properties :
- - device_type : Should be "i2c"
- reg : Offset and length of the register set for the device
+ - compatible : should be "fsl,CHIP-i2c" where CHIP is the name of a
+ compatible processor, e.g. mpc8313, mpc8543, mpc8544, mpc5121,
+ mpc5200 or mpc5200b. For the mpc5121, an additional node
+ "fsl,mpc5121-i2c-ctrl" is required as shown in the example below.
Recommended properties :
- - compatible : compatibility list with 2 entries, the first should
- be "fsl,CHIP-i2c" where CHIP is the name of a compatible processor,
- e.g. mpc8313, mpc8543, mpc8544, mpc5200 or mpc5200b. The second one
- should be "fsl-i2c".
- 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
@@ -24,25 +23,40 @@ Recommended properties :
Examples :
+ /* MPC5121 based board */
+ i2c@1740 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,mpc5121-i2c", "fsl-i2c";
+ reg = <0x1740 0x20>;
+ interrupts = <11 0x8>;
+ interrupt-parent = <&ipic>;
+ clock-frequency = <100000>;
+ };
+
+ i2ccontrol@1760 {
+ compatible = "fsl,mpc5121-i2c-ctrl";
+ reg = <0x1760 0x8>;
+ };
+
+ /* MPC5200B based board */
i2c@3d00 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
- cell-index = <0>;
reg = <0x3d00 0x40>;
interrupts = <2 15 0>;
interrupt-parent = <&mpc5200_pic>;
fsl,preserve-clocking;
};
+ /* MPC8544 base board */
i2c@3100 {
#address-cells = <1>;
#size-cells = <0>;
- cell-index = <1>;
compatible = "fsl,mpc8544-i2c", "fsl-i2c";
reg = <0x3100 0x100>;
interrupts = <43 2>;
interrupt-parent = <&mpic>;
clock-frequency = <400000>;
};
-
--
1.6.2.5
^ permalink raw reply related
* Re: [PATCH 1/6] powerpc: Use lwarx hint in spinlocks
From: Nick Piggin @ 2010-02-17 10:22 UTC (permalink / raw)
To: Anton Blanchard; +Cc: linuxppc-dev
In-Reply-To: <20100217093714.GB24270@kryten>
On Wed, Feb 17, 2010 at 08:37:14PM +1100, Anton Blanchard wrote:
>
> Hi Nick,
>
> > Cool. How does it go when there are significant amount of instructions
> > between the lock and the unlock? A real(ish) workload, like dbench on
> > ramdisk (which should hit the dcache lock).
>
> Good question, I'll see if we can see a difference on dbench.
Well I misread your benchmark. Your test is using pthread mutexes in
order to basically exercise kernel's syscall and context switching and
futex code. Wheras I thought it was just a trivial lock/unlock
sequence being tested.
So I'm much more impressed with your numbers :) dbench would still
be interesting though.
^ permalink raw reply
* Re: [PATCH 6/6] powerpc: Use lwsync for acquire barrier if CPU supports it
From: Nick Piggin @ 2010-02-17 10:41 UTC (permalink / raw)
To: Anton Blanchard; +Cc: linuxppc-dev
In-Reply-To: <20100217094314.GC24270@kryten>
On Wed, Feb 17, 2010 at 08:43:14PM +1100, Anton Blanchard wrote:
>
> Hi Nick,
>
> > Ah, good to see this one come back. I also tested tbench over localhost
> > btw which actually did show some speedup on the G5.
> >
> > BTW. this was the last thing left:
> > http://www.mail-archive.com/linuxppc-dev@lists.ozlabs.org/msg29738.html
> >
> > Don't know if you took a look at that again, but maybe it's worth
> > looking at. Hmm, we do actually seem to be growing number of smp_mb*
> > calls in core kernel too.
>
> Interesting idea! I do worry we will get a late night visit from the
> architecture police. From memory they want the complete larx, stcwx, bne,
> isync sequence to guarantee an acquire barrier.
Yes I suppose the branch can be executed "non speculatively" before the
lwsync is completed. Wheras the larx/stcwx will have to complete before
the branch outcome can be known. I suppose probably not worthwhile
avoiding the full IO sync by adding yet more crap to make this work.
Thanks for putting my mind to rest though :)
I'd still be interested to know how expensive the full sync is when you
have a lot of IOs in flight.
Question, are you going to do the hint and isync->lwsync thing for
userspace as well? Too bad the kernel doesn't export synchronisation
primitives to userspace...
^ permalink raw reply
* Re: [PATCH 6/6] powerpc: Use lwsync for acquire barrier if CPU supports it
From: Benjamin Herrenschmidt @ 2010-02-17 12:12 UTC (permalink / raw)
To: Nick Piggin; +Cc: linuxppc-dev, Anton Blanchard
In-Reply-To: <20100217104153.GA7952@laptop>
> Yes I suppose the branch can be executed "non speculatively" before the
> lwsync is completed. Wheras the larx/stcwx will have to complete before
> the branch outcome can be known. I suppose probably not worthwhile
> avoiding the full IO sync by adding yet more crap to make this work.
>
> Thanks for putting my mind to rest though :)
>
> I'd still be interested to know how expensive the full sync is when you
> have a lot of IOs in flight.
>
> Question, are you going to do the hint and isync->lwsync thing for
> userspace as well? Too bad the kernel doesn't export synchronisation
> primitives to userspace...
We'd love to.... the vdso inherits from all the dynamic patching
features of the kernel and more...
It's really a matter of getting glibc to grok it, and doing so
efficiently (ie, not just having a function point in glibc, might be a
good use of the IFUNC stuff).
Cheers,
Ben.
^ permalink raw reply
* Starting bare metal application on second core of P2020
From: Felix Radensky @ 2010-02-17 12:54 UTC (permalink / raw)
To: linuxppc-dev
Hi,
We'd like to run Linux on core0 of P2020 and some bare metal application
running without OS
on core1. Is it possible to start this application from Linux ? I've
seen example of running 2 copies
of Linux in AMP mode, in which case both are started from u-boot. I'd
like to leave core1 in
reset, start Linux on core0 from u-boot and load bare metal application
from Linux. If this
possible, where can I learn about the procedure ?
Thanks.
Felix.
^ permalink raw reply
* [net-next-2.6 PATCH v2 0/3] Support for MPC512x FEC
From: Anatolij Gustschin @ 2010-02-17 14:55 UTC (permalink / raw)
To: netdev
Cc: Wolfgang Denk, Detlev Zundel, linuxppc-dev, Anatolij Gustschin,
David S. Miller
These patches attempt to provide support for the Freescale MPC512x
FEC in the fs_enet driver. The first cleanup patch replaces printk
by dev_xxx. The second and third attemt to support MPC5121 FEC
in the FEC driver.
Changes since previous version:
- don't attempt to provide runtime selection of
MPC5121 FEC support in the driver since it doesn't
make sence. Select MPC5121 FEC support at compile time.
- fix tx buffer alignment workaround patch to align
only misaligned buffers.
The patches are based on net-next-2.6 and has been
tested on the:
- Freescale/STX "MPC5121ADS" board (board rev. 4) with
a MPC5121e Rev. 2.
- TQM860L and TQM855 boards.
Anatolij Gustschin (3):
fs_enet: use dev_xxx instead of printk
fs_enet: Add support for MPC512x to fs_enet driver
fs_enet: add FEC TX buffer alignment workaround for MPC5121
drivers/net/fs_enet/Kconfig | 10 +++-
drivers/net/fs_enet/fs_enet-main.c | 90 ++++++++++++++++++++++++++----------
drivers/net/fs_enet/fs_enet.h | 49 +++++++++++++++++++-
drivers/net/fs_enet/mac-fcc.c | 5 +-
drivers/net/fs_enet/mac-fec.c | 58 ++++++++++++++---------
drivers/net/fs_enet/mac-scc.c | 9 ++--
drivers/net/fs_enet/mii-fec.c | 4 +-
7 files changed, 166 insertions(+), 59 deletions(-)
^ permalink raw reply
* [net-next-2.6 PATCH v2 1/3] fs_enet: use dev_xxx instead of printk
From: Anatolij Gustschin @ 2010-02-17 14:55 UTC (permalink / raw)
To: netdev
Cc: Wolfgang Denk, Detlev Zundel, linuxppc-dev, Anatolij Gustschin,
David S. Miller
In-Reply-To: <1266418530-2727-1-git-send-email-agust@denx.de>
Signed-off-by: Anatolij Gustschin <agust@denx.de>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
---
drivers/net/fs_enet/fs_enet-main.c | 39 +++++++++++++----------------------
drivers/net/fs_enet/mac-fcc.c | 5 ++-
drivers/net/fs_enet/mac-fec.c | 12 ++++------
drivers/net/fs_enet/mac-scc.c | 9 +++----
4 files changed, 27 insertions(+), 38 deletions(-)
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index ec2f503..c34a7e0 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -108,9 +108,7 @@ static int fs_enet_rx_napi(struct napi_struct *napi, int budget)
* the last indicator should be set.
*/
if ((sc & BD_ENET_RX_LAST) == 0)
- printk(KERN_WARNING DRV_MODULE_NAME
- ": %s rcv is not +last\n",
- dev->name);
+ dev_warn(fep->dev, "rcv is not +last\n");
/*
* Check for errors.
@@ -178,9 +176,8 @@ static int fs_enet_rx_napi(struct napi_struct *napi, int budget)
received++;
netif_receive_skb(skb);
} else {
- printk(KERN_WARNING DRV_MODULE_NAME
- ": %s Memory squeeze, dropping packet.\n",
- dev->name);
+ dev_warn(fep->dev,
+ "Memory squeeze, dropping packet.\n");
fep->stats.rx_dropped++;
skbn = skb;
}
@@ -242,9 +239,7 @@ static int fs_enet_rx_non_napi(struct net_device *dev)
* the last indicator should be set.
*/
if ((sc & BD_ENET_RX_LAST) == 0)
- printk(KERN_WARNING DRV_MODULE_NAME
- ": %s rcv is not +last\n",
- dev->name);
+ dev_warn(fep->dev, "rcv is not +last\n");
/*
* Check for errors.
@@ -313,9 +308,8 @@ static int fs_enet_rx_non_napi(struct net_device *dev)
received++;
netif_rx(skb);
} else {
- printk(KERN_WARNING DRV_MODULE_NAME
- ": %s Memory squeeze, dropping packet.\n",
- dev->name);
+ dev_warn(fep->dev,
+ "Memory squeeze, dropping packet.\n");
fep->stats.rx_dropped++;
skbn = skb;
}
@@ -388,10 +382,10 @@ static void fs_enet_tx(struct net_device *dev)
} else
fep->stats.tx_packets++;
- if (sc & BD_ENET_TX_READY)
- printk(KERN_WARNING DRV_MODULE_NAME
- ": %s HEY! Enet xmit interrupt and TX_READY.\n",
- dev->name);
+ if (sc & BD_ENET_TX_READY) {
+ dev_warn(fep->dev,
+ "HEY! Enet xmit interrupt and TX_READY.\n");
+ }
/*
* Deferred means some collisions occurred during transmit,
@@ -511,9 +505,8 @@ void fs_init_bds(struct net_device *dev)
for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) {
skb = dev_alloc_skb(ENET_RX_FRSIZE);
if (skb == NULL) {
- printk(KERN_WARNING DRV_MODULE_NAME
- ": %s Memory squeeze, unable to allocate skb\n",
- dev->name);
+ dev_warn(fep->dev,
+ "Memory squeeze, unable to allocate skb\n");
break;
}
skb_align(skb, ENET_RX_ALIGN);
@@ -610,8 +603,7 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
* Ooops. All transmit buffers are full. Bail out.
* This should not happen, since the tx queue should be stopped.
*/
- printk(KERN_WARNING DRV_MODULE_NAME
- ": %s tx queue full!.\n", dev->name);
+ dev_warn(fep->dev, "tx queue full!.\n");
return NETDEV_TX_BUSY;
}
@@ -788,8 +780,7 @@ static int fs_enet_open(struct net_device *dev)
r = request_irq(fep->interrupt, fs_enet_interrupt, IRQF_SHARED,
"fs_enet-mac", dev);
if (r != 0) {
- printk(KERN_ERR DRV_MODULE_NAME
- ": %s Could not allocate FS_ENET IRQ!", dev->name);
+ dev_err(fep->dev, "Could not allocate FS_ENET IRQ!");
if (fep->fpi->use_napi)
napi_disable(&fep->napi);
return -EINVAL;
@@ -1053,7 +1044,7 @@ static int __devinit fs_enet_probe(struct of_device *ofdev,
if (ret)
goto out_free_bd;
- printk(KERN_INFO "%s: fs_enet: %pM\n", ndev->name, ndev->dev_addr);
+ pr_info("%s: fs_enet: %pM\n", ndev->name, ndev->dev_addr);
return 0;
diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c
index 482f27d..504add3 100644
--- a/drivers/net/fs_enet/mac-fcc.c
+++ b/drivers/net/fs_enet/mac-fcc.c
@@ -476,8 +476,9 @@ static void clear_int_events(struct net_device *dev, u32 int_events)
static void ev_error(struct net_device *dev, u32 int_events)
{
- printk(KERN_WARNING DRV_MODULE_NAME
- ": %s FS_ENET ERROR(s) 0x%x\n", dev->name, int_events);
+ struct fs_enet_private *fep = netdev_priv(dev);
+
+ dev_warn(fep->dev, "FS_ENET ERROR(s) 0x%x\n", int_events);
}
static int get_regs(struct net_device *dev, void *p, int *sizep)
diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c
index ddf13ef..7047813 100644
--- a/drivers/net/fs_enet/mac-fec.c
+++ b/drivers/net/fs_enet/mac-fec.c
@@ -257,8 +257,7 @@ static void restart(struct net_device *dev)
r = whack_reset(fep->fec.fecp);
if (r != 0)
- printk(KERN_ERR DRV_MODULE_NAME
- ": %s FEC Reset FAILED!\n", dev->name);
+ dev_err(fep->dev, "FEC Reset FAILED!\n");
/*
* Set station address.
*/
@@ -355,9 +354,7 @@ static void stop(struct net_device *dev)
udelay(1);
if (i == FEC_RESET_DELAY)
- printk(KERN_WARNING DRV_MODULE_NAME
- ": %s FEC timeout on graceful transmit stop\n",
- dev->name);
+ dev_warn(fep->dev, "FEC timeout on graceful transmit stop\n");
/*
* Disable FEC. Let only MII interrupts.
*/
@@ -433,8 +430,9 @@ static void clear_int_events(struct net_device *dev, u32 int_events)
static void ev_error(struct net_device *dev, u32 int_events)
{
- printk(KERN_WARNING DRV_MODULE_NAME
- ": %s FEC ERROR(s) 0x%x\n", dev->name, int_events);
+ struct fs_enet_private *fep = netdev_priv(dev);
+
+ dev_warn(fep->dev, "FEC ERROR(s) 0x%x\n", int_events);
}
static int get_regs(struct net_device *dev, void *p, int *sizep)
diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c
index 141dbc9..ff467e4 100644
--- a/drivers/net/fs_enet/mac-scc.c
+++ b/drivers/net/fs_enet/mac-scc.c
@@ -367,9 +367,7 @@ static void stop(struct net_device *dev)
udelay(1);
if (i == SCC_RESET_DELAY)
- printk(KERN_WARNING DRV_MODULE_NAME
- ": %s SCC timeout on graceful transmit stop\n",
- dev->name);
+ dev_warn(fep->dev, "SCC timeout on graceful transmit stop\n");
W16(sccp, scc_sccm, 0);
C32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
@@ -429,8 +427,9 @@ static void clear_int_events(struct net_device *dev, u32 int_events)
static void ev_error(struct net_device *dev, u32 int_events)
{
- printk(KERN_WARNING DRV_MODULE_NAME
- ": %s SCC ERROR(s) 0x%x\n", dev->name, int_events);
+ struct fs_enet_private *fep = netdev_priv(dev);
+
+ dev_warn(fep->dev, "SCC ERROR(s) 0x%x\n", int_events);
}
static int get_regs(struct net_device *dev, void *p, int *sizep)
--
1.6.3.3
^ permalink raw reply related
* [net-next-2.6 PATCH v2 2/3] fs_enet: Add support for MPC512x to fs_enet driver
From: Anatolij Gustschin @ 2010-02-17 14:55 UTC (permalink / raw)
To: netdev
Cc: Wolfgang Denk, Detlev Zundel, linuxppc-dev, Anatolij Gustschin,
David S. Miller, Piotr Ziecik
In-Reply-To: <1266418530-2727-2-git-send-email-agust@denx.de>
Extend the fs_enet driver to support MPC512x FEC.
Enable it with CONFIG_FS_ENET_MPC5121_FEC option.
Signed-off-by: John Rigby <jcrigby@gmail.com>
Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
Signed-off-by: Wolfgang Denk <wd@denx.de>
Signed-off-by: Anatolij Gustschin <agust@denx.de>
---
drivers/net/fs_enet/Kconfig | 10 +++++--
drivers/net/fs_enet/fs_enet-main.c | 7 +++++
drivers/net/fs_enet/fs_enet.h | 49 +++++++++++++++++++++++++++++++++++-
drivers/net/fs_enet/mac-fec.c | 46 ++++++++++++++++++++++-----------
drivers/net/fs_enet/mii-fec.c | 4 +-
5 files changed, 95 insertions(+), 21 deletions(-)
diff --git a/drivers/net/fs_enet/Kconfig b/drivers/net/fs_enet/Kconfig
index 562ea68..fc073b5 100644
--- a/drivers/net/fs_enet/Kconfig
+++ b/drivers/net/fs_enet/Kconfig
@@ -1,9 +1,13 @@
config FS_ENET
tristate "Freescale Ethernet Driver"
- depends on CPM1 || CPM2
+ depends on CPM1 || CPM2 || PPC_MPC512x
select MII
select PHYLIB
+config FS_ENET_MPC5121_FEC
+ def_bool y if (FS_ENET && PPC_MPC512x)
+ select FS_ENET_HAS_FEC
+
config FS_ENET_HAS_SCC
bool "Chip has an SCC usable for ethernet"
depends on FS_ENET && (CPM1 || CPM2)
@@ -16,13 +20,13 @@ config FS_ENET_HAS_FCC
config FS_ENET_HAS_FEC
bool "Chip has an FEC usable for ethernet"
- depends on FS_ENET && CPM1
+ depends on FS_ENET && (CPM1 || FS_ENET_MPC5121_FEC)
select FS_ENET_MDIO_FEC
default y
config FS_ENET_MDIO_FEC
tristate "MDIO driver for FEC"
- depends on FS_ENET && CPM1
+ depends on FS_ENET && (CPM1 || FS_ENET_MPC5121_FEC)
config FS_ENET_MDIO_FCC
tristate "MDIO driver for FCC"
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index c34a7e0..4297021 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -1094,11 +1094,18 @@ static struct of_device_id fs_enet_match[] = {
},
#endif
#ifdef CONFIG_FS_ENET_HAS_FEC
+#ifdef CONFIG_FS_ENET_MPC5121_FEC
+ {
+ .compatible = "fsl,mpc5121-fec",
+ .data = (void *)&fs_fec_ops,
+ },
+#else
{
.compatible = "fsl,pq1-fec-enet",
.data = (void *)&fs_fec_ops,
},
#endif
+#endif
{}
};
MODULE_DEVICE_TABLE(of, fs_enet_match);
diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h
index ef01e09..1ece4b1 100644
--- a/drivers/net/fs_enet/fs_enet.h
+++ b/drivers/net/fs_enet/fs_enet.h
@@ -13,9 +13,56 @@
#ifdef CONFIG_CPM1
#include <asm/cpm1.h>
+#endif
+
+#if defined(CONFIG_FS_ENET_HAS_FEC)
+#include <asm/cpm.h>
+
+#if defined(CONFIG_FS_ENET_MPC5121_FEC)
+/* MPC5121 FEC has different register layout */
+struct fec {
+ u32 fec_reserved0;
+ u32 fec_ievent; /* Interrupt event reg */
+ u32 fec_imask; /* Interrupt mask reg */
+ u32 fec_reserved1;
+ u32 fec_r_des_active; /* Receive descriptor reg */
+ u32 fec_x_des_active; /* Transmit descriptor reg */
+ u32 fec_reserved2[3];
+ u32 fec_ecntrl; /* Ethernet control reg */
+ u32 fec_reserved3[6];
+ u32 fec_mii_data; /* MII manage frame reg */
+ u32 fec_mii_speed; /* MII speed control reg */
+ u32 fec_reserved4[7];
+ u32 fec_mib_ctrlstat; /* MIB control/status reg */
+ u32 fec_reserved5[7];
+ u32 fec_r_cntrl; /* Receive control reg */
+ u32 fec_reserved6[15];
+ u32 fec_x_cntrl; /* Transmit Control reg */
+ u32 fec_reserved7[7];
+ u32 fec_addr_low; /* Low 32bits MAC address */
+ u32 fec_addr_high; /* High 16bits MAC address */
+ u32 fec_opd; /* Opcode + Pause duration */
+ u32 fec_reserved8[10];
+ u32 fec_hash_table_high; /* High 32bits hash table */
+ u32 fec_hash_table_low; /* Low 32bits hash table */
+ u32 fec_grp_hash_table_high; /* High 32bits hash table */
+ u32 fec_grp_hash_table_low; /* Low 32bits hash table */
+ u32 fec_reserved9[7];
+ u32 fec_x_wmrk; /* FIFO transmit water mark */
+ u32 fec_reserved10;
+ u32 fec_r_bound; /* FIFO receive bound reg */
+ u32 fec_r_fstart; /* FIFO receive start reg */
+ u32 fec_reserved11[11];
+ u32 fec_r_des_start; /* Receive descriptor ring */
+ u32 fec_x_des_start; /* Transmit descriptor ring */
+ u32 fec_r_buff_size; /* Maximum receive buff size */
+ u32 fec_reserved12[26];
+ u32 fec_dma_control; /* DMA Endian and other ctrl */
+};
+#endif
struct fec_info {
- fec_t __iomem *fecp;
+ struct fec __iomem *fecp;
u32 mii_speed;
};
#endif
diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c
index 7047813..c9657da 100644
--- a/drivers/net/fs_enet/mac-fec.c
+++ b/drivers/net/fs_enet/mac-fec.c
@@ -80,7 +80,7 @@
*/
#define FEC_RESET_DELAY 50
-static int whack_reset(fec_t __iomem *fecp)
+static int whack_reset(struct fec __iomem *fecp)
{
int i;
@@ -168,7 +168,7 @@ static void cleanup_data(struct net_device *dev)
static void set_promiscuous_mode(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t __iomem *fecp = fep->fec.fecp;
+ struct fec __iomem *fecp = fep->fec.fecp;
FS(fecp, r_cntrl, FEC_RCNTRL_PROM);
}
@@ -216,7 +216,7 @@ static void set_multicast_one(struct net_device *dev, const u8 *mac)
static void set_multicast_finish(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t __iomem *fecp = fep->fec.fecp;
+ struct fec __iomem *fecp = fep->fec.fecp;
/* if all multi or too many multicasts; just enable all */
if ((dev->flags & IFF_ALLMULTI) != 0 ||
@@ -246,7 +246,7 @@ static void set_multicast_list(struct net_device *dev)
static void restart(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t __iomem *fecp = fep->fec.fecp;
+ struct fec __iomem *fecp = fep->fec.fecp;
const struct fs_platform_info *fpi = fep->fpi;
dma_addr_t rx_bd_base_phys, tx_bd_base_phys;
int r;
@@ -280,7 +280,11 @@ static void restart(struct net_device *dev)
* Set maximum receive buffer size.
*/
FW(fecp, r_buff_size, PKT_MAXBLR_SIZE);
+#ifdef CONFIG_FS_ENET_MPC5121_FEC
+ FW(fecp, r_cntrl, PKT_MAXBUF_SIZE << 16);
+#else
FW(fecp, r_hash, PKT_MAXBUF_SIZE);
+#endif
/* get physical address */
rx_bd_base_phys = fep->ring_mem_addr;
@@ -297,7 +301,11 @@ static void restart(struct net_device *dev)
/*
* Enable big endian and don't care about SDMA FC.
*/
+#ifdef CONFIG_FS_ENET_MPC5121_FEC
+ FS(fecp, dma_control, 0xC0000000);
+#else
FW(fecp, fun_code, 0x78000000);
+#endif
/*
* Set MII speed.
@@ -308,9 +316,17 @@ static void restart(struct net_device *dev)
* Clear any outstanding interrupt.
*/
FW(fecp, ievent, 0xffc0);
+#ifndef CONFIG_FS_ENET_MPC5121_FEC
FW(fecp, ivec, (virq_to_hw(fep->interrupt) / 2) << 29);
FW(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */
+#else
+ /*
+ * Only set MII mode - do not touch maximum frame length
+ * configured before.
+ */
+ FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE);
+#endif
/*
* adjust to duplex mode
*/
@@ -339,7 +355,7 @@ static void stop(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
const struct fs_platform_info *fpi = fep->fpi;
- fec_t __iomem *fecp = fep->fec.fecp;
+ struct fec __iomem *fecp = fep->fec.fecp;
struct fec_info* feci= fep->phydev->bus->priv;
@@ -375,7 +391,7 @@ static void stop(struct net_device *dev)
static void napi_clear_rx_event(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t __iomem *fecp = fep->fec.fecp;
+ struct fec __iomem *fecp = fep->fec.fecp;
FW(fecp, ievent, FEC_NAPI_RX_EVENT_MSK);
}
@@ -383,7 +399,7 @@ static void napi_clear_rx_event(struct net_device *dev)
static void napi_enable_rx(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t __iomem *fecp = fep->fec.fecp;
+ struct fec __iomem *fecp = fep->fec.fecp;
FS(fecp, imask, FEC_NAPI_RX_EVENT_MSK);
}
@@ -391,7 +407,7 @@ static void napi_enable_rx(struct net_device *dev)
static void napi_disable_rx(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t __iomem *fecp = fep->fec.fecp;
+ struct fec __iomem *fecp = fep->fec.fecp;
FC(fecp, imask, FEC_NAPI_RX_EVENT_MSK);
}
@@ -399,7 +415,7 @@ static void napi_disable_rx(struct net_device *dev)
static void rx_bd_done(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t __iomem *fecp = fep->fec.fecp;
+ struct fec __iomem *fecp = fep->fec.fecp;
FW(fecp, r_des_active, 0x01000000);
}
@@ -407,7 +423,7 @@ static void rx_bd_done(struct net_device *dev)
static void tx_kickstart(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t __iomem *fecp = fep->fec.fecp;
+ struct fec __iomem *fecp = fep->fec.fecp;
FW(fecp, x_des_active, 0x01000000);
}
@@ -415,7 +431,7 @@ static void tx_kickstart(struct net_device *dev)
static u32 get_int_events(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t __iomem *fecp = fep->fec.fecp;
+ struct fec __iomem *fecp = fep->fec.fecp;
return FR(fecp, ievent) & FR(fecp, imask);
}
@@ -423,7 +439,7 @@ static u32 get_int_events(struct net_device *dev)
static void clear_int_events(struct net_device *dev, u32 int_events)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t __iomem *fecp = fep->fec.fecp;
+ struct fec __iomem *fecp = fep->fec.fecp;
FW(fecp, ievent, int_events);
}
@@ -439,17 +455,17 @@ static int get_regs(struct net_device *dev, void *p, int *sizep)
{
struct fs_enet_private *fep = netdev_priv(dev);
- if (*sizep < sizeof(fec_t))
+ if (*sizep < sizeof(struct fec))
return -EINVAL;
- memcpy_fromio(p, fep->fec.fecp, sizeof(fec_t));
+ memcpy_fromio(p, fep->fec.fecp, sizeof(struct fec));
return 0;
}
static int get_regs_len(struct net_device *dev)
{
- return sizeof(fec_t);
+ return sizeof(struct fec);
}
static void tx_restart(struct net_device *dev)
diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c
index 96eba42..5944b65 100644
--- a/drivers/net/fs_enet/mii-fec.c
+++ b/drivers/net/fs_enet/mii-fec.c
@@ -52,7 +52,7 @@
static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location)
{
struct fec_info* fec = bus->priv;
- fec_t __iomem *fecp = fec->fecp;
+ struct fec __iomem *fecp = fec->fecp;
int i, ret = -1;
BUG_ON((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0);
@@ -75,7 +75,7 @@ static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location)
static int fs_enet_fec_mii_write(struct mii_bus *bus, int phy_id, int location, u16 val)
{
struct fec_info* fec = bus->priv;
- fec_t __iomem *fecp = fec->fecp;
+ struct fec __iomem *fecp = fec->fecp;
int i;
/* this must never happen */
--
1.6.3.3
^ permalink raw reply related
* [net-next-2.6 PATCH v2 3/3] fs_enet: add FEC TX buffer alignment workaround for MPC5121
From: Anatolij Gustschin @ 2010-02-17 14:55 UTC (permalink / raw)
To: netdev
Cc: Wolfgang Denk, Detlev Zundel, linuxppc-dev, Anatolij Gustschin,
David S. Miller, Piotr Ziecik
In-Reply-To: <1266418530-2727-3-git-send-email-agust@denx.de>
MPC5121 FEC requeries 4-byte alignmnent for TX data buffers.
This patch is a work around that copies misaligned tx packets
to an aligned skb before sending.
Signed-off-by: John Rigby <jcrigby@gmail.com>
Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
Signed-off-by: Wolfgang Denk <wd@denx.de>
Signed-off-by: Anatolij Gustschin <agust@denx.de>
---
drivers/net/fs_enet/fs_enet-main.c | 44 ++++++++++++++++++++++++++++++++++++
1 files changed, 44 insertions(+), 0 deletions(-)
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index 4297021..166a89d 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -580,6 +580,37 @@ void fs_cleanup_bds(struct net_device *dev)
/**********************************************************************************/
+#ifdef CONFIG_FS_ENET_MPC5121_FEC
+/*
+ * MPC5121 FEC requeries 4-byte alignment for TX data buffer!
+ */
+static struct sk_buff *tx_skb_align_workaround(struct net_device *dev,
+ struct sk_buff *skb)
+{
+ struct sk_buff *new_skb;
+ struct fs_enet_private *fep = netdev_priv(dev);
+
+ /* Alloc new skb */
+ new_skb = dev_alloc_skb(ENET_RX_FRSIZE + 4);
+ if (!new_skb) {
+ dev_warn(fep->dev, "Memory squeeze, dropping tx packet.\n");
+ return NULL;
+ }
+
+ /* Make sure new skb is properly aligned */
+ skb_align(new_skb, 4);
+
+ /* Copy data to new skb ... */
+ skb_copy_from_linear_data(skb, new_skb->data, skb->len);
+ skb_put(new_skb, skb->len);
+
+ /* ... and free an old one */
+ dev_kfree_skb_any(skb);
+
+ return new_skb;
+}
+#endif
+
static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
@@ -588,6 +619,19 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
u16 sc;
unsigned long flags;
+#ifdef CONFIG_FS_ENET_MPC5121_FEC
+ if (((unsigned long)skb->data) & 0x3) {
+ skb = tx_skb_align_workaround(dev, skb);
+ if (!skb) {
+ /*
+ * We have lost packet due to memory allocation error
+ * in tx_skb_align_workaround(). Hopefully original
+ * skb is still valid, so try transmit it later.
+ */
+ return NETDEV_TX_BUSY;
+ }
+ }
+#endif
spin_lock_irqsave(&fep->tx_lock, flags);
/*
--
1.6.3.3
^ 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