LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] powerpc/mpc512x: Group mpc512x board's selection menu
From: Anatolij Gustschin @ 2010-04-30 20:30 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Anatolij Gustschin, Detlev Zundel

Allow board selection in a drop-down board sub-menu
like many other platforms do.

Before the patch:
...
[ ] Freescale MPC5121E ADS
[ ] Generic support for simple MPC5121 based boards
[ ] 52xx-based boards
...

Patched:
...
[*] 512x-based boards
[ ]   Freescale MPC5121E ADS
[ ]   Generic support for simple MPC5121 based boards
[ ] 52xx-based boards
...

This is a cleanup before adding new board selection entry.

Signed-off-by: Anatolij Gustschin <agust@denx.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
---
 arch/powerpc/platforms/512x/Kconfig |   13 ++++---------
 1 files changed, 4 insertions(+), 9 deletions(-)

diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig
index 4dac9b0..e9dca28 100644
--- a/arch/powerpc/platforms/512x/Kconfig
+++ b/arch/powerpc/platforms/512x/Kconfig
@@ -1,29 +1,24 @@
 config PPC_MPC512x
-	bool
+	bool "512x-based boards"
+	depends on 6xx
 	select FSL_SOC
 	select IPIC
 	select PPC_CLOCK
 	select PPC_PCI_CHOICE
 	select FSL_PCI if PCI
 
-config PPC_MPC5121
-	bool
-	select PPC_MPC512x
-
 config MPC5121_ADS
 	bool "Freescale MPC5121E ADS"
-	depends on 6xx
+	depends on PPC_MPC512x
 	select DEFAULT_UIMAGE
-	select PPC_MPC5121
 	select MPC5121_ADS_CPLD
 	help
 	  This option enables support for the MPC5121E ADS board.
 
 config MPC5121_GENERIC
 	bool "Generic support for simple MPC5121 based boards"
-	depends on 6xx
+	depends on PPC_MPC512x
 	select DEFAULT_UIMAGE
-	select PPC_MPC5121
 	help
 	  This option enables support for simple MPC5121 based boards
 	  which do not need custom platform specific setup.
-- 
1.6.3.3

^ permalink raw reply related

* Re: [PATCH 3/5] powerpc/mpc5121: shared DIU framebuffer support
From: Timur Tabi @ 2010-04-30 18:29 UTC (permalink / raw)
  To: Anatolij Gustschin
  Cc: linux-fbdev, wd, dzu, John Rigby, devicetree-discuss,
	linuxppc-dev, yorksun
In-Reply-To: <20100430190051.3a5ba058@wker>

On Fri, Apr 30, 2010 at 12:00 PM, Anatolij Gustschin <agust@denx.de> wrote:

> Thanks. Sorry for my wrong answer above, now I remember the logic
> behind this and will try to explain. Actually the reason I do not
> use kmalloc() here is that I do not want to _copy_ bitmap data to
> newly allocated frame buffer area (It will negatively affect boot
> time). Instead I reserve the already configured frame buffer area
> so that it won't be destroyed. The starting address of the area
> to reserve and also the lenght is passed to reserve_bootmem().
> This is the real reason for using reserve_bootmem() here.
> I could alloc new bitmap area using allocators, but then I have
> to copy the bitmap data (splash image) to newly allocated area
> and have to re-configure the descriptors to display from new
> bitmap buffer.

Ok, I understand.  Please add this comment to the code, so that no one
else will wonder what you're doing.

-- 
Timur Tabi
Linux kernel developer at Freescale

^ permalink raw reply

* Re: [PATCH 3/5] powerpc/mpc5121: shared DIU framebuffer support
From: Timur Tabi @ 2010-04-30 18:18 UTC (permalink / raw)
  To: Scott Wood
  Cc: linux-fbdev, wd, dzu, John Rigby, devicetree-discuss,
	linuxppc-dev, Anatolij Gustschin, yorksun
In-Reply-To: <20100430162254.GA24285@schlenkerla.am.freescale.net>

On Fri, Apr 30, 2010 at 11:22 AM, Scott Wood <scottwood@freescale.com> wrot=
e:

>> That's what I meant. =A0Actually, I think it's ULL. =A0Regardless, I thi=
nk
>> the compiler will see the =A0"1000000000 ... * 1000" and just combine
>> them together. =A0You're not actually outsmarting the compiler.
>
> The compiler will do no such thing. =A0That's a valid transformation when
> doing pure math, but not when working with integers.

I ran some tests, and it appears you're right.  I doesn't make a lot
of sense to me, but whatever.

However, "(1000000000 / pixclock) * 1000" produces a result that's
less accurate than "1000000000000ULL / pixclock".  Unfortunately, that
math caused a linker problem with __udivdi3 when I tried it, so maybe
you can use do_div() instead?

>> =A0 =A0 err =3D -1;
>>
>> because he wanted it to be the largest possible integer.
>
> -1 is not the largest possible integer. =A0LONG_MAX, perhaps?

What, you don't like implicit casting of -1 to an unsigned? :-)

Since err is a long integer, LONG_MAX is the better choice.

--=20
Timur Tabi
Linux kernel developer at Freescale

^ permalink raw reply

* Re: [PATCH 3/4] of/gpio: Implement GPIOLIB notifier hooks
From: Anton Vorontsov @ 2010-04-30 17:45 UTC (permalink / raw)
  To: Grant Likely
  Cc: David Brownell, Dmitry Eremin-Solenikov, linux-kernel,
	linuxppc-dev, Bill Gatliff, Andrew Morton
In-Reply-To: <fa686aa41003121338oe34eb89o22177cb0a309cc85@mail.gmail.com>

On Fri, Mar 12, 2010 at 02:38:02PM -0700, Grant Likely wrote:
[...]
> How to proceed:  I'd like to leave this series out for the 2.6.34
> cycle and I'll pick it into my OF tree before the 2.6.35 merge window,
> but I'll probably modify it to call the OF hooks directly and leave
> out the unnecessary notifier infrastructure.

Ping?

^ permalink raw reply

* Re: -next Apr 30: OOPS during eHEA driver initialization
From: Grant Likely @ 2010-04-30 17:43 UTC (permalink / raw)
  To: Sachin Sant
  Cc: Linux/PPC Development, linux-next@vger.kernel.org,
	Greg Kroah-Hartman, linux-kernel
In-Reply-To: <n2kfa686aa41004301035p7e15c017u7a1b98389cc1e466@mail.gmail.com>

On Fri, Apr 30, 2010 at 11:35 AM, Grant Likely
<grant.likely@secretlab.ca> wrote:
> On Fri, Apr 30, 2010 at 11:27 AM, Sachin Sant <sachinp@in.ibm.com> wrote:
>> Sachin Sant wrote:
>>>
>>> With today's next eHEA drivers fails to initialize.
>>
>> If i revert the following patch eHEA network interface is initialized
>> properly.
>>
>> commit cebfe0b6709abdab997c1a00499d67efa32ee1f0
>> drivercore: Add of_match_table to the common device drivers
>
> That is an easy one to fix. =A0I'll get it updated today and send you the=
 result.

Let me know if this patch fixes it:

Cheers,
g.

diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c
index ce957a4..693b0e6 100644
--- a/arch/powerpc/kernel/ibmebus.c
+++ b/arch/powerpc/kernel/ibmebus.c
@@ -201,6 +201,9 @@ static int ibmebus_create_devices(const struct
of_device_id *matches)

 int ibmebus_register_driver(struct of_platform_driver *drv)
 {
+	if (!drv->driver.of_match_table)
+		drv->driver.of_match_table =3D drv->match_table;
+
 	/* If the driver uses devices that ibmebus doesn't know, add them */
 	ibmebus_create_devices(drv->driver.of_match_table);



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

^ permalink raw reply related

* Re: -next Apr 30: OOPS during eHEA driver initialization
From: Grant Likely @ 2010-04-30 17:35 UTC (permalink / raw)
  To: Sachin Sant
  Cc: Linux/PPC Development, linux-next@vger.kernel.org,
	Greg Kroah-Hartman, linux-kernel
In-Reply-To: <4BDB12FB.5060806@in.ibm.com>

On Fri, Apr 30, 2010 at 11:27 AM, Sachin Sant <sachinp@in.ibm.com> wrote:
> Sachin Sant wrote:
>>
>> With today's next eHEA drivers fails to initialize.
>
> If i revert the following patch eHEA network interface is initialized
> properly.
>
> commit cebfe0b6709abdab997c1a00499d67efa32ee1f0
> drivercore: Add of_match_table to the common device drivers

That is an easy one to fix.  I'll get it updated today and send you the result.

g.

^ permalink raw reply

* Re: -next Apr 30: OOPS during eHEA driver initialization
From: Sachin Sant @ 2010-04-30 17:27 UTC (permalink / raw)
  To: Linux/PPC Development
  Cc: linux-next@vger.kernel.org, Greg Kroah-Hartman, linux-kernel
In-Reply-To: <4BDAF376.4030005@in.ibm.com>

Sachin Sant wrote:
> With today's next eHEA drivers fails to initialize.
If i revert the following patch eHEA network interface is initialized
properly.

commit cebfe0b6709abdab997c1a00499d67efa32ee1f0
drivercore: Add of_match_table to the common device drivers

Thanks
-Sachin

>
> IBM eHEA ethernet device driver (Release EHEA_0103)
> Unable to handle kernel paging request for data at address 0x00000000
> Faulting instruction address: 0xc0000000004e8d7c
> Oops: Kernel access of bad area, sig: 11 [#1]
> SMP NR_CPUS=1024 NUMA pSeries
> last sysfs file: /sys/devices/vio/30000007/host0/target0:0:2/0:0:2:0/type
> Modules linked in: ehea(+) sr_mod cdrom sg sd_mod crc_t10dif ibmvscsic 
> scsi_transport_srp scsi_tgt scsi_mod
> NIP: c0000000004e8d7c LR: c00000000002614c CTR: c000000000026314
> REGS: c00000000c517810 TRAP: 0300   Not tainted  
> (2.6.34-rc5-autotest-next-20100430)
> MSR: 8000000000009032 <EE,ME,IR,DR>  CR: 24222228  XER: 20000005
> DAR: 0000000000000000, DSISR: 0000000040000000
> TASK = c00000000cf3ced0[730] 'modprobe' THREAD: c00000000c514000 CPU: 0
> GPR00: c00000000002614c c00000000c517a90 c000000000c96358 
> 0000000000000000
> GPR04: c0000000ffff7858 c0000000004e973c c00000000cf3d9c8 
> 0000000000000000
> GPR08: c000000000e4f8a0 0000000000001eed 0000000000000000 
> 00000000000002e7
> GPR12: d000000001bfb0d0 c000000007440000 0000000000000000 
> 0000000000000000
> GPR16: 0000000000000000 0000000000000000 000000001002c598 
> 0000000000000000
> GPR20: 0000000000000000 0000000000000004 0000000000000000 
> 0000000010030218
> GPR24: 0000000010030160 00000fffb7b00000 0000000010030200 
> 0000000000000000
> GPR28: c0000000ffff7858 0000000000000000 c000000000bfd528 
> 0000000000000000
> NIP [c0000000004e8d7c] .of_match_node+0xc0/0x10c
> LR [c00000000002614c] .ibmebus_create_devices+0x48/0x104
> Call Trace:
> [c00000000c517a90] [c0000000004e973c] .of_get_next_child+0x74/0x98 
> (unreliable)
> [c00000000c517b20] [c00000000002614c] .ibmebus_create_devices+0x48/0x104
> [c00000000c517bc0] [c000000000026338] .ibmebus_register_driver+0x24/0x4c
> [c00000000c517c50] [d000000001bfa1bc] .ehea_module_init+0x1d4/0x22b8 
> [ehea]
> [c00000000c517ce0] [c0000000000097a4] .do_one_initcall+0x88/0x1bc
> [c00000000c517d90] [c0000000000cbdf4] .SyS_init_module+0x11c/0x2b0
> [c00000000c517e30] [c0000000000085b4] syscall_exit+0x0/0x40
> Instruction dump:
> 7c7de838 881f0040 2f800000 419e0018 7f83e378 389f0040 4bfffdbd 7c63e838
> 7c7d07b4 2fbd0000 409e0030 3bff00c8 <881f0000> 2f800000 409eff60 881f0020
> ---[ end trace cb522a034d760fb8 ]---
>
> next-20100428 was OK. Will try to bisect.
>
> Thanks
> -Sachin
>
>


-- 

---------------------------------
Sachin Sant
IBM Linux Technology Center
India Systems and Technology Labs
Bangalore, India
---------------------------------

^ permalink raw reply

* Re: [PATCH 3/5] powerpc/mpc5121: shared DIU framebuffer support
From: Anatolij Gustschin @ 2010-04-30 17:00 UTC (permalink / raw)
  To: Timur Tabi
  Cc: linux-fbdev, wd, dzu, John Rigby, devicetree-discuss,
	linuxppc-dev, yorksun
In-Reply-To: <x2ned82fe3e1004300808q757826cs864ac1c7c082f81@mail.gmail.com>

On Fri, 30 Apr 2010 10:08:45 -0500
Timur Tabi <timur.tabi@gmail.com> wrote:

> On Fri, Apr 30, 2010 at 5:19 AM, Anatolij Gustschin <agust@denx.de> wrote:
>=20
> >> How about just doing this?
> >>
> >> .init_early =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =3D mpc512x_init=
_diu,
> >
> > I thought it should be prepared for adding other code here.
> > mpc5121_ads_init_early() is generic and could contain other
> > things as well. I would vote for current version.
>=20
> Do you have any plans to add any additional code?   If not, then I say
> skip the middle-man.  If someone ever needs to do more, he can always
> put that function back.

Currently I do not have such plans. Ok will skip them.

...
> >> Do you really need to use reserve_bootmem? =C2=A0Have you tried kmallo=
c or
> >> alloc_pages_exact()?
> >
> > Yes. No, it is too early to use them here.
>=20
> There was a recent change in the kernel that allows kmalloc to work
> earlier than before.  Take a look at commit
> 85355bb272db31a3f2dd99d547eef794805e1319 ("powerpc: Fix mpic alloc
> warning").

Thanks. Sorry for my wrong answer above, now I remember the logic
behind this and will try to explain. Actually the reason I do not
use kmalloc() here is that I do not want to _copy_ bitmap data to
newly allocated frame buffer area (It will negatively affect boot
time). Instead I reserve the already configured frame buffer area
so that it won't be destroyed. The starting address of the area
to reserve and also the lenght is passed to reserve_bootmem().
This is the real reason for using reserve_bootmem() here.
I could alloc new bitmap area using allocators, but then I have
to copy the bitmap data (splash image) to newly allocated area
and have to re-configure the descriptors to display from new
bitmap buffer.

Anatolij

^ permalink raw reply

* Re: [PATCH 3/5] powerpc/mpc5121: shared DIU framebuffer support
From: Scott Wood @ 2010-04-30 16:22 UTC (permalink / raw)
  To: Timur Tabi
  Cc: linux-fbdev, wd, dzu, John Rigby, devicetree-discuss,
	linuxppc-dev, Anatolij Gustschin, yorksun
In-Reply-To: <x2ned82fe3e1004300808q757826cs864ac1c7c082f81@mail.gmail.com>

On Fri, Apr 30, 2010 at 10:08:45AM -0500, Timur Tabi wrote:
> On Fri, Apr 30, 2010 at 5:19 AM, Anatolij Gustschin <agust@denx.de> wrote:
> 
> >> How about just doing this?
> >>
> >> .init_early             = mpc512x_init_diu,
> >
> > I thought it should be prepared for adding other code here.
> > mpc5121_ads_init_early() is generic and could contain other
> > things as well. I would vote for current version.
> 
> Do you have any plans to add any additional code?   If not, then I say
> skip the middle-man.  If someone ever needs to do more, he can always
> put that function back.
> 
> >> I'm pretty sure the compiler will optimize this to:
> >>
> >>     temp = (1000000000000UL / pixclock);
> >>
> >> so you may as well do it that way.
> >
> > ??
> > 1000000000000 is _not_ UL, but UUL.
> 
> That's what I meant.  Actually, I think it's ULL.  Regardless, I think
> the compiler will see the  "1000000000 ... * 1000" and just combine
> them together.  You're not actually outsmarting the compiler.

The compiler will do no such thing.  That's a valid transformation when
doing pure math, but not when working with integers.

> >> > +       err = 100000000;
> >>
> >> Why do you assign err to this arbitrary value?
> >
> > Dunno. It is Freescale's code and I do not have time to check
> > and understand each bit of it and to explain it.
> 
> *sigh*  You're not the first person to modify the DIU driver without
> understanding what it all does.  I suspect that the original author
> should have done this:
> 
>     err = -1;
> 
> because he wanted it to be the largest possible integer.

-1 is not the largest possible integer.  LONG_MAX, perhaps?

-Scott

^ permalink raw reply

* Re: [PATCH 3/5] powerpc/mpc5121: shared DIU framebuffer support
From: Timur Tabi @ 2010-04-30 15:08 UTC (permalink / raw)
  To: Anatolij Gustschin
  Cc: linux-fbdev, wd, dzu, John Rigby, devicetree-discuss,
	linuxppc-dev, yorksun
In-Reply-To: <20100430121947.1d265ca6@wker>

On Fri, Apr 30, 2010 at 5:19 AM, Anatolij Gustschin <agust@denx.de> wrote:

>> How about just doing this?
>>
>> .init_early =A0 =A0 =A0 =A0 =A0 =A0 =3D mpc512x_init_diu,
>
> I thought it should be prepared for adding other code here.
> mpc5121_ads_init_early() is generic and could contain other
> things as well. I would vote for current version.

Do you have any plans to add any additional code?   If not, then I say
skip the middle-man.  If someone ever needs to do more, he can always
put that function back.

>> I'm pretty sure the compiler will optimize this to:
>>
>> =A0 =A0 temp =3D (1000000000000UL / pixclock);
>>
>> so you may as well do it that way.
>
> ??
> 1000000000000 is _not_ UL, but UUL.

That's what I meant.  Actually, I think it's ULL.  Regardless, I think
the compiler will see the  "1000000000 ... * 1000" and just combine
them together.  You're not actually outsmarting the compiler.

>> > + =A0 =A0 =A0 err =3D 100000000;
>>
>> Why do you assign err to this arbitrary value?
>
> Dunno. It is Freescale's code and I do not have time to check
> and understand each bit of it and to explain it.

*sigh*  You're not the first person to modify the DIU driver without
understanding what it all does.  I suspect that the original author
should have done this:

    err =3D -1;

because he wanted it to be the largest possible integer.

>> Do you really need to use reserve_bootmem? =A0Have you tried kmalloc or
>> alloc_pages_exact()?
>
> Yes. No, it is too early to use them here.

There was a recent change in the kernel that allows kmalloc to work
earlier than before.  Take a look at commit
85355bb272db31a3f2dd99d547eef794805e1319 ("powerpc: Fix mpic alloc
warning").

>> > + =A0 =A0 =A0 mode =3D in_be32(diu_reg + 0x1c);
>> > + =A0 =A0 =A0 if (mode !=3D 1) {
>>
>> How can in_be32() return a -1?
>
> It is a 1, not -1. I will use appropriate macro here and also
> change to use a struct instead of adding offset to register base.

Sorry, I misread the code.  I could have sworn it read "mode !=3D -1"

--=20
Timur Tabi
Linux kernel developer at Freescale

^ permalink raw reply

* -next Apr 30: OOPS during eHEA driver initialization
From: Sachin Sant @ 2010-04-30 15:12 UTC (permalink / raw)
  To: Linux/PPC Development; +Cc: linux-next@vger.kernel.org

With today's next eHEA drivers fails to initialize.

IBM eHEA ethernet device driver (Release EHEA_0103)
Unable to handle kernel paging request for data at address 0x00000000
Faulting instruction address: 0xc0000000004e8d7c
Oops: Kernel access of bad area, sig: 11 [#1]
SMP NR_CPUS=1024 NUMA pSeries
last sysfs file: /sys/devices/vio/30000007/host0/target0:0:2/0:0:2:0/type
Modules linked in: ehea(+) sr_mod cdrom sg sd_mod crc_t10dif ibmvscsic scsi_transport_srp scsi_tgt scsi_mod
NIP: c0000000004e8d7c LR: c00000000002614c CTR: c000000000026314
REGS: c00000000c517810 TRAP: 0300   Not tainted  (2.6.34-rc5-autotest-next-20100430)
MSR: 8000000000009032 <EE,ME,IR,DR>  CR: 24222228  XER: 20000005
DAR: 0000000000000000, DSISR: 0000000040000000
TASK = c00000000cf3ced0[730] 'modprobe' THREAD: c00000000c514000 CPU: 0
GPR00: c00000000002614c c00000000c517a90 c000000000c96358 0000000000000000
GPR04: c0000000ffff7858 c0000000004e973c c00000000cf3d9c8 0000000000000000
GPR08: c000000000e4f8a0 0000000000001eed 0000000000000000 00000000000002e7
GPR12: d000000001bfb0d0 c000000007440000 0000000000000000 0000000000000000
GPR16: 0000000000000000 0000000000000000 000000001002c598 0000000000000000
GPR20: 0000000000000000 0000000000000004 0000000000000000 0000000010030218
GPR24: 0000000010030160 00000fffb7b00000 0000000010030200 0000000000000000
GPR28: c0000000ffff7858 0000000000000000 c000000000bfd528 0000000000000000
NIP [c0000000004e8d7c] .of_match_node+0xc0/0x10c
LR [c00000000002614c] .ibmebus_create_devices+0x48/0x104
Call Trace:
[c00000000c517a90] [c0000000004e973c] .of_get_next_child+0x74/0x98 (unreliable)
[c00000000c517b20] [c00000000002614c] .ibmebus_create_devices+0x48/0x104
[c00000000c517bc0] [c000000000026338] .ibmebus_register_driver+0x24/0x4c
[c00000000c517c50] [d000000001bfa1bc] .ehea_module_init+0x1d4/0x22b8 [ehea]
[c00000000c517ce0] [c0000000000097a4] .do_one_initcall+0x88/0x1bc
[c00000000c517d90] [c0000000000cbdf4] .SyS_init_module+0x11c/0x2b0
[c00000000c517e30] [c0000000000085b4] syscall_exit+0x0/0x40
Instruction dump:
7c7de838 881f0040 2f800000 419e0018 7f83e378 389f0040 4bfffdbd 7c63e838
7c7d07b4 2fbd0000 409e0030 3bff00c8 <881f0000> 2f800000 409eff60 881f0020
---[ end trace cb522a034d760fb8 ]---

next-20100428 was OK. Will try to bisect.

Thanks
-Sachin


-- 

---------------------------------
Sachin Sant
IBM Linux Technology Center
India Systems and Technology Labs
Bangalore, India
---------------------------------

^ permalink raw reply

* Re: [PATCH 1/2] powerpc/mpc5121: move PSC FIFO memory init to platform code
From: Grant Likely @ 2010-04-30 13:42 UTC (permalink / raw)
  To: Anatolij Gustschin
  Cc: spi-devel-general, David Brownell, Wolfgang Denk, Detelv Zundel,
	linuxppc-dev
In-Reply-To: <1272633687-6935-2-git-send-email-agust@denx.de>

On Fri, Apr 30, 2010 at 7:21 AM, Anatolij Gustschin <agust@denx.de> wrote:
> Since PSC could also be used in other modes than UART mode
> we move PSC FIFO memory initialization from serial driver to
> common platform code. The initialized FIFO memory slices may
> not overlap, so the most easy way would be to configure them
> all at once at init time for all PSC devices. This is now done
> by this patch.
>
> Signed-off-by: Anatolij Gustschin <agust@denx.de>

Looks good.  I'll pick it up.

g.

> ---
> =A0arch/powerpc/platforms/512x/mpc512x_shared.c | =A0 78 ++++++++++++++++=
++++++++++
> =A0drivers/serial/mpc52xx_uart.c =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0| =A0 69 =
-----------------------
> =A02 files changed, 78 insertions(+), 69 deletions(-)
>
> diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/=
platforms/512x/mpc512x_shared.c
> index 796080c..a717466 100644
> --- a/arch/powerpc/platforms/512x/mpc512x_shared.c
> +++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
> @@ -26,6 +26,7 @@
> =A0#include <asm/prom.h>
> =A0#include <asm/time.h>
> =A0#include <asm/mpc5121.h>
> +#include <asm/mpc52xx_psc.h>
>
> =A0#include "mpc512x.h"
>
> @@ -369,9 +370,86 @@ void __init mpc512x_declare_of_platform_devices(void=
)
> =A0 =A0 =A0 =A0}
> =A0}
>
> +#define DEFAULT_FIFO_SIZE 16
> +
> +static unsigned int __init get_fifo_size(struct device_node *np,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0char *prop_name)
> +{
> + =A0 =A0 =A0 const unsigned int *fp;
> +
> + =A0 =A0 =A0 fp =3D of_get_property(np, prop_name, NULL);
> + =A0 =A0 =A0 if (fp)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return *fp;
> +
> + =A0 =A0 =A0 pr_warning("no %s property in %s node, defaulting to %d\n",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0prop_name, np->full_name, DEFAULT_FI=
FO_SIZE);
> +
> + =A0 =A0 =A0 return DEFAULT_FIFO_SIZE;
> +}
> +
> +#define FIFOC(_base) ((struct mpc512x_psc_fifo __iomem *) \
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ((u32)(_base) + sizeof(struct mpc52=
xx_psc)))
> +
> +/* Init PSC FIFO space for TX and RX slices */
> +void __init mpc512x_psc_fifo_init(void)
> +{
> + =A0 =A0 =A0 struct device_node *np;
> + =A0 =A0 =A0 void __iomem *psc;
> + =A0 =A0 =A0 unsigned int tx_fifo_size;
> + =A0 =A0 =A0 unsigned int rx_fifo_size;
> + =A0 =A0 =A0 int fifobase =3D 0; /* current fifo address in 32 bit words=
 */
> +
> + =A0 =A0 =A0 for_each_compatible_node(np, NULL, "fsl,mpc5121-psc") {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tx_fifo_size =3D get_fifo_size(np, "fsl,tx-=
fifo-size");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 rx_fifo_size =3D get_fifo_size(np, "fsl,rx-=
fifo-size");
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* size in register is in 4 byte units */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tx_fifo_size /=3D 4;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 rx_fifo_size /=3D 4;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!tx_fifo_size)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 tx_fifo_size =3D 1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!rx_fifo_size)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 rx_fifo_size =3D 1;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 psc =3D of_iomap(np, 0);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!psc) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_err("%s: Can't map %s de=
vice\n",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 __func__, n=
p->full_name);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 continue;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* FIFO space is 4KiB, check if requested s=
ize is available */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if ((fifobase + tx_fifo_size + rx_fifo_size=
) > 0x1000) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_err("%s: no fifo space a=
vailable for %s\n",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 __func__, n=
p->full_name);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 iounmap(psc);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* chances are that anoth=
er device requests less
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* fifo space, so we cont=
inue.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 continue;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* set tx and rx fifo size registers */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(&FIFOC(psc)->txsz, (fifobase << 16=
) | tx_fifo_size);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 fifobase +=3D tx_fifo_size;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(&FIFOC(psc)->rxsz, (fifobase << 16=
) | rx_fifo_size);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 fifobase +=3D rx_fifo_size;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* reset and enable the slices */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(&FIFOC(psc)->txcmd, 0x80);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(&FIFOC(psc)->txcmd, 0x01);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(&FIFOC(psc)->rxcmd, 0x80);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(&FIFOC(psc)->rxcmd, 0x01);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 iounmap(psc);
> + =A0 =A0 =A0 }
> +}
> +
> =A0void __init mpc512x_init(void)
> =A0{
> =A0 =A0 =A0 =A0mpc512x_declare_of_platform_devices();
> =A0 =A0 =A0 =A0mpc5121_clk_init();
> =A0 =A0 =A0 =A0mpc512x_restart_init();
> + =A0 =A0 =A0 mpc512x_psc_fifo_init();
> =A0}
> diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.=
c
> index 3119fdd..843e7fb 100644
> --- a/drivers/serial/mpc52xx_uart.c
> +++ b/drivers/serial/mpc52xx_uart.c
> @@ -430,34 +430,10 @@ static unsigned long mpc512x_getuartclk(void *p)
> =A0 =A0 =A0 =A0return mpc5xxx_get_bus_frequency(p);
> =A0}
>
> -#define DEFAULT_FIFO_SIZE 16
> -
> -static unsigned int __init get_fifo_size(struct device_node *np,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0char *fifo_name)
> -{
> - =A0 =A0 =A0 const unsigned int *fp;
> -
> - =A0 =A0 =A0 fp =3D of_get_property(np, fifo_name, NULL);
> - =A0 =A0 =A0 if (fp)
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 return *fp;
> -
> - =A0 =A0 =A0 pr_warning("no %s property in %s node, defaulting to %d\n",
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0fifo_name, np->full_name, DEFAULT_FI=
FO_SIZE);
> -
> - =A0 =A0 =A0 return DEFAULT_FIFO_SIZE;
> -}
> -
> -#define FIFOC(_base) ((struct mpc512x_psc_fifo __iomem *) \
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ((u32)(_base) + sizeof(struct mpc52=
xx_psc)))
> -
> =A0/* Init PSC FIFO Controller */
> =A0static int __init mpc512x_psc_fifoc_init(void)
> =A0{
> =A0 =A0 =A0 =A0struct device_node *np;
> - =A0 =A0 =A0 void __iomem *psc;
> - =A0 =A0 =A0 unsigned int tx_fifo_size;
> - =A0 =A0 =A0 unsigned int rx_fifo_size;
> - =A0 =A0 =A0 int fifobase =3D 0; /* current fifo address in 32 bit words=
 */
>
> =A0 =A0 =A0 =A0np =3D of_find_compatible_node(NULL, NULL,
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "=
fsl,mpc5121-psc-fifo");
> @@ -480,51 +456,6 @@ static int __init mpc512x_psc_fifoc_init(void)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return -ENODEV;
> =A0 =A0 =A0 =A0}
>
> - =A0 =A0 =A0 for_each_compatible_node(np, NULL, "fsl,mpc5121-psc-uart") =
{
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 tx_fifo_size =3D get_fifo_size(np, "fsl,tx-=
fifo-size");
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 rx_fifo_size =3D get_fifo_size(np, "fsl,rx-=
fifo-size");
> -
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* size in register is in 4 byte units */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 tx_fifo_size /=3D 4;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 rx_fifo_size /=3D 4;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!tx_fifo_size)
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 tx_fifo_size =3D 1;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!rx_fifo_size)
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 rx_fifo_size =3D 1;
> -
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 psc =3D of_iomap(np, 0);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!psc) {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_err("%s: Can't map %s de=
vice\n",
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 __func__, n=
p->full_name);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 continue;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> -
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* FIFO space is 4KiB, check if requested s=
ize is available */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 if ((fifobase + tx_fifo_size + rx_fifo_size=
) > 0x1000) {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_err("%s: no fifo space a=
vailable for %s\n",
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 __func__, n=
p->full_name);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 iounmap(psc);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* chances are that anoth=
er device requests less
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* fifo space, so we cont=
inue.
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 continue;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* set tx and rx fifo size registers */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(&FIFOC(psc)->txsz, (fifobase << 16=
) | tx_fifo_size);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 fifobase +=3D tx_fifo_size;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(&FIFOC(psc)->rxsz, (fifobase << 16=
) | rx_fifo_size);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 fifobase +=3D rx_fifo_size;
> -
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* reset and enable the slices */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(&FIFOC(psc)->txcmd, 0x80);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(&FIFOC(psc)->txcmd, 0x01);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(&FIFOC(psc)->rxcmd, 0x80);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(&FIFOC(psc)->rxcmd, 0x01);
> -
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 iounmap(psc);
> - =A0 =A0 =A0 }
> -
> =A0 =A0 =A0 =A0return 0;
> =A0}
>
> --
> 1.6.3.3
>
>



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

^ permalink raw reply

* Re: [PATCH] add icswx support
From: Michael Ellerman @ 2010-04-30 13:35 UTC (permalink / raw)
  To: Tseng-Hui (Frank) Lin; +Cc: linuxppc-dev
In-Reply-To: <1272405410.6329.16.camel@flin.austin.ibm.com>

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

On Tue, 2010-04-27 at 16:56 -0500, Tseng-Hui (Frank) Lin wrote:
> On Sat, 2010-04-24 at 10:55 +1000, Benjamin Herrenschmidt wrote:
> > On Fri, 2010-04-23 at 17:04 -0500, Tseng-Hui (Frank) Lin wrote:
> > > Add Power7 icswx co-processor instruction support.
> > 
> > Please provide a -much- more detailed explanation of what it is, what it
> > does and why it requires hooking into the MMU context switch code. _I_
> > know these things but nobody else on the list does which limits the
> > ability of people to review your patch.
> >
> 
> icswx is a PowerPC co-processor instruction to send data to a 
> co-processor. On Book-S processors the LPAR_ID and process ID (PID) of 
> the owning process are registered in the window context of the
> co-processor at initial time. When the icswx instruction is executed,
> the L2 generates a cop-reg transaction on PowerBus. The transaction has
> no address and the processor does not perform an MMU access to 
> authenticate the transaction. The coprocessor compares the LPAR_ID and
> the PID included in the transaction and the LPAR_ID and PID held in the
> window context to determine if the process is authorized to generate the
> transaction.

How does userspace discover that there are coprocessors to send requests
to? And how does the coprocessor send results back to the process?

cheers


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

^ permalink raw reply

* [PATCH 2/2] spi: Add SPI master driver for MPC5121 PSC
From: Anatolij Gustschin @ 2010-04-30 13:21 UTC (permalink / raw)
  To: spi-devel-general, linuxppc-dev
  Cc: David Brownell, Wolfgang Denk, Detelv Zundel
In-Reply-To: <1272633687-6935-2-git-send-email-agust@denx.de>

Signed-off-by: John Rigby <jcrigby@gmail.com>
Signed-off-by: Anatolij Gustschin <agust@denx.de>
---
 arch/powerpc/include/asm/mpc52xx_psc.h |    1 +
 drivers/spi/Kconfig                    |    7 +
 drivers/spi/Makefile                   |    1 +
 drivers/spi/mpc512x_psc_spi.c          |  576 ++++++++++++++++++++++++++++++++
 4 files changed, 585 insertions(+), 0 deletions(-)
 create mode 100644 drivers/spi/mpc512x_psc_spi.c

diff --git a/arch/powerpc/include/asm/mpc52xx_psc.h b/arch/powerpc/include/asm/mpc52xx_psc.h
index 42561f4..ecc4fc6 100644
--- a/arch/powerpc/include/asm/mpc52xx_psc.h
+++ b/arch/powerpc/include/asm/mpc52xx_psc.h
@@ -248,6 +248,7 @@ struct mpc52xx_psc_fifo {
 	u16		tflwfptr;	/* PSC + 0x9e */
 };
 
+#define MPC512x_PSC_FIFO_EOF		0x100
 #define MPC512x_PSC_FIFO_RESET_SLICE	0x80
 #define MPC512x_PSC_FIFO_ENABLE_SLICE	0x01
 #define MPC512x_PSC_FIFO_ENABLE_DMA	0x04
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index a191fa2..317bb01 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -165,6 +165,13 @@ config SPI_MPC52xx_PSC
 	  This enables using the Freescale MPC52xx Programmable Serial
 	  Controller in master SPI mode.
 
+config SPI_MPC512x_PSC
+	tristate "Freescale MPC512x PSC SPI controller"
+	depends on SPI_MASTER && PPC_MPC512x
+	help
+	  This enables using the Freescale MPC5121 Programmable Serial
+	  Controller in SPI master mode.
+
 config SPI_MPC8xxx
 	tristate "Freescale MPC8xxx SPI controller"
 	depends on FSL_SOC
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index d7d0f89..b989ffb 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_SPI_OMAP24XX)		+= omap2_mcspi.o
 obj-$(CONFIG_SPI_OMAP_100K)		+= omap_spi_100k.o
 obj-$(CONFIG_SPI_ORION)			+= orion_spi.o
 obj-$(CONFIG_SPI_PL022)			+= amba-pl022.o
