LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: alpha: half done futex implementation
From: Richard Henderson @ 2009-04-13 20:23 UTC (permalink / raw)
  To: Matt Turner
  Cc: Oliver Falk, linux-kernel, linuxppc-dev, Ivan Kokshaysky,
	linux-alpha, Jay Estabrook
In-Reply-To: <b4198de60904111755u5c2078c7xcc689dbd78aeb957@mail.gmail.com>

Matt Turner wrote:
> Hi,
> 
> Going on Richard's advice, I've tried to write an alpha futex
> implementation based on the powerpc futex.h.
> 
> I've gotten this far.. :\
> 

#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
      __asm__ __volatile(             \
      __ASM_MB                        \
      "1: ldl_l   %0,0(%3)\n"         \
          insn                        \
      "2: stl_c   %1,0(%3)\n"         \
      "   beq     %1,4f\n"            \
      "   mov     $31,%1\n"           \
      "3: .subsection 2\n"            \
      "4: br      1b\n"               \
      "   .previous\n"                \
      ".section __ex_table,\"a\"\n"   \
      "   .long   1b-.\n"             \
      "   lda     %0,3b-1b(%2)\n"     \
      "   .long   2b-.\n"             \
      "   lda     %0,3b-2b(%2)\n"     \
      "   .previous\n"                \
      : "=&r" (oldval), "=&r"(ret)    \
      : "r" (uaddr), "r"(oparg)       \
      : "memory")

   switch (op) {
     case FUTEX_OP_SET:
       __futex_atomic_op("mov %0,%1", ret, oldval, uaddr, oparg);
       break;
     case FUTEX_OP_ADD:
       __futex_atomic_op("addl %0,%4,%1\n", ret, oldval, uaddr, oparg);
       break;
     case FUTEX_OP_OR:
       __futex_atomic_op("or %0,%4,%1\n", ret, oldval, uaddr, oparg);
       break;
     case FUTEX_OP_ANDN:
       __futex_atomic_op("andnot %0,%4,%1\n", ret, oldval, uaddr, oparg);
       break;
     case FUTEX_OP_XOR:
       __futex_atomic_op("xor %0,%4,%1\n", ret, oldval, uaddr, oparg);
       break;
     default:
       ret = -ENOSYS;
   }


Also, there's a bug in the powerpc implementation.  It appears that 
oparg is clobbered, and if stwcx fails the operation will be repeated 
with incorrect inputs.


r~

^ permalink raw reply

* Re: bug in drivers/edac/mpc85xx_edac.c:mpc85xx_mc_check() ?
From: Dave Jiang @ 2009-04-13 17:10 UTC (permalink / raw)
  To: Jeff Haran; +Cc: linuxppc-dev, Andrew Morton, linux-kernel, Doug Thompson
In-Reply-To: <20090410144715.0fa5939e.akpm@linux-foundation.org>

Jeff, you are correct. I will submit a patch to correct that.

Andrew Morton wrote:
> (cc's added)
> 
> On Wed, 8 Apr 2009 14:57:42 -0700
> "Jeff Haran" <jharan@Brocade.COM> wrote:
> 
>> Hi,
>>
>> Recent versions of this function start off with:
>>
>> static void mpc85xx_mc_check(struct mem_ctl_info *mci)
>> {
>>     struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
>>     ...
>>
>>     err_detect = in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT);
>>     if (err_detect)
>>         return;
>>
>>     ...
>> }
>>
>> My reading of the Freescale 8548E Manual leads me to conclude that the
>> Memory Error Detect register (ERR_DETECT) will have various bits set if
>> the memory controller has detected an error since the last time it was
>> cleared. If no memory error has occurred, the register will contain 0.
>>
>> Perhaps I am missing something very basic, but it seem to me that the
>> above "if" should be:
>>
>>     if (!err_detect)
>>         return;
>>
>> as the existing code would seem to read "if any errors have occurred,
>> ignore them", though perhaps testing has demonstrated that the Freescale
>> manual is in error.
>>
>> Please include this email address in responses as I do not subscribe.
>>
>> Thanks,
>>
>> Jeff Haran
>> Brocade
> 


-- 

------------------------------------------------------
Dave Jiang
Software Engineer
MontaVista Software, Inc.
http://www.mvista.com
------------------------------------------------------

^ permalink raw reply

* RE: [PATCH] [V2] Xilinx : Framebuffer Driver: Add PLB support(non-DCR)
From: Stephen Neuendorffer @ 2009-04-13 16:49 UTC (permalink / raw)
  To: John Linn, grant.likely
  Cc: Suneel Garapati, akonovalov, linux-fbdev-devel, adaplas,
	linuxppc-dev
In-Reply-To: <20090413141322.1DA064E8054@mail158-wa4.bigfish.com>


I think the mainline driver might (still) assume the presence of a PLB->DCR=
 bridge?  =


So there are really 4 cases: =

Core has DCR access, accessed directly using DCR.
Core has DCR access, accessed indirectly using DCR.
Core has DCR access, accessed through plb->dcr bridge.
Core has PLB access.

Steve

> -----Original Message-----
> From: linuxppc-dev-bounces+stephen.neuendorffer=3Dxilinx.com@ozlabs.org [=
mailto:linuxppc-dev-
> bounces+stephen.neuendorffer=3Dxilinx.com@ozlabs.org] On Behalf Of John L=
inn
> Sent: Monday, April 13, 2009 7:13 AM
> To: grant.likely@secretlab.ca
> Cc: linux-fbdev-devel@lists.sourceforge.net; adaplas@gmail.com; Suneel Ga=
rapati; linuxppc-
> dev@ozlabs.org; akonovalov@ru.mvista.com
> Subject: RE: [PATCH] [V2] Xilinx : Framebuffer Driver: Add PLB support(no=
n-DCR)
> =

> I thought it was based on mainline, but I now see the weirdness you're ta=
lking about.  I'll dig in on
> this and let you know more as I'm confused also.
> =

> -- John
> =