+obj-$(CONFIG_SPI_MPC512x_PSC)		+= mpc512x_psc_spi.o
 obj-$(CONFIG_SPI_MPC52xx_PSC)		+= mpc52xx_psc_spi.o
 obj-$(CONFIG_SPI_MPC52xx)		+= mpc52xx_spi.o
 obj-$(CONFIG_SPI_MPC8xxx)		+= spi_mpc8xxx.o
diff --git a/drivers/spi/mpc512x_psc_spi.c b/drivers/spi/mpc512x_psc_spi.c
new file mode 100644
index 0000000..28a126d
--- /dev/null
+++ b/drivers/spi/mpc512x_psc_spi.c
@@ -0,0 +1,576 @@
+/*
+ * MPC512x PSC in SPI mode driver.
+ *
+ * Copyright (C) 2007,2008 Freescale Semiconductor Inc.
+ * Original port from 52xx driver:
+ *	Hongjun Chen <hong-jun.chen@freescale.com>
+ *
+ * Fork of mpc52xx_psc_spi.c:
+ *	Copyright (C) 2006 TOPTICA Photonics AG., Dragos Carp
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/of_platform.h>
+#include <linux/workqueue.h>
+#include <linux/completion.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/spi/spi.h>
+#include <linux/fsl_devices.h>
+#include <asm/mpc52xx_psc.h>
+
+struct mpc512x_psc_spi {
+	void (*cs_control)(struct spi_device *spi, bool on);
+	u32 sysclk;
+
+	/* driver internal data */
+	struct mpc52xx_psc __iomem *psc;
+	struct mpc512x_psc_fifo __iomem *fifo;
+	unsigned int irq;
+	u8 bits_per_word;
+	u8 busy;
+	u32 mclk;
+	u8 eofbyte;
+
+	struct workqueue_struct *workqueue;
+	struct work_struct work;
+
+	struct list_head queue;
+	spinlock_t lock;	/* Message queue lock */
+
+	struct completion done;
+};
+
+/* controller state */
+struct mpc512x_psc_spi_cs {
+	int bits_per_word;
+	int speed_hz;
+};
+
+/* set clock freq, clock ramp, bits per work
+ * if t is NULL then reset the values to the default values
+ */
+static int mpc512x_psc_spi_transfer_setup(struct spi_device *spi,
+					  struct spi_transfer *t)
+{
+	struct mpc512x_psc_spi_cs *cs = spi->controller_state;
+
+	cs->speed_hz = (t && t->speed_hz)
+	    ? t->speed_hz : spi->max_speed_hz;
+	cs->bits_per_word = (t && t->bits_per_word)
+	    ? t->bits_per_word : spi->bits_per_word;
+	cs->bits_per_word = ((cs->bits_per_word + 7) / 8) * 8;
+	return 0;
+}
+
+static void mpc512x_psc_spi_activate_cs(struct spi_device *spi)
+{
+	struct mpc512x_psc_spi_cs *cs = spi->controller_state;
+	struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
+	struct mpc52xx_psc __iomem *psc = mps->psc;
+	u32 sicr;
+	u32 ccr;
+	u16 bclkdiv;
+
+	sicr = in_be32(&psc->sicr);
+
+	/* Set clock phase and polarity */
+	if (spi->mode & SPI_CPHA)
+		sicr |= 0x00001000;
+	else
+		sicr &= ~0x00001000;
+
+	if (spi->mode & SPI_CPOL)
+		sicr |= 0x00002000;
+	else
+		sicr &= ~0x00002000;
+
+	if (spi->mode & SPI_LSB_FIRST)
+		sicr |= 0x10000000;
+	else
+		sicr &= ~0x10000000;
+	out_be32(&psc->sicr, sicr);
+
+	ccr = in_be32(&psc->ccr);
+	ccr &= 0xFF000000;
+	if (cs->speed_hz)
+		bclkdiv = (mps->mclk / cs->speed_hz) - 1;
+	else
+		bclkdiv = (mps->mclk / 1000000) - 1;	/* default 1MHz */
+
+	ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8));
+	out_be32(&psc->ccr, ccr);
+	mps->bits_per_word = cs->bits_per_word;
+
+	if (mps->cs_control)
+		mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 1 : 0);
+}
+
+static void mpc512x_psc_spi_deactivate_cs(struct spi_device *spi)
+{
+	struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
+
+	if (mps->cs_control)
+		mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 0 : 1);
+
+}
+
+/* extract and scale size field in txsz or rxsz */
+#define MPC512x_PSC_FIFO_SZ(sz) ((sz & 0x7ff) << 2);
+
+#define EOFBYTE 1
+
+static int mpc512x_psc_spi_transfer_rxtx(struct spi_device *spi,
+					 struct spi_transfer *t)
+{
+	struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
+	struct mpc52xx_psc __iomem *psc = mps->psc;
+	struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
+	size_t len = t->len;
+	u8 *tx_buf = (u8 *)t->tx_buf;
+	u8 *rx_buf = (u8 *)t->rx_buf;
+
+	if (!tx_buf && !rx_buf && t->len)
+		return -EINVAL;
+
+	/* Zero MR2 */
+	in_8(&psc->mode);
+	out_8(&psc->mode, 0x0);
+
+	while (len) {
+		int count;
+		int i;
+		u8 data;
+		size_t fifosz;
+		int rxcount;
+
+		/*
+		 * The number of bytes that can be sent at a time
+		 * depends on the fifo size.
+		 */
+		fifosz = MPC512x_PSC_FIFO_SZ(in_be32(&fifo->txsz));
+		count = min(fifosz, len);
+
+		for (i = count; i > 0; i--) {
+			data = tx_buf ? *tx_buf++ : 0;
+			if (len == EOFBYTE)
+				setbits32(&fifo->txcmd, MPC512x_PSC_FIFO_EOF);
+			out_8(&fifo->txdata_8, data);
+			len--;
+		}
+
+		INIT_COMPLETION(mps->done);
+
+		/* interrupt on tx fifo empty */
+		out_be32(&fifo->txisr, MPC512x_PSC_FIFO_EMPTY);
+		out_be32(&fifo->tximr, MPC512x_PSC_FIFO_EMPTY);
+
+		/* enable transmiter/receiver */
+		out_8(&psc->command,
+		      MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
+
+		wait_for_completion(&mps->done);
+
+		mdelay(1);
+
+		/* rx fifo should have count bytes in it */
+		rxcount = in_be32(&fifo->rxcnt);
+		if (rxcount != count)
+			mdelay(1);
+
+		rxcount = in_be32(&fifo->rxcnt);
+		if (rxcount != count) {
+			dev_warn(&spi->dev, "expected %d bytes in rx fifo "
+				 "but got %d\n", count, rxcount);
+		}
+
+		rxcount = min(rxcount, count);
+		for (i = rxcount; i > 0; i--) {
+			data = in_8(&fifo->rxdata_8);
+			if (rx_buf)
+				*rx_buf++ = data;
+		}
+		while (in_be32(&fifo->rxcnt)) {
+			in_8(&fifo->rxdata_8);
+		}
+
+		out_8(&psc->command,
+		      MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
+	}
+	/* disable transmiter/receiver and fifo interrupt */
+	out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
+	out_be32(&fifo->tximr, 0);
+	return 0;
+}
+
+static void mpc512x_psc_spi_work(struct work_struct *work)
+{
+	struct mpc512x_psc_spi *mps = container_of(work,
+						   struct mpc512x_psc_spi,
+						   work);
+
+	spin_lock_irq(&mps->lock);
+	mps->busy = 1;
+	while (!list_empty(&mps->queue)) {
+		struct spi_message *m;
+		struct spi_device *spi;
+		struct spi_transfer *t = NULL;
+		unsigned cs_change;
+		int status;
+
+		m = container_of(mps->queue.next, struct spi_message, queue);
+		list_del_init(&m->queue);
+		spin_unlock_irq(&mps->lock);
+
+		spi = m->spi;
+		cs_change = 1;
+		status = 0;
+		list_for_each_entry(t, &m->transfers, transfer_list) {
+			if (t->bits_per_word || t->speed_hz) {
+				status = mpc512x_psc_spi_transfer_setup(spi, t);
+				if (status < 0)
+					break;
+			}
+
+			if (cs_change)
+				mpc512x_psc_spi_activate_cs(spi);
+			cs_change = t->cs_change;
+
+			status = mpc512x_psc_spi_transfer_rxtx(spi, t);
+			if (status)
+				break;
+			m->actual_length += t->len;
+
+			if (t->delay_usecs)
+				udelay(t->delay_usecs);
+
+			if (cs_change)
+				mpc512x_psc_spi_deactivate_cs(spi);
+		}
+
+		m->status = status;
+		m->complete(m->context);
+
+		if (status || !cs_change)
+			mpc512x_psc_spi_deactivate_cs(spi);
+
+		mpc512x_psc_spi_transfer_setup(spi, NULL);
+
+		spin_lock_irq(&mps->lock);
+	}
+	mps->busy = 0;
+	spin_unlock_irq(&mps->lock);
+}
+
+static int mpc512x_psc_spi_setup(struct spi_device *spi)
+{
+	struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
+	struct mpc512x_psc_spi_cs *cs = spi->controller_state;
+	unsigned long flags;
+
+	if (spi->bits_per_word % 8)
+		return -EINVAL;
+
+	if (!cs) {
+		cs = kzalloc(sizeof *cs, GFP_KERNEL);
+		if (!cs)
+			return -ENOMEM;
+		spi->controller_state = cs;
+	}
+
+	cs->bits_per_word = spi->bits_per_word;
+	cs->speed_hz = spi->max_speed_hz;
+
+	spin_lock_irqsave(&mps->lock, flags);
+	if (!mps->busy)
+		mpc512x_psc_spi_deactivate_cs(spi);
+	spin_unlock_irqrestore(&mps->lock, flags);
+
+	return 0;
+}
+
+static int mpc512x_psc_spi_transfer(struct spi_device *spi,
+				    struct spi_message *m)
+{
+	struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
+	unsigned long flags;
+
+	m->actual_length = 0;
+	m->status = -EINPROGRESS;
+
+	spin_lock_irqsave(&mps->lock, flags);
+	list_add_tail(&m->queue, &mps->queue);
+	queue_work(mps->workqueue, &mps->work);
+	spin_unlock_irqrestore(&mps->lock, flags);
+
+	return 0;
+}
+
+static void mpc512x_psc_spi_cleanup(struct spi_device *spi)
+{
+	kfree(spi->controller_state);
+}
+
+static int mpc512x_psc_spi_port_config(struct spi_master *master,
+				       struct mpc512x_psc_spi *mps)
+{
+	struct mpc52xx_psc __iomem *psc = mps->psc;
+	struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
+	struct clk *spiclk;
+	int ret = 0;
+	char name[32];
+	u32 sicr;
+	u32 ccr;
+	u16 bclkdiv;
+
+	sprintf(name, "psc%d_mclk", master->bus_num);
+	spiclk = clk_get(&master->dev, name);
+	clk_enable(spiclk);
+	mps->mclk = clk_get_rate(spiclk);
+	clk_put(spiclk);
+
+	/* Reset the PSC into a known state */
+	out_8(&psc->command, MPC52xx_PSC_RST_RX);
+	out_8(&psc->command, MPC52xx_PSC_RST_TX);
+	out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
+
+	/* Disable psc interrupts all useful interrupts are in fifo */
+	out_be16(&psc->isr_imr.imr, 0);
+
+	/* Disable fifo interrupts, will be enabled later */
+	out_be32(&fifo->tximr, 0);
+	out_be32(&fifo->rximr, 0);
+
+	/* Setup fifo slice address and size */
+	/*out_be32(&fifo->txsz, 0x0fe00004);*/
+	/*out_be32(&fifo->rxsz, 0x0ff00004);*/
+
+	sicr =	0x01000000 |	/* SIM = 0001 -- 8 bit */
+		0x00800000 |	/* GenClk = 1 -- internal clk */
+		0x00008000 |	/* SPI = 1 */
+		0x00004000 |	/* MSTR = 1   -- SPI master */
+		0x00000800;	/* UseEOF = 1 -- SS low until EOF */
+
+	out_be32(&psc->sicr, sicr);
+
+	ccr = in_be32(&psc->ccr);
+	ccr &= 0xFF000000;
+	bclkdiv = (mps->mclk / 1000000) - 1;	/* default 1MHz */
+	ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8));
+	out_be32(&psc->ccr, ccr);
+
+	/* Set 2ms DTL delay */
+	out_8(&psc->ctur, 0x00);
+	out_8(&psc->ctlr, 0x82);
+
+	/* we don't use the alarms */
+	out_be32(&fifo->rxalarm, 0xfff);
+	out_be32(&fifo->txalarm, 0);
+
+	/* Enable FIFO slices for Rx/Tx */
+	out_be32(&fifo->rxcmd,
+		 MPC512x_PSC_FIFO_ENABLE_SLICE | MPC512x_PSC_FIFO_ENABLE_DMA);
+	out_be32(&fifo->txcmd,
+		 MPC512x_PSC_FIFO_ENABLE_SLICE | MPC512x_PSC_FIFO_ENABLE_DMA);
+
+	mps->bits_per_word = 8;
+
+	return ret;
+}
+
+static irqreturn_t mpc512x_psc_spi_isr(int irq, void *dev_id)
+{
+	struct mpc512x_psc_spi *mps = (struct mpc512x_psc_spi *)dev_id;
+	struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
+
+	/* clear interrupt and wake up the work queue */
+	if (in_be32(&fifo->txisr) &
+	    in_be32(&fifo->tximr) & MPC512x_PSC_FIFO_EMPTY) {
+		out_be32(&fifo->txisr, MPC512x_PSC_FIFO_EMPTY);
+		out_be32(&fifo->tximr, 0);
+		complete(&mps->done);
+		return IRQ_HANDLED;
+	}
+	return IRQ_NONE;
+}
+
+/* bus_num is used only for the case dev->platform_data == NULL */
+static int __init mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
+					   u32 size, unsigned int irq,
+					   s16 bus_num)
+{
+	struct fsl_spi_platform_data *pdata = dev->platform_data;
+	struct mpc512x_psc_spi *mps;
+	struct spi_master *master;
+	int ret;
+	void *tempp;
+
+	master = spi_alloc_master(dev, sizeof *mps);
+	if (master == NULL)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, master);
+	mps = spi_master_get_devdata(master);
+	mps->irq = irq;
+
+	if (pdata == NULL) {
+		dev_err(dev, "probe called without platform data, no "
+			"cs_control function will be called\n");
+		mps->cs_control = NULL;
+		mps->sysclk = 0;
+		master->bus_num = bus_num;
+		master->num_chipselect = 255;
+	} else {
+		mps->cs_control = pdata->cs_control;
+		mps->sysclk = pdata->sysclk;
+		master->bus_num = pdata->bus_num;
+		master->num_chipselect = pdata->max_chipselect;
+	}
+
+	master->setup = mpc512x_psc_spi_setup;
+	master->transfer = mpc512x_psc_spi_transfer;
+	master->cleanup = mpc512x_psc_spi_cleanup;
+
+	tempp = ioremap(regaddr, size);
+	if (!tempp) {
+		dev_err(dev, "could not ioremap I/O port range\n");
+		ret = -EFAULT;
+		goto free_master;
+	}
+	mps->psc = tempp;
+	mps->fifo =
+		(struct mpc512x_psc_fifo *)(tempp + sizeof(struct mpc52xx_psc));
+
+	ret = request_irq(mps->irq, mpc512x_psc_spi_isr, IRQF_SHARED,
+			  "mpc512x-psc-spi", mps);
+	if (ret)
+		goto free_master;
+
+	ret = mpc512x_psc_spi_port_config(master, mps);
+	if (ret < 0)
+		goto free_irq;
+
+	spin_lock_init(&mps->lock);
+	init_completion(&mps->done);
+	INIT_WORK(&mps->work, mpc512x_psc_spi_work);
+	INIT_LIST_HEAD(&mps->queue);
+
+	mps->workqueue =
+		create_singlethread_workqueue(dev_name(master->dev.parent));
+	if (mps->workqueue == NULL) {
+		ret = -EBUSY;
+		goto free_irq;
+	}
+
+	ret = spi_register_master(master);
+	if (ret < 0)
+		goto unreg_master;
+
+	return ret;
+
+unreg_master:
+	destroy_workqueue(mps->workqueue);
+free_irq:
+	free_irq(mps->irq, mps);
+free_master:
+	if (mps->psc)
+		iounmap(mps->psc);
+	spi_master_put(master);
+
+	return ret;
+}
+
+static int __exit mpc512x_psc_spi_do_remove(struct device *dev)
+{
+	struct spi_master *master = dev_get_drvdata(dev);
+	struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
+
+	flush_workqueue(mps->workqueue);
+	destroy_workqueue(mps->workqueue);
+	spi_unregister_master(master);
+	free_irq(mps->irq, mps);
+	if (mps->psc)
+		iounmap(mps->psc);
+
+	return 0;
+}
+
+static int __init mpc512x_psc_spi_of_probe(struct of_device *op,
+					   const struct of_device_id *match)
+{
+	const u32 *regaddr_p;
+	u64 regaddr64, size64;
+	s16 id = -1;
+
+	regaddr_p = of_get_address(op->node, 0, &size64, NULL);
+	if (!regaddr_p) {
+		dev_err(&op->dev, "Invalid PSC address\n");
+		return -EINVAL;
+	}
+	regaddr64 = of_translate_address(op->node, regaddr_p);
+
+	/* get PSC id (0..11, used by port_config) */
+	if (op->dev.platform_data == NULL) {
+		const u32 *psc_nump;
+
+		psc_nump = of_get_property(op->node, "cell-index", NULL);
+		if (!psc_nump || *psc_nump > 11) {
+			dev_err(&op->dev, "mpc512x_psc_spi: Device node %s "
+				"has invalid cell-index property\n",
+				op->node->full_name);
+			return -EINVAL;
+		}
+		id = *psc_nump;
+	}
+
+	return mpc512x_psc_spi_do_probe(&op->dev, (u32) regaddr64, (u32) size64,
+					irq_of_parse_and_map(op->node, 0), id);
+}
+
+static int __exit mpc512x_psc_spi_of_remove(struct of_device *op)
+{
+	return mpc512x_psc_spi_do_remove(&op->dev);
+}
+
+static struct of_device_id mpc512x_psc_spi_of_match[] = {
+	{ .compatible = "fsl,mpc5121-psc-spi", },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, mpc512x_psc_spi_of_match);
+
+static struct of_platform_driver mpc512x_psc_spi_of_driver = {
+	.match_table = mpc512x_psc_spi_of_match,
+	.probe = mpc512x_psc_spi_of_probe,
+	.remove = __exit_p(mpc512x_psc_spi_of_remove),
+	.driver = {
+		.name = "mpc512x-psc-spi",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init mpc512x_psc_spi_init(void)
+{
+	return of_register_platform_driver(&mpc512x_psc_spi_of_driver);
+}
+module_init(mpc512x_psc_spi_init);
+
+static void __exit mpc512x_psc_spi_exit(void)
+{
+	of_unregister_platform_driver(&mpc512x_psc_spi_of_driver);
+}
+module_exit(mpc512x_psc_spi_exit);
+
+MODULE_AUTHOR("John Rigby");
+MODULE_DESCRIPTION("MPC512x PSC SPI Driver");
+MODULE_LICENSE("GPL");
-- 
1.6.3.3

^ permalink raw reply related

* [PATCH 1/2] powerpc/mpc5121: move PSC FIFO memory init to platform code
From: Anatolij Gustschin @ 2010-04-30 13:21 UTC (permalink / raw)
  To: spi-devel-general, linuxppc-dev
  Cc: David Brownell, Wolfgang Denk, Detelv Zundel
In-Reply-To: <1272633687-6935-1-git-send-email-agust@denx.de>

Since PSC could also be used in other modes than UART mode
we move PSC FIFO memory initialization from serial driver to
common platform code. The initialized FIFO memory slices may
not overlap, so the most easy way would be to configure them
all at once at init time for all PSC devices. This is now done
by this patch.

Signed-off-by: Anatolij Gustschin <agust@denx.de>
---
 arch/powerpc/platforms/512x/mpc512x_shared.c |   78 ++++++++++++++++++++++++++
 drivers/serial/mpc52xx_uart.c                |   69 -----------------------
 2 files changed, 78 insertions(+), 69 deletions(-)

diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c
index 796080c..a717466 100644
--- a/arch/powerpc/platforms/512x/mpc512x_shared.c
+++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
@@ -26,6 +26,7 @@
 #include <asm/prom.h>
 #include <asm/time.h>
 #include <asm/mpc5121.h>
+#include <asm/mpc52xx_psc.h>
 
 #include "mpc512x.h"
 
@@ -369,9 +370,86 @@ void __init mpc512x_declare_of_platform_devices(void)
 	}
 }
 
+#define DEFAULT_FIFO_SIZE 16
+
+static unsigned int __init get_fifo_size(struct device_node *np,
+					 char *prop_name)
+{
+	const unsigned int *fp;
+
+	fp = of_get_property(np, prop_name, NULL);
+	if (fp)
+		return *fp;
+
+	pr_warning("no %s property in %s node, defaulting to %d\n",
+		   prop_name, np->full_name, DEFAULT_FIFO_SIZE);
+
+	return DEFAULT_FIFO_SIZE;
+}
+
+#define FIFOC(_base) ((struct mpc512x_psc_fifo __iomem *) \
+		    ((u32)(_base) + sizeof(struct mpc52xx_psc)))
+
+/* Init PSC FIFO space for TX and RX slices */
+void __init mpc512x_psc_fifo_init(void)
+{
+	struct device_node *np;
+	void __iomem *psc;
+	unsigned int tx_fifo_size;
+	unsigned int rx_fifo_size;
+	int fifobase = 0; /* current fifo address in 32 bit words */
+
+	for_each_compatible_node(np, NULL, "fsl,mpc5121-psc") {
+		tx_fifo_size = get_fifo_size(np, "fsl,tx-fifo-size");
+		rx_fifo_size = get_fifo_size(np, "fsl,rx-fifo-size");
+
+		/* size in register is in 4 byte units */
+		tx_fifo_size /= 4;
+		rx_fifo_size /= 4;
+		if (!tx_fifo_size)
+			tx_fifo_size = 1;
+		if (!rx_fifo_size)
+			rx_fifo_size = 1;
+
+		psc = of_iomap(np, 0);
+		if (!psc) {
+			pr_err("%s: Can't map %s device\n",
+				__func__, np->full_name);
+			continue;
+		}
+
+		/* FIFO space is 4KiB, check if requested size is available */
+		if ((fifobase + tx_fifo_size + rx_fifo_size) > 0x1000) {
+			pr_err("%s: no fifo space available for %s\n",
+				__func__, np->full_name);
+			iounmap(psc);
+			/*
+			 * chances are that another device requests less
+			 * fifo space, so we continue.
+			 */
+			continue;
+		}
+
+		/* set tx and rx fifo size registers */
+		out_be32(&FIFOC(psc)->txsz, (fifobase << 16) | tx_fifo_size);
+		fifobase += tx_fifo_size;
+		out_be32(&FIFOC(psc)->rxsz, (fifobase << 16) | rx_fifo_size);
+		fifobase += rx_fifo_size;
+
+		/* reset and enable the slices */
+		out_be32(&FIFOC(psc)->txcmd, 0x80);
+		out_be32(&FIFOC(psc)->txcmd, 0x01);
+		out_be32(&FIFOC(psc)->rxcmd, 0x80);
+		out_be32(&FIFOC(psc)->rxcmd, 0x01);
+
+		iounmap(psc);
+	}
+}
+
 void __init mpc512x_init(void)
 {
 	mpc512x_declare_of_platform_devices();
 	mpc5121_clk_init();
 	mpc512x_restart_init();
+	mpc512x_psc_fifo_init();
 }
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index 3119fdd..843e7fb 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -430,34 +430,10 @@ static unsigned long mpc512x_getuartclk(void *p)
 	return mpc5xxx_get_bus_frequency(p);
 }
 
-#define DEFAULT_FIFO_SIZE 16
-
-static unsigned int __init get_fifo_size(struct device_node *np,
-					 char *fifo_name)
-{
-	const unsigned int *fp;
-
-	fp = of_get_property(np, fifo_name, NULL);
-	if (fp)
-		return *fp;
-
-	pr_warning("no %s property in %s node, defaulting to %d\n",
-		   fifo_name, np->full_name, DEFAULT_FIFO_SIZE);
-
-	return DEFAULT_FIFO_SIZE;
-}
-
-#define FIFOC(_base) ((struct mpc512x_psc_fifo __iomem *) \
-		    ((u32)(_base) + sizeof(struct mpc52xx_psc)))
-
 /* Init PSC FIFO Controller */
 static int __init mpc512x_psc_fifoc_init(void)
 {
 	struct device_node *np;
-	void __iomem *psc;
-	unsigned int tx_fifo_size;
-	unsigned int rx_fifo_size;
-	int fifobase = 0; /* current fifo address in 32 bit words */
 
 	np = of_find_compatible_node(NULL, NULL,
 				     "fsl,mpc5121-psc-fifo");
@@ -480,51 +456,6 @@ static int __init mpc512x_psc_fifoc_init(void)
 		return -ENODEV;
 	}
 