> > -----Original Message-----
> > From: Grant Likely [mailto:grant.likely@secretlab.ca]
> > Sent: Sunday, April 12, 2009 12:15 AM
> > To: John Linn
> > Cc: jwboyer@linux.vnet.ibm.com; linux-fbdev-devel@lists.sourceforge.net=
; linuxppc-dev@ozlabs.org;
> > akonovalov@ru.mvista.com; adaplas@gmail.com; Suneel Garapati
> > Subject: Re: [PATCH] [V2] Xilinx : Framebuffer Driver: Add PLB support =
(non-DCR)
> >
> > What tree is this patch prepared against?  The version in mainline
> > already does PLB access, and doesn't support DCR at all.  It appears
> > that this driver is based on something that does the opposite.
> >
> > g.
> >
> > On Fri, Apr 10, 2009 at 3:17 PM, John Linn <john.linn@xilinx.com> wrote=
:
> > > From: Suneel <suneelg@xilinx.com>
> > >
> > > Added support for the new xps tft controller.
> > >
> > > The new core has PLB interface support in addition to existing
> > > DCR interface.
> > >
> > > The driver has been modified to support this new core which
> > > can be connected on PLB or DCR bus.
> > >
> > > Signed-off-by: Suneel <suneelg@xilinx.com>
> > > Signed-off-by: John Linn <john.linn@xilinx.com>
> > > ---
> > >
> > > V2 - Incorporated comments from Josh, Grant and others
> > >
> > > =A0drivers/video/xilinxfb.c | =A0213 ++++++++++++++++++++++++++++++++=
--------------
> > > =A01 files changed, 150 insertions(+), 63 deletions(-)
> > >
> > > diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c
> > > index a82c530..d151237 100644
> > > --- a/drivers/video/xilinxfb.c
> > > +++ b/drivers/video/xilinxfb.c
> > > @@ -1,13 +1,13 @@
> > > =A0/*
> > > - * xilinxfb.c
> > > =A0*
> > > - * Xilinx TFT LCD frame buffer driver
> > > + * Xilinx TFT frame buffer driver
> > > =A0*
> > > =A0* Author: MontaVista Software, Inc.
> > > =A0* =A0 =A0 =A0 =A0 source@mvista.com
> > > =A0*
> > > =A0* 2002-2007 (c) MontaVista Software, Inc.
> > > =A0* 2007 (c) Secret Lab Technologies, Ltd.
> > > + * 2009 (c) Xilinx Inc.
> > > =A0*
> > > =A0* This file is licensed under the terms of the GNU General Public =
License
> > > =A0* version 2. =A0This program is licensed "as is" without any warra=
nty of any
> > > @@ -31,27 +31,31 @@
> > > =A0#include <linux/fb.h>
> > > =A0#include <linux/init.h>
> > > =A0#include <linux/dma-mapping.h>
> > > -#if defined(CONFIG_OF)
> > > =A0#include <linux/of_device.h>
> > > =A0#include <linux/of_platform.h>
> > > -#endif
> > > -#include <asm/io.h>
> > > +#include <linux/io.h>
> > > =A0#include <linux/xilinxfb.h>
> > > =A0#include <asm/dcr.h>
> > >
> > > =A0#define DRIVER_NAME =A0 =A0 =A0 =A0 =A0 =A0"xilinxfb"
> > > -#define DRIVER_DESCRIPTION =A0 =A0 "Xilinx TFT LCD frame buffer driv=
er"
> > > +
> > >
> > > =A0/*
> > > =A0* Xilinx calls it "PLB TFT LCD Controller" though it can also be u=
sed for
> > > - * the VGA port on the Xilinx ML40x board. This is a hardware displa=
y controller
> > > - * for a 640x480 resolution TFT or VGA screen.
> > > + * the VGA port on the Xilinx ML40x board. This is a hardware displa=
y
> > > + * controller for a 640x480 resolution TFT or VGA screen.
> > > =A0*
> > > =A0* The interface to the framebuffer is nice and simple. =A0There ar=
e two
> > > =A0* control registers. =A0The first tells the LCD interface where in=
 memory
> > > =A0* the frame buffer is (only the 11 most significant bits are used,=
 so
> > > =A0* don't start thinking about scrolling). =A0The second allows the =
LCD to
> > > =A0* be turned on or off as well as rotated 180 degrees.
> > > + *
> > > + * In case of direct PLB access the second control register will be =
at
> > > + * an offset of 4 as compared to the DCR access where the offset is =
1
> > > + * i.e. REG_CTRL. So this is taken care in the function
> > > + * xilinx_fb_out_be32 where it left shifts the offset 2 times in cas=
e of
> > > + * direct PLB access.
> > > =A0*/
> > > =A0#define NUM_REGS =A0 =A0 =A0 2
> > > =A0#define REG_FB_ADDR =A0 =A00
> > > @@ -108,10 +112,18 @@ static struct fb_var_screeninfo xilinx_fb_var =
=3D {
> > > =A0 =A0 =A0 =A0.activate =3D =A0 =A0 FB_ACTIVATE_NOW
> > > =A0};
> > >
> > > +
> > > +#define PLB_ACCESS_FLAG =A0 =A0 =A0 =A00x1 =A0 =A0 =A0 =A0 =A0 =A0 /=
* 1 =3D PLB, 0 =3D DCR */
> > > +
> > > =A0struct xilinxfb_drvdata {
> > >
> > > =A0 =A0 =A0 =A0struct fb_info =A0info; =A0 =A0 =A0 =A0 =A0 /* FB driv=
er info record */
> > >
> > > + =A0 =A0 =A0 phys_addr_t =A0 =A0 regs_phys; =A0 =A0 =A0/* phys. addr=
ess of the control
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 registers */
> > > + =A0 =A0 =A0 void __iomem =A0 =A0*regs; =A0 =A0 =A0 =A0 =A0/* virt. =
address of the control
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 registers */
> > > +
> > > =A0 =A0 =A0 =A0dcr_host_t =A0 =A0 =A0dcr_host;
> > > =A0 =A0 =A0 =A0unsigned int =A0 =A0dcr_start;
> > > =A0 =A0 =A0 =A0unsigned int =A0 =A0dcr_len;
> > > @@ -120,6 +132,8 @@ struct xilinxfb_drvdata {
> > > =A0 =A0 =A0 =A0dma_addr_t =A0 =A0 =A0fb_phys; =A0 =A0 =A0 =A0/* phys.=
 address of the frame buffer */
> > > =A0 =A0 =A0 =A0int =A0 =A0 =A0 =A0 =A0 =A0 fb_alloced; =A0 =A0 /* Fla=
g, was the fb memory alloced? */
> > >
> > > + =A0 =A0 =A0 u8 =A0 =A0 =A0 =A0 =A0 =A0 =A0flags; =A0 =A0 =A0 =A0 =
=A0/* features of the driver */
> > > +
> > > =A0 =A0 =A0 =A0u32 =A0 =A0 =A0 =A0 =A0 =A0 reg_ctrl_default;
> > >
> > > =A0 =A0 =A0 =A0u32 =A0 =A0 =A0 =A0 =A0 =A0 pseudo_palette[PALETTE_ENT=
RIES_NO];
> > > @@ -130,14 +144,19 @@ struct xilinxfb_drvdata {
> > > =A0 =A0 =A0 =A0container_of(_info, struct xilinxfb_drvdata, info)
> > >
> > > =A0/*
> > > - * The LCD controller has DCR interface to its registers, but all
> > > - * the boards and configurations the driver has been tested with
> > > - * use opb2dcr bridge. So the registers are seen as memory mapped.
> > > - * This macro is to make it simple to add the direct DCR access
> > > - * when it's needed.
> > > + * The XPS TFT Controller can be accessed through PLB or DCR interfa=
ce.
> > > + * To perform the read/write on the registers we need to check on
> > > + * which bus its connected and call the appropriate write API.
> > > =A0*/
> > > -#define xilinx_fb_out_be32(driverdata, offset, val) \
> > > - =A0 =A0 =A0 dcr_write(driverdata->dcr_host, offset, val)
> > > +static void xilinx_fb_out_be32(struct xilinxfb_drvdata *drvdata, u32=
 offset,
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 u32 val=
)
> > > +{
> > > + =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG)
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(drvdata->regs + (offset << 2),=
 val);
> > > + =A0 =A0 =A0 else
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dcr_write(drvdata->dcr_host, offset, va=
l);
> > > +
> > > +}
> > >
> > > =A0static int
> > > =A0xilinx_fb_setcolreg(unsigned regno, unsigned red, unsigned green, =
unsigned blue,
> > > @@ -175,7 +194,8 @@ xilinx_fb_blank(int blank_mode, struct fb_info *f=
bi)
> > > =A0 =A0 =A0 =A0switch (blank_mode) {
> > > =A0 =A0 =A0 =A0case FB_BLANK_UNBLANK:
> > > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* turn on panel */
> > > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 xilinx_fb_out_be32(drvdata, REG_CTRL, d=
rvdata->reg_ctrl_default);
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 xilinx_fb_out_be32(drvdata, REG_CTRL,
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 drvdata->reg_ctrl_default);
> > > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;
> > >
> > > =A0 =A0 =A0 =A0case FB_BLANK_NORMAL:
> > > @@ -191,8 +211,7 @@ xilinx_fb_blank(int blank_mode, struct fb_info *f=
bi)
> > > =A0 =A0 =A0 =A0return 0; /* success */
> > > =A0}
> > >
> > > -static struct fb_ops xilinxfb_ops =3D
> > > -{
> > > +static struct fb_ops xilinxfb_ops =3D {
> > > =A0 =A0 =A0 =A0.owner =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=3D THIS_MOD=
ULE,
> > > =A0 =A0 =A0 =A0.fb_setcolreg =A0 =A0 =A0 =A0 =A0 =3D xilinx_fb_setcol=
reg,
> > > =A0 =A0 =A0 =A0.fb_blank =A0 =A0 =A0 =A0 =A0 =A0 =A0 =3D xilinx_fb_bl=
ank,
> > > @@ -205,25 +224,35 @@ static struct fb_ops xilinxfb_ops =3D
> > > =A0* Bus independent setup/teardown
> > > =A0*/
> > >
> > > -static int xilinxfb_assign(struct device *dev, dcr_host_t dcr_host,
> > > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0unsigned int dcr=
_start, unsigned int dcr_len,
> > > +static int xilinxfb_assign(struct device *dev,
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct xilinxfb_=
drvdata *drvdata,
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0unsigned long ph=
ysaddr,
> > > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct xilinxfb_p=
latform_data *pdata)
> > > =A0{
> > > - =A0 =A0 =A0 struct xilinxfb_drvdata *drvdata;
> > > =A0 =A0 =A0 =A0int rc;
> > > =A0 =A0 =A0 =A0int fbsize =3D pdata->xvirt * pdata->yvirt * BYTES_PER=
_PIXEL;
> > >
> > > - =A0 =A0 =A0 /* Allocate the driver data region */
> > > - =A0 =A0 =A0 drvdata =3D kzalloc(sizeof(*drvdata), GFP_KERNEL);
> > > - =A0 =A0 =A0 if (!drvdata) {
> > > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Couldn't allocate device =
private record\n");
> > > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENOMEM;
> > > + =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG) {
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* Map the control registers in if th=
e controller
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* is on direct PLB interface.
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!request_mem_region(physaddr, 8, DR=
IVER_NAME)) {
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Couldn't =
lock memory region at 0x%08lX\n",
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 physadd=
r);
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 rc =3D -ENODEV;
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err_region;
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> > > +
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 drvdata->regs_phys =3D physaddr;
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 drvdata->regs =3D ioremap(physaddr, 8);=

> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!drvdata->regs) {
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Couldn't =
lock memory region at 0x%08lX\n",
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 physadd=
r);
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 rc =3D -ENODEV;
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err_map;
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> > > =A0 =A0 =A0 =A0}
> > > - =A0 =A0 =A0 dev_set_drvdata(dev, drvdata);
> > > -
> > > - =A0 =A0 =A0 drvdata->dcr_start =3D dcr_start;
> > > - =A0 =A0 =A0 drvdata->dcr_len =3D dcr_len;
> > > - =A0 =A0 =A0 drvdata->dcr_host =3D dcr_host;
> > >
> > > =A0 =A0 =A0 =A0/* Allocate the framebuffer memory */
> > > =A0 =A0 =A0 =A0if (pdata->fb_phys) {
> > > @@ -238,7 +267,10 @@ static int xilinxfb_assign(struct device *dev, d=
cr_host_t dcr_host,
> > > =A0 =A0 =A0 =A0if (!drvdata->fb_virt) {
> > > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dev_err(dev, "Could not allocate frame=
 buffer memory\n");
> > > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0rc =3D -ENOMEM;
> > > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err_region;
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG)
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err_fbmem;
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 else
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err_region;
> > > =A0 =A0 =A0 =A0}
> > >
> > > =A0 =A0 =A0 =A0/* Clear (turn to black) the framebuffer */
> > > @@ -251,7 +283,8 @@ static int xilinxfb_assign(struct device *dev, dc=
r_host_t dcr_host,
> > > =A0 =A0 =A0 =A0drvdata->reg_ctrl_default =3D REG_CTRL_ENABLE;
> > > =A0 =A0 =A0 =A0if (pdata->rotate_screen)
> > > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0drvdata->reg_ctrl_default |=3D REG_CTR=
L_ROTATE;
> > > - =A0 =A0 =A0 xilinx_fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl=
_default);
> > > + =A0 =A0 =A0 xilinx_fb_out_be32(drvdata, REG_CTRL,
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 drvdata->reg_ctrl_default);
> > >
> > > =A0 =A0 =A0 =A0/* Fill struct fb_info */
> > > =A0 =A0 =A0 =A0drvdata->info.device =3D dev;
> > > @@ -287,9 +320,14 @@ static int xilinxfb_assign(struct device *dev, d=
cr_host_t dcr_host,
> > > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0goto err_regfb;
> > > =A0 =A0 =A0 =A0}
> > >
> > > + =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG) {
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Put a banner in the log (for DEBUG) =
*/
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_dbg(dev, "regs: phys=3D%lx, virt=3D=
%p\n", physaddr,
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 drvdata->regs);
> > > + =A0 =A0 =A0 }
> > > =A0 =A0 =A0 =A0/* Put a banner in the log (for DEBUG) */
> > > =A0 =A0 =A0 =A0dev_dbg(dev, "fb: phys=3D%p, virt=3D%p, size=3D%x\n",
> > > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 (void*)drvdata->fb_phys, drvdata->fb_vi=
rt, fbsize);
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 (void *)drvdata->fb_phys, drvdata->fb_v=
irt, fbsize);
> > >
> > > =A0 =A0 =A0 =A0return 0; =A0 =A0 =A0 /* success */
> > >
> > > @@ -300,9 +338,20 @@ err_cmap:
> > > =A0 =A0 =A0 =A0if (drvdata->fb_alloced)
> > > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dma_free_coherent(dev, PAGE_ALIGN(fbsi=
ze), drvdata->fb_virt,
> > > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0drvdata->fb_phys);
> > > + =A0 =A0 =A0 else
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 iounmap(drvdata->fb_virt);
> > > +
> > > =A0 =A0 =A0 =A0/* Turn off the display */
> > > =A0 =A0 =A0 =A0xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
> > >
> > > +err_fbmem:
> > > + =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG)
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 iounmap(drvdata->regs);
> > > +
> > > +err_map:
> > > + =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG)
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 release_mem_region(physaddr, 8);
> > > +
> > > =A0err_region:
> > > =A0 =A0 =A0 =A0kfree(drvdata);
> > > =A0 =A0 =A0 =A0dev_set_drvdata(dev, NULL);
> > > @@ -325,11 +374,18 @@ static int xilinxfb_release(struct device *dev)=

> > > =A0 =A0 =A0 =A0if (drvdata->fb_alloced)
> > > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dma_free_coherent(dev, PAGE_ALIGN(drvd=
ata->info.fix.smem_len),
> > > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dr=
vdata->fb_virt, drvdata->fb_phys);
> > > + =A0 =A0 =A0 else
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 iounmap(drvdata->fb_virt);
> > >
> > > =A0 =A0 =A0 =A0/* Turn off the display */
> > > =A0 =A0 =A0 =A0xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
> > >
> > > - =A0 =A0 =A0 dcr_unmap(drvdata->dcr_host, drvdata->dcr_len);
> > > + =A0 =A0 =A0 /* Release the resources, as allocated based on interfa=
ce */
> > > + =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG) {
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 iounmap(drvdata->regs);
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 release_mem_region(drvdata->regs_phys, =
8);
> > > + =A0 =A0 =A0 } else
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dcr_unmap(drvdata->dcr_host, drvdata->d=
cr_len);
> > >
> > > =A0 =A0 =A0 =A0kfree(drvdata);
> > > =A0 =A0 =A0 =A0dev_set_drvdata(dev, NULL);
> > > @@ -341,27 +397,54 @@ static int xilinxfb_release(struct device *dev)=

> > > =A0* OF bus binding
> > > =A0*/
> > >
> > > -#if defined(CONFIG_OF)
> > > =A0static int __devinit
> > > =A0xilinxfb_of_probe(struct of_device *op, const struct of_device_id =
*match)
> > > =A0{
> > > =A0 =A0 =A0 =A0const u32 *prop;
> > > + =A0 =A0 =A0 u32 *p;
> > > + =A0 =A0 =A0 u32 tft_access;
> > > =A0 =A0 =A0 =A0struct xilinxfb_platform_data pdata;
> > > + =A0 =A0 =A0 struct resource res;
> > > =A0 =A0 =A0 =A0int size, rc;
> > > - =A0 =A0 =A0 int start, len;
> > > + =A0 =A0 =A0 int start =3D 0, len =3D 0;
> > > =A0 =A0 =A0 =A0dcr_host_t dcr_host;
> > > + =A0 =A0 =A0 struct xilinxfb_drvdata *drvdata;
> > >
> > > =A0 =A0 =A0 =A0/* Copy with the default pdata (not a ptr reference!) =
*/
> > > =A0 =A0 =A0 =A0pdata =3D xilinx_fb_default_pdata;
> > >
> > > =A0 =A0 =A0 =A0dev_dbg(&op->dev, "xilinxfb_of_probe(%p, %p)\n", op, m=
atch);
> > >
> > > - =A0 =A0 =A0 start =3D dcr_resource_start(op->node, 0);
> > > - =A0 =A0 =A0 len =3D dcr_resource_len(op->node, 0);
> > > - =A0 =A0 =A0 dcr_host =3D dcr_map(op->node, start, len);
> > > - =A0 =A0 =A0 if (!DCR_MAP_OK(dcr_host)) {
> > > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(&op->dev, "invalid address\n");=

> > > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENODEV;
> > > + =A0 =A0 =A0 /*
> > > + =A0 =A0 =A0 =A0* To check whether the core is connected directly to=
 DCR or PLB
> > > + =A0 =A0 =A0 =A0* interface and initialize the tft_access accordingl=
y.
> > > + =A0 =A0 =A0 =A0*/
> > > + =A0 =A0 =A0 p =3D (u32 *)of_get_property(op->node, "xlnx,dcr-splb-s=
lave-if", NULL);
> > > +
> > > + =A0 =A0 =A0 if (p)
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tft_access =3D *p;
> > > + =A0 =A0 =A0 else
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tft_access =3D 0; =A0 =A0 =A0 =A0 /* Fo=
r backward compatibility */
> > > +
> > > + =A0 =A0 =A0 /*
> > > + =A0 =A0 =A0 =A0* Fill the resource structure if its direct PLB inte=
rface
> > > + =A0 =A0 =A0 =A0* otherwise fill the dcr_host structure.
> > > + =A0 =A0 =A0 =A0*/
> > > + =A0 =A0 =A0 if (tft_access) {
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 rc =3D of_address_to_resource(op->node,=
 0, &res);
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (rc) {
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(&op->dev, "inva=
lid address\n");
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENODEV;
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> > > +
> > > + =A0 =A0 =A0 } else {
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 start =3D dcr_resource_start(op->node, =
0);
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 len =3D dcr_resource_len(op->node, 0);
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dcr_host =3D dcr_map(op->node, start, l=
en);
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!DCR_MAP_OK(dcr_host)) {
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(&op->dev, "inva=
lid address\n");
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENODEV;
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> > > =A0 =A0 =A0 =A0}
> > >
> > > =A0 =A0 =A0 =A0prop =3D of_get_property(op->node, "phys-size", &size)=
;
> > > @@ -385,7 +468,26 @@ xilinxfb_of_probe(struct of_device *op, const st=
ruct of_device_id *match)
> > > =A0 =A0 =A0 =A0if (of_find_property(op->node, "rotate-display", NULL)=
)
> > > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pdata.rotate_screen =3D 1;
> > >
> > > - =A0 =A0 =A0 return xilinxfb_assign(&op->dev, dcr_host, start, len, =
&pdata);
> > > + =A0 =A0 =A0 /* Allocate the driver data region */
> > > + =A0 =A0 =A0 drvdata =3D kzalloc(sizeof(*drvdata), GFP_KERNEL);
> > > + =A0 =A0 =A0 if (!drvdata) {
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(&op->dev, "Couldn't allocate de=
vice private record\n");
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENOMEM;
> > > + =A0 =A0 =A0 }
> > > + =A0 =A0 =A0 dev_set_drvdata(&op->dev, drvdata);
> > > +
> > > + =A0 =A0 =A0 if (tft_access)
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 drvdata->flags |=3D PLB_ACCESS_FLAG;
> > > +
> > > + =A0 =A0 =A0 /* Arguments are passed based on the interface */
> > > + =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG) {
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return xilinxfb_assign(&op->dev, drvdat=
a, res.start, &pdata);
> > > + =A0 =A0 =A0 } else {
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 drvdata->dcr_start =3D start;
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 drvdata->dcr_len =3D len;
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 drvdata->dcr_host =3D dcr_host;
> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return xilinxfb_assign(&op->dev, drvdat=
a, 0, &pdata);
> > > + =A0 =A0 =A0 }
> > > =A0}
> > >
> > > =A0static int __devexit xilinxfb_of_remove(struct of_device *op)
> > > @@ -395,6 +497,7 @@ static int __devexit xilinxfb_of_remove(struct of=
_device *op)
> > >
> > > =A0/* Match table for of_platform binding */
> > > =A0static struct of_device_id xilinxfb_of_match[] __devinitdata =3D {=

> > > + =A0 =A0 =A0 { .compatible =3D "xlnx,xps-tft-1.00.a", },
> > > =A0 =A0 =A0 =A0{ .compatible =3D "xlnx,plb-tft-cntlr-ref-1.00.a", },
> > > =A0 =A0 =A0 =A0{ .compatible =3D "xlnx,plb-dvi-cntlr-ref-1.00.c", },
> > > =A0 =A0 =A0 =A0{},
> > > @@ -412,22 +515,6 @@ static struct of_platform_driver xilinxfb_of_dri=
ver =3D {
> > > =A0 =A0 =A0 =A0},
> > > =A0};
> > >
> > > -/* Registration helpers to keep the number of #ifdefs to a minimum *=
/
> > > -static inline int __init xilinxfb_of_register(void)
> > > -{
> > > - =A0 =A0 =A0 pr_debug("xilinxfb: calling of_register_platform_driver=
()\n");
> > > - =A0 =A0 =A0 return of_register_platform_driver(&xilinxfb_of_driver)=
;
> > > -}
> > > -
> > > -static inline void __exit xilinxfb_of_unregister(void)
> > > -{
> > > - =A0 =A0 =A0 of_unregister_platform_driver(&xilinxfb_of_driver);
> > > -}
> > > -#else /* CONFIG_OF */
> > > -/* CONFIG_OF not enabled; do nothing helpers */
> > > -static inline int __init xilinxfb_of_register(void) { return 0; }
> > > -static inline void __exit xilinxfb_of_unregister(void) { }
> > > -#endif /* CONFIG_OF */
> > >
> > > =A0/* ---------------------------------------------------------------=
------
> > > =A0* Module setup and teardown
> > > @@ -436,18 +523,18 @@ static inline void __exit xilinxfb_of_unregiste=
r(void) { }
> > > =A0static int __init
> > > =A0xilinxfb_init(void)
> > > =A0{
> > > - =A0 =A0 =A0 return xilinxfb_of_register();
> > > + =A0 =A0 =A0 return of_register_platform_driver(&xilinxfb_of_driver)=
;
> > > =A0}
> > >
> > > =A0static void __exit
> > > =A0xilinxfb_cleanup(void)
> > > =A0{
> > > - =A0 =A0 =A0 xilinxfb_of_unregister();
> > > + =A0 =A0 =A0 of_unregister_platform_driver(&xilinxfb_of_driver);
> > > =A0}
> > >
> > > =A0module_init(xilinxfb_init);
> > > =A0module_exit(xilinxfb_cleanup);
> > >
> > > =A0MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
> > > -MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
> > > +MODULE_DESCRIPTION("Xilinx TFT frame buffer driver");
> > > =A0MODULE_LICENSE("GPL");
> > > --
> > > 1.6.2.1
> > >
> > >
> > >
> > > This email and any attachments are intended for the sole use of the n=
amed recipient(s) and
> > contain(s) confidential information that may be proprietary, privileged=
 or copyrighted under
> > applicable law. If you are not the intended recipient, do not read, cop=
y, or forward this email
> > message or any attachments. Delete this email message and any attachmen=
ts immediately.
> > >
> > >
> > >
> >
> >
> >
> > --
> > Grant Likely, B.Sc., P.Eng.
> > Secret Lab Technologies Ltd.
> =

> =

> This email and any attachments are intended for the sole use of the named=
 recipient(s) and contain(s)
> confidential information that may be proprietary, privileged or copyright=
ed under applicable law. If
> you are not the intended recipient, do not read, copy, or forward this em=
ail message or any
> attachments. Delete this email message and any attachments immediately.
> =

> =

> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev


This email and any attachments are intended for the sole use of the named r=
ecipient(s) and contain(s) confidential information that may be proprietary=
, privileged or copyrighted under applicable law. If you are not the intend=
ed recipient, do not read, copy, or forward this email message or any attac=
hments. Delete this email message and any attachments immediately.

^ permalink raw reply

* Re: [PATCH] [V2] Xilinx : Framebuffer Driver: Add PLB support(non-DCR)
From: Grant Likely @ 2009-04-13 16:58 UTC (permalink / raw)
  To: Stephen Neuendorffer
  Cc: linux-fbdev-devel, adaplas, Suneel Garapati, linuxppc-dev,
	akonovalov, John Linn
In-Reply-To: <20090413164958.EE0821600054@mail123-va3.bigfish.com>

On Mon, Apr 13, 2009 at 10:49 AM, Stephen Neuendorffer
<stephen.neuendorffer@xilinx.com> wrote:
>
> I think the mainline driver might (still) assume the presence of a PLB->D=
CR bridge?

Correct.

> So there are really 4 cases:
> Core has DCR access, accessed directly using DCR.
> Core has DCR access, accessed indirectly using DCR.
> Core has DCR access, accessed through plb->dcr bridge.
> Core has PLB access.

sounds right to me.

g.

>
> Steve
>
>> -----Original Message-----
>> From: linuxppc-dev-bounces+stephen.neuendorffer=3Dxilinx.com@ozlabs.org =
[mailto:linuxppc-dev-
>> bounces+stephen.neuendorffer=3Dxilinx.com@ozlabs.org] On Behalf Of John =
Linn
>> Sent: Monday, April 13, 2009 7:13 AM
>> To: grant.likely@secretlab.ca
>> Cc: linux-fbdev-devel@lists.sourceforge.net; adaplas@gmail.com; Suneel G=
arapati; linuxppc-
>> dev@ozlabs.org; akonovalov@ru.mvista.com
>> Subject: RE: [PATCH] [V2] Xilinx : Framebuffer Driver: Add PLB support(n=
on-DCR)
>>
>> I thought it was based on mainline, but I now see the weirdness you're t=
alking about. =A0I'll dig in on
>> this and let you know more as I'm confused also.
>>
>> -- John
>>
>> > -----Original Message-----
>> > From: Grant Likely [mailto:grant.likely@secretlab.ca]
>> > Sent: Sunday, April 12, 2009 12:15 AM
>> > To: John Linn
>> > Cc: jwboyer@linux.vnet.ibm.com; linux-fbdev-devel@lists.sourceforge.ne=
t; linuxppc-dev@ozlabs.org;
>> > akonovalov@ru.mvista.com; adaplas@gmail.com; Suneel Garapati
>> > Subject: Re: [PATCH] [V2] Xilinx : Framebuffer Driver: Add PLB support=
 (non-DCR)
>> >
>> > What tree is this patch prepared against? =A0The version in mainline
>> > already does PLB access, and doesn't support DCR at all. =A0It appears
>> > that this driver is based on something that does the opposite.
>> >
>> > g.
>> >
>> > On Fri, Apr 10, 2009 at 3:17 PM, John Linn <john.linn@xilinx.com> wrot=
e:
>> > > From: Suneel <suneelg@xilinx.com>
>> > >
>> > > Added support for the new xps tft controller.
>> > >
>> > > The new core has PLB interface support in addition to existing
>> > > DCR interface.
>> > >
>> > > The driver has been modified to support this new core which
>> > > can be connected on PLB or DCR bus.
>> > >
>> > > Signed-off-by: Suneel <suneelg@xilinx.com>
>> > > Signed-off-by: John Linn <john.linn@xilinx.com>
>> > > ---
>> > >
>> > > V2 - Incorporated comments from Josh, Grant and others
>> > >
>> > > =A0drivers/video/xilinxfb.c | =A0213 +++++++++++++++++++++++++++++++=
+--------------
>> > > =A01 files changed, 150 insertions(+), 63 deletions(-)
>> > >
>> > > diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c
>> > > index a82c530..d151237 100644
>> > > --- a/drivers/video/xilinxfb.c
>> > > +++ b/drivers/video/xilinxfb.c
>> > > @@ -1,13 +1,13 @@
>> > > =A0/*
>> > > - * xilinxfb.c
>> > > =A0*
>> > > - * Xilinx TFT LCD frame buffer driver
>> > > + * Xilinx TFT frame buffer driver
>> > > =A0*
>> > > =A0* Author: MontaVista Software, Inc.
>> > > =A0* =A0 =A0 =A0 =A0 source@mvista.com
>> > > =A0*
>> > > =A0* 2002-2007 (c) MontaVista Software, Inc.
>> > > =A0* 2007 (c) Secret Lab Technologies, Ltd.
>> > > + * 2009 (c) Xilinx Inc.
>> > > =A0*
>> > > =A0* This file is licensed under the terms of the GNU General Public=
 License
>> > > =A0* version 2. =A0This program is licensed "as is" without any warr=
anty of any
>> > > @@ -31,27 +31,31 @@
>> > > =A0#include <linux/fb.h>
>> > > =A0#include <linux/init.h>
>> > > =A0#include <linux/dma-mapping.h>
>> > > -#if defined(CONFIG_OF)
>> > > =A0#include <linux/of_device.h>
>> > > =A0#include <linux/of_platform.h>
>> > > -#endif
>> > > -#include <asm/io.h>
>> > > +#include <linux/io.h>
>> > > =A0#include <linux/xilinxfb.h>
>> > > =A0#include <asm/dcr.h>
>> > >
>> > > =A0#define DRIVER_NAME =A0 =A0 =A0 =A0 =A0 =A0"xilinxfb"
>> > > -#define DRIVER_DESCRIPTION =A0 =A0 "Xilinx TFT LCD frame buffer dri=
ver"
>> > > +
>> > >
>> > > =A0/*
>> > > =A0* Xilinx calls it "PLB TFT LCD Controller" though it can also be =
used for
>> > > - * the VGA port on the Xilinx ML40x board. This is a hardware displ=
ay controller
>> > > - * for a 640x480 resolution TFT or VGA screen.
>> > > + * the VGA port on the Xilinx ML40x board. This is a hardware displ=
ay
>> > > + * controller for a 640x480 resolution TFT or VGA screen.
>> > > =A0*
>> > > =A0* The interface to the framebuffer is nice and simple. =A0There a=
re two
>> > > =A0* control registers. =A0The first tells the LCD interface where i=
n memory
>> > > =A0* the frame buffer is (only the 11 most significant bits are used=
, so
>> > > =A0* don't start thinking about scrolling). =A0The second allows the=
 LCD to
>> > > =A0* be turned on or off as well as rotated 180 degrees.
>> > > + *
>> > > + * In case of direct PLB access the second control register will be=
 at
>> > > + * an offset of 4 as compared to the DCR access where the offset is=
 1
>> > > + * i.e. REG_CTRL. So this is taken care in the function
>> > > + * xilinx_fb_out_be32 where it left shifts the offset 2 times in ca=
se of
>> > > + * direct PLB access.
>> > > =A0*/
>> > > =A0#define NUM_REGS =A0 =A0 =A0 2
>> > > =A0#define REG_FB_ADDR =A0 =A00
>> > > @@ -108,10 +112,18 @@ static struct fb_var_screeninfo xilinx_fb_var =
=3D {
>> > > =A0 =A0 =A0 =A0.activate =3D =A0 =A0 FB_ACTIVATE_NOW
>> > > =A0};
>> > >
>> > > +
>> > > +#define PLB_ACCESS_FLAG =A0 =A0 =A0 =A00x1 =A0 =A0 =A0 =A0 =A0 =A0 =
/* 1 =3D PLB, 0 =3D DCR */
>> > > +
>> > > =A0struct xilinxfb_drvdata {
>> > >
>> > > =A0 =A0 =A0 =A0struct fb_info =A0info; =A0 =A0 =A0 =A0 =A0 /* FB dri=
ver info record */
>> > >
>> > > + =A0 =A0 =A0 phys_addr_t =A0 =A0 regs_phys; =A0 =A0 =A0/* phys. add=
ress of the control
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 registers */
>> > > + =A0 =A0 =A0 void __iomem =A0 =A0*regs; =A0 =A0 =A0 =A0 =A0/* virt.=
 address of the control
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 registers */
>> > > +
>> > > =A0 =A0 =A0 =A0dcr_host_t =A0 =A0 =A0dcr_host;
>> > > =A0 =A0 =A0 =A0unsigned int =A0 =A0dcr_start;
>> > > =A0 =A0 =A0 =A0unsigned int =A0 =A0dcr_len;
>> > > @@ -120,6 +132,8 @@ struct xilinxfb_drvdata {
>> > > =A0 =A0 =A0 =A0dma_addr_t =A0 =A0 =A0fb_phys; =A0 =A0 =A0 =A0/* phys=
. address of the frame buffer */
>> > > =A0 =A0 =A0 =A0int =A0 =A0 =A0 =A0 =A0 =A0 fb_alloced; =A0 =A0 /* Fl=
ag, was the fb memory alloced? */
>> > >
>> > > + =A0 =A0 =A0 u8 =A0 =A0 =A0 =A0 =A0 =A0 =A0flags; =A0 =A0 =A0 =A0 =
=A0/* features of the driver */
>> > > +
>> > > =A0 =A0 =A0 =A0u32 =A0 =A0 =A0 =A0 =A0 =A0 reg_ctrl_default;
>> > >
>> > > =A0 =A0 =A0 =A0u32 =A0 =A0 =A0 =A0 =A0 =A0 pseudo_palette[PALETTE_EN=
TRIES_NO];
>> > > @@ -130,14 +144,19 @@ struct xilinxfb_drvdata {
>> > > =A0 =A0 =A0 =A0container_of(_info, struct xilinxfb_drvdata, info)
>> > >
>> > > =A0/*
>> > > - * The LCD controller has DCR interface to its registers, but all
>> > > - * the boards and configurations the driver has been tested with
>> > > - * use opb2dcr bridge. So the registers are seen as memory mapped.
>> > > - * This macro is to make it simple to add the direct DCR access
>> > > - * when it's needed.
>> > > + * The XPS TFT Controller can be accessed through PLB or DCR interf=
ace.
>> > > + * To perform the read/write on the registers we need to check on
>> > > + * which bus its connected and call the appropriate write API.
>> > > =A0*/
>> > > -#define xilinx_fb_out_be32(driverdata, offset, val) \
>> > > - =A0 =A0 =A0 dcr_write(driverdata->dcr_host, offset, val)
>> > > +static void xilinx_fb_out_be32(struct xilinxfb_drvdata *drvdata, u3=
2 offset,
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 u32 va=
l)
>> > > +{
>> > > + =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG)
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(drvdata->regs + (offset << 2)=
, val);
>> > > + =A0 =A0 =A0 else
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dcr_write(drvdata->dcr_host, offset, v=
al);
>> > > +
>> > > +}
>> > >
>> > > =A0static int
>> > > =A0xilinx_fb_setcolreg(unsigned regno, unsigned red, unsigned green,=
 unsigned blue,
>> > > @@ -175,7 +194,8 @@ xilinx_fb_blank(int blank_mode, struct fb_info *=
fbi)
>> > > =A0 =A0 =A0 =A0switch (blank_mode) {
>> > > =A0 =A0 =A0 =A0case FB_BLANK_UNBLANK:
>> > > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* turn on panel */
>> > > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 xilinx_fb_out_be32(drvdata, REG_CTRL, =
drvdata->reg_ctrl_default);
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 xilinx_fb_out_be32(drvdata, REG_CTRL,
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 drvdata->reg_ctrl_default);
>> > > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;
>> > >
>> > > =A0 =A0 =A0 =A0case FB_BLANK_NORMAL:
>> > > @@ -191,8 +211,7 @@ xilinx_fb_blank(int blank_mode, struct fb_info *=
fbi)
>> > > =A0 =A0 =A0 =A0return 0; /* success */
>> > > =A0}
>> > >
>> > > -static struct fb_ops xilinxfb_ops =3D
>> > > -{
>> > > +static struct fb_ops xilinxfb_ops =3D {
>> > > =A0 =A0 =A0 =A0.owner =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=3D THIS_MO=
DULE,
>> > > =A0 =A0 =A0 =A0.fb_setcolreg =A0 =A0 =A0 =A0 =A0 =3D xilinx_fb_setco=
lreg,
>> > > =A0 =A0 =A0 =A0.fb_blank =A0 =A0 =A0 =A0 =A0 =A0 =A0 =3D xilinx_fb_b=
lank,
>> > > @@ -205,25 +224,35 @@ static struct fb_ops xilinxfb_ops =3D
>> > > =A0* Bus independent setup/teardown
>> > > =A0*/
>> > >
>> > > -static int xilinxfb_assign(struct device *dev, dcr_host_t dcr_host,
>> > > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0unsigned int dc=
r_start, unsigned int dcr_len,
>> > > +static int xilinxfb_assign(struct device *dev,
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct xilinxfb=
_drvdata *drvdata,
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0unsigned long p=
hysaddr,
>> > > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct xilinxfb_=
platform_data *pdata)
>> > > =A0{
>> > > - =A0 =A0 =A0 struct xilinxfb_drvdata *drvdata;
>> > > =A0 =A0 =A0 =A0int rc;
>> > > =A0 =A0 =A0 =A0int fbsize =3D pdata->xvirt * pdata->yvirt * BYTES_PE=
R_PIXEL;
>> > >
>> > > - =A0 =A0 =A0 /* Allocate the driver data region */
>> > > - =A0 =A0 =A0 drvdata =3D kzalloc(sizeof(*drvdata), GFP_KERNEL);
>> > > - =A0 =A0 =A0 if (!drvdata) {
>> > > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Couldn't allocate device=
 private record\n");
>> > > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENOMEM;
>> > > + =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG) {
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* Map the control registers in if t=
he controller
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* is on direct PLB interface.
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!request_mem_region(physaddr, 8, D=
RIVER_NAME)) {
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Couldn't=
 lock memory region at 0x%08lX\n",
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 physad=
dr);
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 rc =3D -ENODEV;
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err_region;
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
>> > > +
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 drvdata->regs_phys =3D physaddr;
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 drvdata->regs =3D ioremap(physaddr, 8)=
;
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!drvdata->regs) {
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Couldn't=
 lock memory region at 0x%08lX\n",
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 physad=
dr);
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 rc =3D -ENODEV;
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err_map;
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
>> > > =A0 =A0 =A0 =A0}
>> > > - =A0 =A0 =A0 dev_set_drvdata(dev, drvdata);
>> > > -
>> > > - =A0 =A0 =A0 drvdata->dcr_start =3D dcr_start;
>> > > - =A0 =A0 =A0 drvdata->dcr_len =3D dcr_len;
>> > > - =A0 =A0 =A0 drvdata->dcr_host =3D dcr_host;
>> > >
>> > > =A0 =A0 =A0 =A0/* Allocate the framebuffer memory */
>> > > =A0 =A0 =A0 =A0if (pdata->fb_phys) {
>> > > @@ -238,7 +267,10 @@ static int xilinxfb_assign(struct device *dev, =
dcr_host_t dcr_host,
>> > > =A0 =A0 =A0 =A0if (!drvdata->fb_virt) {
>> > > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dev_err(dev, "Could not allocate fram=
e buffer memory\n");
>> > > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0rc =3D -ENOMEM;
>> > > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err_region;
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG)
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err_fbmem;
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 else
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err_region;
>> > > =A0 =A0 =A0 =A0}
>> > >
>> > > =A0 =A0 =A0 =A0/* Clear (turn to black) the framebuffer */
>> > > @@ -251,7 +283,8 @@ static int xilinxfb_assign(struct device *dev, d=
cr_host_t dcr_host,
>> > > =A0 =A0 =A0 =A0drvdata->reg_ctrl_default =3D REG_CTRL_ENABLE;
>> > > =A0 =A0 =A0 =A0if (pdata->rotate_screen)
>> > > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0drvdata->reg_ctrl_default |=3D REG_CT=
RL_ROTATE;
>> > > - =A0 =A0 =A0 xilinx_fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctr=
l_default);
>> > > + =A0 =A0 =A0 xilinx_fb_out_be32(drvdata, REG_CTRL,
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 drvdata->reg_ctrl_default);
>> > >
>> > > =A0 =A0 =A0 =A0/* Fill struct fb_info */
>> > > =A0 =A0 =A0 =A0drvdata->info.device =3D dev;
>> > > @@ -287,9 +320,14 @@ static int xilinxfb_assign(struct device *dev, =
dcr_host_t dcr_host,
>> > > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0goto err_regfb;
>> > > =A0 =A0 =A0 =A0}
>> > >
>> > > + =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG) {
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Put a banner in the log (for DEBUG)=
 */
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_dbg(dev, "regs: phys=3D%lx, virt=
=3D%p\n", physaddr,
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 drvdata->regs);
>> > > + =A0 =A0 =A0 }
>> > > =A0 =A0 =A0 =A0/* Put a banner in the log (for DEBUG) */
>> > > =A0 =A0 =A0 =A0dev_dbg(dev, "fb: phys=3D%p, virt=3D%p, size=3D%x\n",
>> > > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 (void*)drvdata->fb_phys, drvdata->fb_v=
irt, fbsize);
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 (void *)drvdata->fb_phys, drvdata->fb_=
virt, fbsize);
>> > >
>> > > =A0 =A0 =A0 =A0return 0; =A0 =A0 =A0 /* success */
>> > >
>> > > @@ -300,9 +338,20 @@ err_cmap:
>> > > =A0 =A0 =A0 =A0if (drvdata->fb_alloced)
>> > > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dma_free_coherent(dev, PAGE_ALIGN(fbs=
ize), drvdata->fb_virt,
>> > > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0drvdata->fb_phys);
>> > > + =A0 =A0 =A0 else
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 iounmap(drvdata->fb_virt);
>> > > +
>> > > =A0 =A0 =A0 =A0/* Turn off the display */
>> > > =A0 =A0 =A0 =A0xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
>> > >
>> > > +err_fbmem:
>> > > + =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG)
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 iounmap(drvdata->regs);
>> > > +
>> > > +err_map:
>> > > + =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG)
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 release_mem_region(physaddr, 8);
>> > > +
>> > > =A0err_region:
>> > > =A0 =A0 =A0 =A0kfree(drvdata);
>> > > =A0 =A0 =A0 =A0dev_set_drvdata(dev, NULL);
>> > > @@ -325,11 +374,18 @@ static int xilinxfb_release(struct device *dev=
)
>> > > =A0 =A0 =A0 =A0if (drvdata->fb_alloced)
>> > > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dma_free_coherent(dev, PAGE_ALIGN(drv=
data->info.fix.smem_len),
>> > > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0d=
rvdata->fb_virt, drvdata->fb_phys);
>> > > + =A0 =A0 =A0 else
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 iounmap(drvdata->fb_virt);
>> > >
>> > > =A0 =A0 =A0 =A0/* Turn off the display */
>> > > =A0 =A0 =A0 =A0xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
>> > >
>> > > - =A0 =A0 =A0 dcr_unmap(drvdata->dcr_host, drvdata->dcr_len);
>> > > + =A0 =A0 =A0 /* Release the resources, as allocated based on interf=
ace */
>> > > + =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG) {
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 iounmap(drvdata->regs);
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 release_mem_region(drvdata->regs_phys,=
 8);
>> > > + =A0 =A0 =A0 } else
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dcr_unmap(drvdata->dcr_host, drvdata->=
dcr_len);
>> > >
>> > > =A0 =A0 =A0 =A0kfree(drvdata);
>> > > =A0 =A0 =A0 =A0dev_set_drvdata(dev, NULL);
>> > > @@ -341,27 +397,54 @@ static int xilinxfb_release(struct device *dev=
)
>> > > =A0* OF bus binding
>> > > =A0*/
>> > >
>> > > -#if defined(CONFIG_OF)
>> > > =A0static int __devinit
>> > > =A0xilinxfb_of_probe(struct of_device *op, const struct of_device_id=
 *match)
>> > > =A0{
>> > > =A0 =A0 =A0 =A0const u32 *prop;
>> > > + =A0 =A0 =A0 u32 *p;
>> > > + =A0 =A0 =A0 u32 tft_access;
>> > > =A0 =A0 =A0 =A0struct xilinxfb_platform_data pdata;
>> > > + =A0 =A0 =A0 struct resource res;
>> > > =A0 =A0 =A0 =A0int size, rc;
>> > > - =A0 =A0 =A0 int start, len;
>> > > + =A0 =A0 =A0 int start =3D 0, len =3D 0;
>> > > =A0 =A0 =A0 =A0dcr_host_t dcr_host;
>> > > + =A0 =A0 =A0 struct xilinxfb_drvdata *drvdata;
>> > >
>> > > =A0 =A0 =A0 =A0/* Copy with the default pdata (not a ptr reference!)=
 */
>> > > =A0 =A0 =A0 =A0pdata =3D xilinx_fb_default_pdata;
>> > >
>> > > =A0 =A0 =A0 =A0dev_dbg(&op->dev, "xilinxfb_of_probe(%p, %p)\n", op, =
match);
>> > >
>> > > - =A0 =A0 =A0 start =3D dcr_resource_start(op->node, 0);
>> > > - =A0 =A0 =A0 len =3D dcr_resource_len(op->node, 0);
>> > > - =A0 =A0 =A0 dcr_host =3D dcr_map(op->node, start, len);
>> > > - =A0 =A0 =A0 if (!DCR_MAP_OK(dcr_host)) {
>> > > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(&op->dev, "invalid address\n")=
;
>> > > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENODEV;
>> > > + =A0 =A0 =A0 /*
>> > > + =A0 =A0 =A0 =A0* To check whether the core is connected directly t=
o DCR or PLB
>> > > + =A0 =A0 =A0 =A0* interface and initialize the tft_access according=
ly.
>> > > + =A0 =A0 =A0 =A0*/
>> > > + =A0 =A0 =A0 p =3D (u32 *)of_get_property(op->node, "xlnx,dcr-splb-=
slave-if", NULL);
>> > > +
>> > > + =A0 =A0 =A0 if (p)
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tft_access =3D *p;
>> > > + =A0 =A0 =A0 else
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tft_access =3D 0; =A0 =A0 =A0 =A0 /* F=
or backward compatibility */
>> > > +
>> > > + =A0 =A0 =A0 /*
>> > > + =A0 =A0 =A0 =A0* Fill the resource structure if its direct PLB int=
erface
>> > > + =A0 =A0 =A0 =A0* otherwise fill the dcr_host structure.
>> > > + =A0 =A0 =A0 =A0*/
>> > > + =A0 =A0 =A0 if (tft_access) {
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 rc =3D of_address_to_resource(op->node=
, 0, &res);
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (rc) {
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(&op->dev, "inv=
alid address\n");
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENODEV;
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
>> > > +
>> > > + =A0 =A0 =A0 } else {
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 start =3D dcr_resource_start(op->node,=
 0);
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 len =3D dcr_resource_len(op->node, 0);
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dcr_host =3D dcr_map(op->node, start, =
len);
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!DCR_MAP_OK(dcr_host)) {
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(&op->dev, "inv=
alid address\n");
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENODEV;
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
>> > > =A0 =A0 =A0 =A0}
>> > >
>> > > =A0 =A0 =A0 =A0prop =3D of_get_property(op->node, "phys-size", &size=
);
>> > > @@ -385,7 +468,26 @@ xilinxfb_of_probe(struct of_device *op, const s=
truct of_device_id *match)
>> > > =A0 =A0 =A0 =A0if (of_find_property(op->node, "rotate-display", NULL=
))
>> > > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pdata.rotate_screen =3D 1;
>> > >
>> > > - =A0 =A0 =A0 return xilinxfb_assign(&op->dev, dcr_host, start, len,=
 &pdata);
>> > > + =A0 =A0 =A0 /* Allocate the driver data region */
>> > > + =A0 =A0 =A0 drvdata =3D kzalloc(sizeof(*drvdata), GFP_KERNEL);
>> > > + =A0 =A0 =A0 if (!drvdata) {
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(&op->dev, "Couldn't allocate d=
evice private record\n");
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENOMEM;
>> > > + =A0 =A0 =A0 }
>> > > + =A0 =A0 =A0 dev_set_drvdata(&op->dev, drvdata);
>> > > +
>> > > + =A0 =A0 =A0 if (tft_access)
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 drvdata->flags |=3D PLB_ACCESS_FLAG;
>> > > +
>> > > + =A0 =A0 =A0 /* Arguments are passed based on the interface */
>> > > + =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG) {
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return xilinxfb_assign(&op->dev, drvda=
ta, res.start, &pdata);
>> > > + =A0 =A0 =A0 } else {
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 drvdata->dcr_start =3D start;
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 drvdata->dcr_len =3D len;
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 drvdata->dcr_host =3D dcr_host;
>> > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return xilinxfb_assign(&op->dev, drvda=
ta, 0, &pdata);
>> > > + =A0 =A0 =A0 }
>> > > =A0}
>> > >
>> > > =A0static int __devexit xilinxfb_of_remove(struct of_device *op)
>> > > @@ -395,6 +497,7 @@ static int __devexit xilinxfb_of_remove(struct o=
f_device *op)
>> > >
>> > > =A0/* Match table for of_platform binding */
>> > > =A0static struct of_device_id xilinxfb_of_match[] __devinitdata =3D =
{
>> > > + =A0 =A0 =A0 { .compatible =3D "xlnx,xps-tft-1.00.a", },
>> > > =A0 =A0 =A0 =A0{ .compatible =3D "xlnx,plb-tft-cntlr-ref-1.00.a", },
>> > > =A0 =A0 =A0 =A0{ .compatible =3D "xlnx,plb-dvi-cntlr-ref-1.00.c", },
>> > > =A0 =A0 =A0 =A0{},
>> > > @@ -412,22 +515,6 @@ static struct of_platform_driver xilinxfb_of_dr=
iver =3D {
>> > > =A0 =A0 =A0 =A0},
>> > > =A0};
>> > >
>> > > -/* Registration helpers to keep the number of #ifdefs to a minimum =
*/
>> > > -static inline int __init xilinxfb_of_register(void)
>> > > -{
>> > > - =A0 =A0 =A0 pr_debug("xilinxfb: calling of_register_platform_drive=
r()\n");
>> > > - =A0 =A0 =A0 return of_register_platform_driver(&xilinxfb_of_driver=
);
>> > > -}
>> > > -
>> > > -static inline void __exit xilinxfb_of_unregister(void)
>> > > -{
>> > > - =A0 =A0 =A0 of_unregister_platform_driver(&xilinxfb_of_driver);
>> > > -}
>> > > -#else /* CONFIG_OF */
>> > > -/* CONFIG_OF not enabled; do nothing helpers */
>> > > -static inline int __init xilinxfb_of_register(void) { return 0; }
>> > > -static inline void __exit xilinxfb_of_unregister(void) { }
>> > > -#endif /* CONFIG_OF */
>> > >
>> > > =A0/* --------------------------------------------------------------=
-------
>> > > =A0* Module setup and teardown
>> > > @@ -436,18 +523,18 @@ static inline void __exit xilinxfb_of_unregist=
er(void) { }
>> > > =A0static int __init
>> > > =A0xilinxfb_init(void)
>> > > =A0{
>> > > - =A0 =A0 =A0 return xilinxfb_of_register();
>> > > + =A0 =A0 =A0 return of_register_platform_driver(&xilinxfb_of_driver=
);
>> > > =A0}
>> > >
>> > > =A0static void __exit
>> > > =A0xilinxfb_cleanup(void)
>> > > =A0{
>> > > - =A0 =A0 =A0 xilinxfb_of_unregister();
>> > > + =A0 =A0 =A0 of_unregister_platform_driver(&xilinxfb_of_driver);
>> > > =A0}
>> > >
>> > > =A0module_init(xilinxfb_init);
>> > > =A0module_exit(xilinxfb_cleanup);
>> > >
>> > > =A0MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
>> > > -MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
>> > > +MODULE_DESCRIPTION("Xilinx TFT frame buffer driver");
>> > > =A0MODULE_LICENSE("GPL");
>> > > --
>> > > 1.6.2.1
>> > >
>> > >
>> > >
>> > > This email and any attachments are intended for the sole use of the =
named recipient(s) and
>> > contain(s) confidential information that may be proprietary, privilege=
d or copyrighted under
>> > applicable law. If you are not the intended recipient, do not read, co=
py, or forward this email
>> > message or any attachments. Delete this email message and any attachme=
nts immediately.
>> > >
>> > >
>> > >
>> >
>> >
>> >
>> > --
>> > Grant Likely, B.Sc., P.Eng.
>> > Secret Lab Technologies Ltd.
>>
>>
>> This email and any attachments are intended for the sole use of the name=
d recipient(s) and contain(s)
>> confidential information that may be proprietary, privileged or copyrigh=
ted under applicable law. If
>> you are not the intended recipient, do not read, copy, or forward this e=
mail message or any
>> attachments. Delete this email message and any attachments immediately.
>>
>>
>> _______________________________________________
>> Linuxppc-dev mailing list
>> Linuxppc-dev@ozlabs.org
>> https://ozlabs.org/mailman/listinfo/linuxppc-dev
>
>
> This email and any attachments are intended for the sole use of the named=
 recipient(s) and contain(s) confidential information that may be proprieta=
ry, privileged or copyrighted under applicable law. If you are not the inte=
nded recipient, do not read, copy, or forward this email message or any att=
achments. Delete this email message and any attachments immediately.
>
>
>



--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* Re: [PATCH 1/3] powerpc, Makefile: Make it possible to safely select CONFIG_FRAME_POINTER
From: Steven Rostedt @ 2009-04-13 15:51 UTC (permalink / raw)
  To: Sam Ravnborg; +Cc: linux-kernel, linuxppc-dev, Paul Mackerras, Ingo Molnar
In-Reply-To: <20090405210756.GG24374@uranus.ravnborg.org>


On Sun, 2009-04-05 at 23:07 +0200, Sam Ravnborg wrote:

> 4) The individual "HAVE_* members should be sorted alphabetically in the arch
>    Kconfig file (which they seldomly are :-( )

Note, my first port of Ftrace to PPC sorted the Kconfig HAVE_* macros,
which ended up being reverted :-/

http://www.mail-archive.com/linuxppc-dev@ozlabs.org/msg21222.html

As stated, I did the sort without reporting the change in the
change-log, which I should have done.

-- Steve

^ permalink raw reply

* Re: [PATCH] therm_pm72: Convert to a new-style i2c driver
From: Jean Delvare @ 2009-04-13 14:51 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev
In-Reply-To: <20090413160927.3b8675b8@hyperion.delvare>

On Mon, 13 Apr 2009 16:09:27 +0200, Jean Delvare wrote:
> The legacy i2c binding model is going away soon, so convert the
> macintosh therm_pm72 driver to the new model or it will break.
> 
> This is really a quick and dirty conversion, that should do the trick
> for now, but no doubt that something cleaner can be done if anyone is
> interested.
> 
> Signed-off-by: Jean Delvare <khali@linux-fr.org>
> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> ---
> Can anyone please run-test this patch? I could only build-test it.

Damn, I forgot once again. You need to apply the following patch
beforehand:
ftp://ftp.kernel.org/pub/linux/kernel/people/jdelvare/linux-2.6/jdelvare-i2c/i2c-loosen-driver-check.patch

I'll push this patch to Linus now.

-- 
Jean Delvare

^ permalink raw reply

* RE: [PATCH] [V2] Xilinx : Framebuffer Driver: Add PLB support (non-DCR)
From: John Linn @ 2009-04-13 14:13 UTC (permalink / raw)
  To: Grant Likely
  Cc: linux-fbdev-devel, adaplas, Suneel Garapati, linuxppc-dev,
	akonovalov
In-Reply-To: <fa686aa40904112315j172ef523xc35f7b0b7fa098db@mail.gmail.com>

I thought it was based on mainline, but I now see the weirdness you're talk=
ing about.  I'll dig in on this and let you know more as I'm confused also.=


-- John

> -----Original Message-----
> From: Grant Likely [mailto:grant.likely@secretlab.ca]
> Sent: Sunday, April 12, 2009 12:15 AM
> To: John Linn
> Cc: jwboyer@linux.vnet.ibm.com; linux-fbdev-devel@lists.sourceforge.net; =
linuxppc-dev@ozlabs.org;
> akonovalov@ru.mvista.com; adaplas@gmail.com; Suneel Garapati
> Subject: Re: [PATCH] [V2] Xilinx : Framebuffer Driver: Add PLB support (n=
on-DCR)
> =

> What tree is this patch prepared against?  The version in mainline
> already does PLB access, and doesn't support DCR at all.  It appears
> that this driver is based on something that does the opposite.
> =

> g.
> =

> On Fri, Apr 10, 2009 at 3:17 PM, John Linn <john.linn@xilinx.com> wrote:
> > From: Suneel <suneelg@xilinx.com>
> >
> > Added support for the new xps tft controller.
> >
> > The new core has PLB interface support in addition to existing
> > DCR interface.
> >
> > The driver has been modified to support this new core which
> > can be connected on PLB or DCR bus.
> >
> > Signed-off-by: Suneel <suneelg@xilinx.com>
> > Signed-off-by: John Linn <john.linn@xilinx.com>
> > ---
> >
> > V2 - Incorporated comments from Josh, Grant and others
> >
> > =A0drivers/video/xilinxfb.c | =A0213 ++++++++++++++++++++++++++++++++--=
------------
> > =A01 files changed, 150 insertions(+), 63 deletions(-)
> >
> > diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c
> > index a82c530..d151237 100644
> > --- a/drivers/video/xilinxfb.c
> > +++ b/drivers/video/xilinxfb.c
> > @@ -1,13 +1,13 @@
> > =A0/*
> > - * xilinxfb.c
> > =A0*
> > - * Xilinx TFT LCD frame buffer driver
> > + * Xilinx TFT frame buffer driver
> > =A0*
> > =A0* Author: MontaVista Software, Inc.
> > =A0* =A0 =A0 =A0 =A0 source@mvista.com
> > =A0*
> > =A0* 2002-2007 (c) MontaVista Software, Inc.
> > =A0* 2007 (c) Secret Lab Technologies, Ltd.
> > + * 2009 (c) Xilinx Inc.
> > =A0*
> > =A0* This file is licensed under the terms of the GNU General Public Li=
cense
> > =A0* version 2. =A0This program is licensed "as is" without any warrant=
y of any
> > @@ -31,27 +31,31 @@
> > =A0#include <linux/fb.h>
> > =A0#include <linux/init.h>
> > =A0#include <linux/dma-mapping.h>
> > -#if defined(CONFIG_OF)
> > =A0#include <linux/of_device.h>
> > =A0#include <linux/of_platform.h>
> > -#endif
> > -#include <asm/io.h>
> > +#include <linux/io.h>
> > =A0#include <linux/xilinxfb.h>
> > =A0#include <asm/dcr.h>
> >
> > =A0#define DRIVER_NAME =A0 =A0 =A0 =A0 =A0 =A0"xilinxfb"
> > -#define DRIVER_DESCRIPTION =A0 =A0 "Xilinx TFT LCD frame buffer driver=
"
> > +
> >
> > =A0/*
> > =A0* Xilinx calls it "PLB TFT LCD Controller" though it can also be use=
d for
> > - * the VGA port on the Xilinx ML40x board. This is a hardware display =
controller
> > - * for a 640x480 resolution TFT or VGA screen.
> > + * the VGA port on the Xilinx ML40x board. This is a hardware display
> > + * controller for a 640x480 resolution TFT or VGA screen.
> > =A0*
> > =A0* The interface to the framebuffer is nice and simple. =A0There are =
two
> > =A0* control registers. =A0The first tells the LCD interface where in m=
emory
> > =A0* the frame buffer is (only the 11 most significant bits are used, s=
o
> > =A0* don't start thinking about scrolling). =A0The second allows the LC=
D to
> > =A0* be turned on or off as well as rotated 180 degrees.
> > + *
> > + * In case of direct PLB access the second control register will be at=

> > + * an offset of 4 as compared to the DCR access where the offset is 1
> > + * i.e. REG_CTRL. So this is taken care in the function
> > + * xilinx_fb_out_be32 where it left shifts the offset 2 times in case =
of
> > + * direct PLB access.
> > =A0*/
> > =A0#define NUM_REGS =A0 =A0 =A0 2
> > =A0#define REG_FB_ADDR =A0 =A00
> > @@ -108,10 +112,18 @@ static struct fb_var_screeninfo xilinx_fb_var =3D=
 {
> > =A0 =A0 =A0 =A0.activate =3D =A0 =A0 FB_ACTIVATE_NOW
> > =A0};
> >
> > +
> > +#define PLB_ACCESS_FLAG =A0 =A0 =A0 =A00x1 =A0 =A0 =A0 =A0 =A0 =A0 /* =
1 =3D PLB, 0 =3D DCR */
> > +
> > =A0struct xilinxfb_drvdata {
> >
> > =A0 =A0 =A0 =A0struct fb_info =A0info; =A0 =A0 =A0 =A0 =A0 /* FB driver=
 info record */
> >
> > + =A0 =A0 =A0 phys_addr_t =A0 =A0 regs_phys; =A0 =A0 =A0/* phys. addres=
s of the control
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 registers */
> > + =A0 =A0 =A0 void __iomem =A0 =A0*regs; =A0 =A0 =A0 =A0 =A0/* virt. ad=
dress of the control
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 registers */
> > +
> > =A0 =A0 =A0 =A0dcr_host_t =A0 =A0 =A0dcr_host;
> > =A0 =A0 =A0 =A0unsigned int =A0 =A0dcr_start;
> > =A0 =A0 =A0 =A0unsigned int =A0 =A0dcr_len;
> > @@ -120,6 +132,8 @@ struct xilinxfb_drvdata {
> > =A0 =A0 =A0 =A0dma_addr_t =A0 =A0 =A0fb_phys; =A0 =A0 =A0 =A0/* phys. a=
ddress of the frame buffer */
> > =A0 =A0 =A0 =A0int =A0 =A0 =A0 =A0 =A0 =A0 fb_alloced; =A0 =A0 /* Flag,=
 was the fb memory alloced? */
> >
> > + =A0 =A0 =A0 u8 =A0 =A0 =A0 =A0 =A0 =A0 =A0flags; =A0 =A0 =A0 =A0 =A0/=
* features of the driver */
> > +
> > =A0 =A0 =A0 =A0u32 =A0 =A0 =A0 =A0 =A0 =A0 reg_ctrl_default;
> >
> > =A0 =A0 =A0 =A0u32 =A0 =A0 =A0 =A0 =A0 =A0 pseudo_palette[PALETTE_ENTRI=
ES_NO];
> > @@ -130,14 +144,19 @@ struct xilinxfb_drvdata {
> > =A0 =A0 =A0 =A0container_of(_info, struct xilinxfb_drvdata, info)
> >
> > =A0/*
> > - * The LCD controller has DCR interface to its registers, but all
> > - * the boards and configurations the driver has been tested with
> > - * use opb2dcr bridge. So the registers are seen as memory mapped.
> > - * This macro is to make it simple to add the direct DCR access
> > - * when it's needed.
> > + * The XPS TFT Controller can be accessed through PLB or DCR interface=
.
> > + * To perform the read/write on the registers we need to check on
> > + * which bus its connected and call the appropriate write API.
> > =A0*/
> > -#define xilinx_fb_out_be32(driverdata, offset, val) \
> > - =A0 =A0 =A0 dcr_write(driverdata->dcr_host, offset, val)
> > +static void xilinx_fb_out_be32(struct xilinxfb_drvdata *drvdata, u32 o=
ffset,
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 u32 val)
> > +{
> > + =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG)
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(drvdata->regs + (offset << 2), v=
al);
> > + =A0 =A0 =A0 else
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dcr_write(drvdata->dcr_host, offset, val)=
;
> > +
> > +}
> >
> > =A0static int
> > =A0xilinx_fb_setcolreg(unsigned regno, unsigned red, unsigned green, un=
signed blue,
> > @@ -175,7 +194,8 @@ xilinx_fb_blank(int blank_mode, struct fb_info *fbi=
)
> > =A0 =A0 =A0 =A0switch (blank_mode) {
> > =A0 =A0 =A0 =A0case FB_BLANK_UNBLANK:
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* turn on panel */
> > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 xilinx_fb_out_be32(drvdata, REG_CTRL, drv=
data->reg_ctrl_default);
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 xilinx_fb_out_be32(drvdata, REG_CTRL,
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 drvdata->reg_ctrl_default);
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;
> >
> > =A0 =A0 =A0 =A0case FB_BLANK_NORMAL:
> > @@ -191,8 +211,7 @@ xilinx_fb_blank(int blank_mode, struct fb_info *fbi=
)
> > =A0 =A0 =A0 =A0return 0; /* success */
> > =A0}
> >
> > -static struct fb_ops xilinxfb_ops =3D
> > -{
> > +static struct fb_ops xilinxfb_ops =3D {
> > =A0 =A0 =A0 =A0.owner =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=3D THIS_MODUL=
E,
> > =A0 =A0 =A0 =A0.fb_setcolreg =A0 =A0 =A0 =A0 =A0 =3D xilinx_fb_setcolre=
g,
> > =A0 =A0 =A0 =A0.fb_blank =A0 =A0 =A0 =A0 =A0 =A0 =A0 =3D xilinx_fb_blan=
k,
> > @@ -205,25 +224,35 @@ static struct fb_ops xilinxfb_ops =3D
> > =A0* Bus independent setup/teardown
> > =A0*/
> >
> > -static int xilinxfb_assign(struct device *dev, dcr_host_t dcr_host,
> > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0unsigned int dcr_s=
tart, unsigned int dcr_len,
> > +static int xilinxfb_assign(struct device *dev,
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct xilinxfb_dr=
vdata *drvdata,
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0unsigned long phys=
addr,
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct xilinxfb_pla=
tform_data *pdata)
> > =A0{
> > - =A0 =A0 =A0 struct xilinxfb_drvdata *drvdata;
> > =A0 =A0 =A0 =A0int rc;
> > =A0 =A0 =A0 =A0int fbsize =3D pdata->xvirt * pdata->yvirt * BYTES_PER_P=
IXEL;
> >
> > - =A0 =A0 =A0 /* Allocate the driver data region */
> > - =A0 =A0 =A0 drvdata =3D kzalloc(sizeof(*drvdata), GFP_KERNEL);
> > - =A0 =A0 =A0 if (!drvdata) {
> > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Couldn't allocate device pr=
ivate record\n");
> > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENOMEM;
> > + =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG) {
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* Map the control registers in if the =
controller
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* is on direct PLB interface.
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!request_mem_region(physaddr, 8, DRIV=
ER_NAME)) {
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Couldn't lo=
ck memory region at 0x%08lX\n",
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 physaddr)=
;
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 rc =3D -ENODEV;
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err_region;
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> > +
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 drvdata->regs_phys =3D physaddr;
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 drvdata->regs =3D ioremap(physaddr, 8);
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!drvdata->regs) {
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Couldn't lo=
ck memory region at 0x%08lX\n",
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 physaddr)=
;
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 rc =3D -ENODEV;
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err_map;
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> > =A0 =A0 =A0 =A0}
> > - =A0 =A0 =A0 dev_set_drvdata(dev, drvdata);
> > -
> > - =A0 =A0 =A0 drvdata->dcr_start =3D dcr_start;
> > - =A0 =A0 =A0 drvdata->dcr_len =3D dcr_len;
> > - =A0 =A0 =A0 drvdata->dcr_host =3D dcr_host;
> >
> > =A0 =A0 =A0 =A0/* Allocate the framebuffer memory */
> > =A0 =A0 =A0 =A0if (pdata->fb_phys) {
> > @@ -238,7 +267,10 @@ static int xilinxfb_assign(struct device *dev, dcr=
_host_t dcr_host,
> > =A0 =A0 =A0 =A0if (!drvdata->fb_virt) {
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dev_err(dev, "Could not allocate frame b=
uffer memory\n");
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0rc =3D -ENOMEM;
> > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err_region;
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG)
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err_fbmem;
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 else
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err_region;
> > =A0 =A0 =A0 =A0}
> >
> > =A0 =A0 =A0 =A0/* Clear (turn to black) the framebuffer */
> > @@ -251,7 +283,8 @@ static int xilinxfb_assign(struct device *dev, dcr_=
host_t dcr_host,
> > =A0 =A0 =A0 =A0drvdata->reg_ctrl_default =3D REG_CTRL_ENABLE;
> > =A0 =A0 =A0 =A0if (pdata->rotate_screen)
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0drvdata->reg_ctrl_default |=3D REG_CTRL_=
ROTATE;
> > - =A0 =A0 =A0 xilinx_fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_d=
efault);
> > + =A0 =A0 =A0 xilinx_fb_out_be32(drvdata, REG_CTRL,
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 drvdata->reg_ctrl_default);
> >
> > =A0 =A0 =A0 =A0/* Fill struct fb_info */
> > =A0 =A0 =A0 =A0drvdata->info.device =3D dev;
> > @@ -287,9 +320,14 @@ static int xilinxfb_assign(struct device *dev, dcr=
_host_t dcr_host,
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0goto err_regfb;
> > =A0 =A0 =A0 =A0}
> >
> > + =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG) {
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Put a banner in the log (for DEBUG) */=

> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_dbg(dev, "regs: phys=3D%lx, virt=3D%p=
\n", physaddr,
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 drvdata->regs);
> > + =A0 =A0 =A0 }
> > =A0 =A0 =A0 =A0/* Put a banner in the log (for DEBUG) */
> > =A0 =A0 =A0 =A0dev_dbg(dev, "fb: phys=3D%p, virt=3D%p, size=3D%x\n",
> > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 (void*)drvdata->fb_phys, drvdata->fb_virt=
, fbsize);
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 (void *)drvdata->fb_phys, drvdata->fb_vir=
t, fbsize);
> >
> > =A0 =A0 =A0 =A0return 0; =A0 =A0 =A0 /* success */
> >
> > @@ -300,9 +338,20 @@ err_cmap:
> > =A0 =A0 =A0 =A0if (drvdata->fb_alloced)
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dma_free_coherent(dev, PAGE_ALIGN(fbsize=
), drvdata->fb_virt,
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0drvdata->fb_phys);
> > + =A0 =A0 =A0 else
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 iounmap(drvdata->fb_virt);
> > +
> > =A0 =A0 =A0 =A0/* Turn off the display */
> > =A0 =A0 =A0 =A0xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
> >
> > +err_fbmem:
> > + =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG)
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 iounmap(drvdata->regs);
> > +
> > +err_map:
> > + =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG)
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 release_mem_region(physaddr, 8);
> > +
> > =A0err_region:
> > =A0 =A0 =A0 =A0kfree(drvdata);
> > =A0 =A0 =A0 =A0dev_set_drvdata(dev, NULL);
> > @@ -325,11 +374,18 @@ static int xilinxfb_release(struct device *dev)
> > =A0 =A0 =A0 =A0if (drvdata->fb_alloced)
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dma_free_coherent(dev, PAGE_ALIGN(drvdat=
a->info.fix.smem_len),
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0drvd=
ata->fb_virt, drvdata->fb_phys);
> > + =A0 =A0 =A0 else
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 iounmap(drvdata->fb_virt);
> >
> > =A0 =A0 =A0 =A0/* Turn off the display */
> > =A0 =A0 =A0 =A0xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
> >
> > - =A0 =A0 =A0 dcr_unmap(drvdata->dcr_host, drvdata->dcr_len);
> > + =A0 =A0 =A0 /* Release the resources, as allocated based on interface=
 */
> > + =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG) {
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 iounmap(drvdata->regs);
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 release_mem_region(drvdata->regs_phys, 8)=
;
> > + =A0 =A0 =A0 } else
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dcr_unmap(drvdata->dcr_host, drvdata->dcr=
_len);
> >
> > =A0 =A0 =A0 =A0kfree(drvdata);
> > =A0 =A0 =A0 =A0dev_set_drvdata(dev, NULL);
> > @@ -341,27 +397,54 @@ static int xilinxfb_release(struct device *dev)
> > =A0* OF bus binding
> > =A0*/
> >
> > -#if defined(CONFIG_OF)
> > =A0static int __devinit
> > =A0xilinxfb_of_probe(struct of_device *op, const struct of_device_id *m=
atch)
> > =A0{
> > =A0 =A0 =A0 =A0const u32 *prop;
> > + =A0 =A0 =A0 u32 *p;
> > + =A0 =A0 =A0 u32 tft_access;
> > =A0 =A0 =A0 =A0struct xilinxfb_platform_data pdata;
> > + =A0 =A0 =A0 struct resource res;
> > =A0 =A0 =A0 =A0int size, rc;
> > - =A0 =A0 =A0 int start, len;
> > + =A0 =A0 =A0 int start =3D 0, len =3D 0;
> > =A0 =A0 =A0 =A0dcr_host_t dcr_host;
> > + =A0 =A0 =A0 struct xilinxfb_drvdata *drvdata;
> >
> > =A0 =A0 =A0 =A0/* Copy with the default pdata (not a ptr reference!) */=

> > =A0 =A0 =A0 =A0pdata =3D xilinx_fb_default_pdata;
> >
> > =A0 =A0 =A0 =A0dev_dbg(&op->dev, "xilinxfb_of_probe(%p, %p)\n", op, mat=
ch);
> >
> > - =A0 =A0 =A0 start =3D dcr_resource_start(op->node, 0);
> > - =A0 =A0 =A0 len =3D dcr_resource_len(op->node, 0);
> > - =A0 =A0 =A0 dcr_host =3D dcr_map(op->node, start, len);
> > - =A0 =A0 =A0 if (!DCR_MAP_OK(dcr_host)) {
> > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(&op->dev, "invalid address\n");
> > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENODEV;
> > + =A0 =A0 =A0 /*
> > + =A0 =A0 =A0 =A0* To check whether the core is connected directly to D=
CR or PLB
> > + =A0 =A0 =A0 =A0* interface and initialize the tft_access accordingly.=

> > + =A0 =A0 =A0 =A0*/
> > + =A0 =A0 =A0 p =3D (u32 *)of_get_property(op->node, "xlnx,dcr-splb-sla=
ve-if", NULL);
> > +
> > + =A0 =A0 =A0 if (p)
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tft_access =3D *p;
> > + =A0 =A0 =A0 else
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tft_access =3D 0; =A0 =A0 =A0 =A0 /* For =
backward compatibility */
> > +
> > + =A0 =A0 =A0 /*
> > + =A0 =A0 =A0 =A0* Fill the resource structure if its direct PLB interf=
ace
> > + =A0 =A0 =A0 =A0* otherwise fill the dcr_host structure.
> > + =A0 =A0 =A0 =A0*/
> > + =A0 =A0 =A0 if (tft_access) {
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 rc =3D of_address_to_resource(op->node, 0=
, &res);
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (rc) {
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(&op->dev, "invali=
d address\n");
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENODEV;
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> > +
> > + =A0 =A0 =A0 } else {
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 start =3D dcr_resource_start(op->node, 0)=
;
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 len =3D dcr_resource_len(op->node, 0);
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dcr_host =3D dcr_map(op->node, start, len=
);
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!DCR_MAP_OK(dcr_host)) {
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(&op->dev, "invali=
d address\n");
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENODEV;
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> > =A0 =A0 =A0 =A0}
> >
> > =A0 =A0 =A0 =A0prop =3D of_get_property(op->node, "phys-size", &size);
> > @@ -385,7 +468,26 @@ xilinxfb_of_probe(struct of_device *op, const stru=
ct of_device_id *match)
> > =A0 =A0 =A0 =A0if (of_find_property(op->node, "rotate-display", NULL))
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pdata.rotate_screen =3D 1;
> >
> > - =A0 =A0 =A0 return xilinxfb_assign(&op->dev, dcr_host, start, len, &p=
data);
> > + =A0 =A0 =A0 /* Allocate the driver data region */
> > + =A0 =A0 =A0 drvdata =3D kzalloc(sizeof(*drvdata), GFP_KERNEL);
> > + =A0 =A0 =A0 if (!drvdata) {
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(&op->dev, "Couldn't allocate devi=
ce private record\n");
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENOMEM;
> > + =A0 =A0 =A0 }
> > + =A0 =A0 =A0 dev_set_drvdata(&op->dev, drvdata);
> > +
> > + =A0 =A0 =A0 if (tft_access)
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 drvdata->flags |=3D PLB_ACCESS_FLAG;
> > +
> > + =A0 =A0 =A0 /* Arguments are passed based on the interface */
> > + =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG) {
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return xilinxfb_assign(&op->dev, drvdata,=
 res.start, &pdata);
> > + =A0 =A0 =A0 } else {
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 drvdata->dcr_start =3D start;
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 drvdata->dcr_len =3D len;
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 drvdata->dcr_host =3D dcr_host;
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return xilinxfb_assign(&op->dev, drvdata,=
 0, &pdata);
> > + =A0 =A0 =A0 }
> > =A0}
> >
> > =A0static int __devexit xilinxfb_of_remove(struct of_device *op)
> > @@ -395,6 +497,7 @@ static int __devexit xilinxfb_of_remove(struct of_d=
evice *op)
> >
> > =A0/* Match table for of_platform binding */
> > =A0static struct of_device_id xilinxfb_of_match[] __devinitdata =3D {
> > + =A0 =A0 =A0 { .compatible =3D "xlnx,xps-tft-1.00.a", },
> > =A0 =A0 =A0 =A0{ .compatible =3D "xlnx,plb-tft-cntlr-ref-1.00.a", },
> > =A0 =A0 =A0 =A0{ .compatible =3D "xlnx,plb-dvi-cntlr-ref-1.00.c", },
> > =A0 =A0 =A0 =A0{},
> > @@ -412,22 +515,6 @@ static struct of_platform_driver xilinxfb_of_drive=
r =3D {
> > =A0 =A0 =A0 =A0},
> > =A0};
> >
> > -/* Registration helpers to keep the number of #ifdefs to a minimum */
> > -static inline int __init xilinxfb_of_register(void)
> > -{
> > - =A0 =A0 =A0 pr_debug("xilinxfb: calling of_register_platform_driver()=
\n");
> > - =A0 =A0 =A0 return of_register_platform_driver(&xilinxfb_of_driver);
> > -}
> > -
> > -static inline void __exit xilinxfb_of_unregister(void)
> > -{
> > - =A0 =A0 =A0 of_unregister_platform_driver(&xilinxfb_of_driver);
> > -}
> > -#else /* CONFIG_OF */
> > -/* CONFIG_OF not enabled; do nothing helpers */
> > -static inline int __init xilinxfb_of_register(void) { return 0; }
> > -static inline void __exit xilinxfb_of_unregister(void) { }
> > -#endif /* CONFIG_OF */
> >
> > =A0/* -----------------------------------------------------------------=
----
> > =A0* Module setup and teardown
> > @@ -436,18 +523,18 @@ static inline void __exit xilinxfb_of_unregister(=
void) { }
> > =A0static int __init
> > =A0xilinxfb_init(void)
> > =A0{
> > - =A0 =A0 =A0 return xilinxfb_of_register();
> > + =A0 =A0 =A0 return of_register_platform_driver(&xilinxfb_of_driver);
> > =A0}
> >
> > =A0static void __exit
> > =A0xilinxfb_cleanup(void)
> > =A0{
> > - =A0 =A0 =A0 xilinxfb_of_unregister();
> > + =A0 =A0 =A0 of_unregister_platform_driver(&xilinxfb_of_driver);
> > =A0}
> >
> > =A0module_init(xilinxfb_init);
> > =A0module_exit(xilinxfb_cleanup);
> >
> > =A0MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
> > -MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
> > +MODULE_DESCRIPTION("Xilinx TFT frame buffer driver");
> > =A0MODULE_LICENSE("GPL");
> > --
> > 1.6.2.1
> >
> >
> >
> > This email and any attachments are intended for the sole use of the nam=
ed recipient(s) and
> contain(s) confidential information that may be proprietary, privileged o=
r copyrighted under
> applicable law. If you are not the intended recipient, do not read, copy,=
 or forward this email
> message or any attachments. Delete this email message and any attachments=
 immediately.
> >
> >
> >
> =

> =

> =

> --
> Grant Likely, B.Sc., P.Eng.
> Secret Lab Technologies Ltd.


This email and any attachments are intended for the sole use of the named r=
ecipient(s) and contain(s) confidential information that may be proprietary=
, privileged or copyrighted under applicable law. If you are not the intend=
ed recipient, do not read, copy, or forward this email message or any attac=
hments. Delete this email message and any attachments immediately.

^ permalink raw reply

* [PATCH] therm_pm72: Convert to a new-style i2c driver
From: Jean Delvare @ 2009-04-13 14:09 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev

The legacy i2c binding model is going away soon, so convert the
macintosh therm_pm72 driver to the new model or it will break.

This is really a quick and dirty conversion, that should do the trick
for now, but no doubt that something cleaner can be done if anyone is
interested.

Signed-off-by: Jean Delvare <khali@linux-fr.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
Can anyone please run-test this patch? I could only build-test it.

 drivers/macintosh/therm_pm72.c |   95 +++++++++++++++++++---------------------
 1 file changed, 47 insertions(+), 48 deletions(-)

--- linux-2.6.30-rc1.orig/drivers/macintosh/therm_pm72.c	2009-04-12 08:49:54.000000000 +0200
+++ linux-2.6.30-rc1/drivers/macintosh/therm_pm72.c	2009-04-13 09:50:50.000000000 +0200
@@ -287,22 +287,6 @@ struct fcu_fan_table	fcu_fans[] = {
 };
 
 /*
- * i2c_driver structure to attach to the host i2c controller
- */
-
-static int therm_pm72_attach(struct i2c_adapter *adapter);
-static int therm_pm72_detach(struct i2c_adapter *adapter);
-
-static struct i2c_driver therm_pm72_driver =
-{
-	.driver = {
-		.name	= "therm_pm72",
-	},
-	.attach_adapter	= therm_pm72_attach,
-	.detach_adapter	= therm_pm72_detach,
-};
-
-/*
  * Utility function to create an i2c_client structure and
  * attach it to one of u3 adapters
  */
@@ -310,6 +294,7 @@ static struct i2c_client *attach_i2c_chi
 {
 	struct i2c_client *clt;
 	struct i2c_adapter *adap;
+	struct i2c_board_info info;
 
 	if (id & 0x200)
 		adap = k2;
@@ -320,31 +305,21 @@ static struct i2c_client *attach_i2c_chi
 	if (adap == NULL)
 		return NULL;
 
-	clt = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-	if (clt == NULL)
-		return NULL;
-
-	clt->addr = (id >> 1) & 0x7f;
-	clt->adapter = adap;
-	clt->driver = &therm_pm72_driver;
-	strncpy(clt->name, name, I2C_NAME_SIZE-1);
-
-	if (i2c_attach_client(clt)) {
+	memset(&info, 0, sizeof(struct i2c_board_info));
+	info.addr = (id >> 1) & 0x7f;
+	strlcpy(info.type, "therm_pm72", I2C_NAME_SIZE);
+	clt = i2c_new_device(adap, &info);
+	if (!clt) {
 		printk(KERN_ERR "therm_pm72: Failed to attach to i2c ID 0x%x\n", id);
-		kfree(clt);
 		return NULL;
 	}
-	return clt;
-}
 
-/*
- * Utility function to get rid of the i2c_client structure
- * (will also detach from the adapter hopepfully)
- */
-static void detach_i2c_chip(struct i2c_client *clt)
-{
-	i2c_detach_client(clt);
-	kfree(clt);
+	/*
+	 * Let i2c-core delete that device on driver removal.
+	 * This is safe because i2c-core holds the core_lock mutex for us.
+	 */
+	list_add_tail(&clt->detected, &clt->driver->clients);
+	return clt;
 }
 
 /*
@@ -1203,8 +1178,6 @@ static int init_cpu_state(struct cpu_pid
 
 	return 0;
  fail:
-	if (state->monitor)
-		detach_i2c_chip(state->monitor);
 	state->monitor = NULL;
 	
 	return -ENODEV;
@@ -1232,7 +1205,6 @@ static void dispose_cpu_state(struct cpu
 		device_remove_file(&of_dev->dev, &dev_attr_cpu1_intake_fan_rpm);
 	}
 
-	detach_i2c_chip(state->monitor);
 	state->monitor = NULL;
 }
 
@@ -1407,7 +1379,6 @@ static void dispose_backside_state(struc
 	device_remove_file(&of_dev->dev, &dev_attr_backside_temperature);
 	device_remove_file(&of_dev->dev, &dev_attr_backside_fan_pwm);
 
-	detach_i2c_chip(state->monitor);
 	state->monitor = NULL;
 }
  
@@ -1532,7 +1503,6 @@ static void dispose_drives_state(struct
 	device_remove_file(&of_dev->dev, &dev_attr_drives_temperature);
 	device_remove_file(&of_dev->dev, &dev_attr_drives_fan_rpm);
 
-	detach_i2c_chip(state->monitor);
 	state->monitor = NULL;
 }
 
@@ -1654,7 +1624,6 @@ static void dispose_dimms_state(struct d
 
 	device_remove_file(&of_dev->dev, &dev_attr_dimms_temperature);
 
-	detach_i2c_chip(state->monitor);
 	state->monitor = NULL;
 }
 
@@ -1779,7 +1748,6 @@ static void dispose_slots_state(struct s
 	device_remove_file(&of_dev->dev, &dev_attr_slots_temperature);
 	device_remove_file(&of_dev->dev, &dev_attr_slots_fan_pwm);
 
-	detach_i2c_chip(state->monitor);
 	state->monitor = NULL;
 }
 
@@ -2008,8 +1976,6 @@ static int attach_fcu(void)
  */
 static void detach_fcu(void)
 {
-	if (fcu)
-		detach_i2c_chip(fcu);
 	fcu = NULL;
 }
 
@@ -2060,12 +2026,21 @@ static int therm_pm72_attach(struct i2c_
 	return 0;
 }
 
+static int therm_pm72_probe(struct i2c_client *client,
+			    const struct i2c_device_id *id)
+{
+	/* Always succeed, the real work was done in therm_pm72_attach() */
+	return 0;
+}
+
 /*
- * Called on every adapter when the driver or the i2c controller
+ * Called when any of the devices which participates into thermal management
  * is going away.
  */
-static int therm_pm72_detach(struct i2c_adapter *adapter)
+static int therm_pm72_remove(struct i2c_client *client)
 {
+	struct i2c_adapter *adapter = client->adapter;
+
 	mutex_lock(&driver_lock);
 
 	if (state != state_detached)
@@ -2096,6 +2071,30 @@ static int therm_pm72_detach(struct i2c_
 	return 0;
 }
 
+/*
+ * i2c_driver structure to attach to the host i2c controller
+ */
+
+static const struct i2c_device_id therm_pm72_id[] = {
+	/*
+	 * Fake device name, thermal management is done by several
+	 * chips but we don't need to differentiate between them at
+	 * this point.
+	 */
+	{ "therm_pm72", 0 },
+	{ }
+};
+
+static struct i2c_driver therm_pm72_driver = {
+	.driver = {
+		.name	= "therm_pm72",
+	},
+	.attach_adapter	= therm_pm72_attach,
+	.probe		= therm_pm72_probe,
+	.remove		= therm_pm72_remove,
+	.id_table	= therm_pm72_id,
+};
+
 static int fan_check_loc_match(const char *loc, int fan)
 {
 	char	tmp[64];


-- 
Jean Delvare

^ permalink raw reply

* Help!Some memory doesn't work on PPC405Ex based board!
From: SunNeo @ 2009-04-13 12:05 UTC (permalink / raw)
  To: linuxppc-dev

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


Hi, All,
I'm porting Linux-2.6.29 on PPC405Ex based board, it's very similar to AMCC "Kilauea" evb.

 

In my board, two 512MB DDRII memory is connected to 2 ranks of the 405Ex CPU. This 1GB memory works well at U-Boot-2009.01, but when I boot Linux-2.6.29, the kernel hangs somewhere. What interesting is, if I configured the system to use only 512MB memory at U-Boot, the Linux can boot normally.

 

The following is some error info I dumped:

 

<6>Using Kilauea machine description
<5>Linux version 2.6.29.1 (root@localhost.localdomain) (gcc version 4.2.2) #4 Mon Apr 13 19:26:57 CST 2009
<4>Found initrd at 0xeedaa000:0xeffff8f3
<7>Found legacy serial port 0 for /plb/opb/serial@ef600200
<7>  mem=ef600200, taddr=ef600200, irq=0, clk=7407407, speed=0
<7>Found legacy serial port 1 for /plb/opb/serial@ef600300
<7>  mem=ef600300, taddr=ef600300, irq=0, clk=7407407, speed=0
<7>Top of RAM: 0x40000000, Total RAM: 0x40000000
<7>Memory hole size: 0MB
<4>Zone PFN ranges:
<4>  DMA      0x00000000 -> 0x00030000
<4>  Normal   0x00030000 -> 0x00030000
<4>  HighMem  0x00030000 -> 0x00040000
<4>Movable zone start PFN for each node
<4>early_node_map[1] active PFN ranges
<4>    0: 0x00000000 -> 0x00040000
<7>On node 0 totalpages: 262144
<7>free_area_init_node: node 0, pgdat c03304a0, node_mem_map c07fd000
<7>  DMA zone: 1536 pages used for memmap
<7>  DMA zone: 0 pages reserved
<7>  DMA zone: 195072 pages, LIFO batch:31
<7>  HighMem zone: 512 pages used for memmap
<7>  HighMem zone: 65024 pages, LIFO batch:15
<6>MMU: Allocated 1088 bytes of context maps for 255 contexts
<4>Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 260096
<5>Kernel command line: ramdisk_size=65536 root=/dev/ram rw ip=10.204.29.214:10.204.29.153:10.204.28.1:255.255.252.0:obs600:eth0:off panic=1 console=ttyS0,115200
<4>UIC0 (32 IRQ sources) at DCR 0xc0
<4>UIC1 (32 IRQ sources) at DCR 0xd0
<4>UIC2 (32 IRQ sources) at DCR 0xe0
<4>PID hash table entries: 4096 (order: 12, 16384 bytes)
<7>time_init: decrementer frequency = 400.000000 MHz
<7>time_init: processor frequency   = 400.000000 MHz
<6>clocksource: timebase mult[a00000] shift[22] registered
<7>clockevent: decrementer mult[6666] shift[16] cpu[0]
<6>Dentry cache hash table entries: 131072 (order: 7, 524288 bytes)
<6>Inode-cache hash table entries: 65536 (order: 6, 262144 bytes)
<7>High memory: 262144k
<6>Memory: 1016784k/1048576k available (3136k kernel code, 31244k reserved, 136k data, 140k bss, 144k init)
<6>SLUB: Genslabs=10, HWalign=32, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
<6>Calibrating delay loop... 798.72 BogoMIPS (lpj=1597440)
<4>Mount-cache hash table entries: 512
<4>Instruction machine check in kernel mode.
<4>Oops: Machine check, sig: 7 [#1]
<4>Kilauea
<4>Modules linked in:
<4>NIP: c000c63c LR: c000eb44 CTR: ee82a000
<4>REGS: eeda7f50 TRAP: 0202   Not tainted  (2.6.29.1)
<4>MSR: 00021030 <ME,CE,IR,DR>  CR: 90029030  XER: c0000060
<4>TASK = ee82a3e0[2] 'kthreadd' THREAD: ee82e000
<6>GPR00: 3ffa80dc 3ffae128 ee82a3e0 3ffae138 88000000 00000000 00000000 c023d0ac 
<6>GPR08: c0342e54 c000eb44 00021032 c000c63c c035d000 00000000 3ffb2f00 00000000 
<6>GPR16: 3ffa80dc 3ffae1e8 00000000 00000000 00000000 00000000 00000000 00000000 
<6>GPR24: c03153d0 ee82ffb8 c00350f4 c031544c c0315458 ee82df08 c00350f4 ee82dee4 
<4>NIP [c000c63c] program_check_exception+0x0/0x59c
<4>LR [c000eb44] ret_from_except_full+0x0/0x4c
<4>Call Trace:
<4>Instruction dump:
<4>3920000b 409eff88 4bffff90 813f0080 7fe3fb78 39290004 913f0080 80010014 
<4>83e1000c 7c0803a6 38210010 4bffff14 <9421ffe0> 7c0802a6 7d800026 bfc10018 
<4>---[ end trace 31fd0ba7d8756001 ]---
<4>Oops: Exception in kernel mode, sig: 4 [#2]
<4>Kilauea
<4>Modules linked in:
<4>NIP: ee82ff80 LR: ee82ffb0 CTR: ee82a000
<4>REGS: ee835f50 TRAP: c03153d0   Tainted: G      D     (2.6.29.1)
<4>MSR: c0312318 <FP,DE,DR>  CR: 00029030  XER: c02368e0
<4>TASK = ee82a7c0[3] 'kthreadd' THREAD: ee834000
<6>GPR00: 3ffa80dc ee836000 ee82a7c0 00000000 ee82ffb0 00029030 00000000 ee82ff80 
<6>GPR08: c0312318 00000000 00000000 c0312318 c033b260 00000000 3ffb2f00 00000000 
<6>GPR16: 3ffa80dc 3ffae1e8 00000000 00000000 00000000 00000000 00000000 00000000 
<6>GPR24: c03153d0 ee82ffb8 c00350f4 c031544c c0315458 ee82df08 c00350f4 ee82dee4 
<4>NIP [ee82ff80] 0xee82ff80
<4>LR [ee82ffb0] 0xee82ffb0
<4>Call Trace:
<4>Instruction dump:
<4>XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX 
<4>XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX 
<4>---[ end trace 31fd0ba7d8756002 ]---

 

Please help,

 

Best Regards,

Sun

 

_________________________________________________________________
Messenger安全保护中心,免费修复系统漏洞,保护Messenger安全!
http://im.live.cn/safe/

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

^ permalink raw reply

* Re: "ahci: drop intx manipulation on msi enable" breaks ULI M1575
From: Michael Ellerman @ 2009-04-13 11:34 UTC (permalink / raw)
  To: Jeff Garzik
  Cc: x.xiao, Linux PPC Development, linux-ide, Tejun Heo, Timur Tabi
In-Reply-To: <49DD8871.2030404@garzik.org>

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

On Thu, 2009-04-09 at 01:32 -0400, Jeff Garzik wrote:
> Michael Ellerman wrote:
> > On Wed, 2009-04-08 at 23:23 -0500, Kumar Gala wrote:
> >> On Apr 8, 2009, at 6:53 PM, Michael Ellerman wrote:
> >>
> >>> On Wed, 2009-04-08 at 17:15 -0500, Timur Tabi wrote:
> >>>> On Wed, Apr 8, 2009 at 4:31 PM, Tejun Heo <tj@kernel.org> wrote:
> >>>>> Hmmm... for now,
> >>>>> I think it would be best to revert the original change.  Jeff, can  
> >>>>> you
> >>>>> please do that?
> >>>> Actually, give me a few days before you do that.  A colleague gave me
> >>>> some suggestions to debug this.
> >>> What device did you say it was? A "ULI M1575" ?
> >>>
> >>> Is that this one?
> >>>
> >>> DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x1575,  
> >>> hpcd_quirk_uli1575);
> >>>
> >>> static void __devinit hpcd_quirk_uli1575(struct pci_dev *dev)
> >>> {
> >>>        u32 temp32;
> >>>
> >>>        if (!machine_is(mpc86xx_hpcd))
> >>>                return;
> >>>
> >>>        /* Disable INTx */
> >>>        pci_read_config_dword(dev, 0x48, &temp32);
> >>>        pci_write_config_dword(dev, 0x48, (temp32 | 1<<26));
> >>> ..
> >> It is the odd thing is the board he's running on is a mpc86xx_hpcd so  
> >> he shouldn't be hitting the code that actually disables INTx.
> > 
> > Sorry Kumar that's not parsing :)
> > 
> > He is running an mpc86xx_hpcd, so he _should_ be hitting the code that
> > disables INTX?
> 
> The reversed logic of the PCI bit itself also makes for confusing 
> discusion.  In an attempt to be helpful, here is a restatement of what 
> is happening:
> 
> 1) Old 'ahci' used to clear PCI_COMMAND_INTX_DISABLE, thus ensuring INTX 
> interrupts are enabled... if and only if MSI is unavailable.
> 
> 2) Current 'ahci' no longer does this
> 
> 3) As a result, Timur's 'ahci' is no longer receiving interrupts. 
> Presumably this means that BOTH of the following conditions are true
> 
> 	a) INTX is disabled
> 	b) MSI is not available

Agreed.

> Today I am thinking we should either revert the libata commit 
> (a5bfc4714b3f01365aef89a92673f2ceb1ccf246), or poke PCI to twiddle INTX 
> for us at pci_enable_device() time, perhaps.
> 
> I lean towards the former, but maybe the platform folks prefer a third 
> solution?

But the device should have INTX enabled, the core shouldn't need to
twiddle it. If the device comes up with INTX disabled then it needs a
quirk to turn it on.

But in this case we have a quirk to turn INTX _off_, which just seems
odd. Can anyone say _why_ we need a quirk to turn INTX off? Looking at
the git history that quirk has been there ever since the MPC8610 HPCD
support went in (0e65bfe34c1000581746b9889d095241c4cf4a5c).

cheers

-- 
Michael Ellerman
OzLabs, IBM Australia Development Lab

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

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

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

^ permalink raw reply

* [v2 PATCH 0/3] Add CPC925 Memory Controller EDAC drivers
From: Harry Ciao @ 2009-04-13  6:05 UTC (permalink / raw)
  To: norsk5, michael, bluesmoke-devel, linuxppc-dev; +Cc: linux-kernel


Hi Doug and Michael,

This is the latest v2 patches, the 1/3 of CPC925 MC EDAC driver remains
the same as before, the 2/3 has been pushed to Andrew already, and the 
3/3 has integrated Michael's suggestions to add a fixup routine for the 
memory controller on Maple that has incorrect number of cells, and create
related platform_device for CPC925 on Motorola ATCA-6101 target by far.

All patches have been tested, please give me your further concerns or 
suggestions, thanks!

Best regards,

Harry

^ permalink raw reply

* [v2 PATCH 2/3] EDAC: Add edac_device_alloc_index()
From: Harry Ciao @ 2009-04-13  6:05 UTC (permalink / raw)
  To: norsk5, michael, bluesmoke-devel, linuxppc-dev; +Cc: linux-kernel
In-Reply-To: <1239602716-18352-2-git-send-email-qingtao.cao@windriver.com>

Add edac_device_alloc_index(), because for MAPLE platform there may
exist several EDAC driver modules that could make use of
edac_device_ctl_info structure at the same time. The index allocation
for these structures should be taken care of by EDAC core.

Signed-off-by: Harry Ciao <qingtao.cao@windriver.com>
---
 drivers/edac/amd8111_edac.c |    3 +--
 drivers/edac/edac_core.h    |    1 +
 drivers/edac/edac_device.c  |   13 +++++++++++++
 3 files changed, 15 insertions(+), 2 deletions(-)

--- a/drivers/edac/amd8111_edac.c
+++ b/drivers/edac/amd8111_edac.c
@@ -37,7 +37,6 @@
 #define AMD8111_EDAC_MOD_STR	"amd8111_edac"
 
 #define PCI_DEVICE_ID_AMD_8111_PCI	0x7460
-static int edac_dev_idx;
 
 enum amd8111_edac_devs {
 	LPC_BRIDGE = 0,
@@ -377,7 +376,7 @@ static int amd8111_dev_probe(struct pci_
 	 * edac_device_ctl_info, but make use of existing
 	 * one instead.
 	*/
-	dev_info->edac_idx = edac_dev_idx++;
+	dev_info->edac_idx = edac_device_alloc_index();
 	dev_info->edac_dev =
 		edac_device_alloc_ctl_info(0, dev_info->ctl_name, 1,
 					   NULL, 0, 0,
--- a/drivers/edac/edac_core.h
+++ b/drivers/edac/edac_core.h
@@ -819,6 +819,7 @@ extern void edac_device_handle_ue(struct
 				int inst_nr, int block_nr, const char *msg);
 extern void edac_device_handle_ce(struct edac_device_ctl_info *edac_dev,
 				int inst_nr, int block_nr, const char *msg);
+extern int edac_device_alloc_index(void);
 
 /*
  * edac_pci APIs
--- a/drivers/edac/edac_device.c
+++ b/drivers/edac/edac_device.c
@@ -37,6 +37,7 @@
  */
 static DEFINE_MUTEX(device_ctls_mutex);
 static LIST_HEAD(edac_device_list);
+static atomic_t device_indexes = ATOMIC_INIT(0);
 
 #ifdef CONFIG_EDAC_DEBUG
 static void edac_device_dump_device(struct edac_device_ctl_info *edac_dev)
@@ -490,6 +491,18 @@ void edac_device_reset_delay_period(stru
 	mutex_unlock(&device_ctls_mutex);
 }
 
+/*
+ * edac_device_alloc_index: Allocate a unique device index number
+ *
+ * Return:
+ *	allocated index number
+ */
+int edac_device_alloc_index(void)
+{
+	return atomic_inc_return(&device_indexes) - 1;
+}
+EXPORT_SYMBOL_GPL(edac_device_alloc_index);
+
 /**
  * edac_device_add_device: Insert the 'edac_dev' structure into the
  * edac_device global list and create sysfs entries associated with

^ permalink raw reply

* [v2 PATCH 1/3] EDAC: Add CPC925 Memory Controller driver
From: Harry Ciao @ 2009-04-13  6:05 UTC (permalink / raw)
  To: norsk5, michael, bluesmoke-devel, linuxppc-dev; +Cc: linux-kernel
In-Reply-To: <1239602716-18352-1-git-send-email-qingtao.cao@windriver.com>

Introduce IBM CPC925 EDAC driver, which makes use of ECC, CPU and
HyperTransport Link error detections and corrections on the IBM
CPC925 Bridge and Memory Controller.

Signed-off-by: Harry Ciao <qingtao.cao@windriver.com>
---
 drivers/edac/Kconfig       |    9 +
 drivers/edac/Makefile      |    1 +
 drivers/edac/cpc925_edac.c | 1020 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1030 insertions(+), 0 deletions(-)
 create mode 100644 drivers/edac/cpc925_edac.c

diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 13ccec6..1a320b4 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -188,4 +188,13 @@ config EDAC_AMD8131
 	  Support for error detection and correction on the
 	  AMD8131 HyperTransport PCI-X Tunnel chip.
 
+config EDAC_CPC925
+	tristate "IBM CPC925 Memory Controller (PPC970FX)"
+	depends on EDAC_MM_EDAC && PPC64
+	help
+	  Support for error detection and correction on the
+	  IBM CPC925 Bridge and Memory Controller, which is
+	  a companion chip to the PowerPC 970 family of
+	  processors.
+
 endif # EDAC
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index 407601f..b4e0d86 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -36,4 +36,5 @@ obj-$(CONFIG_EDAC_MV64X60)		+= mv64x60_edac.o
 obj-$(CONFIG_EDAC_CELL)			+= cell_edac.o
 obj-$(CONFIG_EDAC_AMD8111)		+= amd8111_edac.o
 obj-$(CONFIG_EDAC_AMD8131)		+= amd8131_edac.o
+obj-$(CONFIG_EDAC_CPC925)		+= cpc925_edac.o
 
diff --git a/drivers/edac/cpc925_edac.c b/drivers/edac/cpc925_edac.c
new file mode 100644
index 0000000..7236847
--- /dev/null
+++ b/drivers/edac/cpc925_edac.c
@@ -0,0 +1,1020 @@
+/*
+ * cpc925_edac.c, EDAC driver for IBM CPC925 Bridge and Memory Controller.
+ *
+ * Copyright (c) 2008 Wind River Systems, Inc.
+ *
+ * Authors:	Cao Qingtao <qingtao.cao@windriver.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/edac.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+#define CPC925_EDAC_REVISION	" Ver: 1.0.0 " __DATE__
+#define CPC925_EDAC_MOD_STR	"cpc925_edac"
+
+#define cpc925_printk(level, fmt, arg...) \
+	edac_printk(level, "CPC925", fmt, ##arg)
+
+#define cpc925_mc_printk(mci, level, fmt, arg...) \
+	edac_mc_chipset_printk(mci, level, "CPC925", fmt, ##arg)
+
+/*
+ * CPC925 registers are of 32 bits with bit0 defined at the
+ * most significant bit and bit31 at that of least significant.
+ */
+#define CPC925_BITS_PER_REG	32
+#define CPC925_BIT(nr)		(1UL << (CPC925_BITS_PER_REG - 1 - nr))
+
+/*
+ * EDAC device names for the error detections of
+ * CPU Interface and Hypertransport Link.
+ */
+#define CPC925_CPU_ERR_DEV	"cpu"
+#define CPC925_HT_LINK_DEV	"htlink"
+
+/* Suppose DDR Refresh cycle is 15.6 microsecond */
+#define CPC925_REF_FREQ		0xFA69
+#define CPC925_SCRUB_BLOCK_SIZE 64	/* bytes */
+#define CPC925_NR_CSROWS	8
+
+/*
+ * All registers and bits definitions are taken from
+ * "CPC925 Bridge and Memory Controller User Manual, SA14-2761-02".
+ */
+
+/*
+ * CPU and Memory Controller Registers
+ */
+/************************************************************
+ *	Processor Interface Exception Mask Register (APIMASK)
+ ************************************************************/
+#define REG_APIMASK_OFFSET	0x30070
+enum apimask_bits {
+	APIMASK_DART	= CPC925_BIT(0), /* DART Exception */
+	APIMASK_ADI0	= CPC925_BIT(1), /* Handshake Error on PI0_ADI */
+	APIMASK_ADI1	= CPC925_BIT(2), /* Handshake Error on PI1_ADI */
+	APIMASK_STAT	= CPC925_BIT(3), /* Status Exception */
+	APIMASK_DERR	= CPC925_BIT(4), /* Data Error Exception */
+	APIMASK_ADRS0	= CPC925_BIT(5), /* Addressing Exception on PI0 */
+	APIMASK_ADRS1	= CPC925_BIT(6), /* Addressing Exception on PI1 */
+					 /* BIT(7) Reserved */
+	APIMASK_ECC_UE_H = CPC925_BIT(8), /* UECC upper */
+	APIMASK_ECC_CE_H = CPC925_BIT(9), /* CECC upper */
+	APIMASK_ECC_UE_L = CPC925_BIT(10), /* UECC lower */
+	APIMASK_ECC_CE_L = CPC925_BIT(11), /* CECC lower */
+
+	CPU_MASK_ENABLE = (APIMASK_DART | APIMASK_ADI0 | APIMASK_ADI1 |
+			   APIMASK_STAT | APIMASK_DERR | APIMASK_ADRS0 |
+			   APIMASK_ADRS1),
+	ECC_MASK_ENABLE = (APIMASK_ECC_UE_H | APIMASK_ECC_CE_H |
+			   APIMASK_ECC_UE_L | APIMASK_ECC_CE_L),
+};
+
+/************************************************************
+ *	Processor Interface Exception Register (APIEXCP)
+ ************************************************************/
+#define REG_APIEXCP_OFFSET	0x30060
+enum apiexcp_bits {
+	APIEXCP_DART	= CPC925_BIT(0), /* DART Exception */
+	APIEXCP_ADI0	= CPC925_BIT(1), /* Handshake Error on PI0_ADI */
+	APIEXCP_ADI1	= CPC925_BIT(2), /* Handshake Error on PI1_ADI */
+	APIEXCP_STAT	= CPC925_BIT(3), /* Status Exception */
+	APIEXCP_DERR	= CPC925_BIT(4), /* Data Error Exception */
+	APIEXCP_ADRS0	= CPC925_BIT(5), /* Addressing Exception on PI0 */
+	APIEXCP_ADRS1	= CPC925_BIT(6), /* Addressing Exception on PI1 */
+					 /* BIT(7) Reserved */
+	APIEXCP_ECC_UE_H = CPC925_BIT(8), /* UECC upper */
+	APIEXCP_ECC_CE_H = CPC925_BIT(9), /* CECC upper */
+	APIEXCP_ECC_UE_L = CPC925_BIT(10), /* UECC lower */
+	APIEXCP_ECC_CE_L = CPC925_BIT(11), /* CECC lower */
+
+	CPU_EXCP_DETECTED = (APIEXCP_DART | APIEXCP_ADI0 | APIEXCP_ADI1 |
+			     APIEXCP_STAT | APIEXCP_DERR | APIEXCP_ADRS0 |
+			     APIEXCP_ADRS1),
+	UECC_EXCP_DETECTED = (APIEXCP_ECC_UE_H | APIEXCP_ECC_UE_L),
+	CECC_EXCP_DETECTED = (APIEXCP_ECC_CE_H | APIEXCP_ECC_CE_L),
+	ECC_EXCP_DETECTED = (UECC_EXCP_DETECTED | CECC_EXCP_DETECTED),
+};
+
+/************************************************************
+ *	Memory Bus Configuration Register (MBCR)
+************************************************************/
+#define REG_MBCR_OFFSET		0x2190
+#define MBCR_64BITCFG_SHIFT	23
+#define MBCR_64BITCFG_MASK	(1UL << MBCR_64BITCFG_SHIFT)
+#define MBCR_64BITBUS_SHIFT	22
+#define MBCR_64BITBUS_MASK	(1UL << MBCR_64BITBUS_SHIFT)
+
+/************************************************************
+ *	Memory Bank Mode Register (MBMR)
+************************************************************/
+#define REG_MBMR_OFFSET		0x21C0
+#define MBMR_MODE_MAX_VALUE	0xF
+#define MBMR_MODE_SHIFT		25
+#define MBMR_MODE_MASK		(MBMR_MODE_MAX_VALUE << MBMR_MODE_SHIFT)
+#define MBMR_BBA_SHIFT		24
+#define MBMR_BBA_MASK		(1UL << MBMR_BBA_SHIFT)
+
+/************************************************************
+ *	Memory Bank Boundary Address Register (MBBAR)
+ ************************************************************/
+#define REG_MBBAR_OFFSET	0x21D0
+#define MBBAR_BBA_MAX_VALUE	0xFF
+#define MBBAR_BBA_SHIFT		24
+#define MBBAR_BBA_MASK		(MBBAR_BBA_MAX_VALUE << MBBAR_BBA_SHIFT)
+
+/************************************************************
+ *	Memory Scrub Control Register (MSCR)
+ ************************************************************/
+#define REG_MSCR_OFFSET		0x2400
+#define MSCR_SCRUB_MOD_MASK	0xC0000000 /* scrub_mod - bit0:1*/
+#define MSCR_BACKGR_SCRUB	0x40000000 /* 01 */
+#define MSCR_SI_SHIFT		16 	/* si - bit8:15*/
+#define MSCR_SI_MAX_VALUE	0xFF
+#define MSCR_SI_MASK		(MSCR_SI_MAX_VALUE << MSCR_SI_SHIFT)
+
+/************************************************************
+ *	Memory Scrub Range Start Register (MSRSR)
+ ************************************************************/
+#define REG_MSRSR_OFFSET	0x2410
+
+/************************************************************
+ *	Memory Scrub Range End Register (MSRER)
+ ************************************************************/
+#define REG_MSRER_OFFSET	0x2420
+
+/************************************************************
+ *	Memory Scrub Pattern Register (MSPR)
+ ************************************************************/
+#define REG_MSPR_OFFSET		0x2430
+
+/************************************************************
+ *	Memory Check Control Register (MCCR)
+ ************************************************************/
+#define REG_MCCR_OFFSET		0x2440
+enum mccr_bits {
+	MCCR_ECC_EN	= CPC925_BIT(0), /* ECC high and low check */
+};
+
+/************************************************************
+ *	Memory Check Range End Register (MCRER)
+ ************************************************************/
+#define REG_MCRER_OFFSET	0x2450
+
+/************************************************************
+ *	Memory Error Address Register (MEAR)
+ ************************************************************/
+#define REG_MEAR_OFFSET		0x2460
+#define MEAR_BCNT_MAX_VALUE	0x3
+#define MEAR_BCNT_SHIFT		30
+#define MEAR_BCNT_MASK		(MEAR_BCNT_MAX_VALUE << MEAR_BCNT_SHIFT)
+#define MEAR_RANK_MAX_VALUE	0x7
+#define MEAR_RANK_SHIFT		27
+#define MEAR_RANK_MASK		(MEAR_RANK_MAX_VALUE << MEAR_RANK_SHIFT)
+#define MEAR_COL_MAX_VALUE	0x7FF
+#define MEAR_COL_SHIFT		16
+#define MEAR_COL_MASK		(MEAR_COL_MAX_VALUE << MEAR_COL_SHIFT)
+#define MEAR_BANK_MAX_VALUE	0x3
+#define MEAR_BANK_SHIFT		14
+#define MEAR_BANK_MASK		(MEAR_BANK_MAX_VALUE << MEAR_BANK_SHIFT)
+#define MEAR_ROW_MASK		0x00003FFF
+
+/************************************************************
+ *	Memory Error Syndrome Register (MESR)
+ ************************************************************/
+#define REG_MESR_OFFSET		0x2470
+#define MESR_ECC_SYN_H_MASK	0xFF00
+#define MESR_ECC_SYN_L_MASK	0x00FF
+
+/************************************************************
+ *	Memory Mode Control Register (MMCR)
+ ************************************************************/
+#define REG_MMCR_OFFSET		0x2500
+enum mmcr_bits {
+	MMCR_REG_DIMM_MODE = CPC925_BIT(3),
+};
+
+/*
+ * HyperTransport Link Registers
+ */
+/************************************************************
+ *  Error Handling/Enumeration Scratch Pad Register (ERRCTRL)
+ ************************************************************/
+#define REG_ERRCTRL_OFFSET	0x70140
+enum errctrl_bits {			 /* nonfatal interrupts for */
+	ERRCTRL_SERR_NF	= CPC925_BIT(0), /* system error */
+	ERRCTRL_CRC_NF	= CPC925_BIT(1), /* CRC error */
+	ERRCTRL_RSP_NF	= CPC925_BIT(2), /* Response error */
+	ERRCTRL_EOC_NF	= CPC925_BIT(3), /* End-Of-Chain error */
+	ERRCTRL_OVF_NF	= CPC925_BIT(4), /* Overflow error */
+	ERRCTRL_PROT_NF	= CPC925_BIT(5), /* Protocol error */
+
+	ERRCTRL_RSP_ERR	= CPC925_BIT(6), /* Response error received */
+	ERRCTRL_CHN_FAL = CPC925_BIT(7), /* Sync flooding detected */
+
+	HT_ERRCTRL_ENABLE = (ERRCTRL_SERR_NF | ERRCTRL_CRC_NF |
+			     ERRCTRL_RSP_NF | ERRCTRL_EOC_NF |
+			     ERRCTRL_OVF_NF | ERRCTRL_PROT_NF),
+	HT_ERRCTRL_DETECTED = (ERRCTRL_RSP_ERR | ERRCTRL_CHN_FAL),
+};
+
+/************************************************************
+ *  Link Configuration and Link Control Register (LINKCTRL)
+ ************************************************************/
+#define REG_LINKCTRL_OFFSET	0x70110
+enum linkctrl_bits {
+	LINKCTRL_CRC_ERR	= (CPC925_BIT(22) | CPC925_BIT(23)),
+	LINKCTRL_LINK_FAIL	= CPC925_BIT(27),
+
+	HT_LINKCTRL_DETECTED	= (LINKCTRL_CRC_ERR | LINKCTRL_LINK_FAIL),
+};
+
+/************************************************************
+ *  Link FreqCap/Error/Freq/Revision ID Register (LINKERR)
+ ************************************************************/
+#define REG_LINKERR_OFFSET	0x70120
+enum linkerr_bits {
+	LINKERR_EOC_ERR		= CPC925_BIT(17), /* End-Of-Chain error */
+	LINKERR_OVF_ERR		= CPC925_BIT(18), /* Receive Buffer Overflow */
+	LINKERR_PROT_ERR	= CPC925_BIT(19), /* Protocol error */
+
+	HT_LINKERR_DETECTED	= (LINKERR_EOC_ERR | LINKERR_OVF_ERR |
+				   LINKERR_PROT_ERR),
+};
+
+/************************************************************
+ *	Bridge Control Register (BRGCTRL)
+ ************************************************************/
+#define REG_BRGCTRL_OFFSET	0x70300
+enum brgctrl_bits {
+	BRGCTRL_DETSERR = CPC925_BIT(0), /* SERR on Secondary Bus */
+	BRGCTRL_SECBUSRESET = CPC925_BIT(9), /* Secondary Bus Reset */
+};
+
+/* Private structure for edac memory controller */
+struct cpc925_mc_pdata {
+	void __iomem *vbase;
+	unsigned long total_mem;
+	const char *name;
+	int edac_idx;
+};
+
+/* Private structure for common edac device */
+struct cpc925_dev_info {
+	void __iomem *vbase;
+	struct platform_device *pdev;
+	char *ctl_name;
+	int edac_idx;
+	struct edac_device_ctl_info *edac_dev;
+	void (*init)(struct cpc925_dev_info *dev_info);
+	void (*exit)(struct cpc925_dev_info *dev_info);
+	void (*check)(struct edac_device_ctl_info *edac_dev);
+};
+
+
+static int edac_mc_idx;
+
+/* Get total memory size from Open Firmware DTB */
+static void get_total_mem(struct cpc925_mc_pdata *pdata)
+{
+	struct device_node *np = NULL;
+	const unsigned int *reg, *reg_end;
+	int len, sw, aw;
+	unsigned long start, size;
+
+	np = of_find_node_by_type(NULL, "memory");
+	if (!np)
+		return;
+
+	aw = of_n_addr_cells(np);
+	sw = of_n_size_cells(np);
+	reg = (const unsigned int *)of_get_property(np, "reg", &len);
+	reg_end = reg + len/4;
+
+	pdata->total_mem = 0;
+	do {
+		start = of_read_number(reg, aw);
+		reg += aw;
+		size = of_read_number(reg, sw);
+		reg += sw;
+		debugf1("%s: start 0x%lx, size 0x%lx\n", __func__,
+			start, size);
+		pdata->total_mem += size;
+	} while (reg < reg_end);
+
+	of_node_put(np);
+	debugf0("%s: total_mem 0x%lx\n", __func__, pdata->total_mem);
+}
+
+static void cpc925_init_csrows(struct mem_ctl_info *mci)
+{
+	struct cpc925_mc_pdata *pdata = mci->pvt_info;
+	struct csrow_info *csrow;
+	int index;
+	u32 mbmr, mbbar, bba;
+	unsigned long row_size, last_nr_pages = 0;
+
+	get_total_mem(pdata);
+
+	for (index = 0; index < mci->nr_csrows; index++) {
+		mbmr = __raw_readl(pdata->vbase + REG_MBMR_OFFSET +
+				   0x20 * index);
+		mbbar = __raw_readl(pdata->vbase + REG_MBBAR_OFFSET +
+				   0x20 + index);
+		bba = (((mbmr & MBMR_BBA_MASK) >> MBMR_BBA_SHIFT) << 8) |
+		       ((mbbar & MBBAR_BBA_MASK) >> MBBAR_BBA_SHIFT);
+
+		if (bba == 0)
+			continue; /* not populated */
+
+		csrow = &mci->csrows[index];
+
+		row_size = bba * (1UL << 28);	/* 256M */
+		csrow->first_page = last_nr_pages;
+		csrow->nr_pages = row_size >> PAGE_SHIFT;
+		csrow->last_page = csrow->first_page + csrow->nr_pages - 1;
+		last_nr_pages = csrow->last_page + 1;
+
+		csrow->mtype = MEM_RDDR;
+		csrow->edac_mode = EDAC_SECDED;
+
+		switch (csrow->nr_channels) {
+		case 1: /* Single channel */
+			csrow->grain = 32; /* four-beat burst of 32 bytes */
+			break;
+		case 2: /* Dual channel */
+		default:
+			csrow->grain = 64; /* four-beat burst of 64 bytes */
+			break;
+		}
+
+		switch ((mbmr & MBMR_MODE_MASK) >> MBMR_MODE_SHIFT) {
+		case 6: /* 0110, no way to differentiate X8 VS X16 */
+		case 5:	/* 0101 */
+		case 8: /* 1000 */
+			csrow->dtype = DEV_X16;
+			break;
+		case 7: /* 0111 */
+		case 9: /* 1001 */
+			csrow->dtype = DEV_X8;
+			break;
+		default:
+			csrow->dtype = DEV_UNKNOWN;
+			break;
+		}
+	}
+}
+
+/* Enable memory controller ECC detection */
+static void cpc925_mc_init(struct mem_ctl_info *mci)
+{
+	struct cpc925_mc_pdata *pdata = mci->pvt_info;
+	u32 apimask;
+	u32 mccr;
+
+	/* Enable various ECC error exceptions */
+	apimask = __raw_readl(pdata->vbase + REG_APIMASK_OFFSET);
+	if ((apimask & ECC_MASK_ENABLE) == 0) {
+		apimask |= ECC_MASK_ENABLE;
+		__raw_writel(apimask, pdata->vbase + REG_APIMASK_OFFSET);
+	}
+
+	/* Enable ECC detection */
+	mccr = __raw_readl(pdata->vbase + REG_MCCR_OFFSET);
+	if ((mccr & MCCR_ECC_EN) == 0) {
+		mccr |= MCCR_ECC_EN;
+		__raw_writel(mccr, pdata->vbase + REG_MCCR_OFFSET);
+	}
+}
+
+/* Disable memory controller ECC detection */
+static void cpc925_mc_exit(struct mem_ctl_info *mci)
+{
+	/*
+	 * WARNING:
+	 * We are supposed to clear the ECC error detection bits,
+	 * and it will be no problem to do so. However, once they
+	 * are cleared here if we want to re-install CPC925 EDAC
+	 * module later, setting them up in cpc925_mc_init() will
+	 * trigger machine check exception.
+	 * Also, it's ok to leave ECC error detection bits enabled,
+	 * since they are reset to 1 by default or by boot loader.
+	 */
+
+	return;
+}
+
+/*
+ * Revert DDR column/row/bank addresses into page frame number and
+ * offset in page.
+ *
+ * Suppose memory mode is 0x0111(128-bit mode, identical DIMM pairs),
+ * physical address(PA) bits to column address(CA) bits mappings are:
+ * CA	0   1   2   3   4   5   6   7   8   9   10
+ * PA	59  58  57  56  55  54  53  52  51  50  49
+ *
+ * physical address(PA) bits to bank address(BA) bits mappings are:
+ * BA	0   1
+ * PA	43  44
+ *
+ * physical address(PA) bits to row address(RA) bits mappings are:
+ * RA	0   1   2   3   4   5   6   7   8   9   10   11   12
+ * PA	36  35  34  48  47  46  45  40  41  42  39   38   37
+ */
+static void cpc925_mc_get_pfn(struct mem_ctl_info *mci, u32 mear,
+		unsigned long *pfn, unsigned long *offset, int *csrow)
+{
+	u32 bcnt, rank, col, bank, row;
+	u32 c;
+	unsigned long pa;
+	int i;
+
+	bcnt = (mear & MEAR_BCNT_MASK) >> MEAR_BCNT_SHIFT;
+	rank = (mear & MEAR_RANK_MASK) >> MEAR_RANK_SHIFT;
+	col = (mear & MEAR_COL_MASK) >> MEAR_COL_SHIFT;
+	bank = (mear & MEAR_BANK_MASK) >> MEAR_BANK_SHIFT;
+	row = mear & MEAR_ROW_MASK;
+
+	*csrow = rank;
+
+#ifdef CONFIG_EDAC_DEBUG
+	if (mci->csrows[rank].first_page == 0) {
+		cpc925_mc_printk(mci, KERN_ERR, "ECC occurs in a "
+			"non-populated csrow, broken hardware?\n");
+		return;
+	}
+#endif
+
+	/* Revert csrow number */
+	pa = mci->csrows[rank].first_page << PAGE_SHIFT;
+
+	/* Revert column address */
+	col += bcnt;
+	for (i = 0; i < 11; i++) {
+		c = col & 0x1;
+		col >>= 1;
+		pa |= c << (14 - i);
+	}
+
+	/* Revert bank address */
+	pa |= bank << 19;
+
+	/* Revert row address, in 4 steps */
+	for (i = 0; i < 3; i++) {
+		c = row & 0x1;
+		row >>= 1;
+		pa |= c << (26 - i);
+	}
+
+	for (i = 0; i < 3; i++) {
+		c = row & 0x1;
+		row >>= 1;
+		pa |= c << (21 + i);
+	}
+
+	for (i = 0; i < 4; i++) {
+		c = row & 0x1;
+		row >>= 1;
+		pa |= c << (18 - i);
+	}
+
+	for (i = 0; i < 3; i++) {
+		c = row & 0x1;
+		row >>= 1;
+		pa |= c << (29 - i);
+	}
+
+	*offset = pa & (PAGE_SIZE - 1);
+	*pfn = pa >> PAGE_SHIFT;
+
+	debugf0("%s: ECC physical address 0x%lx\n", __func__, pa);
+}
+
+static int cpc925_mc_find_channel(struct mem_ctl_info *mci, u16 syndrome)
+{
+	if ((syndrome & MESR_ECC_SYN_H_MASK) == 0)
+		return 0;
+
+	if ((syndrome & MESR_ECC_SYN_L_MASK) == 0)
+		return 1;
+
+	cpc925_mc_printk(mci, KERN_INFO, "Unexpected syndrome value: 0x%x\n",
+			 syndrome);
+	return 1;
+}
+
+/* Check memory controller registers for ECC errors */
+static void cpc925_mc_check(struct mem_ctl_info *mci)
+{
+	struct cpc925_mc_pdata *pdata = mci->pvt_info;
+	u32 apiexcp;
+	u32 mear;
+	u32 mesr;
+	u16 syndrome;
+	unsigned long pfn = 0, offset = 0;
+	int csrow = 0, channel = 0;
+
+	/* APIEXCP is cleared when read */
+	apiexcp = __raw_readl(pdata->vbase + REG_APIEXCP_OFFSET);
+	if ((apiexcp & ECC_EXCP_DETECTED) == 0)
+		return;
+
+	mesr = __raw_readl(pdata->vbase + REG_MESR_OFFSET);
+	syndrome = mesr | (MESR_ECC_SYN_H_MASK | MESR_ECC_SYN_L_MASK);
+
+	mear = __raw_readl(pdata->vbase + REG_MEAR_OFFSET);
+
+	/* Revert column/row addresses into page frame number, etc */
+	cpc925_mc_get_pfn(mci, mear, &pfn, &offset, &csrow);
+
+	if (apiexcp & UECC_EXCP_DETECTED) {
+		cpc925_mc_printk(mci, KERN_INFO, "DRAM UECC Fault\n");
+		channel = cpc925_mc_find_channel(mci, syndrome);
+		edac_mc_handle_ce(mci, pfn, offset, syndrome,
+				  csrow, channel, mci->ctl_name);
+	}
+
+	if (apiexcp & CECC_EXCP_DETECTED) {
+		cpc925_mc_printk(mci, KERN_INFO, "DRAM CECC Fault\n");
+		edac_mc_handle_ue(mci, pfn, offset,
+				  csrow, mci->ctl_name);
+	}
+
+	cpc925_mc_printk(mci, KERN_INFO, "Dump registers:\n");
+	cpc925_mc_printk(mci, KERN_INFO, "APIMASK		0x%08x\n",
+		__raw_readl(pdata->vbase + REG_APIMASK_OFFSET));
+	cpc925_mc_printk(mci, KERN_INFO, "APIEXCP		0x%08x\n",
+		apiexcp);
+	cpc925_mc_printk(mci, KERN_INFO, "Mem Scrub Ctrl	0x%08x\n",
+		__raw_readl(pdata->vbase + REG_MSCR_OFFSET));
+	cpc925_mc_printk(mci, KERN_INFO, "Mem Scrub Rge Start	0x%08x\n",
+		__raw_readl(pdata->vbase + REG_MSRSR_OFFSET));
+	cpc925_mc_printk(mci, KERN_INFO, "Mem Scrub Rge End	0x%08x\n",
+		__raw_readl(pdata->vbase + REG_MSRER_OFFSET));
+	cpc925_mc_printk(mci, KERN_INFO, "Mem Scrub Pattern	0x%08x\n",
+		__raw_readl(pdata->vbase + REG_MSPR_OFFSET));
+	cpc925_mc_printk(mci, KERN_INFO, "Mem Chk Ctrl		0x%08x\n",
+		__raw_readl(pdata->vbase + REG_MCCR_OFFSET));
+	cpc925_mc_printk(mci, KERN_INFO, "Mem Chk Rge End	0x%08x\n",
+		__raw_readl(pdata->vbase + REG_MCRER_OFFSET));
+	cpc925_mc_printk(mci, KERN_INFO, "Mem Err Address	0x%08x\n",
+		mesr);
+	cpc925_mc_printk(mci, KERN_INFO, "Mem Err Syndrome	0x%08x\n",
+		syndrome);
+}
+
+/******************** CPU err device********************************/
+/* Enable CPU Errors detection */
+static void cpc925_cpu_init(struct cpc925_dev_info *dev_info)
+{
+	u32 apimask;
+
+	apimask = __raw_readl(dev_info->vbase + REG_APIMASK_OFFSET);
+	if ((apimask & CPU_MASK_ENABLE) == 0) {
+		apimask |= CPU_MASK_ENABLE;
+		__raw_writel(apimask, dev_info->vbase + REG_APIMASK_OFFSET);
+	}
+}
+
+/* Disable CPU Errors detection */
+static void cpc925_cpu_exit(struct cpc925_dev_info *dev_info)
+{
+	/*
+	 * WARNING:
+	 * We are supposed to clear the CPU error detection bits,
+	 * and it will be no problem to do so. However, once they
+	 * are cleared here if we want to re-install CPC925 EDAC
+	 * module later, setting them up in cpc925_cpu_init() will
+	 * trigger machine check exception.
+	 * Also, it's ok to leave CPU error detection bits enabled,
+	 * since they are reset to 1 by default.
+	 */
+
+	return;
+}
+
+/* Check for CPU Errors */
+static void cpc925_cpu_check(struct edac_device_ctl_info *edac_dev)
+{
+	struct cpc925_dev_info *dev_info = edac_dev->pvt_info;
+	u32 apiexcp;
+	u32 apimask;
+
+	/* APIEXCP is cleared when read */
+	apiexcp = __raw_readl(dev_info->vbase + REG_APIEXCP_OFFSET);
+	if ((apiexcp & CPU_EXCP_DETECTED) == 0)
+		return;
+
+	apimask = __raw_readl(dev_info->vbase + REG_APIMASK_OFFSET);
+	cpc925_printk(KERN_INFO, "Processor Interface Fault\n"
+				 "Processor Interface register dump:\n");
+	cpc925_printk(KERN_INFO, "APIMASK		0x%08x\n", apimask);
+	cpc925_printk(KERN_INFO, "APIEXCP		0x%08x\n", apiexcp);
+
+	edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name);
+}
+
+/******************** HT Link err device****************************/
+/* Enable HyperTransport Link Error detection */
+static void cpc925_htlink_init(struct cpc925_dev_info *dev_info)
+{
+	u32 ht_errctrl;
+
+	ht_errctrl = __raw_readl(dev_info->vbase + REG_ERRCTRL_OFFSET);
+	if ((ht_errctrl & HT_ERRCTRL_ENABLE) == 0) {
+		ht_errctrl |= HT_ERRCTRL_ENABLE;
+		__raw_writel(ht_errctrl, dev_info->vbase + REG_ERRCTRL_OFFSET);
+	}
+}
+
+/* Disable HyperTransport Link Error detection */
+static void cpc925_htlink_exit(struct cpc925_dev_info *dev_info)
+{
+	u32 ht_errctrl;
+
+	ht_errctrl = __raw_readl(dev_info->vbase + REG_ERRCTRL_OFFSET);
+	ht_errctrl &= ~HT_ERRCTRL_ENABLE;
+	__raw_writel(ht_errctrl, dev_info->vbase + REG_ERRCTRL_OFFSET);
+}
+
+/* Check for HyperTransport Link errors */
+static void cpc925_htlink_check(struct edac_device_ctl_info *edac_dev)
+{
+	struct cpc925_dev_info *dev_info = edac_dev->pvt_info;
+	u32 brgctrl = __raw_readl(dev_info->vbase + REG_BRGCTRL_OFFSET);
+	u32 linkctrl = __raw_readl(dev_info->vbase + REG_LINKCTRL_OFFSET);
+	u32 errctrl = __raw_readl(dev_info->vbase + REG_ERRCTRL_OFFSET);
+	u32 linkerr = __raw_readl(dev_info->vbase + REG_LINKERR_OFFSET);
+
+	if (!((brgctrl & BRGCTRL_DETSERR) ||
+	      (linkctrl & HT_LINKCTRL_DETECTED) ||
+	      (errctrl & HT_ERRCTRL_DETECTED) ||
+	      (linkerr & HT_LINKERR_DETECTED)))
+		return;
+
+	cpc925_printk(KERN_INFO, "HT Link Fault\n"
+				 "HT register dump:\n");
+	cpc925_printk(KERN_INFO, "Bridge Ctrl			0x%08x\n",
+		      brgctrl);
+	cpc925_printk(KERN_INFO, "Link Config Ctrl		0x%08x\n",
+		      linkctrl);
+	cpc925_printk(KERN_INFO, "Error Enum and Ctrl		0x%08x\n",
+		      errctrl);
+	cpc925_printk(KERN_INFO, "Link Error			0x%08x\n",
+		      linkerr);
+
+	/* Clear by write 1 */
+	if (brgctrl & BRGCTRL_DETSERR)
+		__raw_writel(BRGCTRL_DETSERR,
+				dev_info->vbase + REG_BRGCTRL_OFFSET);
+
+	if (linkctrl & HT_LINKCTRL_DETECTED)
+		__raw_writel(HT_LINKCTRL_DETECTED,
+				dev_info->vbase + REG_LINKCTRL_OFFSET);
+
+	/* Initiate Secondary Bus Reset to clear the chain failure */
+	if (errctrl & ERRCTRL_CHN_FAL)
+		__raw_writel(BRGCTRL_SECBUSRESET,
+				dev_info->vbase + REG_BRGCTRL_OFFSET);
+
+	if (errctrl & ERRCTRL_RSP_ERR)
+		__raw_writel(ERRCTRL_RSP_ERR,
+				dev_info->vbase + REG_ERRCTRL_OFFSET);
+
+	if (linkerr & HT_LINKERR_DETECTED)
+		__raw_writel(HT_LINKERR_DETECTED,
+				dev_info->vbase + REG_LINKERR_OFFSET);
+
+	edac_device_handle_ce(edac_dev, 0, 0, edac_dev->ctl_name);
+}
+
+static struct cpc925_dev_info cpc925_devs[] = {
+	{
+	.ctl_name = CPC925_CPU_ERR_DEV,
+	.init = cpc925_cpu_init,
+	.exit = cpc925_cpu_exit,
+	.check = cpc925_cpu_check,
+	},
+	{
+	.ctl_name = CPC925_HT_LINK_DEV,
+	.init = cpc925_htlink_init,
+	.exit = cpc925_htlink_exit,
+	.check = cpc925_htlink_check,
+	},
+	{0}, /* Terminated by NULL */
+};
+
+/*
+ * Add CPU Err detection and HyperTransport Link Err detection
+ * as common "edac_device", they have no corresponding device
+ * nodes in the Open Firmware DTB and we have to add platform
+ * devices for them. Also, they will share the MMIO with that
+ * of memory controller.
+ */
+static void cpc925_add_edac_devices(void __iomem *vbase)
+{
+	struct cpc925_dev_info *dev_info;
+
+	if (!vbase) {
+		cpc925_printk(KERN_ERR, "MMIO not established yet\n");
+		return;
+	}
+
+	for (dev_info = &cpc925_devs[0]; dev_info->init; dev_info++) {
+		dev_info->vbase = vbase;
+		dev_info->pdev = platform_device_register_simple(
+					dev_info->ctl_name, 0, NULL, 0);
+		if (IS_ERR(dev_info->pdev)) {
+			cpc925_printk(KERN_ERR,
+				"Can't register platform device for %s\n",
+				dev_info->ctl_name);
+			continue;
+		}
+
+		/*
+		 * Don't have to allocate private structure but
+		 * make use of cpc925_devs[] instead.
+		 */
+		dev_info->edac_idx = edac_device_alloc_index();
+		dev_info->edac_dev =
+			edac_device_alloc_ctl_info(0, dev_info->ctl_name,
+				1, NULL, 0, 0, NULL, 0, dev_info->edac_idx);
+		if (!dev_info->edac_dev) {
+			cpc925_printk(KERN_ERR, "No memory for edac device\n");
+			goto err1;
+		}
+
+		dev_info->edac_dev->pvt_info = dev_info;
+		dev_info->edac_dev->dev = &dev_info->pdev->dev;
+		dev_info->edac_dev->ctl_name = dev_info->ctl_name;
+		dev_info->edac_dev->mod_name = CPC925_EDAC_MOD_STR;
+		dev_info->edac_dev->dev_name = dev_name(&dev_info->pdev->dev);
+
+		if (edac_op_state == EDAC_OPSTATE_POLL)
+			dev_info->edac_dev->edac_check = dev_info->check;
+
+		if (dev_info->init)
+			dev_info->init(dev_info);
+
+		if (edac_device_add_device(dev_info->edac_dev) > 0) {
+			cpc925_printk(KERN_ERR,
+				"Unable to add edac device for %s\n",
+				dev_info->ctl_name);
+			goto err2;
+		}
+
+		debugf0("%s: Successfully added edac device for %s\n",
+			__func__, dev_info->ctl_name);
+
+		continue;
+
+err2:
+		if (dev_info->exit)
+			dev_info->exit(dev_info);
+		edac_device_free_ctl_info(dev_info->edac_dev);
+err1:
+		platform_device_unregister(dev_info->pdev);
+	}
+}
+
+/*
+ * Delete the common "edac_device" for CPU Err Detection
+ * and HyperTransport Link Err Detection
+ */
+static void cpc925_del_edac_devices(void)
+{
+	struct cpc925_dev_info *dev_info;
+
+	for (dev_info = &cpc925_devs[0]; dev_info->init; dev_info++) {
+		if (dev_info->edac_dev) {
+			edac_device_del_device(dev_info->edac_dev->dev);
+			edac_device_free_ctl_info(dev_info->edac_dev);
+			platform_device_unregister(dev_info->pdev);
+		}
+
+		if (dev_info->exit)
+			dev_info->exit(dev_info);
+
+		debugf0("%s: Successfully deleted edac device for %s\n",
+			__func__, dev_info->ctl_name);
+	}
+}
+
+/* Convert current back-ground scrub rate into byte/sec bandwith */
+static int cpc925_get_sdram_scrub_rate(struct mem_ctl_info *mci, u32 *bw)
+{
+	struct cpc925_mc_pdata *pdata = mci->pvt_info;
+	u32 mscr;
+	u8 si;
+
+	mscr = __raw_readl(pdata->vbase + REG_MSCR_OFFSET);
+	si = (mscr & MSCR_SI_MASK) >> MSCR_SI_SHIFT;
+
+	debugf0("%s, Mem Scrub Ctrl Register 0x%x\n", __func__, mscr);
+
+	if (((mscr & MSCR_SCRUB_MOD_MASK) != MSCR_BACKGR_SCRUB) ||
+	    (si == 0)) {
+		cpc925_mc_printk(mci, KERN_INFO, "Scrub mode not enabled\n");
+		*bw = 0;
+	} else
+		*bw = CPC925_SCRUB_BLOCK_SIZE * 0xFA67 / si;
+
+	return 0;
+}
+
+/* Return 0 for single channel; 1 for dual channel */
+static int cpc925_mc_get_channels(void __iomem *vbase)
+{
+	int dual = 0;
+	u32 mbcr;
+
+	mbcr = __raw_readl(vbase + REG_MBCR_OFFSET);
+
+	/*
+	 * Dual channel only when 128-bit wide physical bus
+	 * and 128-bit configuration.
+	 */
+	if (((mbcr & MBCR_64BITCFG_MASK) == 0) &&
+	    ((mbcr & MBCR_64BITBUS_MASK) == 0))
+		dual = 1;
+
+	debugf0("%s: %s channel\n", __func__,
+		(dual > 0) ? "Dual" : "Single");
+
+	return dual;
+}
+
+static int __devinit cpc925_probe(struct platform_device *pdev)
+{
+	struct mem_ctl_info *mci;
+	void __iomem *vbase;
+	struct cpc925_mc_pdata *pdata;
+	struct resource *r;
+	int res = 0, nr_channels;
+
+	debugf0("%s: %s platform device found!\n", __func__, pdev->name);
+
+	if (!devres_open_group(&pdev->dev, cpc925_probe, GFP_KERNEL)) {
+		res = -ENOMEM;
+		goto out;
+	}
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!r) {
+		cpc925_printk(KERN_ERR, "Unable to get resource\n");
+		res = -ENOENT;
+		goto err1;
+	}
+
+	if (!devm_request_mem_region(&pdev->dev,
+				     r->start,
+				     r->end - r->start + 1,
+				     pdev->name)) {
+		cpc925_printk(KERN_ERR, "Unable to request mem region\n");
+		res = -EBUSY;
+		goto err1;
+	}
+
+	vbase = devm_ioremap(&pdev->dev, r->start, r->end - r->start + 1);
+	if (!vbase) {
+		cpc925_printk(KERN_ERR, "Unable to ioremap device\n");
+		res = -ENOMEM;
+		goto err2;
+	}
+
+	nr_channels = cpc925_mc_get_channels(vbase);
+	mci = edac_mc_alloc(sizeof(struct cpc925_mc_pdata),
+			CPC925_NR_CSROWS, nr_channels + 1, edac_mc_idx);
+	if (!mci) {
+		cpc925_printk(KERN_ERR, "No memory for mem_ctl_info\n");
+		res = -ENOMEM;
+		goto err2;
+	}
+
+	pdata = mci->pvt_info;
+	pdata->vbase = vbase;
+	pdata->edac_idx = edac_mc_idx++;
+	pdata->name = pdev->name;
+
+	mci->dev = &pdev->dev;
+	platform_set_drvdata(pdev, mci);
+	mci->dev_name = dev_name(&pdev->dev);
+	mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_DDR;
+	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
+	mci->edac_cap = EDAC_FLAG_SECDED;
+	mci->mod_name = CPC925_EDAC_MOD_STR;
+	mci->mod_ver = CPC925_EDAC_REVISION;
+	mci->ctl_name = pdev->name;
+
+	if (edac_op_state == EDAC_OPSTATE_POLL)
+		mci->edac_check = cpc925_mc_check;
+
+	mci->ctl_page_to_phys = NULL;
+	mci->scrub_mode = SCRUB_SW_SRC;
+	mci->set_sdram_scrub_rate = NULL;
+	mci->get_sdram_scrub_rate = cpc925_get_sdram_scrub_rate;
+
+	cpc925_init_csrows(mci);
+
+	/* Setup memory controller registers */
+	cpc925_mc_init(mci);
+
+	if (edac_mc_add_mc(mci) > 0) {
+		cpc925_mc_printk(mci, KERN_ERR, "Failed edac_mc_add_mc()\n");
+		goto err3;
+	}
+
+	cpc925_add_edac_devices(vbase);
+
+	/* get this far and it's successful */
+	debugf0("%s: success\n", __func__);
+
+	res = 0;
+	goto out;
+
+err3:
+	cpc925_mc_exit(mci);
+	edac_mc_free(mci);
+err2:
+	devm_release_mem_region(&pdev->dev, r->start, r->end-r->start+1);
+err1:
+	devres_release_group(&pdev->dev, cpc925_probe);
+out:
+	return res;
+}
+
+static int cpc925_remove(struct platform_device *pdev)
+{
+	struct mem_ctl_info *mci = platform_get_drvdata(pdev);
+
+	/*
+	 * Delete common edac devices before edac mc, because
+	 * the former share the MMIO of the latter.
+	 */
+	cpc925_del_edac_devices();
+	cpc925_mc_exit(mci);
+
+	edac_mc_del_mc(&pdev->dev);
+	edac_mc_free(mci);
+
+	return 0;
+}
+
+static struct platform_driver cpc925_edac_driver = {
+	.probe = cpc925_probe,
+	.remove = cpc925_remove,
+	.driver = {
+		   .name = "cpc925_edac",
+	}
+};
+
+static int __init cpc925_edac_init(void)
+{
+	int ret = 0;
+
+	printk(KERN_INFO "IBM CPC925 EDAC driver " CPC925_EDAC_REVISION "\n");
+	printk(KERN_INFO "\t(c) 2008 Wind River Systems, Inc\n");
+
+	/* Only support POLL mode so far */
+	edac_op_state = EDAC_OPSTATE_POLL;
+
+	ret = platform_driver_register(&cpc925_edac_driver);
+	if (ret) {
+		printk(KERN_WARNING "Failed to register %s\n",
+			CPC925_EDAC_MOD_STR);
+	}
+
+	return ret;
+}
+
+static void __exit cpc925_edac_exit(void)
+{
+	platform_driver_unregister(&cpc925_edac_driver);
+}
+
+module_init(cpc925_edac_init);
+module_exit(cpc925_edac_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Cao Qingtao <qingtao.cao@windriver.com>");
+MODULE_DESCRIPTION("IBM CPC925 Bridge and MC EDAC kernel module");
-- 
1.5.6.2

^ permalink raw reply related

* [v2 PATCH 3/3] EDAC: CPC925 MC platform device setup
From: Harry Ciao @ 2009-04-13  6:05 UTC (permalink / raw)
  To: norsk5, michael, bluesmoke-devel, linuxppc-dev; +Cc: linux-kernel
In-Reply-To: <1239602716-18352-3-git-send-email-qingtao.cao@windriver.com>

Fixup the number of cells for the values of CPC925 Memory Controller,
and setup related platform device during system booting up, against 
which CPC925 Memory Controller EDAC driver would be matched.

Signed-off-by: Harry Ciao <qingtao.cao@windriver.com>
---
 arch/powerpc/kernel/prom_init.c      |   33 +++++++++++++++++++
 arch/powerpc/platforms/maple/setup.c |   59 +++++++++++++++++++++++++++++++++++
 2 files changed, 92 insertions(+)

--- a/arch/powerpc/platforms/maple/setup.c
+++ b/arch/powerpc/platforms/maple/setup.c
@@ -335,3 +335,62 @@ define_machine(maple) {
 	.progress		= maple_progress,
 	.power_save		= power4_idle,
 };
+
+#ifdef CONFIG_EDAC
+/*
+ * Register a platform device for CPC925 memory controller on
+ * Motorola ATCA-6101 blade.
+ */
+#define MAPLE_CPC925_MODEL	"Motorola,ATCA-6101"
+static int __init maple_cpc925_edac_setup(void)
+{
+	struct platform_device *pdev;
+	struct device_node *np = NULL;
+	struct resource r;
+	const unsigned char *model;
+	int ret;
+
+	np = of_find_node_by_path("/");
+	if (!np) {
+		printk(KERN_ERR "%s: Unable to get root node\n", __func__);
+		return -ENODEV;
+	}
+
+	model = (const unsigned char *)of_get_property(np, "model", NULL);
+	if (!model) {
+		printk(KERN_ERR "%s: Unabel to get model info\n", __func__);
+		return -ENODEV;
+	}
+
+	ret = strcmp(model, MAPLE_CPC925_MODEL);
+	of_node_put(np);
+
+	if (ret != 0)
+		return 0;
+
+	np = of_find_node_by_type(NULL, "memory-controller");
+	if (!np) {
+		printk(KERN_ERR "%s: Unable to find memory-controller node\n",
+			__func__);
+		return -ENODEV;
+	}
+
+	ret = of_address_to_resource(np, 0, &r);
+	of_node_put(np);
+
+	if (ret < 0) {
+		printk(KERN_ERR "%s: Unable to get memory-controller reg\n",
+			__func__);
+		return -ENODEV;
+	}
+
+	pdev = platform_device_register_simple("cpc925_edac", 0, &r, 1);
+	if (IS_ERR(pdev))
+		return PTR_ERR(pdev);
+
+	printk(KERN_INFO "%s: CPC925 platform device created\n", __func__);
+
+	return 0;
+}
+machine_device_initcall(maple, maple_cpc925_edac_setup);
+#endif
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -1948,8 +1948,40 @@ static void __init fixup_device_tree_map
 	prom_setprop(isa, name, "ranges",
 			isa_ranges, sizeof(isa_ranges));
 }
+
+#define CPC925_MC_START		0xf8000000
+#define CPC925_MC_LENGTH	0x1000000
+/* The values for memory-controller don't have right number of cells */
+static void __init fixup_device_tree_maple_memory_controller(void)
+{
+	phandle mc;
+	u32 mc_reg[4];
+	char *name = "/hostbridge@f8000000";
+
+	mc = call_prom("finddevice", 1, 1, ADDR(name));
+	if (!PHANDLE_VALID(mc))
+		return;
+
+	if (prom_getproplen(mc, "reg") != 8)
+		return;
+
+	if (prom_getprop(mc, "reg", mc_reg, sizeof(mc_reg)) == PROM_ERROR)
+		return;
+
+	if (mc_reg[0] != CPC925_MC_START || mc_reg[1] != CPC925_MC_LENGTH)
+		return;
+
+	prom_printf("Fixing up bogus hostbridge on Maple...\n");
+
+	mc_reg[0] = 0x0;
+	mc_reg[1] = CPC925_MC_START;
+	mc_reg[2] = 0x0;
+	mc_reg[3] = CPC925_MC_LENGTH;
+	prom_setprop(mc, name, "reg", mc_reg, sizeof(mc_reg));
+}
 #else
 #define fixup_device_tree_maple()
+#define fixup_device_tree_maple_memory_controller()
 #endif
 
 #ifdef CONFIG_PPC_CHRP
@@ -2190,6 +2222,7 @@ static void __init fixup_device_tree_efi
 static void __init fixup_device_tree(void)
 {
 	fixup_device_tree_maple();
+	fixup_device_tree_maple_memory_controller();
 	fixup_device_tree_chrp();
 	fixup_device_tree_pmac();
 	fixup_device_tree_efika();

^ permalink raw reply

* Re: [v1 PATCH 1/1] Fix 64bit Maple Host Bridge Address and Size Nodes
From: Tiejun Chen @ 2009-04-13  2:27 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, michael, linuxppc-dev, akpm
In-Reply-To: <49E2A2D2.2000606@windriver.com>

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

Michael and Ben,

If you are free please help me check this delayed patch.

For the original thread please filter email with the key words "Fix 64bit".

Best Regards
Tiejun



> In the DTB tree created by firmware on some Maple 64bit targets, such as
> ATCA6101,
> these two properties, address&size, should be 2. But the actual
> corresponding
> values
> of host bridge node are set 1 incorrectly by the firmware, we have to
> provide one
> fixup function to fix that.
>
> Signed-off-by: Tiejun Chen <tiejun.china@gmail.com>
> ---
>  arch/powerpc/kernel/prom_init.c |   51
> ++++++++++++++++++++++++++++++++++++++-
>  1 files changed, 50 insertions(+), 1 deletions(-)
>
> diff --git a/arch/powerpc/kernel/prom_init.c
> b/arch/powerpc/kernel/prom_init.c
> index 2445945..7848b45 100644
> --- a/arch/powerpc/kernel/prom_init.c
> +++ b/arch/powerpc/kernel/prom_init.c
> @@ -1907,14 +1907,63 @@ static void __init flatten_device_tree(void)
>  }
>
>  #ifdef CONFIG_PPC_MAPLE
> +/* On ATCA6101 64bit target host bridge parent node has specified address
> and
> + * size properties to be 2. But the actual "cell" value for host bridge
> node
> + * is 1 since early MOTLoad internal bug. */
> +static void __init fixup_device_tree_atca6101(void)
> +{
> +       phandle hb;
> +       u32 hb_ranges[4];
> +       u32 size_cell, addr_cell;
> +       struct prom_t *_prom = &RELOC(prom);
> +       char *name;
> +
> +       name = "/hostbridge@f8000000";
> +       hb = call_prom("finddevice", 1, 1, ADDR(name));
> +       if (!PHANDLE_VALID(hb))
> +               return;
> +
> +       if (prom_getproplen(hb, "reg") != 8)
> +               return;
> +
> +       if (prom_getprop(hb, "reg", hb_ranges, (sizeof(hb_ranges))/2)
> +               == PROM_ERROR)
> +               return;
> +
> +       prom_getprop(_prom->root, "#address-cells", &addr_cell,
> sizeof(addr_cell));
> +       prom_getprop(_prom->root, "#size-cells", &size_cell,
> sizeof(size_cell));
> +
> +       if ((addr_cell != 2) || (size_cell != 2) ||
> +               (hb_ranges[0] != 0xf8000000))
> +               return;
> +
> +       prom_printf("Fixing up bogus HOSTBRIDGE reg on ATCA6101...\n");
> +
> +       hb_ranges[3] = hb_ranges[1];
> +       hb_ranges[1] = hb_ranges[0];
> +       hb_ranges[0] = hb_ranges[2] = 0;
> +       prom_setprop(hb, name, "reg",
> +       hb_ranges, sizeof(hb_ranges));
> +}
>  /* PIBS Version 1.05.0000 04/26/2005 has an incorrect /ht/isa/ranges
> property.
> - * The values are bad, and it doesn't even have the right number of cells.
> */
> + * The values are bad, and it doesn't even have the right number of cells.
> + * Additionally, the early MOTLoad generate incorrect address&size cells
> on
> + * some Maple platform such as ATCA6101. */
>  static void __init fixup_device_tree_maple(void)
>  {
>        phandle isa;
>        u32 rloc = 0x01002000; /* IO space; PCI device = 4 */
>        u32 isa_ranges[6];
>        char *name;
> +       u32 node;
> +       char prop[64];
> +       int model;
> +
> +       /*  FIXME: This may be used for more Maple targets not only
> ATCA6101. */
> +       node = call_prom("finddevice", 1, 1, ADDR("/"));
> +       model = prom_getprop(node, "model", prop, sizeof(prop));
> +       if (model != PROM_ERROR && (strcmp(prop, "Motorola,ATCA-6101") ==
> 0))
> +                fixup_device_tree_atca6101();
>
>        name = "/ht@0/isa@4";
>        isa = call_prom("finddevice", 1, 1, ADDR(name));
> --
> 1.5.6
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
>
>

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

^ permalink raw reply

* Re: [PATCH] Powerpc: Xilinx: Intc: Fix level irqs which have duplicates
From: Grant Likely @ 2009-04-12  6:18 UTC (permalink / raw)
  To: John Linn; +Cc: linuxppc-dev
In-Reply-To: <20090403225517.26D941870050@mail94-sin.bigfish.com>

I think this looks good.  I'll need to pull it into my tree and try it out.

g.

On Fri, Apr 3, 2009 at 4:55 PM, John Linn <john.linn@xilinx.com> wrote:
> The interrupt controller was not handling level interrupts correctly
> such that duplicate interrupts were happening. This fixes the problem
> and adds edge type interrupts which are needed in Xilinx hardware.
>
> Signed-off-by: John Linn <john.linn@xilinx.com>
> ---
> =A0arch/powerpc/sysdev/xilinx_intc.c | =A0112 +++++++++++++++++++++++++++=
+++++++---
> =A01 files changed, 103 insertions(+), 9 deletions(-)
>
> diff --git a/arch/powerpc/sysdev/xilinx_intc.c b/arch/powerpc/sysdev/xili=
nx_intc.c
> index a22e1a2..7c99a1e 100644
> --- a/arch/powerpc/sysdev/xilinx_intc.c
> +++ b/arch/powerpc/sysdev/xilinx_intc.c
> @@ -41,8 +41,30 @@
>
> =A0static struct irq_host *master_irqhost;
>
> +/* The following table allows the interrupt type, edge or level,
> + * to be cached after being read from the device tree until the interrup=
t
> + * is mapped
> + */
> +static int xilinx_intc_typetable[32];
> +
> +/* Map the interrupt type from the device tree to the interrupt types
> + * used by the interrupt subsystem
> + */
> +static unsigned char xilinx_intc_map_senses[] =3D {
> + =A0 =A0 =A0 IRQ_TYPE_EDGE_RISING,
> + =A0 =A0 =A0 IRQ_TYPE_EDGE_FALLING,
> + =A0 =A0 =A0 IRQ_TYPE_LEVEL_HIGH,
> + =A0 =A0 =A0 IRQ_TYPE_LEVEL_LOW,
> +};
> +
> =A0/*
> - * IRQ Chip operations
> + * The interrupt controller is setup such that it doesn't work well with
> + * the level interrupt handler in the kernel because the handler acks th=
e
> + * interrupt before calling the application interrupt handler. To deal w=
ith
> + * that, we use 2 different irq chips so that different functions can be
> + * used for level and edge type interrupts.
> + *
> + * IRQ Chip common (across level and edge) operations
> =A0*/
> =A0static void xilinx_intc_mask(unsigned int virq)
> =A0{
> @@ -52,15 +74,54 @@ static void xilinx_intc_mask(unsigned int virq)
> =A0 =A0 =A0 =A0out_be32(regs + XINTC_CIE, 1 << irq);
> =A0}
>
> -static void xilinx_intc_unmask(unsigned int virq)
> +static int xilinx_intc_set_type(unsigned int virq, unsigned int flow_typ=
e)
> +{
> + =A0 =A0 =A0 struct irq_desc *desc =3D get_irq_desc(virq);
> +
> + =A0 =A0 =A0 desc->status &=3D ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
> + =A0 =A0 =A0 desc->status |=3D flow_type & IRQ_TYPE_SENSE_MASK;
> + =A0 =A0 =A0 if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 desc->status |=3D IRQ_LEVEL;
> + =A0 =A0 =A0 return 0;
> +}
> +
> +/*
> + * IRQ Chip level operations
> + */
> +static void xilinx_intc_level_unmask(unsigned int virq)
> =A0{
> =A0 =A0 =A0 =A0int irq =3D virq_to_hw(virq);
> =A0 =A0 =A0 =A0void * regs =3D get_irq_chip_data(virq);
> =A0 =A0 =A0 =A0pr_debug("unmask: %d\n", irq);
> =A0 =A0 =A0 =A0out_be32(regs + XINTC_SIE, 1 << irq);
> +
> + =A0 =A0 =A0 /* ack level irqs because they can't be acked during
> + =A0 =A0 =A0 =A0* ack function since the handle_level_irq function
> + =A0 =A0 =A0 =A0* acks the irq before calling the inerrupt handler
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 out_be32(regs + XINTC_IAR, 1 << irq);
> +}
> +
> +static struct irq_chip xilinx_intc_level_irqchip =3D {
> + =A0 =A0 =A0 .typename =3D "Xilinx Level INTC",
> + =A0 =A0 =A0 .mask =3D xilinx_intc_mask,
> + =A0 =A0 =A0 .mask_ack =3D xilinx_intc_mask,
> + =A0 =A0 =A0 .unmask =3D xilinx_intc_level_unmask,
> + =A0 =A0 =A0 .set_type =3D xilinx_intc_set_type,
> +};
> +
> +/*
> + * IRQ Chip edge operations
> + */
> +static void xilinx_intc_edge_unmask(unsigned int virq)
> +{
> + =A0 =A0 =A0 int irq =3D virq_to_hw(virq);
> + =A0 =A0 =A0 void *regs =3D get_irq_chip_data(virq);
> + =A0 =A0 =A0 pr_debug("unmask: %d\n", irq);
> + =A0 =A0 =A0 out_be32(regs + XINTC_SIE, 1 << irq);
> =A0}
>
> -static void xilinx_intc_ack(unsigned int virq)
> +static void xilinx_intc_edge_ack(unsigned int virq)
> =A0{
> =A0 =A0 =A0 =A0int irq =3D virq_to_hw(virq);
> =A0 =A0 =A0 =A0void * regs =3D get_irq_chip_data(virq);
> @@ -68,27 +129,60 @@ static void xilinx_intc_ack(unsigned int virq)
> =A0 =A0 =A0 =A0out_be32(regs + XINTC_IAR, 1 << irq);
> =A0}
>
> -static struct irq_chip xilinx_intc_irqchip =3D {
> - =A0 =A0 =A0 .typename =3D "Xilinx INTC",
> +static struct irq_chip xilinx_intc_edge_irqchip =3D {
> + =A0 =A0 =A0 .typename =3D "Xilinx Edge =A0INTC",
> =A0 =A0 =A0 =A0.mask =3D xilinx_intc_mask,
> - =A0 =A0 =A0 .unmask =3D xilinx_intc_unmask,
> - =A0 =A0 =A0 .ack =3D xilinx_intc_ack,
> + =A0 =A0 =A0 .unmask =3D xilinx_intc_edge_unmask,
> + =A0 =A0 =A0 .ack =3D xilinx_intc_edge_ack,
> + =A0 =A0 =A0 .set_type =3D xilinx_intc_set_type,
> =A0};
>
> =A0/*
> =A0* IRQ Host operations
> =A0*/
> +
> +/**
> + * xilinx_intc_xlate - translate virq# from device tree interrupts prope=
rty
> + */
> +static int xilinx_intc_xlate(struct irq_host *h, struct device_node *ct,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 u32 *intspe=
c, unsigned int intsize,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 irq_hw_numb=
er_t *out_hwirq,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 unsigned in=
t *out_flags)
> +{
> + =A0 =A0 =A0 if (intsize !=3D 2)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -1;
> +
> + =A0 =A0 =A0 /* keep a copy of the interrupt type til the interrupt is m=
apped
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 xilinx_intc_typetable[intspec[0]] =3D xilinx_intc_map_sense=
s[intspec[1]];
> +
> + =A0 =A0 =A0 /* Xilinx uses 2 interrupt entries, the 1st being the h/w
> + =A0 =A0 =A0 =A0* interrupt number, the 2nd being the interrupt type, ed=
ge or level
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 *out_hwirq =3D intspec[0];
> + =A0 =A0 =A0 *out_flags =3D xilinx_intc_map_senses[intspec[1]];
> +
> + =A0 =A0 =A0 return 0;
> +}
> =A0static int xilinx_intc_map(struct irq_host *h, unsigned int virq,
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0irq_hw=
_number_t irq)
> =A0{
> =A0 =A0 =A0 =A0set_irq_chip_data(virq, h->host_data);
> - =A0 =A0 =A0 set_irq_chip_and_handler(virq, &xilinx_intc_irqchip, handle=
_level_irq);
> - =A0 =A0 =A0 set_irq_type(virq, IRQ_TYPE_NONE);
> +
> + =A0 =A0 =A0 if (xilinx_intc_typetable[irq] =3D=3D IRQ_TYPE_LEVEL_HIGH |=
|
> + =A0 =A0 =A0 =A0 =A0 xilinx_intc_typetable[irq] =3D=3D IRQ_TYPE_LEVEL_LO=
W) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 set_irq_chip_and_handler(virq, &xilinx_intc=
_level_irqchip,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 handle_level_irq);
> + =A0 =A0 =A0 } else {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 set_irq_chip_and_handler(virq, &xilinx_intc=
_edge_irqchip,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 handle_edge_irq);
> + =A0 =A0 =A0 }
> =A0 =A0 =A0 =A0return 0;
> =A0}
>
> =A0static struct irq_host_ops xilinx_intc_ops =3D {
> =A0 =A0 =A0 =A0.map =3D xilinx_intc_map,
> + =A0 =A0 =A0 .xlate =3D xilinx_intc_xlate,
> =A0};
>
> =A0struct irq_host * __init
> --
> 1.6.2.1
>
>
>
> This email and any attachments are intended for the sole use of the named=
 recipient(s) and contain(s) confidential information that may be proprieta=
ry, privileged or copyrighted under applicable law. If you are not the inte=
nded recipient, do not read, copy, or forward this email message or any att=
achments. Delete this email message and any attachments immediately.
>
>
>



--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* Re: [PATCH] [V2] Xilinx : Framebuffer Driver: Add PLB support (non-DCR)
From: Grant Likely @ 2009-04-12  6:15 UTC (permalink / raw)
  To: John Linn; +Cc: linux-fbdev-devel, adaplas, Suneel, linuxppc-dev, akonovalov
In-Reply-To: <20090410211754.1ECF9FC804E@mail107-sin.bigfish.com>

What tree is this patch prepared against?  The version in mainline
already does PLB access, and doesn't support DCR at all.  It appears
that this driver is based on something that does the opposite.

g.

On Fri, Apr 10, 2009 at 3:17 PM, John Linn <john.linn@xilinx.com> wrote:
> From: Suneel <suneelg@xilinx.com>
>
> Added support for the new xps tft controller.
>
> The new core has PLB interface support in addition to existing
> DCR interface.
>
> The driver has been modified to support this new core which
> can be connected on PLB or DCR bus.
>
> Signed-off-by: Suneel <suneelg@xilinx.com>
> Signed-off-by: John Linn <john.linn@xilinx.com>
> ---
>
> V2 - Incorporated comments from Josh, Grant and others
>
> =A0drivers/video/xilinxfb.c | =A0213 ++++++++++++++++++++++++++++++++----=
----------
> =A01 files changed, 150 insertions(+), 63 deletions(-)
>
> diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c
> index a82c530..d151237 100644
> --- a/drivers/video/xilinxfb.c
> +++ b/drivers/video/xilinxfb.c
> @@ -1,13 +1,13 @@
> =A0/*
> - * xilinxfb.c
> =A0*
> - * Xilinx TFT LCD frame buffer driver
> + * Xilinx TFT frame buffer driver
> =A0*
> =A0* Author: MontaVista Software, Inc.
> =A0* =A0 =A0 =A0 =A0 source@mvista.com
> =A0*
> =A0* 2002-2007 (c) MontaVista Software, Inc.
> =A0* 2007 (c) Secret Lab Technologies, Ltd.
> + * 2009 (c) Xilinx Inc.
> =A0*
> =A0* This file is licensed under the terms of the GNU General Public Lice=
nse
> =A0* version 2. =A0This program is licensed "as is" without any warranty =
of any
> @@ -31,27 +31,31 @@
> =A0#include <linux/fb.h>
> =A0#include <linux/init.h>
> =A0#include <linux/dma-mapping.h>
> -#if defined(CONFIG_OF)
> =A0#include <linux/of_device.h>
> =A0#include <linux/of_platform.h>
> -#endif
> -#include <asm/io.h>
> +#include <linux/io.h>
> =A0#include <linux/xilinxfb.h>
> =A0#include <asm/dcr.h>
>
> =A0#define DRIVER_NAME =A0 =A0 =A0 =A0 =A0 =A0"xilinxfb"
> -#define DRIVER_DESCRIPTION =A0 =A0 "Xilinx TFT LCD frame buffer driver"
> +
>
> =A0/*
> =A0* Xilinx calls it "PLB TFT LCD Controller" though it can also be used =
for
> - * the VGA port on the Xilinx ML40x board. This is a hardware display co=
ntroller
> - * for a 640x480 resolution TFT or VGA screen.
> + * the VGA port on the Xilinx ML40x board. This is a hardware display
> + * controller for a 640x480 resolution TFT or VGA screen.
> =A0*
> =A0* The interface to the framebuffer is nice and simple. =A0There are tw=
o
> =A0* control registers. =A0The first tells the LCD interface where in mem=
ory
> =A0* the frame buffer is (only the 11 most significant bits are used, so
> =A0* don't start thinking about scrolling). =A0The second allows the LCD =
to
> =A0* be turned on or off as well as rotated 180 degrees.
> + *
> + * In case of direct PLB access the second control register will be at
> + * an offset of 4 as compared to the DCR access where the offset is 1
> + * i.e. REG_CTRL. So this is taken care in the function
> + * xilinx_fb_out_be32 where it left shifts the offset 2 times in case of
> + * direct PLB access.
> =A0*/
> =A0#define NUM_REGS =A0 =A0 =A0 2
> =A0#define REG_FB_ADDR =A0 =A00
> @@ -108,10 +112,18 @@ static struct fb_var_screeninfo xilinx_fb_var =3D {
> =A0 =A0 =A0 =A0.activate =3D =A0 =A0 FB_ACTIVATE_NOW
> =A0};
>
> +
> +#define PLB_ACCESS_FLAG =A0 =A0 =A0 =A00x1 =A0 =A0 =A0 =A0 =A0 =A0 /* 1 =
=3D PLB, 0 =3D DCR */
> +
> =A0struct xilinxfb_drvdata {
>
> =A0 =A0 =A0 =A0struct fb_info =A0info; =A0 =A0 =A0 =A0 =A0 /* FB driver i=
nfo record */
>
> + =A0 =A0 =A0 phys_addr_t =A0 =A0 regs_phys; =A0 =A0 =A0/* phys. address =
of the control
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 registers */
> + =A0 =A0 =A0 void __iomem =A0 =A0*regs; =A0 =A0 =A0 =A0 =A0/* virt. addr=
ess of the control
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 registers */
> +
> =A0 =A0 =A0 =A0dcr_host_t =A0 =A0 =A0dcr_host;
> =A0 =A0 =A0 =A0unsigned int =A0 =A0dcr_start;
> =A0 =A0 =A0 =A0unsigned int =A0 =A0dcr_len;
> @@ -120,6 +132,8 @@ struct xilinxfb_drvdata {
> =A0 =A0 =A0 =A0dma_addr_t =A0 =A0 =A0fb_phys; =A0 =A0 =A0 =A0/* phys. add=
ress of the frame buffer */
> =A0 =A0 =A0 =A0int =A0 =A0 =A0 =A0 =A0 =A0 fb_alloced; =A0 =A0 /* Flag, w=
as the fb memory alloced? */
>
> + =A0 =A0 =A0 u8 =A0 =A0 =A0 =A0 =A0 =A0 =A0flags; =A0 =A0 =A0 =A0 =A0/* =
features of the driver */
> +
> =A0 =A0 =A0 =A0u32 =A0 =A0 =A0 =A0 =A0 =A0 reg_ctrl_default;
>
> =A0 =A0 =A0 =A0u32 =A0 =A0 =A0 =A0 =A0 =A0 pseudo_palette[PALETTE_ENTRIES=
_NO];
> @@ -130,14 +144,19 @@ struct xilinxfb_drvdata {
> =A0 =A0 =A0 =A0container_of(_info, struct xilinxfb_drvdata, info)
>
> =A0/*
> - * The LCD controller has DCR interface to its registers, but all
> - * the boards and configurations the driver has been tested with
> - * use opb2dcr bridge. So the registers are seen as memory mapped.
> - * This macro is to make it simple to add the direct DCR access
> - * when it's needed.
> + * The XPS TFT Controller can be accessed through PLB or DCR interface.
> + * To perform the read/write on the registers we need to check on
> + * which bus its connected and call the appropriate write API.
> =A0*/
> -#define xilinx_fb_out_be32(driverdata, offset, val) \
> - =A0 =A0 =A0 dcr_write(driverdata->dcr_host, offset, val)
> +static void xilinx_fb_out_be32(struct xilinxfb_drvdata *drvdata, u32 off=
set,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 u32 val)
> +{
> + =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(drvdata->regs + (offset << 2), val=
);
> + =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dcr_write(drvdata->dcr_host, offset, val);
> +
> +}
>
> =A0static int
> =A0xilinx_fb_setcolreg(unsigned regno, unsigned red, unsigned green, unsi=
gned blue,
> @@ -175,7 +194,8 @@ xilinx_fb_blank(int blank_mode, struct fb_info *fbi)
> =A0 =A0 =A0 =A0switch (blank_mode) {
> =A0 =A0 =A0 =A0case FB_BLANK_UNBLANK:
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* turn on panel */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 xilinx_fb_out_be32(drvdata, REG_CTRL, drvda=
ta->reg_ctrl_default);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 xilinx_fb_out_be32(drvdata, REG_CTRL,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 drvdata->reg_ctrl_default);
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;
>
> =A0 =A0 =A0 =A0case FB_BLANK_NORMAL:
> @@ -191,8 +211,7 @@ xilinx_fb_blank(int blank_mode, struct fb_info *fbi)
> =A0 =A0 =A0 =A0return 0; /* success */
> =A0}
>
> -static struct fb_ops xilinxfb_ops =3D
> -{
> +static struct fb_ops xilinxfb_ops =3D {
> =A0 =A0 =A0 =A0.owner =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=3D THIS_MODULE,
> =A0 =A0 =A0 =A0.fb_setcolreg =A0 =A0 =A0 =A0 =A0 =3D xilinx_fb_setcolreg,
> =A0 =A0 =A0 =A0.fb_blank =A0 =A0 =A0 =A0 =A0 =A0 =A0 =3D xilinx_fb_blank,
> @@ -205,25 +224,35 @@ static struct fb_ops xilinxfb_ops =3D
> =A0* Bus independent setup/teardown
> =A0*/
>
> -static int xilinxfb_assign(struct device *dev, dcr_host_t dcr_host,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0unsigned int dcr_sta=
rt, unsigned int dcr_len,
> +static int xilinxfb_assign(struct device *dev,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct xilinxfb_drvd=
ata *drvdata,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0unsigned long physad=
dr,
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct xilinxfb_platf=
orm_data *pdata)
> =A0{
> - =A0 =A0 =A0 struct xilinxfb_drvdata *drvdata;
> =A0 =A0 =A0 =A0int rc;
> =A0 =A0 =A0 =A0int fbsize =3D pdata->xvirt * pdata->yvirt * BYTES_PER_PIX=
EL;
>
> - =A0 =A0 =A0 /* Allocate the driver data region */
> - =A0 =A0 =A0 drvdata =3D kzalloc(sizeof(*drvdata), GFP_KERNEL);
> - =A0 =A0 =A0 if (!drvdata) {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Couldn't allocate device priv=
ate record\n");
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENOMEM;
> + =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* Map the control registers in if the co=
ntroller
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* is on direct PLB interface.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!request_mem_region(physaddr, 8, DRIVER=
_NAME)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Couldn't lock=
 memory region at 0x%08lX\n",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 physaddr);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 rc =3D -ENODEV;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err_region;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 drvdata->regs_phys =3D physaddr;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 drvdata->regs =3D ioremap(physaddr, 8);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!drvdata->regs) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Couldn't lock=
 memory region at 0x%08lX\n",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 physaddr);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 rc =3D -ENODEV;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err_map;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> =A0 =A0 =A0 =A0}
> - =A0 =A0 =A0 dev_set_drvdata(dev, drvdata);
> -
> - =A0 =A0 =A0 drvdata->dcr_start =3D dcr_start;
> - =A0 =A0 =A0 drvdata->dcr_len =3D dcr_len;
> - =A0 =A0 =A0 drvdata->dcr_host =3D dcr_host;
>
> =A0 =A0 =A0 =A0/* Allocate the framebuffer memory */
> =A0 =A0 =A0 =A0if (pdata->fb_phys) {
> @@ -238,7 +267,10 @@ static int xilinxfb_assign(struct device *dev, dcr_h=
ost_t dcr_host,
> =A0 =A0 =A0 =A0if (!drvdata->fb_virt) {
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dev_err(dev, "Could not allocate frame buf=
fer memory\n");
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0rc =3D -ENOMEM;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err_region;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err_fbmem;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err_region;
> =A0 =A0 =A0 =A0}
>
> =A0 =A0 =A0 =A0/* Clear (turn to black) the framebuffer */
> @@ -251,7 +283,8 @@ static int xilinxfb_assign(struct device *dev, dcr_ho=
st_t dcr_host,
> =A0 =A0 =A0 =A0drvdata->reg_ctrl_default =3D REG_CTRL_ENABLE;
> =A0 =A0 =A0 =A0if (pdata->rotate_screen)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0drvdata->reg_ctrl_default |=3D REG_CTRL_RO=
TATE;
> - =A0 =A0 =A0 xilinx_fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_def=
ault);
> + =A0 =A0 =A0 xilinx_fb_out_be32(drvdata, REG_CTRL,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 drvdata->reg_ctrl_default);
>
> =A0 =A0 =A0 =A0/* Fill struct fb_info */
> =A0 =A0 =A0 =A0drvdata->info.device =3D dev;
> @@ -287,9 +320,14 @@ static int xilinxfb_assign(struct device *dev, dcr_h=
ost_t dcr_host,
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0goto err_regfb;
> =A0 =A0 =A0 =A0}
>
> + =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Put a banner in the log (for DEBUG) */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_dbg(dev, "regs: phys=3D%lx, virt=3D%p\n=
", physaddr,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 drvdata->regs);
> + =A0 =A0 =A0 }
> =A0 =A0 =A0 =A0/* Put a banner in the log (for DEBUG) */
> =A0 =A0 =A0 =A0dev_dbg(dev, "fb: phys=3D%p, virt=3D%p, size=3D%x\n",
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 (void*)drvdata->fb_phys, drvdata->fb_virt, =
fbsize);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 (void *)drvdata->fb_phys, drvdata->fb_virt,=
 fbsize);
>
> =A0 =A0 =A0 =A0return 0; =A0 =A0 =A0 /* success */
>
> @@ -300,9 +338,20 @@ err_cmap:
> =A0 =A0 =A0 =A0if (drvdata->fb_alloced)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dma_free_coherent(dev, PAGE_ALIGN(fbsize),=
 drvdata->fb_virt,
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0drvdata->fb_phys);
> + =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 iounmap(drvdata->fb_virt);
> +
> =A0 =A0 =A0 =A0/* Turn off the display */
> =A0 =A0 =A0 =A0xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
>
> +err_fbmem:
> + =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 iounmap(drvdata->regs);
> +
> +err_map:
> + =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 release_mem_region(physaddr, 8);
> +
> =A0err_region:
> =A0 =A0 =A0 =A0kfree(drvdata);
> =A0 =A0 =A0 =A0dev_set_drvdata(dev, NULL);
> @@ -325,11 +374,18 @@ static int xilinxfb_release(struct device *dev)
> =A0 =A0 =A0 =A0if (drvdata->fb_alloced)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dma_free_coherent(dev, PAGE_ALIGN(drvdata-=
>info.fix.smem_len),
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0drvdat=
a->fb_virt, drvdata->fb_phys);
> + =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 iounmap(drvdata->fb_virt);
>
> =A0 =A0 =A0 =A0/* Turn off the display */
> =A0 =A0 =A0 =A0xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
>
> - =A0 =A0 =A0 dcr_unmap(drvdata->dcr_host, drvdata->dcr_len);
> + =A0 =A0 =A0 /* Release the resources, as allocated based on interface *=
/
> + =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 iounmap(drvdata->regs);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 release_mem_region(drvdata->regs_phys, 8);
> + =A0 =A0 =A0 } else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dcr_unmap(drvdata->dcr_host, drvdata->dcr_l=
en);
>
> =A0 =A0 =A0 =A0kfree(drvdata);
> =A0 =A0 =A0 =A0dev_set_drvdata(dev, NULL);
> @@ -341,27 +397,54 @@ static int xilinxfb_release(struct device *dev)
> =A0* OF bus binding
> =A0*/
>
> -#if defined(CONFIG_OF)
> =A0static int __devinit
> =A0xilinxfb_of_probe(struct of_device *op, const struct of_device_id *mat=
ch)
> =A0{
> =A0 =A0 =A0 =A0const u32 *prop;
> + =A0 =A0 =A0 u32 *p;
> + =A0 =A0 =A0 u32 tft_access;
> =A0 =A0 =A0 =A0struct xilinxfb_platform_data pdata;
> + =A0 =A0 =A0 struct resource res;
> =A0 =A0 =A0 =A0int size, rc;
> - =A0 =A0 =A0 int start, len;
> + =A0 =A0 =A0 int start =3D 0, len =3D 0;
> =A0 =A0 =A0 =A0dcr_host_t dcr_host;
> + =A0 =A0 =A0 struct xilinxfb_drvdata *drvdata;
>
> =A0 =A0 =A0 =A0/* Copy with the default pdata (not a ptr reference!) */
> =A0 =A0 =A0 =A0pdata =3D xilinx_fb_default_pdata;
>
> =A0 =A0 =A0 =A0dev_dbg(&op->dev, "xilinxfb_of_probe(%p, %p)\n", op, match=
);
>
> - =A0 =A0 =A0 start =3D dcr_resource_start(op->node, 0);
> - =A0 =A0 =A0 len =3D dcr_resource_len(op->node, 0);
> - =A0 =A0 =A0 dcr_host =3D dcr_map(op->node, start, len);
> - =A0 =A0 =A0 if (!DCR_MAP_OK(dcr_host)) {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(&op->dev, "invalid address\n");
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENODEV;
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* To check whether the core is connected directly to DCR=
 or PLB
> + =A0 =A0 =A0 =A0* interface and initialize the tft_access accordingly.
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 p =3D (u32 *)of_get_property(op->node, "xlnx,dcr-splb-slave=
-if", NULL);
> +
> + =A0 =A0 =A0 if (p)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tft_access =3D *p;
> + =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tft_access =3D 0; =A0 =A0 =A0 =A0 /* For ba=
ckward compatibility */
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* Fill the resource structure if its direct PLB interfac=
e
> + =A0 =A0 =A0 =A0* otherwise fill the dcr_host structure.
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 if (tft_access) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 rc =3D of_address_to_resource(op->node, 0, =
&res);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (rc) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(&op->dev, "invalid =
address\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENODEV;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 } else {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 start =3D dcr_resource_start(op->node, 0);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 len =3D dcr_resource_len(op->node, 0);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dcr_host =3D dcr_map(op->node, start, len);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!DCR_MAP_OK(dcr_host)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(&op->dev, "invalid =
address\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENODEV;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> =A0 =A0 =A0 =A0}
>
> =A0 =A0 =A0 =A0prop =3D of_get_property(op->node, "phys-size", &size);
> @@ -385,7 +468,26 @@ xilinxfb_of_probe(struct of_device *op, const struct=
 of_device_id *match)
> =A0 =A0 =A0 =A0if (of_find_property(op->node, "rotate-display", NULL))
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pdata.rotate_screen =3D 1;
>
> - =A0 =A0 =A0 return xilinxfb_assign(&op->dev, dcr_host, start, len, &pda=
ta);
> + =A0 =A0 =A0 /* Allocate the driver data region */
> + =A0 =A0 =A0 drvdata =3D kzalloc(sizeof(*drvdata), GFP_KERNEL);
> + =A0 =A0 =A0 if (!drvdata) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(&op->dev, "Couldn't allocate device=
 private record\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENOMEM;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 dev_set_drvdata(&op->dev, drvdata);
> +
> + =A0 =A0 =A0 if (tft_access)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 drvdata->flags |=3D PLB_ACCESS_FLAG;
> +
> + =A0 =A0 =A0 /* Arguments are passed based on the interface */
> + =A0 =A0 =A0 if (drvdata->flags & PLB_ACCESS_FLAG) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return xilinxfb_assign(&op->dev, drvdata, r=
es.start, &pdata);
> + =A0 =A0 =A0 } else {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 drvdata->dcr_start =3D start;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 drvdata->dcr_len =3D len;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 drvdata->dcr_host =3D dcr_host;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return xilinxfb_assign(&op->dev, drvdata, 0=
, &pdata);
> + =A0 =A0 =A0 }
> =A0}
>
> =A0static int __devexit xilinxfb_of_remove(struct of_device *op)
> @@ -395,6 +497,7 @@ static int __devexit xilinxfb_of_remove(struct of_dev=
ice *op)
>
> =A0/* Match table for of_platform binding */
> =A0static struct of_device_id xilinxfb_of_match[] __devinitdata =3D {
> + =A0 =A0 =A0 { .compatible =3D "xlnx,xps-tft-1.00.a", },
> =A0 =A0 =A0 =A0{ .compatible =3D "xlnx,plb-tft-cntlr-ref-1.00.a", },
> =A0 =A0 =A0 =A0{ .compatible =3D "xlnx,plb-dvi-cntlr-ref-1.00.c", },
> =A0 =A0 =A0 =A0{},
> @@ -412,22 +515,6 @@ static struct of_platform_driver xilinxfb_of_driver =
=3D {
> =A0 =A0 =A0 =A0},
> =A0};
>
> -/* Registration helpers to keep the number of #ifdefs to a minimum */
> -static inline int __init xilinxfb_of_register(void)
> -{
> - =A0 =A0 =A0 pr_debug("xilinxfb: calling of_register_platform_driver()\n=
");
> - =A0 =A0 =A0 return of_register_platform_driver(&xilinxfb_of_driver);
> -}
> -
> -static inline void __exit xilinxfb_of_unregister(void)
> -{
> - =A0 =A0 =A0 of_unregister_platform_driver(&xilinxfb_of_driver);
> -}
> -#else /* CONFIG_OF */
> -/* CONFIG_OF not enabled; do nothing helpers */
> -static inline int __init xilinxfb_of_register(void) { return 0; }
> -static inline void __exit xilinxfb_of_unregister(void) { }
> -#endif /* CONFIG_OF */
>
> =A0/* -------------------------------------------------------------------=
--
> =A0* Module setup and teardown
> @@ -436,18 +523,18 @@ static inline void __exit xilinxfb_of_unregister(vo=
id) { }
> =A0static int __init
> =A0xilinxfb_init(void)
> =A0{
> - =A0 =A0 =A0 return xilinxfb_of_register();
> + =A0 =A0 =A0 return of_register_platform_driver(&xilinxfb_of_driver);
> =A0}
>
> =A0static void __exit
> =A0xilinxfb_cleanup(void)
> =A0{
> - =A0 =A0 =A0 xilinxfb_of_unregister();
> + =A0 =A0 =A0 of_unregister_platform_driver(&xilinxfb_of_driver);
> =A0}
>
> =A0module_init(xilinxfb_init);
> =A0module_exit(xilinxfb_cleanup);
>
> =A0MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
> -MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
> +MODULE_DESCRIPTION("Xilinx TFT frame buffer driver");
> =A0MODULE_LICENSE("GPL");
> --
> 1.6.2.1
>
>
>
> This email and any attachments are intended for the sole use of the named=
 recipient(s) and contain(s) confidential information that may be proprieta=
ry, privileged or copyrighted under applicable law. If you are not the inte=
nded recipient, do not read, copy, or forward this email message or any att=
achments. Delete this email message and any attachments immediately.
>
>
>



--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* Re: [PATCH 2/4 v2] mtd/powerpc: Factor out MTD physmap bindings into mtd-physmap.txt
From: Grant Likely @ 2009-04-12  6:07 UTC (permalink / raw)
  To: Stefan Roese; +Cc: linuxppc-dev, devicetree-discuss, linux-mtd
In-Reply-To: <1239093568-12094-1-git-send-email-sr@denx.de>

On Tue, Apr 7, 2009 at 2:39 AM, Stefan Roese <sr@denx.de> wrote:
> Signed-off-by: Stefan Roese <sr@denx.de>
Acked-by: Grant Likely <grant.likely@secretlab.ca>

But you should really have a commit message of some sort describing
the reason for the change.

g.

> ---
> =A0Documentation/powerpc/booting-without-of.txt =A0 =A0 =A0 | =A0 89 +++-=
----------------
> =A0Documentation/powerpc/dts-bindings/mtd-physmap.txt | =A0 63 ++++++++++=
++++
> =A02 files changed, 75 insertions(+), 77 deletions(-)
> =A0create mode 100644 Documentation/powerpc/dts-bindings/mtd-physmap.txt
>
> diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation=
/powerpc/booting-without-of.txt
> index 0ab0230..d16b7a1 100644
> --- a/Documentation/powerpc/booting-without-of.txt
> +++ b/Documentation/powerpc/booting-without-of.txt
> @@ -43,12 +43,11 @@ Table of Contents
> =A0 =A0 2) Representing devices without a current OF specification
> =A0 =A0 =A0 a) PHY nodes
> =A0 =A0 =A0 b) Interrupt controllers
> - =A0 =A0 =A0c) CFI or JEDEC memory-mapped NOR flash
> - =A0 =A0 =A0d) 4xx/Axon EMAC ethernet nodes
> - =A0 =A0 =A0e) Xilinx IP cores
> - =A0 =A0 =A0f) USB EHCI controllers
> - =A0 =A0 =A0g) MDIO on GPIOs
> - =A0 =A0 =A0h) SPI busses
> + =A0 =A0 =A0c) 4xx/Axon EMAC ethernet nodes
> + =A0 =A0 =A0d) Xilinx IP cores
> + =A0 =A0 =A0e) USB EHCI controllers
> + =A0 =A0 =A0f) MDIO on GPIOs
> + =A0 =A0 =A0g) SPI busses
>
> =A0 VII - Marvell Discovery mv64[345]6x System Controller chips
> =A0 =A0 1) The /system-controller node
> @@ -999,7 +998,7 @@ compatibility.
> =A0 =A0 =A0 translation of SOC addresses for memory mapped SOC registers.
> =A0 =A0 - bus-frequency: Contains the bus frequency for the SOC node.
> =A0 =A0 =A0 Typically, the value of this field is filled in by the boot
> - =A0 =A0 =A0loader.
> + =A0 =A0 =A0loader.
>
>
> =A0 Recommended properties:
> @@ -1287,71 +1286,7 @@ platforms are moved over to use the flattened-devi=
ce-tree model.
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0device_type =3D "open-pic";
> =A0 =A0 =A0 =A0};
>
> - =A0 c) CFI or JEDEC memory-mapped NOR flash
> -
> - =A0 =A0Flash chips (Memory Technology Devices) are often used for solid=
 state
> - =A0 =A0file systems on embedded devices.
> -
> - =A0 =A0 - compatible : should contain the specific model of flash chip(=
s)
> - =A0 =A0 =A0 used, if known, followed by either "cfi-flash" or "jedec-fl=
ash"
> - =A0 =A0 - reg : Address range of the flash chip
> - =A0 =A0 - bank-width : Width (in bytes) of the flash bank. =A0Equal to =
the
> - =A0 =A0 =A0 device width times the number of interleaved chips.
> - =A0 =A0 - device-width : (optional) Width of a single flash chip. =A0If
> - =A0 =A0 =A0 omitted, assumed to be equal to 'bank-width'.
> - =A0 =A0 - #address-cells, #size-cells : Must be present if the flash ha=
s
> - =A0 =A0 =A0 sub-nodes representing partitions (see below). =A0In this c=
ase
> - =A0 =A0 =A0 both #address-cells and #size-cells must be equal to 1.
> -
> - =A0 =A0For JEDEC compatible devices, the following additional propertie=
s
> - =A0 =A0are defined:
> -
> - =A0 =A0 - vendor-id : Contains the flash chip's vendor id (1 byte).
> - =A0 =A0 - device-id : Contains the flash chip's device id (1 byte).
> -
> - =A0 =A0In addition to the information on the flash bank itself, the
> - =A0 =A0device tree may optionally contain additional information
> - =A0 =A0describing partitions of the flash address space. =A0This can be
> - =A0 =A0used on platforms which have strong conventions about which
> - =A0 =A0portions of the flash are used for what purposes, but which don'=
t
> - =A0 =A0use an on-flash partition table such as RedBoot.
> -
> - =A0 =A0Each partition is represented as a sub-node of the flash device.
> - =A0 =A0Each node's name represents the name of the corresponding
> - =A0 =A0partition of the flash device.
> -
> - =A0 =A0Flash partitions
> - =A0 =A0 - reg : The partition's offset and size within the flash bank.
> - =A0 =A0 - label : (optional) The label / name for this flash partition.
> - =A0 =A0 =A0 If omitted, the label is taken from the node name (excludin=
g
> - =A0 =A0 =A0 the unit address).
> - =A0 =A0 - read-only : (optional) This parameter, if present, is a hint =
to
> - =A0 =A0 =A0 Linux that this flash partition should only be mounted
> - =A0 =A0 =A0 read-only. =A0This is usually used for flash partitions
> - =A0 =A0 =A0 containing early-boot firmware images or data which should =
not
> - =A0 =A0 =A0 be clobbered.
> -
> - =A0 =A0Example:
> -
> - =A0 =A0 =A0 flash@ff000000 {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "amd,am29lv128ml", "cfi-flas=
h";
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <ff000000 01000000>;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 bank-width =3D <4>;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 device-width =3D <1>;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 #address-cells =3D <1>;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 #size-cells =3D <1>;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 fs@0 {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 label =3D "fs";
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0 f80000>;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 firmware@f80000 {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 label =3D"firmware";
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <f80000 80000>;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 read-only;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> - =A0 =A0 =A0 };
> -
> - =A0 =A0d) 4xx/Axon EMAC ethernet nodes
> + =A0 =A0c) 4xx/Axon EMAC ethernet nodes
>
> =A0 =A0 The EMAC ethernet controller in IBM and AMCC 4xx chips, and also
> =A0 =A0 the Axon bridge. =A0To operate this needs to interact with a ths
> @@ -1499,7 +1434,7 @@ platforms are moved over to use the flattened-devic=
e-tree model.
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 available.
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 For Axon: 0x0000012a
>
> - =A0 e) Xilinx IP cores
> + =A0 d) Xilinx IP cores
>
> =A0 =A0The Xilinx EDK toolchain ships with a set of IP cores (devices) fo=
r use
> =A0 =A0in Xilinx Spartan and Virtex FPGAs. =A0The devices cover the whole=
 range
> @@ -1761,7 +1696,7 @@ platforms are moved over to use the flattened-devic=
e-tree model.
> =A0 =A0 =A0 listed above, nodes for these devices should include a phy-ha=
ndle
> =A0 =A0 =A0 property, and may include other common network device propert=
ies
> =A0 =A0 =A0 like local-mac-address.
> -
> +
> =A0 =A0 =A0 iv) Xilinx Uartlite
>
> =A0 =A0 =A0 Xilinx uartlite devices are simple fixed speed serial ports.
> @@ -1793,7 +1728,7 @@ platforms are moved over to use the flattened-devic=
e-tree model.
> =A0 =A0 =A0 =A0- reg-offset : A value of 3 is required
> =A0 =A0 =A0 =A0- reg-shift : A value of 2 is required
>
> - =A0 =A0f) USB EHCI controllers
> + =A0 =A0e) USB EHCI controllers
>
> =A0 =A0 Required properties:
> =A0 =A0 =A0 - compatible : should be "usb-ehci".
> @@ -1819,7 +1754,7 @@ platforms are moved over to use the flattened-devic=
e-tree model.
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 big-endian;
> =A0 =A0 =A0 =A0 =A0 };
>
> - =A0 g) MDIO on GPIOs
> + =A0 f) MDIO on GPIOs
>
> =A0 =A0Currently defined compatibles:
> =A0 =A0- virtual,gpio-mdio
> @@ -1839,7 +1774,7 @@ platforms are moved over to use the flattened-devic=
e-tree model.
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &qe_pio_c 6>;
> =A0 =A0 =A0 =A0};
>
> - =A0 =A0h) SPI (Serial Peripheral Interface) busses
> + =A0 =A0g) SPI (Serial Peripheral Interface) busses
>
> =A0 =A0 SPI busses can be described with a node for the SPI master device
> =A0 =A0 and a set of child nodes for each SPI slave on the bus. =A0For th=
is
> diff --git a/Documentation/powerpc/dts-bindings/mtd-physmap.txt b/Documen=
tation/powerpc/dts-bindings/mtd-physmap.txt
> new file mode 100644
> index 0000000..cd474f9
> --- /dev/null
> +++ b/Documentation/powerpc/dts-bindings/mtd-physmap.txt
> @@ -0,0 +1,63 @@
> +CFI or JEDEC memory-mapped NOR flash
> +
> +Flash chips (Memory Technology Devices) are often used for solid state
> +file systems on embedded devices.
> +
> + - compatible : should contain the specific model of flash chip(s)
> + =A0 used, if known, followed by either "cfi-flash" or "jedec-flash"
> + - reg : Address range of the flash chip
> + - bank-width : Width (in bytes) of the flash bank. =A0Equal to the
> + =A0 device width times the number of interleaved chips.
> + - device-width : (optional) Width of a single flash chip. =A0If
> + =A0 omitted, assumed to be equal to 'bank-width'.
> + - #address-cells, #size-cells : Must be present if the flash has
> + =A0 sub-nodes representing partitions (see below). =A0In this case
> + =A0 both #address-cells and #size-cells must be equal to 1.
> +
> +For JEDEC compatible devices, the following additional properties
> +are defined:
> +
> + - vendor-id : Contains the flash chip's vendor id (1 byte).
> + - device-id : Contains the flash chip's device id (1 byte).
> +
> +In addition to the information on the flash bank itself, the
> +device tree may optionally contain additional information
> +describing partitions of the flash address space. =A0This can be
> +used on platforms which have strong conventions about which
> +portions of the flash are used for what purposes, but which don't
> +use an on-flash partition table such as RedBoot.
> +
> +Each partition is represented as a sub-node of the flash device.
> +Each node's name represents the name of the corresponding
> +partition of the flash device.
> +
> +Flash partitions
> + - reg : The partition's offset and size within the flash bank.
> + - label : (optional) The label / name for this flash partition.
> + =A0 If omitted, the label is taken from the node name (excluding
> + =A0 the unit address).
> + - read-only : (optional) This parameter, if present, is a hint to
> + =A0 Linux that this flash partition should only be mounted
> + =A0 read-only. =A0This is usually used for flash partitions
> + =A0 containing early-boot firmware images or data which should not
> + =A0 be clobbered.
> +
> +Example:
> +
> + =A0 =A0 =A0 flash@ff000000 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "amd,am29lv128ml", "cfi-flas=
h";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <ff000000 01000000>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 bank-width =3D <4>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 device-width =3D <1>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 #address-cells =3D <1>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 #size-cells =3D <1>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 fs@0 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 label =3D "fs";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <0 f80000>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 firmware@f80000 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 label =3D"firmware";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg =3D <f80000 80000>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 read-only;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 };
> + =A0 =A0 =A0 };
> --
> 1.6.2.2
>
>



--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* Re: [PATCH 4/4 v2] mtd/powerpc: Describe multiple "reg" tuples usage
From: Grant Likely @ 2009-04-12  6:05 UTC (permalink / raw)
  To: Stefan Roese; +Cc: linuxppc-dev, devicetree-discuss, linux-mtd
In-Reply-To: <1239093583-12201-1-git-send-email-sr@denx.de>

On Tue, Apr 7, 2009 at 2:39 AM, Stefan Roese <sr@denx.de> wrote:
> Signed-off-by: Stefan Roese <sr@denx.de>
> CC: Grant Likely <grant.likely@secretlab.ca>
> ---
> =A0Documentation/powerpc/dts-bindings/mtd-physmap.txt | =A0 20 ++++++++++=
+++++++++-
> =A01 files changed, 19 insertions(+), 1 deletions(-)
>
> diff --git a/Documentation/powerpc/dts-bindings/mtd-physmap.txt b/Documen=
tation/powerpc/dts-bindings/mtd-physmap.txt
> index ab1115e..a3fa9e0 100644
> --- a/Documentation/powerpc/dts-bindings/mtd-physmap.txt
> +++ b/Documentation/powerpc/dts-bindings/mtd-physmap.txt
> @@ -5,7 +5,10 @@ file systems on embedded devices.
>
> =A0- compatible : should contain the specific model of flash chip(s)
> =A0 =A0used, if known, followed by either "cfi-flash" or "jedec-flash"
> - - reg : Address range of the flash chip
> + - reg : Address range(s) of the flash chip(s)
> + =A0 It's possible to (optionally) define multiple "reg" tuples so that =
the
> + =A0 Intel P30 48F4400 chip which consists internally of 2 non-identical
> + =A0 NOR chips on one die can also be supported.

This isn't a P30 48F4400 specific feature, even if it is the only
current user.  This description works for any arrangement of multiple
NOR chips.  I isn't really appropriate to mention the P30 in this way
and it should be more generic.

> =A0- bank-width : Width (in bytes) of the flash bank. =A0Equal to the
> =A0 =A0device width times the number of interleaved chips.
> =A0- #address-cells, #size-cells : Must be present if the flash has
> @@ -58,3 +61,18 @@ Example:
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0read-only;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0};
> =A0 =A0 =A0 =A0};
> +
> +Here an example with multiple "reg" tuples (e.g. Intel P30):

However, it is completely appropriate to mention P30 here because it
is in the context of an example.

> +
> + =A0 =A0 =A0 flash@f0000000,0 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 #address-cells =3D <1>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 #size-cells =3D <1>;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "cfi-flash";

For best practice, compatible should also specify the exact chip in this ca=
se.

g.

--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* Re: [PATCH 3/4 v2] mtd/powerpc: Remove unused "device-width" property
From: Grant Likely @ 2009-04-12  6:01 UTC (permalink / raw)
  To: Stefan Roese; +Cc: Scott Wood, linuxppc-dev, devicetree-discuss, linux-mtd
In-Reply-To: <200904071854.16818.sr@denx.de>

On Tue, Apr 7, 2009 at 10:54 AM, Stefan Roese <sr@denx.de> wrote:
> On Tuesday 07 April 2009, Scott Wood wrote:
>> Stefan Roese wrote:
>> > This property is unused. It's not handled as all by the physmap_of
>> > driver. So let's remove it from the documentation.
>> >
>> > Signed-off-by: Stefan Roese <sr@denx.de>
>> > CC: Grant Likely <grant.likely@secretlab.ca>
>>
>> The device tree describes the hardware, not what Linux happens to do
>> with it at the moment.
>>
>> I'd rather keep it.
>
> I find it rather confusing to "see" such bindings that are not supported. One
> could expect something to happen/change after defining this property. So in
> general I think adding unsupported properties to the Documentation is a bad
> idea. But that's just my 2 cents. If the general opinion is to keep this
> property, I'll keep it in of course.

I say keep it.  It is a valid way to describe the hardware regardless
of whether or not the driver supports it yet.

g.

-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* Re: [PATCH 1/4 v2] mtd: physmap_of: Add multiple regions and concatenation support
From: Grant Likely @ 2009-04-12  5:58 UTC (permalink / raw)
  To: Stefan Roese; +Cc: linuxppc-dev, devicetree-discuss, linux-mtd
In-Reply-To: <1239093559-12043-1-git-send-email-sr@denx.de>

On Tue, Apr 7, 2009 at 2:39 AM, Stefan Roese <sr@denx.de> wrote:
> This patch adds support to handle multiple non-identical chips in one
> flash device tree node. It also adds concat support to physmap_of. This
> makes it possible to support e.g. the Intel P30 48F4400 chips which
> internally consists of 2 non-identical NOR chips on one die. Additionally
> partitions now can span over multiple chips.
>
[...]
> Signed-off-by: Stefan Roese <sr@denx.de>
> CC: Grant Likely <grant.likely@secretlab.ca>

Looks good to me.  To comments below, but neither are enough to hold back m=
y:

Reviewd-by: Grant Likely <grant.likely@secretlab.ca>

However, I have not tested this.  I'd like to hear of some larger
field testing before it is merged.

g.

> + =A0 =A0 =A0 reg_tuple_size =3D (of_n_addr_cells(dp) + of_n_size_cells(d=
p)) * 4;

Ideally s/4/sizeof(u32)/, but not a huge deal.

> + =A0 =A0 =A0 info =3D kzalloc(sizeof(struct of_flash) +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0sizeof(struct of_flash_list)=
 * count, GFP_KERNEL);
> + =A0 =A0 =A0 if (!info)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err_out;
> +
> + =A0 =A0 =A0 mtd_list =3D kzalloc(sizeof(struct mtd_info) * count, GFP_K=
ERNEL);

Typically I prefer to see a single kzalloc in a driver which allocates
all the space needed in one go because it simplifies the error/unwind
path.

Cheers,
g.

--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* Re: [BUILD FAILURE 04] Next April 9 : PPC64 randconfig [drivers/net/ibm_newemac/core.c]
From: David Miller @ 2009-04-11  9:44 UTC (permalink / raw)
  To: a.beregalov
  Cc: sachinp, sfr, netdev, linux-kernel, Linuxppc-dev, linux-next,
	greg, linux-net, subrata
In-Reply-To: <20090410015614.GA5781@orion>

From: Alexander Beregalov <a.beregalov@gmail.com>
Date: Fri, 10 Apr 2009 05:56:14 +0400

> Subject: [PATCH] ibm_newemac: convert to netdev_ops
> 
> 
> Reported-by: Subrata Modak <subrata@linux.vnet.ibm.com>
> Signed-off-by: Alexander Beregalov <a.beregalov@gmail.com>

Applied.

^ permalink raw reply

* Re: [PATCH] fs_enet: convert to netdev_ops
From: David Miller @ 2009-04-11  9:44 UTC (permalink / raw)
  To: subrata; +Cc: sachinp, netdev, linux-next, a.beregalov, Linuxppc-dev
In-Reply-To: <1239288588.5188.77.camel@subratamodak.linux.ibm.com>

From: Subrata Modak <subrata@linux.vnet.ibm.com>
Date: Thu, 09 Apr 2009 20:19:48 +0530

> On Thu, 2009-04-09 at 18:46 +0400, Alexander Beregalov wrote:
>> Reported-by: Subrata Modak <subrata@linux.vnet.ibm.com>
>> Signed-off-by: Alexander Beregalov <a.beregalov@gmail.com>
> 
> Thanks. Adding Sachin in Cc:

I've applied this patch.

^ permalink raw reply

* Re: [PATCH] Quieten arch/powerpc in a allmodconfig build.
From: Scott Wood @ 2009-04-10 21:51 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: Stephen Rothwell, linuxppc-dev
In-Reply-To: <FECC6BB4-0505-4319-BCD5-81E8B1C825B5@kernel.crashing.org>

Segher Boessenkool wrote:
>> And further, there is no separation of warning classes into 
>> might-be-uninitialized and is-uninitialized-compiler-can-tell-for-sure.
> 
> Indeed.  Please file a bug report.

Done: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=39731

-Scott

^ permalink raw reply

* Re: bug in drivers/edac/mpc85xx_edac.c:mpc85xx_mc_check() ?
From: Andrew Morton @ 2009-04-10 21:47 UTC (permalink / raw)
  To: Jeff Haran; +Cc: linuxppc-dev, Dave Jiang, linux-kernel, Doug Thompson
In-Reply-To: <57AC2FA1761300418C7AB8F3EA493C9702C5F200@HQ-EXCH-5.corp.brocade.com>

(cc's added)

On Wed, 8 Apr 2009 14:57:42 -0700
"Jeff Haran" <jharan@Brocade.COM> wrote:

> Hi,
> 
> Recent versions of this function start off with:
> 
> static void mpc85xx_mc_check(struct mem_ctl_info *mci)
> {
>     struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
>     ...
> 
>     err_detect = in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT);
>     if (err_detect)
>         return;
> 
>     ...
> }
> 
> My reading of the Freescale 8548E Manual leads me to conclude that the
> Memory Error Detect register (ERR_DETECT) will have various bits set if
> the memory controller has detected an error since the last time it was
> cleared. If no memory error has occurred, the register will contain 0.
> 
> Perhaps I am missing something very basic, but it seem to me that the
> above "if" should be:
> 
>     if (!err_detect)
>         return;
> 
> as the existing code would seem to read "if any errors have occurred,
> ignore them", though perhaps testing has demonstrated that the Freescale
> manual is in error.
> 
> Please include this email address in responses as I do not subscribe.
> 
> Thanks,
> 
> Jeff Haran
> Brocade

^ permalink raw reply


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