-	for_each_compatible_node(np, NULL, "fsl,mpc5121-psc-uart") {
-		tx_fifo_size = get_fifo_size(np, "fsl,tx-fifo-size");
-		rx_fifo_size = get_fifo_size(np, "fsl,rx-fifo-size");
-
-		/* size in register is in 4 byte units */
-		tx_fifo_size /= 4;
-		rx_fifo_size /= 4;
-		if (!tx_fifo_size)
-			tx_fifo_size = 1;
-		if (!rx_fifo_size)
-			rx_fifo_size = 1;
-
-		psc = of_iomap(np, 0);
-		if (!psc) {
-			pr_err("%s: Can't map %s device\n",
-				__func__, np->full_name);
-			continue;
-		}
-
-		/* FIFO space is 4KiB, check if requested size is available */
-		if ((fifobase + tx_fifo_size + rx_fifo_size) > 0x1000) {
-			pr_err("%s: no fifo space available for %s\n",
-				__func__, np->full_name);
-			iounmap(psc);
-			/*
-			 * chances are that another device requests less
-			 * fifo space, so we continue.
-			 */
-			continue;
-		}
-		/* set tx and rx fifo size registers */
-		out_be32(&FIFOC(psc)->txsz, (fifobase << 16) | tx_fifo_size);
-		fifobase += tx_fifo_size;
-		out_be32(&FIFOC(psc)->rxsz, (fifobase << 16) | rx_fifo_size);
-		fifobase += rx_fifo_size;
-
-		/* reset and enable the slices */
-		out_be32(&FIFOC(psc)->txcmd, 0x80);
-		out_be32(&FIFOC(psc)->txcmd, 0x01);
-		out_be32(&FIFOC(psc)->rxcmd, 0x80);
-		out_be32(&FIFOC(psc)->rxcmd, 0x01);
-
-		iounmap(psc);
-	}
-
 	return 0;
 }
 
-- 
1.6.3.3

^ permalink raw reply related

* [PATCH 0/2] Add SPI driver for MPC5121 PSC SPI
From: Anatolij Gustschin @ 2010-04-30 13:21 UTC (permalink / raw)
  To: spi-devel-general, linuxppc-dev
  Cc: David Brownell, Wolfgang Denk, Detelv Zundel

Anatolij Gustschin (2):
  powerpc/mpc5121: move PSC FIFO memory init to platform code
  spi: Add SPI master driver for MPC5121 PSC

 arch/powerpc/include/asm/mpc52xx_psc.h       |    1 +
 arch/powerpc/platforms/512x/mpc512x_shared.c |   78 ++++
 drivers/serial/mpc52xx_uart.c                |   69 ---
 drivers/spi/Kconfig                          |    7 +
 drivers/spi/Makefile                         |    1 +
 drivers/spi/mpc512x_psc_spi.c                |  576 ++++++++++++++++++++++++++
 6 files changed, 663 insertions(+), 69 deletions(-)
 create mode 100644 drivers/spi/mpc512x_psc_spi.c

^ permalink raw reply

* [PATCH v2 3/5] powerpc/mpc5121: shared DIU framebuffer support
From: Anatolij Gustschin @ 2010-04-30 10:40 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: linux-fbdev, wd, dzu, John Rigby, devicetree-discuss, yorksun
In-Reply-To: <1272584978-19063-4-git-send-email-agust@denx.de>

MPC5121 DIU configuration/setup as initialized by the boot
loader currently will get lost while booting Linux. As a
result displaying the boot splash is not possible through
the boot process.

To prevent this we reserve configured DIU frame buffer
address range while booting and preserve AOI descriptor
and gamma table so that DIU continues displaying through
the whole boot process. On first open from user space
DIU frame buffer driver releases the reserved frame
buffer area and continues to operate as usual.

Signed-off-by: John Rigby <jrigby@gmail.com>
Signed-off-by: Anatolij Gustschin <agust@denx.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
---
v1 -> v2:
 - use struct for CCM register access, don't use offset macros,
   so CCM struct definition is added now
 - use struct for DIU descriptors access
 - simplify code and correct variable types as suggested by Timur

 arch/powerpc/include/asm/mpc5121.h            |   32 +++
 arch/powerpc/platforms/512x/mpc5121_ads.c     |    7 +
 arch/powerpc/platforms/512x/mpc5121_generic.c |   12 +
 arch/powerpc/platforms/512x/mpc512x.h         |    2 +
 arch/powerpc/platforms/512x/mpc512x_shared.c  |  274 +++++++++++++++++++++++++
 arch/powerpc/sysdev/fsl_soc.h                 |    1 +
 drivers/video/fsl-diu-fb.c                    |   17 ++-
 7 files changed, 343 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/include/asm/mpc5121.h b/arch/powerpc/include/asm/mpc5121.h
index e6a30bb..8c0ab2c 100644
--- a/arch/powerpc/include/asm/mpc5121.h
+++ b/arch/powerpc/include/asm/mpc5121.h
@@ -21,4 +21,36 @@ struct mpc512x_reset_module {
 	u32	rcer;	/* Reset Control Enable Register */
 };
 
+/*
+ * Clock Control Module
+ */
+struct mpc512x_ccm {
+	u32	spmr;	/* System PLL Mode Register */
+	u32	sccr1;	/* System Clock Control Register 1 */
+	u32	sccr2;	/* System Clock Control Register 2 */
+	u32	scfr1;	/* System Clock Frequency Register 1 */
+	u32	scfr2;	/* System Clock Frequency Register 2 */
+	u32	scfr2s;	/* System Clock Frequency Shadow Register 2 */
+	u32	bcr;	/* Bread Crumb Register */
+	u32	p0ccr;	/* PSC0 Clock Control Register */
+	u32	p1ccr;	/* PSC1 CCR */
+	u32	p2ccr;	/* PSC2 CCR */
+	u32	p3ccr;	/* PSC3 CCR */
+	u32	p4ccr;	/* PSC4 CCR */
+	u32	p5ccr;	/* PSC5 CCR */
+	u32	p6ccr;	/* PSC6 CCR */
+	u32	p7ccr;	/* PSC7 CCR */
+	u32	p8ccr;	/* PSC8 CCR */
+	u32	p9ccr;	/* PSC9 CCR */
+	u32	p10ccr;	/* PSC10 CCR */
+	u32	p11ccr;	/* PSC11 CCR */
+	u32	spccr;	/* SPDIF Clock Control Register */
+	u32	cccr;	/* CFM Clock Control Register */
+	u32	dccr;	/* DIU Clock Control Register */
+	u32	m1ccr;	/* MSCAN1 CCR */
+	u32	m2ccr;	/* MSCAN2 CCR */
+	u32	m3ccr;	/* MSCAN3 CCR */
+	u32	m4ccr;	/* MSCAN4 CCR */
+	u8	res[0x98]; /* Reserved */
+};
 #endif /* __ASM_POWERPC_MPC5121_H__ */
diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.c b/arch/powerpc/platforms/512x/mpc5121_ads.c
index ee6ae12..082aa6f 100644
--- a/arch/powerpc/platforms/512x/mpc5121_ads.c
+++ b/arch/powerpc/platforms/512x/mpc5121_ads.c
@@ -42,6 +42,7 @@ static void __init mpc5121_ads_setup_arch(void)
 	for_each_compatible_node(np, "pci", "fsl,mpc5121-pci")
 		mpc83xx_add_bridge(np);
 #endif
+	mpc512x_setup_diu();
 }
 
 static void __init mpc5121_ads_init_IRQ(void)
@@ -60,11 +61,17 @@ static int __init mpc5121_ads_probe(void)
 	return of_flat_dt_is_compatible(root, "fsl,mpc5121ads");
 }
 
+void __init mpc5121_ads_init_early(void)
+{
+	mpc512x_init_diu();
+}
+
 define_machine(mpc5121_ads) {
 	.name			= "MPC5121 ADS",
 	.probe			= mpc5121_ads_probe,
 	.setup_arch		= mpc5121_ads_setup_arch,
 	.init			= mpc512x_init,
+	.init_early		= mpc512x_init_diu,
 	.init_IRQ		= mpc5121_ads_init_IRQ,
 	.get_irq		= ipic_get_irq,
 	.calibrate_decr		= generic_calibrate_decr,
diff --git a/arch/powerpc/platforms/512x/mpc5121_generic.c b/arch/powerpc/platforms/512x/mpc5121_generic.c
index a6c0e3a..c5ecb3d 100644
--- a/arch/powerpc/platforms/512x/mpc5121_generic.c
+++ b/arch/powerpc/platforms/512x/mpc5121_generic.c
@@ -48,10 +48,22 @@ static int __init mpc5121_generic_probe(void)
 	return board[i] != NULL;
 }
 
+void __init mpc512x_generic_init_early(void)
+{
+	mpc512x_init_diu();
+}
+
+void __init mpc512x_generic_setup_arch(void)
+{
+	mpc512x_setup_diu();
+}
+
 define_machine(mpc5121_generic) {
 	.name			= "MPC5121 generic",
 	.probe			= mpc5121_generic_probe,
 	.init			= mpc512x_init,
+	.init_early		= mpc512x_generic_init_early,
+	.setup_arch		= mpc512x_generic_setup_arch,
 	.init_IRQ		= mpc512x_init_IRQ,
 	.get_irq		= ipic_get_irq,
 	.calibrate_decr		= generic_calibrate_decr,
diff --git a/arch/powerpc/platforms/512x/mpc512x.h b/arch/powerpc/platforms/512x/mpc512x.h
index b2daca0..1ab6d11 100644
--- a/arch/powerpc/platforms/512x/mpc512x.h
+++ b/arch/powerpc/platforms/512x/mpc512x.h
@@ -16,4 +16,6 @@ extern void __init mpc512x_init(void);
 extern int __init mpc5121_clk_init(void);
 void __init mpc512x_declare_of_platform_devices(void);
 extern void mpc512x_restart(char *cmd);
+extern void mpc512x_init_diu(void);
+extern void mpc512x_setup_diu(void);
 #endif				/* __MPC512X_H__ */
diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c
index b7f518a..e5a8e8a 100644
--- a/arch/powerpc/platforms/512x/mpc512x_shared.c
+++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
@@ -16,7 +16,11 @@
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/of_platform.h>
+#include <linux/fsl-diu-fb.h>
+#include <linux/bootmem.h>
+#include <sysdev/fsl_soc.h>
 
+#include <asm/cacheflush.h>
 #include <asm/machdep.h>
 #include <asm/ipic.h>
 #include <asm/prom.h>
@@ -53,6 +57,276 @@ void mpc512x_restart(char *cmd)
 		;
 }
 
+struct fsl_diu_shared_fb {
+	u8		gamma[0x300];	/* 32-bit aligned! */
+	struct diu_ad	ad0;		/* 32-bit aligned! */
+	phys_addr_t	fb_phys;
+	size_t		fb_len;
+	bool		in_use;
+};
+
+unsigned int mpc512x_get_pixel_format(unsigned int bits_per_pixel,
+				      int monitor_port)
+{
+	switch (bits_per_pixel) {
+	case 32:
+		return 0x88883316;
+	case 24:
+		return 0x88082219;
+	case 16:
+		return 0x65053118;
+	}
+	return 0x00000400;
+}
+
+void mpc512x_set_gamma_table(int monitor_port, char *gamma_table_base)
+{
+}
+
+void mpc512x_set_monitor_port(int monitor_port)
+{
+}
+
+#define DIU_DIV_MASK	0x000000ff
+void mpc512x_set_pixel_clock(unsigned int pixclock)
+{
+	unsigned long bestval, bestfreq, speed_ccb, busfreq;
+	unsigned long minpixclock, maxpixclock, pixval;
+	struct mpc512x_ccm __iomem *ccm;
+	struct device_node *np;
+	u32 temp;
+	long err;
+	int i;
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clock");
+	if (!np) {
+		pr_err("Can't find clock control module.\n");
+		return;
+	}
+
+	ccm = of_iomap(np, 0);
+	of_node_put(np);
+	if (!ccm) {
+		pr_err("Can't map clock control module reg.\n");
+		return;
+	}
+
+	np = of_find_node_by_type(NULL, "cpu");
+	if (np) {
+		const unsigned int *prop =
+			of_get_property(np, "bus-frequency", NULL);
+
+		of_node_put(np);
+		if (prop) {
+			busfreq = *prop;
+		} else {
+			pr_err("Can't get bus-frequency property\n");
+			return;
+		}
+	} else {
+		pr_err("Can't find 'cpu' node.\n");
+		return;
+	}
+
+	/* Pixel Clock configuration */
+	pr_debug("DIU: Bus Frequency = %lu\n", busfreq);
+	speed_ccb = busfreq * 4;
+
+	/* Calculate the pixel clock with the smallest error */
+	/* calculate the following in steps to avoid overflow */
+	pr_debug("DIU pixclock in ps - %d\n", pixclock);
+	temp = (1000000000 / pixclock) * 1000;
+	pixclock = temp;
+	pr_debug("DIU pixclock freq - %u\n", pixclock);
+
+	temp = temp / 20; /* pixclock * 0.05 */
+	pr_debug("deviation = %d\n", temp);
+	minpixclock = pixclock - temp;
+	maxpixclock = pixclock + temp;
+	pr_debug("DIU minpixclock - %lu\n", minpixclock);
+	pr_debug("DIU maxpixclock - %lu\n", maxpixclock);
+	pixval = speed_ccb/pixclock;
+	pr_debug("DIU pixval = %lu\n", pixval);
+
+	err = 100000000;
+	bestval = pixval;
+	pr_debug("DIU bestval = %lu\n", bestval);
+
+	bestfreq = 0;
+	for (i = -1; i <= 1; i++) {
+		temp = speed_ccb / (pixval+i);
+		pr_debug("DIU test pixval i=%d, pixval=%lu, temp freq. = %u\n",
+			i, pixval, temp);
+		if ((temp < minpixclock) || (temp > maxpixclock))
+			pr_debug("DIU exceeds monitor range (%lu to %lu)\n",
+				minpixclock, maxpixclock);
+		else if (abs(temp - pixclock) < err) {
+			pr_debug("Entered the else if block %d\n", i);
+			err = abs(temp - pixclock);
+			bestval = pixval + i;
+			bestfreq = temp;
+		}
+	}
+
+	pr_debug("DIU chose = %lx\n", bestval);
+	pr_debug("DIU error = %ld\n NomPixClk ", err);
+	pr_debug("DIU: Best Freq = %lx\n", bestfreq);
+	/* Modify DIU_DIV in CCM SCFR1 */
+	temp = in_be32(&ccm->scfr1);
+	pr_debug("DIU: Current value of SCFR1: 0x%08x\n", temp);
+	temp &= ~DIU_DIV_MASK;
+	temp |= (bestval & DIU_DIV_MASK);
+	out_be32(&ccm->scfr1, temp);
+	pr_debug("DIU: Modified value of SCFR1: 0x%08x\n", temp);
+	iounmap(ccm);
+}
+
+ssize_t mpc512x_show_monitor_port(int monitor_port, char *buf)
+{
+	return sprintf(buf, "0 - 5121 LCD\n");
+}
+
+int mpc512x_set_sysfs_monitor_port(int val)
+{
+	return 0;
+}
+
+static struct fsl_diu_shared_fb __attribute__ ((__aligned__(8))) diu_shared_fb;
+
+#if defined(CONFIG_FB_FSL_DIU) || \
+    defined(CONFIG_FB_FSL_DIU_MODULE)
+static inline void mpc512x_free_bootmem(struct page *page)
+{
+	__ClearPageReserved(page);
+	BUG_ON(PageTail(page));
+	BUG_ON(atomic_read(&page->_count) > 1);
+	atomic_set(&page->_count, 1);
+	__free_page(page);
+	totalram_pages++;
+}
+
+void mpc512x_release_bootmem(void)
+{
+	unsigned long addr = diu_shared_fb.fb_phys & PAGE_MASK;
+	unsigned long size = diu_shared_fb.fb_len;
+	unsigned long start, end;
+
+	if (diu_shared_fb.in_use) {
+		start = PFN_UP(addr);
+		end = PFN_DOWN(addr + size);
+
+		for (; start < end; start++)
+			mpc512x_free_bootmem(pfn_to_page(start));
+
+		diu_shared_fb.in_use = false;
+	}
+	diu_ops.release_bootmem	= NULL;
+}
+#endif
+
+/*
+ * Check if DIU was pre-initialized. If so, perform steps
+ * needed to continue displaying through the whole boot process.
+ * Move area descriptor and gamma table elsewhere, they are
+ * destroyed by bootmem allocator otherwise. The frame buffer
+ * address range will be reserved in setup_arch() after bootmem
+ * allocator is up.
+ */
+void __init mpc512x_init_diu(void)
+{
+	struct device_node *np;
+	struct diu __iomem *diu_reg;
+	phys_addr_t desc;
+	void __iomem *vaddr;
+	unsigned long mode, pix_fmt, res, bpp;
+	unsigned long dst;
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-diu");
+	if (!np) {
+		pr_err("No DIU node\n");
+		return;
+	}
+
+	diu_reg = of_iomap(np, 0);
+	of_node_put(np);
+	if (!diu_reg) {
+		pr_err("Can't map DIU\n");
+		return;
+	}
+
+	mode = in_be32(&diu_reg->diu_mode);
+	if (mode != MFB_MODE1) {
+		pr_info("%s: DIU OFF\n", __func__);
+		goto out;
+	}
+
+	desc = in_be32(&diu_reg->desc[0]);
+	vaddr = ioremap(desc, sizeof(struct diu_ad));
+	if (!vaddr) {
+		pr_err("Can't map DIU area desc.\n");
+		goto out;
+	}
+	memcpy(&diu_shared_fb.ad0, vaddr, sizeof(struct diu_ad));
+	/* flush fb area descriptor */
+	dst = (unsigned long)&diu_shared_fb.ad0;
+	flush_dcache_range(dst, dst + sizeof(struct diu_ad) - 1);
+
+	res = in_be32(&diu_reg->disp_size);
+	pix_fmt = in_le32(vaddr);
+	bpp = ((pix_fmt >> 16) & 0x3) + 1;
+	diu_shared_fb.fb_phys = in_le32(vaddr + 4);
+	diu_shared_fb.fb_len = ((res & 0xfff0000) >> 16) * (res & 0xfff) * bpp;
+	diu_shared_fb.in_use = true;
+	iounmap(vaddr);
+
+	desc = in_be32(&diu_reg->gamma);
+	vaddr = ioremap(desc, sizeof(diu_shared_fb.gamma));
+	if (!vaddr) {
+		pr_err("Can't map DIU area desc.\n");
+		diu_shared_fb.in_use = false;
+		goto out;
+	}
+	memcpy(&diu_shared_fb.gamma, vaddr, sizeof(diu_shared_fb.gamma));
+	/* flush gamma table */
+	dst = (unsigned long)&diu_shared_fb.gamma;
+	flush_dcache_range(dst, dst + sizeof(diu_shared_fb.gamma) - 1);
+
+	iounmap(vaddr);
+	out_be32(&diu_reg->gamma, virt_to_phys(&diu_shared_fb.gamma));
+	out_be32(&diu_reg->desc[1], 0);
+	out_be32(&diu_reg->desc[2], 0);
+	out_be32(&diu_reg->desc[0], virt_to_phys(&diu_shared_fb.ad0));
+
+out:
+	iounmap(diu_reg);
+}
+
+void __init mpc512x_setup_diu(void)
+{
+	int ret;
+
+	if (diu_shared_fb.in_use) {
+		ret = reserve_bootmem(diu_shared_fb.fb_phys,
+				      diu_shared_fb.fb_len,
+				      BOOTMEM_EXCLUSIVE);
+		if (ret) {
+			pr_err("%s: reserve bootmem failed\n", __func__);
+			diu_shared_fb.in_use = false;
+		}
+	}
+
+#if defined(CONFIG_FB_FSL_DIU) || \
+    defined(CONFIG_FB_FSL_DIU_MODULE)
+	diu_ops.get_pixel_format	= mpc512x_get_pixel_format;
+	diu_ops.set_gamma_table		= mpc512x_set_gamma_table;
+	diu_ops.set_monitor_port	= mpc512x_set_monitor_port;
+	diu_ops.set_pixel_clock		= mpc512x_set_pixel_clock;
+	diu_ops.show_monitor_port	= mpc512x_show_monitor_port;
+	diu_ops.set_sysfs_monitor_port	= mpc512x_set_sysfs_monitor_port;
+	diu_ops.release_bootmem		= mpc512x_release_bootmem;
+#endif
+}
+
 void __init mpc512x_init_IRQ(void)
 {
 	struct device_node *np;
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
index 42381bb..5360948 100644
--- a/arch/powerpc/sysdev/fsl_soc.h
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -30,6 +30,7 @@ struct platform_diu_data_ops {
 	void (*set_pixel_clock) (unsigned int pixclock);
 	ssize_t (*show_monitor_port) (int monitor_port, char *buf);
 	int (*set_sysfs_monitor_port) (int val);
+	void (*release_bootmem) (void);
 };
 
 extern struct platform_diu_data_ops diu_ops;
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index 7acdc09..81dec09 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -1103,6 +1103,10 @@ static int fsl_diu_open(struct fb_info *info, int user)
 	struct mfb_info *mfbi = info->par;
 	int res = 0;
 
+	/* free boot splash memory on first /dev/fb0 open */
+	if (!mfbi->index && diu_ops.release_bootmem)
+		diu_ops.release_bootmem();
+
 	spin_lock(&diu_lock);
 	mfbi->count++;
 	if (mfbi->count == 1) {
@@ -1430,6 +1434,7 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev,
 	int ret, i, error = 0;
 	struct resource res;
 	struct fsl_diu_data *machine_data;
+	int diu_mode;
 
 	machine_data = kzalloc(sizeof(struct fsl_diu_data), GFP_KERNEL);
 	if (!machine_data)
@@ -1466,7 +1471,9 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev,
 		goto error2;
 	}
 
-	out_be32(&dr.diu_reg->diu_mode, 0);		/* disable DIU anyway*/
+	diu_mode = in_be32(&dr.diu_reg->diu_mode);
+	if (diu_mode != MFB_MODE1)
+		out_be32(&dr.diu_reg->diu_mode, 0);	/* disable DIU */
 
 	/* Get the IRQ of the DIU */
 	machine_data->irq = irq_of_parse_and_map(np, 0);
@@ -1514,7 +1521,13 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev,
 	machine_data->dummy_ad->offset_xyd = 0;
 	machine_data->dummy_ad->next_ad = 0;
 
-	out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->paddr);
+	/*
+	 * Let DIU display splash screen if it was pre-initialized
+	 * by the bootloader, set dummy area descriptor otherwise.
+	 */
+	if (diu_mode != MFB_MODE1)
+		out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->paddr);
+
 	out_be32(&dr.diu_reg->desc[1], machine_data->dummy_ad->paddr);
 	out_be32(&dr.diu_reg->desc[2], machine_data->dummy_ad->paddr);
 
-- 
1.6.3.3

^ permalink raw reply related

* Re: [PATCH 3/5] powerpc/mpc5121: shared DIU framebuffer support
From: Anatolij Gustschin @ 2010-04-30 10:19 UTC (permalink / raw)
  To: Timur Tabi
  Cc: linux-fbdev, wd, dzu, John Rigby, devicetree-discuss,
	linuxppc-dev, yorksun
In-Reply-To: <s2ted82fe3e1004291905mf562f0cbi24054bb973aa2dbb@mail.gmail.com>

On Thu, 29 Apr 2010 21:05:26 -0500
Timur Tabi <timur.tabi@gmail.com> wrote:

> On Thu, Apr 29, 2010 at 6:49 PM, Anatolij Gustschin <agust@denx.de> wrote:
>=20
>=20
> > +void __init mpc5121_ads_init_early(void)
> > +{
> > + =C2=A0 =C2=A0 =C2=A0 mpc512x_init_diu();
> > +}
> > +
> > =C2=A0define_machine(mpc5121_ads) {
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0.name =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =3D "MPC5121 ADS",
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0.probe =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0=3D mpc5121_ads_probe,
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0.setup_arch =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =3D mpc5121_ads_setup_arch,
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0.init =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =3D mpc512x_init,
> > + =C2=A0 =C2=A0 =C2=A0 .init_early =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =3D mpc5121_ads_init_early,
>=20
> How about just doing this?
>=20
> .init_early             =3D mpc512x_init_diu,

I thought it should be prepared for adding other code here.
mpc5121_ads_init_early() is generic and could contain other
things as well. I would vote for current version.

> > +void __init mpc512x_generic_init_early(void)
> > +{
> > + =C2=A0 =C2=A0 =C2=A0 mpc512x_init_diu();
> > +}
> > +
> > +void __init mpc512x_generic_setup_arch(void)
> > +{
> > + =C2=A0 =C2=A0 =C2=A0 mpc512x_setup_diu();
> > +}
> > +
> > =C2=A0define_machine(mpc5121_generic) {
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0.name =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =3D "MPC5121 generic",
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0.probe =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0=3D mpc5121_generic_probe,
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0.init =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =3D mpc512x_init,
> > + =C2=A0 =C2=A0 =C2=A0 .init_early =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =3D mpc512x_generic_init_early,
> > + =C2=A0 =C2=A0 =C2=A0 .setup_arch =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =3D mpc512x_generic_setup_arch,
>=20
> And a similar change here.

Same here.

...
> > diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerp=
c/platforms/512x/mpc512x_shared.c
> > index b7f518a..8e297fa 100644
> > --- a/arch/powerpc/platforms/512x/mpc512x_shared.c
> > +++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
> > @@ -16,7 +16,11 @@
> > =C2=A0#include <linux/io.h>
> > =C2=A0#include <linux/irq.h>
> > =C2=A0#include <linux/of_platform.h>
> > +#include <linux/fsl-diu-fb.h>
> > +#include <linux/bootmem.h>
> > +#include <sysdev/fsl_soc.h>
> >
> > +#include <asm/cacheflush.h>
> > =C2=A0#include <asm/machdep.h>
> > =C2=A0#include <asm/ipic.h>
> > =C2=A0#include <asm/prom.h>
> > @@ -53,6 +57,286 @@ void mpc512x_restart(char *cmd)
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;
> > =C2=A0}
> >
> > +struct fsl_diu_shared_fb {
> > + =C2=A0 =C2=A0 =C2=A0 char =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ga=
mma[0x300]; =C2=A0 /* 32-bit aligned! */
>=20
> char or u8?

Will use u8.

> > + =C2=A0 =C2=A0 =C2=A0 struct diu_ad =C2=A0 ad0; =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0/* 32-bit aligned! */
> > + =C2=A0 =C2=A0 =C2=A0 phys_addr_t =C2=A0 =C2=A0 fb_phys;
> > + =C2=A0 =C2=A0 =C2=A0 size_t =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0fb_len;
> > + =C2=A0 =C2=A0 =C2=A0 bool =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0in=
_use;
> > +};
>=20
> Where did "bool" come from?  Use "int" instead.

It is common practise to use "bool" type, grep in drivers dir.

> > +unsigned int mpc512x_get_pixel_format(unsigned int bits_per_pixel,
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 int monitor_port)
> > +{
> > + =C2=A0 =C2=A0 =C2=A0 unsigned int pix_fmt;
> > +
> > + =C2=A0 =C2=A0 =C2=A0 switch (bits_per_pixel) {
> > + =C2=A0 =C2=A0 =C2=A0 case 32:
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 pix_fmt =3D 0x888833=
16;
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 break;
> > + =C2=A0 =C2=A0 =C2=A0 case 24:
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 pix_fmt =3D 0x880822=
19;
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 break;
> > + =C2=A0 =C2=A0 =C2=A0 case 16:
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 pix_fmt =3D 0x650531=
18;
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 break;
> > + =C2=A0 =C2=A0 =C2=A0 default:
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 pix_fmt =3D 0x000004=
00;
> > + =C2=A0 =C2=A0 =C2=A0 }
> > + =C2=A0 =C2=A0 =C2=A0 return pix_fmt;
> > +}
>=20
> This is simpler:
>=20
>        switch (bits_per_pixel) {
>        case 32:
>                return 0x88883316;
>        case 24:
>                return 0x88082219;
>        case 16:
>                return =3D 0x65053118;
>       }
>=20
>       return 0x00000400;
> }

Will simplify as suggested, thanks!

> > + =C2=A0 =C2=A0 =C2=A0 ccm =3D of_iomap(np, 0);
> > + =C2=A0 =C2=A0 =C2=A0 if (!ccm) {
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 pr_err("Can't map cl=
ock control module reg.\n");
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 of_node_put(np);
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return;
> > + =C2=A0 =C2=A0 =C2=A0 }
> > + =C2=A0 =C2=A0 =C2=A0 of_node_put(np);
>=20
> This is simpler:
>=20
>        ccm =3D of_iomap(np, 0);
>        of_node_put(np);
>        if (!ccm) {
>                pr_err("Can't map clock control module reg.\n");
>                return;
>        }

OK, will fix, thanks.

>=20
> > + =C2=A0 =C2=A0 =C2=A0 np =3D of_find_node_by_type(NULL, "cpu");
> > + =C2=A0 =C2=A0 =C2=A0 if (np) {
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 unsigned int size;
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 const unsigned int *=
prop =3D
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 of_get_property(np, "bus-frequency", &size);
>=20
> Since you don't use 'size', you can skip it:
>=20
>               const unsigned int *prop =3D
>                       of_get_property(np, "bus-frequency", NULL);
>=20
> > + =C2=A0 =C2=A0 =C2=A0 } else {
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 pr_err("Can't find \=
"cpu\" node.\n");
>=20
> 'cpu' is simpler than \"cpu\"

Will simplify, too.

> > + =C2=A0 =C2=A0 =C2=A0 /* Calculate the pixel clock with the smallest e=
rror */
> > + =C2=A0 =C2=A0 =C2=A0 /* calculate the following in steps to avoid ove=
rflow */
> > + =C2=A0 =C2=A0 =C2=A0 pr_debug("DIU pixclock in ps - %d\n", pixclock);
> > + =C2=A0 =C2=A0 =C2=A0 temp =3D (1000000000 / pixclock) * 1000;
>=20
> I'm pretty sure the compiler will optimize this to:
>=20
>     temp =3D (1000000000000UL / pixclock);
>=20
> so you may as well do it that way.

??
1000000000000 is _not_ UL, but UUL.

>=20
> > + =C2=A0 =C2=A0 =C2=A0 pixclock =3D temp;
> > + =C2=A0 =C2=A0 =C2=A0 pr_debug("DIU pixclock freq - %u\n", pixclock);
> > +
> > + =C2=A0 =C2=A0 =C2=A0 temp =3D (temp * 5) / 100; /* pixclock * 0.05 */
>=20
> The compiler will optimize this to:
>=20
>     temp /=3D 20;

Can do it, too. Thanks.

> > + =C2=A0 =C2=A0 =C2=A0 pr_debug("deviation =3D %d\n", temp);
> > + =C2=A0 =C2=A0 =C2=A0 minpixclock =3D pixclock - temp;
> > + =C2=A0 =C2=A0 =C2=A0 maxpixclock =3D pixclock + temp;
> > + =C2=A0 =C2=A0 =C2=A0 pr_debug("DIU minpixclock - %lu\n", minpixclock);
> > + =C2=A0 =C2=A0 =C2=A0 pr_debug("DIU maxpixclock - %lu\n", maxpixclock);
> > + =C2=A0 =C2=A0 =C2=A0 pixval =3D speed_ccb/pixclock;
> > + =C2=A0 =C2=A0 =C2=A0 pr_debug("DIU pixval =3D %lu\n", pixval);
> > +
> > + =C2=A0 =C2=A0 =C2=A0 err =3D 100000000;
>=20
> Why do you assign err to this arbitrary value?

Dunno. It is Freescale's code and I do not have time to check
and understand each bit of it and to explain it.

> > + =C2=A0 =C2=A0 =C2=A0 bestval =3D pixval;
> > + =C2=A0 =C2=A0 =C2=A0 pr_debug("DIU bestval =3D %lu\n", bestval);
> > +
> > + =C2=A0 =C2=A0 =C2=A0 bestfreq =3D 0;
> > + =C2=A0 =C2=A0 =C2=A0 for (i =3D -1; i <=3D 1; i++) {
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 temp =3D speed_ccb /=
 (pixval+i);
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 pr_debug("DIU test p=
ixval i=3D%d, pixval=3D%lu, temp freq. =3D %u\n",
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 i, pixval, temp);
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if ((temp < minpixcl=
ock) || (temp > maxpixclock))
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 pr_debug("DIU exceeds monitor range (%lu to %lu)\n",
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 minpixclock, maxpixclock);
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 else if (abs(temp - =
pixclock) < err) {
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 pr_debug("Entered the else if block %d\n", i);
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 err =3D abs(temp - pixclock);
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 bestval =3D pixval + i;
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 bestfreq =3D temp;
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 }
> > + =C2=A0 =C2=A0 =C2=A0 }
> > +
> > + =C2=A0 =C2=A0 =C2=A0 pr_debug("DIU chose =3D %lx\n", bestval);
> > + =C2=A0 =C2=A0 =C2=A0 pr_debug("DIU error =3D %ld\n NomPixClk ", err);
> > + =C2=A0 =C2=A0 =C2=A0 pr_debug("DIU: Best Freq =3D %lx\n", bestfreq);
> > + =C2=A0 =C2=A0 =C2=A0 /* Modify DIU_DIV in CCM SCFR1 */
> > + =C2=A0 =C2=A0 =C2=A0 temp =3D in_be32(ccm + CCM_SCFR1);
>=20
> Don't use offsets like + CCM_SCFR1.  Create a structure and use that inst=
ead.

Done in next patch version.

> > + =C2=A0 =C2=A0 =C2=A0 pr_debug("DIU: Current value of SCFR1: 0x%08x\n"=
, temp);
> > + =C2=A0 =C2=A0 =C2=A0 temp &=3D ~DIU_DIV_MASK;
> > + =C2=A0 =C2=A0 =C2=A0 temp |=3D (bestval & DIU_DIV_MASK);
> > + =C2=A0 =C2=A0 =C2=A0 out_be32(ccm + CCM_SCFR1, temp);
> > + =C2=A0 =C2=A0 =C2=A0 pr_debug("DIU: Modified value of SCFR1: 0x%08x\n=
", temp);
> > + =C2=A0 =C2=A0 =C2=A0 iounmap(ccm);
> > +}
> > +
> > +ssize_t mpc512x_show_monitor_port(int monitor_port, char *buf)
> > +{
> > + =C2=A0 =C2=A0 =C2=A0 return snprintf(buf, PAGE_SIZE, "0 - 5121 LCD\n"=
);
>=20
> There's no point in using snprintf since you're printing a string
> literal.  You can use sprintf.

Will do, thanks.

> > +}
> > +
> > +int mpc512x_set_sysfs_monitor_port(int val)
> > +{
> > + =C2=A0 =C2=A0 =C2=A0 return 0;
> > +}
> > +
> > +static struct fsl_diu_shared_fb __attribute__ ((__aligned__(8))) diu_s=
hared_fb;
> > +
> > +#if defined(CONFIG_FB_FSL_DIU) || \
> > + =C2=A0 =C2=A0defined(CONFIG_FB_FSL_DIU_MODULE)
> > +static inline void mpc512x_free_bootmem(struct page *page)
> > +{
> > + =C2=A0 =C2=A0 =C2=A0 __ClearPageReserved(page);
> > + =C2=A0 =C2=A0 =C2=A0 BUG_ON(PageTail(page));
> > + =C2=A0 =C2=A0 =C2=A0 BUG_ON(atomic_read(&page->_count) > 1);
> > + =C2=A0 =C2=A0 =C2=A0 atomic_set(&page->_count, 1);
> > + =C2=A0 =C2=A0 =C2=A0 __free_page(page);
> > + =C2=A0 =C2=A0 =C2=A0 totalram_pages++;
> > +}
> > +
> > +void mpc512x_release_bootmem(void)
> > +{
> > + =C2=A0 =C2=A0 =C2=A0 unsigned long addr =3D diu_shared_fb.fb_phys & P=
AGE_MASK;
> > + =C2=A0 =C2=A0 =C2=A0 unsigned long size =3D diu_shared_fb.fb_len;
> > + =C2=A0 =C2=A0 =C2=A0 unsigned long start, end;
> > +
> > + =C2=A0 =C2=A0 =C2=A0 if (diu_shared_fb.in_use) {
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 start =3D PFN_UP(add=
r);
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 end =3D PFN_DOWN(add=
r + size);
> > +
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 for (; start < end; =
start++)
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 mpc512x_free_bootmem(pfn_to_page(start));
> > +
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 diu_shared_fb.in_use=
 =3D false;
> > + =C2=A0 =C2=A0 =C2=A0 }
> > + =C2=A0 =C2=A0 =C2=A0 diu_ops.release_bootmem =3D NULL;
> > +}
> > +#endif
>=20
> Do you really need to use reserve_bootmem?  Have you tried kmalloc or
> alloc_pages_exact()?

Yes. No, it is too early to use them here.

> > +
> > +/*
> > + * Check if DIU was pre-initialized. If so, perform steps
> > + * needed to continue displaying through the whole boot process.
> > + * Move area descriptor and gamma table elsewhere, they are
> > + * destroyed by bootmem allocator otherwise. The frame buffer
> > + * address range will be reserved in setup_arch() after bootmem
> > + * allocator is up.
> > + */
> > +void __init mpc512x_init_diu(void)
> > +{
> > + =C2=A0 =C2=A0 =C2=A0 struct device_node *np;
> > + =C2=A0 =C2=A0 =C2=A0 void __iomem *diu_reg;
> > + =C2=A0 =C2=A0 =C2=A0 phys_addr_t desc;
> > + =C2=A0 =C2=A0 =C2=A0 void __iomem *vaddr;
> > + =C2=A0 =C2=A0 =C2=A0 unsigned long mode, pix_fmt, res, bpp;
> > + =C2=A0 =C2=A0 =C2=A0 unsigned long dst;
> > +
> > + =C2=A0 =C2=A0 =C2=A0 np =3D of_find_compatible_node(NULL, NULL, "fsl,=
mpc5121-diu");
> > + =C2=A0 =C2=A0 =C2=A0 if (!np) {
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 pr_err("No DIU node\=
n");
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return;
> > + =C2=A0 =C2=A0 =C2=A0 }
>=20
> Shouldn't you be probing as an OF driver instead of manually searching
> for the DIU node?

No, not here.

> > +
> > + =C2=A0 =C2=A0 =C2=A0 diu_reg =3D of_iomap(np, 0);
> > + =C2=A0 =C2=A0 =C2=A0 of_node_put(np);
> > + =C2=A0 =C2=A0 =C2=A0 if (!diu_reg) {
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 pr_err("Can't map DI=
U\n");
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return;
> > + =C2=A0 =C2=A0 =C2=A0 }
> > +
> > + =C2=A0 =C2=A0 =C2=A0 mode =3D in_be32(diu_reg + 0x1c);
> > + =C2=A0 =C2=A0 =C2=A0 if (mode !=3D 1) {
>=20
> How can in_be32() return a -1?

It is a 1, not -1. I will use appropriate macro here and also
change to use a struct instead of adding offset to register base.

Thanks for your review and comments!
Anatolij

^ permalink raw reply

* [PATCH v2 5/5] fsl-diu-fb: Support setting display mode using EDID
From: Anatolij Gustschin @ 2010-04-30  8:09 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: linux-fbdev, wd, dzu, devicetree-discuss, yorksun
In-Reply-To: <1272584978-19063-6-git-send-email-agust@denx.de>

Adds support for encoding display mode information
in the device tree using verbatim EDID block.

If the EDID entry in the DIU node is present, the
driver will build mode database using EDID data
and allow setting the display modes from this database.
Otherwise display mode will be set using mode
entries from driver's internal database as usual.

This patch also updates device tree bindings.

Signed-off-by: Anatolij Gustschin <agust@denx.de>
---
v1 -> v2:
 - fix EDID property to be lower-case
 - use u8 * type for EDID block pointer
 - simplify "info->monspecs.modedb != NULL" condition test

 Documentation/powerpc/dts-bindings/fsl/diu.txt |    6 ++
 drivers/video/Kconfig                          |    1 +
 drivers/video/fsl-diu-fb.c                     |   80 ++++++++++++++++++++++--
 3 files changed, 81 insertions(+), 6 deletions(-)

diff --git a/Documentation/powerpc/dts-bindings/fsl/diu.txt b/Documentation/powerpc/dts-bindings/fsl/diu.txt
index 326cddf..47e777e 100644
--- a/Documentation/powerpc/dts-bindings/fsl/diu.txt
+++ b/Documentation/powerpc/dts-bindings/fsl/diu.txt
@@ -11,6 +11,11 @@ Required properties:
 - interrupt-parent : the phandle for the interrupt controller that
   services interrupts for this device.
 
+Optional properties:
+- edid : verbatim EDID data block describing attached display.
+  Data from the detailed timing descriptor will be used to
+  program the display controller.
+
 Example (MPC8610HPCD):
 	display@2c000 {
 		compatible = "fsl,diu";
@@ -25,4 +30,5 @@ Example for MPC5121:
 		reg = <0x2100 0x100>;
 		interrupts = <64 0x8>;
 		interrupt-parent = <&ipic>;
+		edid = [edid-data];
 	};
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 6e16244..eca1e49 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1855,6 +1855,7 @@ config FB_MBX_DEBUG
 config FB_FSL_DIU
 	tristate "Freescale DIU framebuffer support"
 	depends on FB && FSL_SOC
+	select FB_MODE_HELPERS
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index 81dec09..2b99f29 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -35,6 +35,7 @@
 
 #include <sysdev/fsl_soc.h>
 #include <linux/fsl-diu-fb.h>
+#include "edid.h"
 
 /*
  * These parameters give default parameters
@@ -217,6 +218,7 @@ struct mfb_info {
 	int x_aoi_d;		/* aoi display x offset to physical screen */
 	int y_aoi_d;		/* aoi display y offset to physical screen */
 	struct fsl_diu_data *parent;
+	u8 *edid_data;
 };
 
 
@@ -1180,18 +1182,30 @@ static int __devinit install_fb(struct fb_info *info)
 	int rc;
 	struct mfb_info *mfbi = info->par;
 	const char *aoi_mode, *init_aoi_mode = "320x240";
+	struct fb_videomode *db = fsl_diu_mode_db;
+	unsigned int dbsize = ARRAY_SIZE(fsl_diu_mode_db);
+	int has_default_mode = 1;
 
 	if (init_fbinfo(info))
 		return -EINVAL;
 
-	if (mfbi->index == 0)	/* plane 0 */
+	if (mfbi->index == 0) {	/* plane 0 */
+		if (mfbi->edid_data) {
+			/* Now build modedb from EDID */
+			fb_edid_to_monspecs(mfbi->edid_data, &info->monspecs);
+			fb_videomode_to_modelist(info->monspecs.modedb,
+						 info->monspecs.modedb_len,
+						 &info->modelist);
+			db = info->monspecs.modedb;
+			dbsize = info->monspecs.modedb_len;
+		}
 		aoi_mode = fb_mode;
-	else
+	} else {
 		aoi_mode = init_aoi_mode;
+	}
 	pr_debug("mode used = %s\n", aoi_mode);
-	rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db,
-	     ARRAY_SIZE(fsl_diu_mode_db), &fsl_diu_default_mode, default_bpp);
-
+	rc = fb_find_mode(&info->var, info, aoi_mode, db, dbsize,
+			  &fsl_diu_default_mode, default_bpp);
 	switch (rc) {
 	case 1:
 		pr_debug("using mode specified in @mode\n");
@@ -1209,10 +1223,50 @@ static int __devinit install_fb(struct fb_info *info)
 	default:
 		pr_debug("rc = %d\n", rc);
 		pr_debug("failed to find mode\n");
-		return -EINVAL;
+		/*
+		 * For plane 0 we continue and look into
+		 * driver's internal modedb.
+		 */
+		if (mfbi->index == 0 && mfbi->edid_data)
+			has_default_mode = 0;
+		else
+			return -EINVAL;
 		break;
 	}
 
+	if (!has_default_mode) {
+		rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db,
+				  ARRAY_SIZE(fsl_diu_mode_db),
+				  &fsl_diu_default_mode,
+				  default_bpp);
+		if (rc > 0 && rc < 5)
+			has_default_mode = 1;
+	}
+
+	/* Still not found, use preferred mode from database if any */
+	if (!has_default_mode && info->monspecs.modedb) {
+		struct fb_monspecs *specs = &info->monspecs;
+		struct fb_videomode *modedb = &specs->modedb[0];
+
+		/*
+		 * Get preferred timing. If not found,
+		 * first mode in database will be used.
+		 */
+		if (specs->misc & FB_MISC_1ST_DETAIL) {
+			int i;
+
+			for (i = 0; i < specs->modedb_len; i++) {
+				if (specs->modedb[i].flag & FB_MODE_IS_FIRST) {
+					modedb = &specs->modedb[i];
+					break;
+				}
+			}
+		}
+
+		info->var.bits_per_pixel = default_bpp;
+		fb_videomode_to_var(&info->var, modedb);
+	}
+
 	pr_debug("xres_virtual %d\n", info->var.xres_virtual);
 	pr_debug("bits_per_pixel %d\n", info->var.bits_per_pixel);
 
@@ -1251,6 +1305,9 @@ static void uninstall_fb(struct fb_info *info)
 	if (!mfbi->registered)
 		return;
 
+	if (mfbi->index == 0)
+		kfree(mfbi->edid_data);
+
 	unregister_framebuffer(info);
 	unmap_video_memory(info);
 	if (&info->cmap)
@@ -1451,6 +1508,17 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev,
 		mfbi = machine_data->fsl_diu_info[i]->par;
 		memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info));
 		mfbi->parent = machine_data;
+
+		if (mfbi->index == 0) {
+			const u8 *prop;
+			int len;
+
+			/* Get EDID */
+			prop = of_get_property(np, "edid", &len);
+			if (prop && len == EDID_LENGTH)
+				mfbi->edid_data = kmemdup(prop, EDID_LENGTH,
+							  GFP_KERNEL);
+		}
 	}
 
 	ret = of_address_to_resource(np, 0, &res);
-- 
1.6.3.3

^ permalink raw reply related

* Re: [PATCH 5/5] fsl-diu-fb: Support setting display mode using EDID
From: Anatolij Gustschin @ 2010-04-30  7:43 UTC (permalink / raw)
  To: Timur Tabi
  Cc: linux-fbdev, wd, dzu, devicetree-discuss, linuxppc-dev, yorksun
In-Reply-To: <n2oed82fe3e1004291844habbdfe76lc369d66cf9a9d9fd@mail.gmail.com>

On Thu, 29 Apr 2010 20:44:12 -0500
Timur Tabi <timur.tabi@gmail.com> wrote:

> On Thu, Apr 29, 2010 at 6:49 PM, Anatolij Gustschin <agust@denx.de> wrote:
>=20
> > +Optional properties:
> > +- EDID : verbatim EDID data block describing attached display.
> > + =C2=A0Data from the detailed timing descriptor will be used to
> > + =C2=A0program the display controller.
>=20
> The property name should be lower-case.

Will change to lower-case.

> > =C2=A0/*
> > =C2=A0* These parameters give default parameters
> > @@ -217,6 +218,7 @@ struct mfb_info {
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0int x_aoi_d; =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0/* aoi display x offset to physical screen */
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0int y_aoi_d; =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0/* aoi display y offset to physical screen */
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0struct fsl_diu_data *parent;
> > + =C2=A0 =C2=A0 =C2=A0 char *edid_data;
>=20
> edid_data should be "u8 *".  "char *" is should be used only for
> strings or arrays of characters.

Will fix it, too.

> > + =C2=A0 =C2=A0 =C2=A0 /* Still not found, use preferred mode from data=
base if any */
> > + =C2=A0 =C2=A0 =C2=A0 if (!has_default_mode && info->monspecs.modedb !=
=3D NULL) {
>=20
> No need for the "!=3D NULL"

Ok, I will simplify this.

Thanks,
Anatolij

^ permalink raw reply

* Re: [PATCH 0/5] Rework MPC5121 DIU support (for 2.6.35)
From: Anatolij Gustschin @ 2010-04-30  7:41 UTC (permalink / raw)
  To: Timur Tabi
  Cc: linux-fbdev, wd, dzu, devicetree-discuss, linuxppc-dev, yorksun
In-Reply-To: <y2med82fe3e1004291839m92dea081o6a46dc307e07c4ad@mail.gmail.com>

On Thu, 29 Apr 2010 20:39:02 -0500
Timur Tabi <timur.tabi@gmail.com> wrote:

> On Thu, Apr 29, 2010 at 6:49 PM, Anatolij Gustschin <agust@denx.de> wrote:
> > This patch series rework DIU support patches submitted
> > previously. Comments to the previos patch series have
> > been addressed, not related changes are dropped and some
> > changes are split out to separate patches to simplify
> > review. Furthermore a patch has been added to support
> > setting display mode using EDID block in the device tree.
> 
> Have you tested these changes on an MPC8610 HPCD?  If not, do you
> think your changes will break that platform?

I've compile tested these changes using 86xx/mpc8610_hpcd_defconfig.
Unfortunately I don't have an MPC8610 HPCD and can not test it
more, but I don't think these patches will break that platform. 

Anatolij

^ permalink raw reply

* Re: [PATCH 2/3] powerpc: Add form 1 NUMA affinity
From: Anton Blanchard @ 2010-04-30  7:33 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev
In-Reply-To: <1272612299.13814.0.camel@pasglop>

 
Hi Ben,

> I sent your previous version of that one to Linus, it's already up. Can
> you check it's allright ?

No change to this patch, but I thought I would send them as a series since they
build on each other. I'll double check mainline looks good.

Anton

^ permalink raw reply

* Re: [PATCH 2/3] powerpc: Add form 1 NUMA affinity
From: Benjamin Herrenschmidt @ 2010-04-30  7:24 UTC (permalink / raw)
  To: Anton Blanchard; +Cc: linuxppc-dev
In-Reply-To: <20100430043407.GC4622@kryten>

On Fri, 2010-04-30 at 14:34 +1000, Anton Blanchard wrote:
> Firmware changed the way it represents memory and cpu affinity on POWER7.
> Unfortunately the old method now caps the topology to work around issues
> with legacy operating systems. For Linux to get the correct topology we
> need to use the new form 1 affinity information.
> 
> We set the form 1 field in the client architecture, and if we see "1" in the
> ibm,associativity-form property firmware supports form 1 affinity and
> we should look at the first field in the ibm,associativity-reference-points
> array. If not we use the second field as we always have.
> 
> Signed-off-by: Anton Blanchard <anton@samba.org>
> ---

I sent your previous version of that one to Linus, it's already up. Can
you check it's allright ?

Cheers,
Ben.

^ permalink raw reply

* [PATCH 3/3] powerpc: Use form 1 affinity to setup node distance
From: Anton Blanchard @ 2010-04-30  4:43 UTC (permalink / raw)
  To: benh; +Cc: linuxppc-dev
In-Reply-To: <20100430043407.GC4622@kryten>


Form 1 affinity allows multiple entries in ibm,associativity-reference-points
which represent affinity domains in decreasing order of importance. The
Linux concept of a node is always the first entry, but using the other
values as an input to node_distance() allows the memory allocator to make
better decisions on which node to go first when local memory has been
exhausted.

We keep things simple and create an array indexed by NUMA node, capped at
4 entries. Each time we lookup an associativity property we initialise
the array which is overkill, but since we should only hit this path during
boot it didn't seem worth adding a per node valid bit.

Signed-off-by: Anton Blanchard <anton@samba.org>
---

Index: linux-2.6/arch/powerpc/include/asm/topology.h
===================================================================
--- linux-2.6.orig/arch/powerpc/include/asm/topology.h	2010-04-29 15:58:58.000000000 +1000
+++ linux-2.6/arch/powerpc/include/asm/topology.h	2010-04-29 15:59:00.000000000 +1000
@@ -77,6 +77,9 @@ static inline int pcibus_to_node(struct 
 	.balance_interval	= 1,					\
 }
 
+extern int __node_distance(int, int);
+#define node_distance(a, b) __node_distance(a, b)
+
 extern void __init dump_numa_cpu_topology(void);
 
 extern int sysfs_add_device_to_node(struct sys_device *dev, int nid);
Index: linux-2.6/arch/powerpc/mm/numa.c
===================================================================
--- linux-2.6.orig/arch/powerpc/mm/numa.c	2010-04-29 15:58:59.000000000 +1000
+++ linux-2.6/arch/powerpc/mm/numa.c	2010-04-29 22:05:24.000000000 +1000
@@ -42,6 +42,12 @@ EXPORT_SYMBOL(node_data);
 
 static int min_common_depth;
 static int n_mem_addr_cells, n_mem_size_cells;
+static int form1_affinity;
+
+#define MAX_DISTANCE_REF_POINTS 4
+static int distance_ref_points_depth;
+static const unsigned int *distance_ref_points;
+static int distance_lookup_table[MAX_NUMNODES][MAX_DISTANCE_REF_POINTS];
 
 static int __cpuinit fake_numa_create_new_node(unsigned long end_pfn,
 						unsigned int *nid)
@@ -179,6 +185,39 @@ static const u32 *of_get_usable_memory(s
 	return prop;
 }
 
+int __node_distance(int a, int b)
+{
+	int i;
+	int distance = LOCAL_DISTANCE;
+
+	if (!form1_affinity)
+		return distance;
+
+	for (i = 0; i < distance_ref_points_depth; i++) {
+		if (distance_lookup_table[a][i] == distance_lookup_table[b][i])
+			break;
+
+		/* Double the distance for each NUMA level */
+		distance *= 2;
+	}
+
+	return distance;
+}
+
+static void initialize_distance_lookup_table(int nid,
+		const unsigned int *associativity)
+{
+	int i;
+
+	if (!form1_affinity)
+		return;
+
+	for (i = 0; i < distance_ref_points_depth; i++) {
+		distance_lookup_table[nid][i] =
+			associativity[distance_ref_points[i]];
+	}
+}
+
 /* Returns nid in the range [0..MAX_NUMNODES-1], or -1 if no useful numa
  * info is found.
  */
@@ -200,6 +239,10 @@ static int of_node_to_nid_single(struct 
 	/* POWER4 LPAR uses 0xffff as invalid node */
 	if (nid == 0xffff || nid >= MAX_NUMNODES)
 		nid = -1;
+
+	if (nid > 0 && tmp[0] >= distance_ref_points_depth)
+		initialize_distance_lookup_table(nid, tmp);
+
 out:
 	return nid;
 }
@@ -226,26 +269,10 @@ int of_node_to_nid(struct device_node *d
 }
 EXPORT_SYMBOL_GPL(of_node_to_nid);
 
-/*
- * In theory, the "ibm,associativity" property may contain multiple
- * associativity lists because a resource may be multiply connected
- * into the machine.  This resource then has different associativity
- * characteristics relative to its multiple connections.  We ignore
- * this for now.  We also assume that all cpu and memory sets have
- * their distances represented at a common level.  This won't be
- * true for hierarchical NUMA.
- *
- * In any case the ibm,associativity-reference-points should give
- * the correct depth for a normal NUMA system.
- *
- * - Dave Hansen <haveblue@us.ibm.com>
- */
 static int __init find_min_common_depth(void)
 {
-	int depth, index;
-	const unsigned int *ref_points;
+	int depth;
 	struct device_node *rtas_root;
-	unsigned int len;
 	struct device_node *options;
 
 	rtas_root = of_find_node_by_path("/rtas");
@@ -254,35 +281,62 @@ static int __init find_min_common_depth(
 		return -1;
 
 	/*
-	 * this property is 2 32-bit integers, each representing a level of
-	 * depth in the associativity nodes.  The first is for an SMP
-	 * configuration (should be all 0's) and the second is for a normal
-	 * NUMA configuration.
+	 * This property is a set of 32-bit integers, each representing
+	 * an index into the ibm,associativity nodes.
+	 *
+	 * With form 0 affinity the first integer is for an SMP configuration
+	 * (should be all 0's) and the second is for a normal NUMA
+	 * configuration. We have only one level of NUMA.
+	 *
+	 * With form 1 affinity the first integer is the most significant
+	 * NUMA boundary and the following are progressively less significant
+	 * boundaries. There can be more than one level of NUMA.
 	 */
-	index = 1;
-	ref_points = of_get_property(rtas_root,
-			"ibm,associativity-reference-points", &len);
+	distance_ref_points = of_get_property(rtas_root,
+			"ibm,associativity-reference-points",
+			&distance_ref_points_depth);
+
+	if (!distance_ref_points)
+		goto err;
+
+	distance_ref_points_depth /= sizeof(int);
 
-	/*
-	 * For type 1 affinity information we want the first field
-	 */
 	options = of_find_node_by_path("/options");
 	if (options) {
 		const char *str;
 		str = of_get_property(options, "ibm,associativity-form", NULL);
 		if (str && !strcmp(str, "1"))
-                        index = 0;
+			form1_affinity = 1;
 	}
 
-	if ((len >= 2 * sizeof(unsigned int)) && ref_points) {
-		depth = ref_points[index];
+	if (form1_affinity) {
+		depth = distance_ref_points[0];
 	} else {
-		dbg("NUMA: ibm,associativity-reference-points not found.\n");
-		depth = -1;
+		if (distance_ref_points_depth < 2)
+			goto err;
+
+		depth = distance_ref_points[1];
 	}
+
+	/*
+	 * Warn and cap if the hardware supports more than
+	 * MAX_DISTANCE_REF_POINTS domains.
+	 */
+	if (distance_ref_points_depth > MAX_DISTANCE_REF_POINTS) {
+		printk(KERN_WARNING
+		       "NUMA: distance array capped at %d entries\n",
+			MAX_DISTANCE_REF_POINTS);
+		distance_ref_points_depth = MAX_DISTANCE_REF_POINTS;
+	}
+
 	of_node_put(rtas_root);
 
 	return depth;
+
+err:
+	dbg("NUMA: ibm,associativity-reference-points not found.\n");
+	of_node_put(rtas_root);
+	return -1;
 }
 
 static void __init get_n_mem_cells(int *n_addr_cells, int *n_size_cells)

^ permalink raw reply

* [PATCH 2/3] powerpc: Add form 1 NUMA affinity
From: Anton Blanchard @ 2010-04-30  4:34 UTC (permalink / raw)
  To: benh; +Cc: linuxppc-dev
In-Reply-To: <20100430043324.GB4622@kryten>


Firmware changed the way it represents memory and cpu affinity on POWER7.
Unfortunately the old method now caps the topology to work around issues
with legacy operating systems. For Linux to get the correct topology we
need to use the new form 1 affinity information.

We set the form 1 field in the client architecture, and if we see "1" in the
ibm,associativity-form property firmware supports form 1 affinity and
we should look at the first field in the ibm,associativity-reference-points
array. If not we use the second field as we always have.

Signed-off-by: Anton Blanchard <anton@samba.org>
---

Index: linux-2.6.34-rc3/arch/powerpc/kernel/prom_init.c
===================================================================
--- linux-2.6.34-rc3.orig/arch/powerpc/kernel/prom_init.c	2010-04-02 07:52:10.000000000 -0500
+++ linux-2.6.34-rc3/arch/powerpc/kernel/prom_init.c	2010-04-07 07:06:45.000000000 -0500
@@ -653,6 +653,7 @@
 #else
 #define OV5_CMO			0x00
 #endif
+#define OV5_TYPE1_AFFINITY	0x80	/* Type 1 NUMA affinity */
 
 /* Option Vector 6: IBM PAPR hints */
 #define OV6_LINUX		0x02	/* Linux is our OS */
@@ -706,7 +707,7 @@
 	OV5_DONATE_DEDICATE_CPU | OV5_MSI,
 	0,
 	OV5_CMO,
-	0,
+	OV5_TYPE1_AFFINITY,
 	0,
 	0,
 	0,
Index: linux-2.6.34-rc3/arch/powerpc/mm/numa.c
===================================================================
--- linux-2.6.34-rc3.orig/arch/powerpc/mm/numa.c	2010-04-07 07:06:32.000000000 -0500
+++ linux-2.6.34-rc3/arch/powerpc/mm/numa.c	2010-04-07 09:43:48.000000000 -0500
@@ -242,10 +243,11 @@
  */
 static int __init find_min_common_depth(void)
 {
-	int depth;
+	int depth, index;
 	const unsigned int *ref_points;
 	struct device_node *rtas_root;
 	unsigned int len;
+	struct device_node *options;
 
 	rtas_root = of_find_node_by_path("/rtas");
 
@@ -258,11 +260,23 @@
 	 * configuration (should be all 0's) and the second is for a normal
 	 * NUMA configuration.
 	 */
+	index = 1;
 	ref_points = of_get_property(rtas_root,
 			"ibm,associativity-reference-points", &len);
 
+	/*
+	 * For type 1 affinity information we want the first field
+	 */
+	options = of_find_node_by_path("/options");
+	if (options) {
+		const char *str;
+		str = of_get_property(options, "ibm,associativity-form", NULL);
+		if (str && !strcmp(str, "1"))
+                        index = 0;
+	}
+
 	if ((len >= 2 * sizeof(unsigned int)) && ref_points) {
-		depth = ref_points[1];
+		depth = ref_points[index];
 	} else {
 		dbg("NUMA: ibm,associativity-reference-points not found.\n");
 		depth = -1;

^ 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