* [PATCH] [POWERPC] Add AMCC Glacier 460GT eval board dts
From: Stefan Roese @ 2008-03-19 16:15 UTC (permalink / raw)
To: linuxppc-dev
The patch adds the Glacier dts. The Glacier is nearly identical to the
Canyonlands (460EX). Here the differences:
- 4 ethernet ports instead of 2
- no SATA port
- no USB port
Signed-off-by: Stefan Roese <sr@denx.de>
---
arch/powerpc/boot/dts/glacier.dts | 464 +++++++++++++++++++++++++++++++++++++
1 files changed, 464 insertions(+), 0 deletions(-)
create mode 100644 arch/powerpc/boot/dts/glacier.dts
diff --git a/arch/powerpc/boot/dts/glacier.dts b/arch/powerpc/boot/dts/glacier.dts
new file mode 100644
index 0000000..7381cdd
--- /dev/null
+++ b/arch/powerpc/boot/dts/glacier.dts
@@ -0,0 +1,464 @@
+/*
+ * Device Tree Source for AMCC Glacier (460GT)
+ *
+ * Copyright 2008 DENX Software Engineering, Stefan Roese <sr@denx.de>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without
+ * any warranty of any kind, whether express or implied.
+ */
+
+/ {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ model = "amcc,glacier";
+ compatible = "amcc,canyonlands";
+ dcr-parent = <&/cpus/cpu@0>;
+
+ aliases {
+ ethernet0 = &EMAC0;
+ ethernet1 = &EMAC1;
+ ethernet2 = &EMAC2;
+ ethernet3 = &EMAC3;
+ serial0 = &UART0;
+ serial1 = &UART1;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ model = "PowerPC,460GT";
+ reg = <0>;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+ timebase-frequency = <0>; /* Filled in by U-Boot */
+ i-cache-line-size = <20>;
+ d-cache-line-size = <20>;
+ i-cache-size = <8000>;
+ d-cache-size = <8000>;
+ dcr-controller;
+ dcr-access-method = "native";
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0 0 0>; /* Filled in by U-Boot */
+ };
+
+ UIC0: interrupt-controller0 {
+ compatible = "ibm,uic-460gt","ibm,uic";
+ interrupt-controller;
+ cell-index = <0>;
+ dcr-reg = <0c0 009>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ #interrupt-cells = <2>;
+ };
+
+ UIC1: interrupt-controller1 {
+ compatible = "ibm,uic-460gt","ibm,uic";
+ interrupt-controller;
+ cell-index = <1>;
+ dcr-reg = <0d0 009>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ #interrupt-cells = <2>;
+ interrupts = <1e 4 1f 4>; /* cascade */
+ interrupt-parent = <&UIC0>;
+ };
+
+ UIC2: interrupt-controller2 {
+ compatible = "ibm,uic-460gt","ibm,uic";
+ interrupt-controller;
+ cell-index = <2>;
+ dcr-reg = <0e0 009>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ #interrupt-cells = <2>;
+ interrupts = <a 4 b 4>; /* cascade */
+ interrupt-parent = <&UIC0>;
+ };
+
+ UIC3: interrupt-controller3 {
+ compatible = "ibm,uic-460gt","ibm,uic";
+ interrupt-controller;
+ cell-index = <3>;
+ dcr-reg = <0f0 009>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ #interrupt-cells = <2>;
+ interrupts = <10 4 11 4>; /* cascade */
+ interrupt-parent = <&UIC0>;
+ };
+
+ SDR0: sdr {
+ compatible = "ibm,sdr-460gt";
+ dcr-reg = <00e 002>;
+ };
+
+ CPR0: cpr {
+ compatible = "ibm,cpr-460gt";
+ dcr-reg = <00c 002>;
+ };
+
+ plb {
+ compatible = "ibm,plb-460gt", "ibm,plb4";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ ranges;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+
+ SDRAM0: sdram {
+ compatible = "ibm,sdram-460gt", "ibm,sdram-405gp";
+ dcr-reg = <010 2>;
+ };
+
+ MAL0: mcmal {
+ compatible = "ibm,mcmal-460gt", "ibm,mcmal2";
+ dcr-reg = <180 62>;
+ num-tx-chans = <4>;
+ num-rx-chans = <20>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-parent = <&UIC2>;
+ interrupts = < /*TXEOB*/ 6 4
+ /*RXEOB*/ 7 4
+ /*SERR*/ 3 4
+ /*TXDE*/ 4 4
+ /*RXDE*/ 5 4>;
+ desc-base-addr-high = <8>;
+ };
+
+ POB0: opb {
+ compatible = "ibm,opb-460gt", "ibm,opb";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <b0000000 4 b0000000 50000000>;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+
+ EBC0: ebc {
+ compatible = "ibm,ebc-460gt", "ibm,ebc";
+ dcr-reg = <012 2>;
+ #address-cells = <2>;
+ #size-cells = <1>;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+ interrupts = <6 4>;
+ interrupt-parent = <&UIC1>;
+ };
+
+ UART0: serial@ef600300 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <ef600300 8>;
+ virtual-reg = <ef600300>;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+ current-speed = <0>; /* Filled in by U-Boot */
+ interrupt-parent = <&UIC1>;
+ interrupts = <1 4>;
+ };
+
+ UART1: serial@ef600400 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <ef600400 8>;
+ virtual-reg = <ef600400>;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+ current-speed = <0>; /* Filled in by U-Boot */
+ interrupt-parent = <&UIC0>;
+ interrupts = <1 4>;
+ };
+
+ UART2: serial@ef600500 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <ef600500 8>;
+ virtual-reg = <ef600500>;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+ current-speed = <0>; /* Filled in by U-Boot */
+ interrupt-parent = <&UIC1>;
+ interrupts = <1d 4>;
+ };
+
+ UART3: serial@ef600600 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <ef600600 8>;
+ virtual-reg = <ef600600>;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+ current-speed = <0>; /* Filled in by U-Boot */
+ interrupt-parent = <&UIC1>;
+ interrupts = <1e 4>;
+ };
+
+ IIC0: i2c@ef600700 {
+ compatible = "ibm,iic-460gt", "ibm,iic";
+ reg = <ef600700 14>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <2 4>;
+ };
+
+ IIC1: i2c@ef600800 {
+ compatible = "ibm,iic-460gt", "ibm,iic";
+ reg = <ef600800 14>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <3 4>;
+ };
+
+ ZMII0: emac-zmii@ef600d00 {
+ compatible = "ibm,zmii-460gt", "ibm,zmii";
+ reg = <ef600d00 c>;
+ };
+
+ RGMII0: emac-rgmii@ef601500 {
+ compatible = "ibm,rgmii-460gt", "ibm,rgmii";
+ reg = <ef601500 8>;
+ has-mdio;
+ };
+
+ RGMII1: emac-rgmii@ef601600 {
+ compatible = "ibm,rgmii-460gt", "ibm,rgmii";
+ reg = <ef601600 8>;
+ has-mdio;
+ };
+
+ TAH0: emac-tah@ef601350 {
+ compatible = "ibm,tah-460gt", "ibm,tah";
+ reg = <ef601350 30>;
+ };
+
+ TAH1: emac-tah@ef601450 {
+ compatible = "ibm,tah-460gt", "ibm,tah";
+ reg = <ef601450 30>;
+ };
+
+ EMAC0: ethernet@ef600e00 {
+ device_type = "network";
+ compatible = "ibm,emac-460gt", "ibm,emac4";
+ interrupt-parent = <&EMAC0>;
+ interrupts = <0 1>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-map = </*Status*/ 0 &UIC2 10 4
+ /*Wake*/ 1 &UIC2 14 4>;
+ reg = <ef600e00 70>;
+ local-mac-address = [000000000000]; /* Filled in by U-Boot */
+ mal-device = <&MAL0>;
+ mal-tx-channel = <0>;
+ mal-rx-channel = <0>;
+ cell-index = <0>;
+ max-frame-size = <2328>;
+ rx-fifo-size = <1000>;
+ tx-fifo-size = <800>;
+ phy-mode = "rgmii";
+ phy-map = <00000000>;
+ rgmii-device = <&RGMII0>;
+ rgmii-channel = <0>;
+ tah-device = <&TAH0>;
+ tah-channel = <0>;
+ has-inverted-stacr-oc;
+ has-new-stacr-staopc;
+ };
+
+ EMAC1: ethernet@ef600f00 {
+ device_type = "network";
+ compatible = "ibm,emac-460gt", "ibm,emac4";
+ interrupt-parent = <&EMAC1>;
+ interrupts = <0 1>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-map = </*Status*/ 0 &UIC2 11 4
+ /*Wake*/ 1 &UIC2 15 4>;
+ reg = <ef600f00 70>;
+ local-mac-address = [000000000000]; /* Filled in by U-Boot */
+ mal-device = <&MAL0>;
+ mal-tx-channel = <1>;
+ mal-rx-channel = <8>;
+ cell-index = <1>;
+ max-frame-size = <2328>;
+ rx-fifo-size = <1000>;
+ tx-fifo-size = <800>;
+ phy-mode = "rgmii";
+ phy-map = <00000000>;
+ rgmii-device = <&RGMII0>;
+ rgmii-channel = <1>;
+ tah-device = <&TAH1>;
+ tah-channel = <0>;
+ has-inverted-stacr-oc;
+ has-new-stacr-staopc;
+ };
+
+ EMAC2: ethernet@ef601100 {
+ device_type = "network";
+ compatible = "ibm,emac-460gt", "ibm,emac4";
+ interrupt-parent = <&EMAC2>;
+ interrupts = <0 1>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-map = </*Status*/ 0 &UIC2 12 4
+ /*Wake*/ 1 &UIC2 16 4>;
+ reg = <ef601100 70>;
+ local-mac-address = [000000000000]; /* Filled in by U-Boot */
+ mal-device = <&MAL0>;
+ mal-tx-channel = <2>;
+ mal-rx-channel = <10>;
+ cell-index = <2>;
+ max-frame-size = <2328>;
+ rx-fifo-size = <1000>;
+ tx-fifo-size = <800>;
+ phy-mode = "rgmii";
+ phy-map = <00000000>;
+ rgmii-device = <&RGMII1>;
+ rgmii-channel = <0>;
+ has-inverted-stacr-oc;
+ has-new-stacr-staopc;
+ };
+
+ EMAC3: ethernet@ef601200 {
+ device_type = "network";
+ compatible = "ibm,emac-460gt", "ibm,emac4";
+ interrupt-parent = <&EMAC3>;
+ interrupts = <0 1>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-map = </*Status*/ 0 &UIC2 13 4
+ /*Wake*/ 1 &UIC2 17 4>;
+ reg = <ef601200 70>;
+ local-mac-address = [000000000000]; /* Filled in by U-Boot */
+ mal-device = <&MAL0>;
+ mal-tx-channel = <3>;
+ mal-rx-channel = <18>;
+ cell-index = <3>;
+ max-frame-size = <2328>;
+ rx-fifo-size = <1000>;
+ tx-fifo-size = <800>;
+ phy-mode = "rgmii";
+ phy-map = <00000000>;
+ rgmii-device = <&RGMII1>;
+ rgmii-channel = <1>;
+ has-inverted-stacr-oc;
+ has-new-stacr-staopc;
+ };
+ };
+
+ PCIX0: pci@c0ec00000 {
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ compatible = "ibm,plb-pcix-460gt", "ibm,plb-pcix";
+ primary;
+ large-inbound-windows;
+ enable-msi-hole;
+ reg = <c 0ec00000 8 /* Config space access */
+ 0 0 0 /* no IACK cycles */
+ c 0ed00000 4 /* Special cycles */
+ c 0ec80000 100 /* Internal registers */
+ c 0ec80100 fc>; /* Internal messaging registers */
+
+ /* Outbound ranges, one memory and one IO,
+ * later cannot be changed
+ */
+ ranges = <02000000 0 80000000 0000000d 80000000 0 80000000
+ 01000000 0 00000000 0000000c 08000000 0 00010000>;
+
+ /* Inbound 2GB range starting at 0 */
+ dma-ranges = <42000000 0 0 0 0 0 80000000>;
+
+ /* This drives busses 0 to 0x3f */
+ bus-range = <0 3f>;
+
+ /* All PCI interrupts are routed to ext IRQ 2 -> UIC1-0 */
+ interrupt-map-mask = <0000 0 0 0>;
+ interrupt-map = < 0000 0 0 0 &UIC1 0 8 >;
+ };
+
+ PCIE0: pciex@d00000000 {
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ compatible = "ibm,plb-pciex-460ex", "ibm,plb-pciex";
+ primary;
+ port = <0>; /* port number */
+ reg = <d 00000000 20000000 /* Config space access */
+ c 08010000 00001000>; /* Registers */
+ dcr-reg = <100 020>;
+ sdr-base = <300>;
+
+ /* Outbound ranges, one memory and one IO,
+ * later cannot be changed
+ */
+ ranges = <02000000 0 80000000 0000000e 00000000 0 80000000
+ 01000000 0 00000000 0000000f 80000000 0 00010000>;
+
+ /* Inbound 2GB range starting at 0 */
+ dma-ranges = <42000000 0 0 0 0 0 80000000>;
+
+ /* This drives busses 40 to 0x7f */
+ bus-range = <40 7f>;
+
+ /* Legacy interrupts (note the weird polarity, the bridge seems
+ * to invert PCIe legacy interrupts).
+ * We are de-swizzling here because the numbers are actually for
+ * port of the root complex virtual P2P bridge. But I want
+ * to avoid putting a node for it in the tree, so the numbers
+ * below are basically de-swizzled numbers.
+ * The real slot is on idsel 0, so the swizzling is 1:1
+ */
+ interrupt-map-mask = <0000 0 0 7>;
+ interrupt-map = <
+ 0000 0 0 1 &UIC3 c 4 /* swizzled int A */
+ 0000 0 0 2 &UIC3 d 4 /* swizzled int B */
+ 0000 0 0 3 &UIC3 e 4 /* swizzled int C */
+ 0000 0 0 4 &UIC3 f 4 /* swizzled int D */>;
+ };
+
+ PCIE1: pciex@d20000000 {
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ compatible = "ibm,plb-pciex-460ex", "ibm,plb-pciex";
+ primary;
+ port = <1>; /* port number */
+ reg = <d 20000000 20000000 /* Config space access */
+ c 08011000 00001000>; /* Registers */
+ dcr-reg = <120 020>;
+ sdr-base = <340>;
+
+ /* Outbound ranges, one memory and one IO,
+ * later cannot be changed
+ */
+ ranges = <02000000 0 80000000 0000000e 80000000 0 80000000
+ 01000000 0 00000000 0000000f 80010000 0 00010000>;
+
+ /* Inbound 2GB range starting at 0 */
+ dma-ranges = <42000000 0 0 0 0 0 80000000>;
+
+ /* This drives busses 80 to 0xbf */
+ bus-range = <80 bf>;
+
+ /* Legacy interrupts (note the weird polarity, the bridge seems
+ * to invert PCIe legacy interrupts).
+ * We are de-swizzling here because the numbers are actually for
+ * port of the root complex virtual P2P bridge. But I want
+ * to avoid putting a node for it in the tree, so the numbers
+ * below are basically de-swizzled numbers.
+ * The real slot is on idsel 0, so the swizzling is 1:1
+ */
+ interrupt-map-mask = <0000 0 0 7>;
+ interrupt-map = <
+ 0000 0 0 1 &UIC3 10 4 /* swizzled int A */
+ 0000 0 0 2 &UIC3 11 4 /* swizzled int B */
+ 0000 0 0 3 &UIC3 12 4 /* swizzled int C */
+ 0000 0 0 4 &UIC3 13 4 /* swizzled int D */>;
+ };
+ };
+};
--
1.5.4.4
^ permalink raw reply related
* RE: XUPV2P board opb_emac cannot work with linux-2.6-xlnx
From: Stephen Neuendorffer @ 2008-03-19 16:16 UTC (permalink / raw)
To: Qin Lin, linuxppc-embedded
In-Reply-To: <16137363.post@talk.nabble.com>
>From the data sheet:
"The OPB BUS clock frequency must be greater than or equal to 65 MHz for
100 Mbs Ethernet operation and greater than or equal to 6.5 Mhz for 10
Mbs Ethernet operation"
Steve
> -----Original Message-----
> From: linuxppc-embedded-bounces+stephen=3Dneuendorffer.name@ozlabs.org
[mailto:linuxppc-embedded-
> bounces+stephen=3Dneuendorffer.name@ozlabs.org] On Behalf Of Qin Lin
> Sent: Tuesday, March 18, 2008 10:27 PM
> To: linuxppc-embedded@ozlabs.org
> Subject: Re: XUPV2P board opb_emac cannot work with linux-2.6-xlnx
>=20
>=20
> Hi,All
>=20
> I found out what the problem was from.
> When i set the Bus clock frequency to 50MHz and Processor clock
Frequency
> 200MHz, opb_ethernet does not work with the driver.
>=20
> And i check the driver,don't find the code base on the frequency .
Anyone
> knows the reason?
>=20
>=20
>=20
> --
> View this message in context:
http://www.nabble.com/XUPV2P-board-opb_emac-cannot-work-with-linux-2.6-
> xlnx-tp16089631p16137363.html
> Sent from the linuxppc-embedded mailing list archive at Nabble.com.
>=20
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
^ permalink raw reply
* Re: Hi,friends, the question about the u-boot and device tree?
From: Scott Wood @ 2008-03-19 16:17 UTC (permalink / raw)
To: ????; +Cc: u-boot-users, linuxppc-embedded
In-Reply-To: <405889728.25141@tsinghua.org.cn>
On Wed, Mar 19, 2008 at 09:22:08AM +0800, ???? wrote:
> My board is MPC8360EMDS, my bootm command is "bootm uImage ramdisk_ppc
> mpc836x_mds.dtb", I used the MPC8360E_PB_K26_20071012-LTIB.iso to generate above
> uImage, ramdisk_ppc,mpc836x_mds.dtb.
Could you try the latest upstream u-boot, dts, and kernel to see if
things are better?
> If I fill the frequency to zero on mpc836x_mds.dts,
Which frequency property? Did you get any device-tree-related error
messages from u-boot?
> I also has another question, I modified the HRCW to config the cpu as 660/330/400
> MHZ during power on, I used the "clocks" command on u-boot to see that the clock
> is real 660/330/400 MHZ, then I changed the frequency value on dts to 660/330/400,
> after the bootm command, the linux was not carshed after serial configuration, but
> the output is random.
>
> "
> Serial: 8250/16550 driver $Revision: 1.90 $ 4 ports, IRQ sharing disabled
> serial8250.0: ttyS0 at MMIO 0xe0004500 (irq = 16) is a 16550A
> [output from serial is random]
> "
>
> I have config the frequency both on HRCW and devie tree is the same, why the
> frequency for serial on linux is not right? Why the 528/260/400 is Ok, the
> 660/330/400 has problem on serial.
What are you putting in the serial nodes' clock-frequency in each case?
-Scott
^ permalink raw reply
* Re: [PATCH] MPC8313 NAND fixes
From: Scott Wood @ 2008-03-19 17:02 UTC (permalink / raw)
To: Mike Hench; +Cc: linuxppc-dev, linux-mtd
In-Reply-To: <6629C06B144F5C4098DFF95C4FF9DAF702BA1D02@mailsrv.engagenet.com>
On Wed, Mar 19, 2008 at 10:28:19AM -0500, Mike Hench wrote:
>
> From: Mike Hench
> Sent: Wednesday, March 19, 2008 10:22 AM
> To: 'mhench@wi.rr.com'
> Subject: [PATCH] MPC813 NAND fixes
This patch is whitespace-mangled. Also, please don't post HTML.
> - unsigned int irq_status; /* status read from LTESR by irq
> handler */
>
> + volatile unsigned int irq_status; /* status read from LTESR
> by irq handler */
This change is not needed; both out_be32() and wait_event() act as
optimization barriers.
> @@ -379,13 +379,13 @@ static int fsl_elbc_run_command(struct m
>
> in_be32(&lbc->fbar), in_be32(&lbc->fpar),
>
> in_be32(&lbc->fbcr), priv->bank);
>
>
>
> + ctrl->irq_status = 0;
>
> /* execute special operation */
>
> out_be32(&lbc->lsor, priv->bank);
>
>
>
> /* wait for FCM complete flag or timeout */
>
> - ctrl->irq_status = 0;
ACK this change.
> wait_event_timeout(ctrl->irq_wait, ctrl->irq_status,
>
> - FCM_TIMEOUT_MSECS * HZ/1000);
>
> + (FCM_TIMEOUT_MSECS * HZ)/1000);
This change is a no-op. Multiplication and division are evaluated at the
same precedence, left-to-right.
> if (mtd->writesize == 512) {
>
> priv->page_size = 0;
>
> - clrbits32(&lbc->bank[priv->bank].or,
> ~OR_FCM_PGS);
>
> + clrbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS);
D'oh! Thanks for finding this.
ACK this change.
> - /* The default u-boot configuration on MPC8313ERDB causes
> errors;
>
> - * more delay is needed. This should be safe for other
> boards
>
> - * as well.
>
> - */
>
> - setbits32(&lbc->bank[priv->bank].or, 0x70);
And this one.
-Scott
^ permalink raw reply
* muram in device tree for mpc8250 in arch/powerpc
From: James Black @ 2008-03-19 17:06 UTC (permalink / raw)
To: linuxppc-embedded
I am porting a proprietary mpc8250 board to 2.6.24. I have the 2.6.19
kernel from denx working. I have ported to u-boot 1.3.2 and have the
platform setup within the 2.6.24 kernel and used pq2fads.dts as an
example of the device tree.
Everything in u-boot is working. u-boot doesn't complain about the
device tree and fills in the clocks and memory using the "fdt
boardsetup" command. In fact, u-boot 1.3.2 can boot the 2.6.29 kernel,
no problem.
I turned on early kernel debugging in 2.6.24 and it looks like all the
device tree parsing is working. The boot hangs and or crashes while
trying to setup the paging. I drilled down the code from init/main.c
and found that it seems the muram device node is killing the
allocator.
I tried to fully describe the segments in muram node and it seems to
mess things up even worse. Can anyone give some pointers to help me
work out this issue?
I wanted to start with as simple a description as possible. The
following tree describes the flash, SDRAM, SCC1, SCC3 and FCC1.
/*
* Device Tree for the CTA5000S board with an MPC8250 chip.
* Device Tree for the PQ2FADS-ZU board with an MPC8280 chip.
*
* Copyright 2007 Freescale Semiconductor Inc.
*
* 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.
*/
/ {
model = "cta5000s";
compatible = "fsl,cta5000s";
#address-cells = <1>;
#size-cells = <1>;
cpus {
#address-cells = <1>;
#size-cells = <0>;
PowerPC,8250@0 {
device_type = "cpu";
reg = <0>;
d-cache-line-size = <20>;
i-cache-line-size = <20>;
d-cache-size = <4000>;
i-cache-size = <4000>;
timebase-frequency = <0>;
clock-frequency = <0>;
};
};
memory {
device_type = "memory";
reg = <0 0>;
};
localbus@f0010100 {
compatible = "fsl,mpc8250-localbus",
"fsl,pq2-localbus";
#address-cells = <2>;
#size-cells = <1>;
reg = <f0010100 60>;
ranges = <0 0 fe000000 00200000>;
flash@fe000000,0 {
compatible = "amd", "cfi-flash";
reg = <0 fe000000 00200000>;
bank-width = <2>;
device-width = <1>;
};
};
soc@f0000000 {
#address-cells = <1>;
#size-cells = <1>;
device_type = "soc";
compatible = "fsl,mpc8250", "fsl,pq2-soc";
ranges = <00000000 f0000000 00014000>;
// Temporary -- will go away once kernel uses ranges for get_immrbase().
reg = <f0000000 00014000>;
cpm@119c0 {
#address-cells = <1>;
#size-cells = <1>;
#interrupt-cells = <2>;
compatible = "fsl,mpc8250-cpm", "fsl,cpm2";
reg = <119c0 30>;
ranges;
muram@0 {
#address-cells = <1>;
#size-cells = <1>;
ranges = <0 0 10000>;
data@0 {
compatible = "fsl,cpm-muram-data";
reg = <0 4000 8000 4000>;
};
};
brg@119f0 {
compatible = "fsl,mpc8250-brg",
"fsl,cpm2-brg",
"fsl,cpm-brg";
reg = <119f0 10 115f0 10>;
};
serial@11a00 {
device_type = "serial";
compatible = "fsl,mpc8250-scc-uart",
"fsl,cpm2-scc-uart";
reg = <11a00 20 8000 100>;
interrupts = <28 8>;
interrupt-parent = <&PIC>;
fsl,cpm-brg = <1>;
fsl,cpm-command = <00800000>;
};
serial@11a40 {
device_type = "serial";
compatible = "fsl,mpc8250-scc-uart",
"fsl,cpm2-scc-uart";
reg = <11a40 20 8200 100>;
interrupts = <2a 8>;
interrupt-parent = <&PIC>;
fsl,cpm-brg = <5>;
fsl,cpm-command = <11800000>;
};
ethernet@11300 {
device_type = "network";
compatible = "fsl,mpc8250-fcc-enet",
"fsl,cpm2-fcc-enet";
reg = <11300 20 8400 100>;
interrupts = <20 8>;
interrupt-parent = <&PIC>;
linux,network-index = <0>;
fsl,cpm-command = <14000300>;
};
};
PIC: interrupt-controller@10c00 {
#interrupt-cells = <2>;
interrupt-controller;
reg = <10c00 80>;
compatible = "fsl,mpc8250-pic", "fsl,cpm2-pic";
};
};
chosen {
linux,stdout-path = "/soc/cpm/serial@11a00";
};
};
^ permalink raw reply
* RE: [PATCH] [RFC] Xilinx: Add generic configuration option to enable all xilinx drivers.
From: Stephen Neuendorffer @ 2008-03-19 17:21 UTC (permalink / raw)
To: Grant Likely; +Cc: linuxppc-dev
In-Reply-To: <fa686aa40803182205n741c652ci1e1871707c5c3e13@mail.gmail.com>
My feeling is if the drivers should be consistently enabled or not, then
we should enforce that consistency by the structure of the code.
Steve
> -----Original Message-----
> From: glikely@secretlab.ca [mailto:glikely@secretlab.ca] On Behalf Of
Grant Likely
> Sent: Tuesday, March 18, 2008 10:06 PM
> To: Stephen Neuendorffer
> Cc: linuxppc-dev@ozlabs.org; jacmet@sunsite.dk
> Subject: Re: [PATCH] [RFC] Xilinx: Add generic configuration option to
enable all xilinx drivers.
>=20
> On Tue, Mar 18, 2008 at 10:32 PM, Stephen Neuendorffer
> <stephen.neuendorffer@xilinx.com> wrote:
> >
> >
> >
> >
> > Hmm... interesting points. I guess my feeling was that
XILINX_DRIVERS could
> > be a more broadly configurable option, with some of these ideas in
mind.
> > Currently, it's hidden by default, but we could easily change this
to be
> > visible by default, or selected by a broader number of
architectures. I
> > tend to think about them as a group: What if x86 *did* support the
> > primitives needed by these drivers, then if the individual drivers
depend on
> > XILINX_DRIVERS, then the modification could be made in one spot. By
your
> > suggestion, we would have to modify each one independantly.
>=20
> Heh; it's not *that* many drivers and it's just Kconfig stuff which is
> real easy to change. My preference would be to eliminate
> XILINX_DRIVERS entirely, but I'm not going to fight about it. :-)
>=20
> Cheers,
> g.
>=20
> --
> Grant Likely, B.Sc., P.Eng.
> Secret Lab Technologies Ltd.
^ permalink raw reply
* Uart(lite)/ELDK 4.1 section mismatch -> ML403
From: Phil Hochstetler @ 2008-03-19 17:27 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 1510 bytes --]
I just booted the "git.xilinx.com/Linux-2.6-xlnx" source code to a login
prompt last week. I'm using Xilinx EDK 9.2 and ELDK 4.1 crosstools
(uclib version) and Ubuntu 7.10 workstation as my host OS (under
VMware). The easiest path is to use the Uartlite driver (and disable
the 82550 stuff because the stand directory will not compile currently,
there is a patch somewhere on the last from last Jan about what defines
are missing but you can just use uartlite instead). Be sure to use the
correct reference design (I started with the Virtex4_PPC_Example_9_2.zip
in EDK/EDKexamples directory). Add the sysace driver into the design
and (w/ interrupts on) and make sure you have uartlite selected (with
interrupts on). Build the design and use the xparameters_403.h file to
build your kernel. In this case, be sure to turn on uartlite console
support and turn off 82550 console support or your kernel will not work.
Also be sure to add Ext3 filesystem to your kernel config. Once you add
the sysace driver support, you can then create a ace file and replace
their kernel on the compact flash and boot it to their root filesystem
(works, I just did it). This gets you a full booted kernel on a working
root filesystem with min work.
For references see:
http://wiki.secretlab.ca/index.php/Linux_on_Xilinx_Virtex
http://simfami.marlab.ac.uk/piprg/wiki/index.php?title=Installing_Linux_
Kernel_2.6.23_on_the_PPC405_core_of_a_Xilinx_ML403_board
--phil
[-- Attachment #2: Type: text/html, Size: 3591 bytes --]
^ permalink raw reply
* [PATCH] [RFC][v2] Xilinx: Add generic configuration option to enable all xilinx drivers.
From: Stephen Neuendorffer @ 2008-03-19 17:24 UTC (permalink / raw)
To: grant.likely, linuxppc-dev, jacmet, git-dev
In the future, this will be used to provide similar configuration for
PowerPC and Microblaze. It may also be convenient for those using
Xilinx cores as peripherals for external processors, rather than
explicitly having a dependance on the processor architecture.
Signed-off-by: Stephen Neuendorffer <stephen.neuendorffer@xilinx.com>
[V2] Updated to depend on PPC32, rather than just XILINX_VIRTEX, to let
these drivers be compiled in more configurations.
---
Grant,
There is still the issue of the ppc part, which is
required for backward compatibility. If this has to wait until ppc
dies, then that's fine with me, I guess.
Steve
---
drivers/block/Kconfig | 2 +-
drivers/char/Kconfig | 2 +-
drivers/misc/Kconfig | 17 +++++++++++++++++
drivers/serial/Kconfig | 2 +-
drivers/spi/Kconfig | 2 +-
drivers/video/Kconfig | 2 +-
6 files changed, 22 insertions(+), 5 deletions(-)
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 4d0119e..7f55ba4 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -412,7 +412,7 @@ source "drivers/s390/block/Kconfig"
config XILINX_SYSACE
tristate "Xilinx SystemACE support"
- depends on 4xx
+ depends on XILINX_DRIVERS
help
Include support for the Xilinx SystemACE CompactFlash interface
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 157ae2a..8230ad1 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -833,7 +833,7 @@ config DTLK
config XILINX_HWICAP
tristate "Xilinx HWICAP Support"
- depends on XILINX_VIRTEX
+ depends on XILINX_DRIVERS
help
This option enables support for Xilinx Internal Configuration
Access Port (ICAP) driver.
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index b5e67c0..89f9309 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -233,3 +233,20 @@ config ATMEL_SSC
If unsure, say N.
endif # MISC_DEVICES
+endmenu
+
+
+#
+# Xilinx devices and common device driver infrastructure
+#
+
+config XILINX_DRIVERS
+ bool
+ depends on PPC32
+ default y
+ ---help---
+ This option is used to enable all of the Xilinx drivers on
+ supported architectures. This is often useful if you have a
+ Xilinx FPGA in a system, either using embedded processors
+ internal to the FPGA or external processors.
+
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index d7e1996..d4e8879 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -757,7 +757,7 @@ config SERIAL_IMX_CONSOLE
config SERIAL_UARTLITE
tristate "Xilinx uartlite serial port support"
- depends on PPC32
+ depends on XILINX_DRIVERS
select SERIAL_CORE
help
Say Y here if you want to use the Xilinx uartlite serial controller.
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index abf0504..c66838f 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -183,7 +183,7 @@ config SPI_TXX9
config SPI_XILINX
tristate "Xilinx SPI controller"
- depends on SPI_MASTER && XILINX_VIRTEX && EXPERIMENTAL
+ depends on SPI_MASTER && XILINX_DRIVERS && EXPERIMENTAL
select SPI_BITBANG
help
This exposes the SPI controller IP from the Xilinx EDK.
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 5b3dbcf..a66ff4b 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1871,7 +1871,7 @@ config FB_PS3_DEFAULT_SIZE_M
config FB_XILINX
tristate "Xilinx frame buffer support"
- depends on FB && XILINX_VIRTEX
+ depends on FB && XILINX_DRIVERS
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
--
1.5.3.4-dirty
^ permalink raw reply related
* [[PATCH] corrected MPC8313 NAND fixes
From: Mike Hench @ 2008-03-19 17:40 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev, linux-mtd, dwmw2
Fix a race condition in fsl_elbc_run_command
Fix incorrect usage of clearbits32 that bashed option register
Remove work around for bashed register
Signed-off-by: Mike Hench <mhench@elutions.com>
---
--- linux-2.6.25-rc5.orig/drivers/mtd/nand/fsl_elbc_nand.c
2008-03-10 00:22:27.000000000 -0500
+++ linux-2.6.25-rc5/drivers/mtd/nand/fsl_elbc_nand.c 2008-03-19
12:34:36.000000000 -0500
@@ -379,11 +379,11 @@ static int fsl_elbc_run_command(struct m
in_be32(&lbc->fbar), in_be32(&lbc->fpar),
in_be32(&lbc->fbcr), priv->bank);
=20
+ ctrl->irq_status =3D 0;
/* execute special operation */
out_be32(&lbc->lsor, priv->bank);
=20
/* wait for FCM complete flag or timeout */
- ctrl->irq_status =3D 0;
wait_event_timeout(ctrl->irq_wait, ctrl->irq_status,
FCM_TIMEOUT_MSECS * HZ/1000);
ctrl->status =3D ctrl->irq_status;
@@ -861,7 +861,7 @@ static int fsl_elbc_chip_init_tail(struc
/* adjust Option Register and ECC to match Flash page size */
if (mtd->writesize =3D=3D 512) {
priv->page_size =3D 0;
- clrbits32(&lbc->bank[priv->bank].or, ~OR_FCM_PGS);
+ clrbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS);
} else if (mtd->writesize =3D=3D 2048) {
priv->page_size =3D 1;
setbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS);
@@ -882,11 +882,6 @@ static int fsl_elbc_chip_init_tail(struc
return -1;
}
=20
- /* The default u-boot configuration on MPC8313ERDB causes
errors;
- * more delay is needed. This should be safe for other boards
- * as well.
- */
- setbits32(&lbc->bank[priv->bank].or, 0x70);
return 0;
}
^ permalink raw reply
* Re: muram in device tree for mpc8250 in arch/powerpc
From: Scott Wood @ 2008-03-19 17:40 UTC (permalink / raw)
To: James Black; +Cc: linuxppc-embedded
In-Reply-To: <b77025b40803191006m60dc3145la368ac227df43b17@mail.gmail.com>
On Wed, Mar 19, 2008 at 11:06:02AM -0600, James Black wrote:
> I turned on early kernel debugging in 2.6.24 and it looks like all the
> device tree parsing is working. The boot hangs and or crashes while
> trying to setup the paging. I drilled down the code from init/main.c
> and found that it seems the muram device node is killing the
> allocator.
That's strange... how in particular was it killing it? Which allocator?
Do you know which particular line of code is crashing?
> I tried to fully describe the segments in muram node and it seems to
> mess things up even worse.
What do you mean? What changes did you make, and what was the result?
> / {
>
> model = "cta5000s";
> compatible = "fsl,cta5000s";
> #address-cells = <1>;
> #size-cells = <1>;
> cpus {
It'd be a lot more readable if indentation were kept intact...
> localbus@f0010100 {
> compatible = "fsl,mpc8250-localbus",
> "fsl,pq2-localbus";
> #address-cells = <2>;
> #size-cells = <1>;
> reg = <f0010100 60>;
> ranges = <0 0 fe000000 00200000>;
> flash@fe000000,0 {
> compatible = "amd", "cfi-flash";
"amd" isn't a valid compatible name.
> cpm@119c0 {
> #address-cells = <1>;
> #size-cells = <1>;
> #interrupt-cells = <2>;
> compatible = "fsl,mpc8250-cpm", "fsl,cpm2";
> reg = <119c0 30>;
> ranges;
>
> muram@0 {
> #address-cells = <1>;
> #size-cells = <1>;
> ranges = <0 0 10000>;
>
> data@0 {
> compatible = "fsl,cpm-muram-data";
> reg = <0 4000 8000 4000>;
> };
>
> };
reg for 8250 should be <0 4000>. Otherwise, the muram node looks fine
(well, the unit address shouldn't be there, but that won't affect
anything).
> serial@11a40 {
> device_type = "serial";
> compatible = "fsl,mpc8250-scc-uart",
> "fsl,cpm2-scc-uart";
> reg = <11a40 20 8200 100>;
> interrupts = <2a 8>;
> interrupt-parent = <&PIC>;
> fsl,cpm-brg = <5>;
> fsl,cpm-command = <11800000>;
cpm-command should be <08c00000>.
> };
>
>
> ethernet@11300 {
> device_type = "network";
> compatible = "fsl,mpc8250-fcc-enet",
> "fsl,cpm2-fcc-enet";
> reg = <11300 20 8400 100>;
> interrupts = <20 8>;
> interrupt-parent = <&PIC>;
> linux,network-index = <0>;
> fsl,cpm-command = <14000300>;
cpm-command should be <12000300>.
-Scott
^ permalink raw reply
* Re: [PATCH] corrected MPC8313 NAND fixes
From: Scott Wood @ 2008-03-19 17:41 UTC (permalink / raw)
To: Mike Hench; +Cc: linuxppc-dev, linux-mtd, dwmw2
In-Reply-To: <6629C06B144F5C4098DFF95C4FF9DAF702BA1D11@mailsrv.engagenet.com>
On Wed, Mar 19, 2008 at 12:40:15PM -0500, Mike Hench wrote:
> Fix a race condition in fsl_elbc_run_command
> Fix incorrect usage of clearbits32 that bashed option register
> Remove work around for bashed register
>
> Signed-off-by: Mike Hench <mhench@elutions.com>
Acked-by: Scott Wood <scottwood@freescale.com>
-Scott
^ permalink raw reply
* v2 patch for Freescale DIU driver
From: York Sun @ 2008-03-19 18:50 UTC (permalink / raw)
To: linux-kernel; +Cc: linuxppc-dev, linux-fbdev-devel
This is the version 2 patch for Freescale DIU driver. Thanks for all the feedback.
The first patch is the driver. The second patch adds platform support for MPC8610HPCD board.
To compile, enable the "Freescale MPC8610/MPC5121 DIU framebuffer support" in the menuconfig.
^ permalink raw reply
* [PATCH 2/2 v2] Add DIU platform code for MPC8610HPCD
From: York Sun @ 2008-03-19 18:50 UTC (permalink / raw)
To: linux-kernel; +Cc: linuxppc-dev, linux-fbdev-devel, York Sun
In-Reply-To: <12059526274026-git-send-email-yorksun@freescale.com>
Add platform code to support Freescale DIU. The platform code includes
framebuffer memory allocation, pixel format, monitor port, etc.
Signed-off-by: York Sun <yorksun@freescale.com>
---
This patch is targeting 2.6.26 kernel.
arch/powerpc/platforms/86xx/mpc8610_hpcd.c | 182 +++++++++++++++++++++++++++-
arch/powerpc/sysdev/fsl_soc.c | 41 ++++++
arch/powerpc/sysdev/fsl_soc.h | 22 ++++
3 files changed, 243 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
index 0b07485..e087aa3 100644
--- a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
+++ b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
@@ -3,6 +3,7 @@
*
* Initial author: Xianghua Xiao <x.xiao@freescale.com>
* Recode: Jason Jin <jason.jin@freescale.com>
+ * York Sun <yorksun@freescale.com>
*
* Rewrite the interrupt routing. remove the 8259PIC support,
* All the integrated device in ULI use sideband interrupt.
@@ -38,6 +39,8 @@
#include <sysdev/fsl_pci.h>
#include <sysdev/fsl_soc.h>
+static unsigned char *pixis_bdcfg0, *pixis_arch;
+
static struct of_device_id __initdata mpc8610_ids[] = {
{ .compatible = "fsl,mpc8610-immr", },
{}
@@ -161,12 +164,160 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x5229, quirk_uli5229);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, 0x5288, final_uli5288);
#endif /* CONFIG_PCI */
+#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+
+static u32 get_busfreq(void)
+{
+ struct device_node *node;
+
+ u32 fs_busfreq = 0;
+ node = of_find_node_by_type(NULL, "cpu");
+ if (node) {
+ unsigned int size;
+ const unsigned int *prop =
+ of_get_property(node, "bus-frequency", &size);
+ if (prop)
+ fs_busfreq = *prop;
+ of_node_put(node);
+ };
+ return fs_busfreq;
+}
+
+unsigned int mpc8610hpcd_get_pixel_format
+ (unsigned int bits_per_pixel, int monitor_port)
+{
+ static const unsigned long pixelformat[][3] = {
+ {0x88882317, 0x88083218, 0x65052119},
+ {0x88883316, 0x88082219, 0x65053118},
+ };
+ unsigned int pix_fmt, arch_monitor;
+
+ arch_monitor = ((*pixis_arch == 0x01) && (monitor_port == 0))? 0 : 1;
+ /* DVI port for board version 0x01 */
+
+ if (bits_per_pixel == 32)
+ pix_fmt = pixelformat[arch_monitor][0];
+ else if (bits_per_pixel == 24)
+ pix_fmt = pixelformat[arch_monitor][1];
+ else if (bits_per_pixel == 16)
+ pix_fmt = pixelformat[arch_monitor][2];
+ else
+ pix_fmt = pixelformat[1][0];
+
+ return pix_fmt;
+}
+
+void mpc8610hpcd_set_gamma_table(int monitor_port, char *gamma_table_base)
+{
+ int i;
+ if (monitor_port == 2) { /* dual link LVDS */
+ for (i = 0; i < 256*3; i++)
+ gamma_table_base[i] = (gamma_table_base[i] << 2) |
+ ((gamma_table_base[i] >> 6) & 0x03);
+ }
+}
+
+void mpc8610hpcd_set_monitor_port(int monitor_port)
+{
+ static const u8 bdcfg[] = {0xBD, 0xB5, 0xA5};
+ if (monitor_port < 3)
+ *pixis_bdcfg0 = bdcfg[monitor_port];
+}
+
+void mpc8610hpcd_set_pixel_clock(unsigned int pixclock)
+{
+ u32 __iomem *clkdvdr;
+ u32 temp;
+ /* variables for pixel clock calcs */
+ ulong bestval, bestfreq, speed_ccb, minpixclock, maxpixclock;
+ ulong pixval;
+ long err;
+ int i;
+
+ clkdvdr = ioremap(get_immrbase() + 0xe0800, sizeof(u32));
+ if (!clkdvdr) {
+ printk(KERN_ERR "Err: can't map clock divider register!\n");
+ return;
+ }
+
+ /* Pixel Clock configuration */
+ pr_debug("DIU: Bus Frequency = %d\n", get_busfreq());
+ speed_ccb = get_busfreq();
+
+ /* 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;
+ temp *= 1000;
+ pixclock = temp;
+ pr_debug("DIU pixclock freq - %u\n", pixclock);
+
+ temp = pixclock * 5 / 100;
+ 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) + 1);
+ 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 PXCLK in GUTS CLKDVDR */
+ pr_debug("DIU: Current value of CLKDVDR = 0x%08x\n", (*clkdvdr));
+ temp = (*clkdvdr) & 0x2000FFFF;
+ *clkdvdr = temp; /* turn off clock */
+ *clkdvdr = temp | 0x80000000 | (((bestval) & 0x1F) << 16);
+ pr_debug("DIU: Modified value of CLKDVDR = 0x%08x\n", (*clkdvdr));
+ iounmap(clkdvdr);
+}
+
+ssize_t mpc8610hpcd_show_monitor_port(int monitor_port, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE,
+ "%c0 - DVI\n"
+ "%c1 - Single link LVDS\n"
+ "%c2 - Dual link LVDS\n",
+ monitor_port == 0 ? '*' : ' ',
+ monitor_port == 1 ? '*' : ' ',
+ monitor_port == 2 ? '*' : ' ');
+}
+
+int mpc8610hpcd_set_sysfs_monitor_port(int val)
+{
+ return val < 3 ? val : 0;
+}
+
+#endif
+
+int __init preallocate_diu_videomemory(void);
static void __init
mpc86xx_hpcd_setup_arch(void)
{
-#ifdef CONFIG_PCI
+ struct resource r;
struct device_node *np;
-#endif
+
if (ppc_md.progress)
ppc_md.progress("mpc86xx_hpcd_setup_arch()", 0);
@@ -183,6 +334,33 @@ mpc86xx_hpcd_setup_arch(void)
}
}
#endif
+#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+ preallocate_diu_videomemory();
+ diu_ops.get_pixel_format = mpc8610hpcd_get_pixel_format;
+ diu_ops.set_gamma_table = mpc8610hpcd_set_gamma_table;
+ diu_ops.set_monitor_port = mpc8610hpcd_set_monitor_port;
+ diu_ops.set_pixel_clock = mpc8610hpcd_set_pixel_clock;
+ diu_ops.show_monitor_port = mpc8610hpcd_show_monitor_port;
+ diu_ops.set_sysfs_monitor_port = mpc8610hpcd_set_sysfs_monitor_port;
+#endif
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,fpga-pixis");
+ if (np) {
+ of_address_to_resource(np, 0, &r);
+ of_node_put(np);
+ pixis_bdcfg0 = ioremap(r.start + 0x00000008, sizeof(u8));
+ if (!pixis_bdcfg0) {
+ printk(KERN_ERR "Err: can't map FPGA cfg register!\n");
+ return;
+ }
+ pixis_arch = ioremap(r.start + 0x00000001, sizeof(u8));
+ if (!pixis_arch) {
+ printk(KERN_ERR "Err: can't map FPGA arch register!\n");
+ return;
+ }
+ } else
+ printk(KERN_ERR "Err: "
+ "can't find device node 'fsl,fpga-pixis'\n");
printk("MPC86xx HPCD board from Freescale Semiconductor\n");
}
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index 2c5388c..38a52c9 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -1438,3 +1438,44 @@ void fsl_rstcr_restart(char *cmd)
while (1) ;
}
#endif
+
+#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+struct platform_diu_data_ops diu_ops = {
+ .diu_size = 1280 * 1024 * 4, /* default one 1280x1024 buffer */
+};
+EXPORT_SYMBOL(diu_ops);
+
+int __init preallocate_diu_videomemory(void)
+{
+ pr_debug("diu_size=%lu\n", diu_ops.diu_size);
+
+ diu_ops.diu_mem = __alloc_bootmem(diu_ops.diu_size, 8, 0);
+ if (!diu_ops.diu_mem) {
+ printk(KERN_ERR "fsl-diu: cannot allocate %lu bytes\n",
+ diu_ops.diu_size);
+ return -ENOMEM;
+ }
+
+ printk(KERN_INFO "%s: diu_mem=%p\n", __func__, diu_ops.diu_mem);
+
+ rh_init(&diu_ops.diu_rh_info, 4096, ARRAY_SIZE(diu_ops.diu_rh_block),
+ diu_ops.diu_rh_block);
+ return rh_attach_region(&diu_ops.diu_rh_info,
+ (unsigned long) diu_ops.diu_mem,
+ diu_ops.diu_size);
+}
+
+static int __init early_parse_diufb(char *p)
+{
+ if (!p)
+ return 1;
+
+ diu_ops.diu_size = _ALIGN_UP(memparse(p, &p), 8);
+
+ printk(KERN_INFO "%s: diu_size=%lu\n", __func__, diu_ops.diu_size);
+
+ return 0;
+}
+early_param("diufb", early_parse_diufb);
+
+#endif
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
index 63e7db3..5601be1 100644
--- a/arch/powerpc/sysdev/fsl_soc.h
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -16,5 +16,27 @@ extern int fsl_spi_init(struct spi_board_info *board_infos,
void (*deactivate_cs)(u8 cs, u8 polarity));
extern void fsl_rstcr_restart(char *cmd);
+
+#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+#include <linux/bootmem.h>
+#include <asm/rheap.h>
+struct platform_diu_data_ops {
+ rh_block_t diu_rh_block[16];
+ rh_info_t diu_rh_info;
+ unsigned long diu_size;
+ void *diu_mem;
+
+ unsigned int (*get_pixel_format) (unsigned int bits_per_pixel,
+ int monitor_port);
+ void (*set_gamma_table) (int monitor_port, char *gamma_table_base);
+ void (*set_monitor_port) (int monitor_port);
+ void (*set_pixel_clock) (unsigned int pixclock);
+ ssize_t (*show_monitor_port) (int monitor_port, char *buf);
+ int (*set_sysfs_monitor_port) (int val);
+};
+
+extern struct platform_diu_data_ops diu_ops;
+#endif
+
#endif
#endif
--
1.5.2.2
^ permalink raw reply related
* [PATCH 1/2 v2] Driver for Freescale 8610 and 5121 DIU
From: York Sun @ 2008-03-19 18:50 UTC (permalink / raw)
To: linux-kernel; +Cc: linuxppc-dev, Timur Tabi, linux-fbdev-devel, York Sun
In-Reply-To: <12059526271941-git-send-email-yorksun@freescale.com>
The following features are supported:
plane 0 works as a regular frame buffer, can be accessed by /dev/fb0
plane 1 has two AOIs (area of interest), can be accessed by /dev/fb1 and /dev/fb2
plane 2 has two AOIs, can be accessed by /dev/fb3 and /dev/fb4
Special ioctls support AOIs
All /dev/fb* can be used as regular frame buffer devices, except hardware change can
only be made through /dev/fb0. Changing pixel clock has no effect on other fbs.
Limitation of usage of AOIs:
AOIs on the same plane can not be horizonally overlapped
AOIs have horizonal order, i.e. AOI0 should be always on top of AOI1
AOIs can not beyond phisical display area. Application should check AOI geometry
before changing physical resolution on /dev/fb0
required command line parameters to preallocate memory for frame buffer
diufb=15M
optional command line parameters to set modes and monitor
video=fslfb:[resolution][,bpp][,monitor]
Syntax:
Resolution
xres x yres-bpp@refresh_rate, the -bpp and @refresh_rate are optional
eg, 1024x768, 1280x1024, 1280x1024-32, 1280x1024@60, 1280x1024-32@60, 1280x480-32@60
Bpp
bpp=32, bpp=24, or bpp=16
Monitor
monitor=0, monitor=1, monitor=2
0 is DVI
1 is Single link LVDS
2 is Double link LVDS
Note: switching monitor is a board feather, not DIU feather. MPC8610HPCD has three
monitor ports to swtich to. MPC5121ADS doesn't have additional monitor port. So switching
monirot port for MPC5121ADS has no effect.
If compiled as a module, it takes pamameters mode, bpp, monitor with the same syntax above.
Signed-off-by: York Sun <yorksun@freescale.com>
Signed-off-by: Timur Tabi <timur@freescale.com>
---
This patch is targeting 2.6.26 kernel.
Documentation/powerpc/booting-without-of.txt | 34 +
arch/powerpc/boot/dts/mpc8610_hpcd.dts | 13 +
drivers/video/Kconfig | 10 +
drivers/video/Makefile | 1 +
drivers/video/fsl-diu-fb.c | 1735 ++++++++++++++++++++++++++
drivers/video/fsl-diu-fb.h | 224 ++++
6 files changed, 2017 insertions(+), 0 deletions(-)
create mode 100644 drivers/video/fsl-diu-fb.c
create mode 100644 drivers/video/fsl-diu-fb.h
diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index 7b4e8a7..f7ae14a 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -2816,6 +2816,40 @@ platforms are moved over to use the flattened-device-tree model.
big-endian;
};
+ r) Freescale Display Interface Unit
+
+ The Freescale DIU is a LCD controller, with proper hardware, it can also
+ drive DVI monitors.
+
+ Required properties:
+ - compatible : should be "fsl-diu".
+ - reg : should contain at least address and length of the DIU register
+ set.
+ - Interrupts : one DIU interrupt should be describe here.
+
+ Example (MPC8610HPCD)
+ diu@2c000 {
+ device_type = "lcd";
+ compatible = "fsl-diu";
+ reg = <0x2c000 100>;
+ interrupts = <72 2>;
+ interrupt-parent = <&mpic>;
+ };
+
+ s) Freescale on board FPGA
+
+ This is the memory-mapped registers for on board FPGA.
+
+ Required properities:
+ - compatible : should be "fsl,fpga-pixis".
+ - reg : should contain the address and the lenght of the FPPGA register
+ set.
+
+ Example (MPC8610HPCD)
+ fpga {
+ compatible = "fsl,fpga-pixis";
+ reg = <0xe8000000 20>;
+ };
More devices will be defined as this spec matures.
diff --git a/arch/powerpc/boot/dts/mpc8610_hpcd.dts b/arch/powerpc/boot/dts/mpc8610_hpcd.dts
index 16c947b..78c67ee 100644
--- a/arch/powerpc/boot/dts/mpc8610_hpcd.dts
+++ b/arch/powerpc/boot/dts/mpc8610_hpcd.dts
@@ -45,6 +45,11 @@
reg = <0x00000000 0x20000000>; // 512M at 0x0
};
+ fpga {
+ compatible = "fsl,fpga-pixis";
+ reg = <0xe8000000 20>; // pixis at 0xe8000000
+ };
+
soc@e0000000 {
#address-cells = <1>;
#size-cells = <1>;
@@ -104,6 +109,14 @@
interrupt-parent = <&mpic>;
};
+ diu@2c000 {
+ device_type = "lcd";
+ compatible = "fsl-diu";
+ reg = <0x2c000 100>;
+ interrupts = <72 2>;
+ interrupt-parent = <&mpic>;
+ };
+
mpic: interrupt-controller@40000 {
clock-frequency = <0>;
interrupt-controller;
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 758435f..8923327 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1766,6 +1766,16 @@ config FB_MBX_DEBUG
If unsure, say N.
+config FB_FSL_DIU
+ tristate "Freescale MPC8610/MPC5121 DIU framebuffer support"
+ depends on FB && (MPC8610 || MPC5121)
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ select PPC_LIB_RHEAP
+ ---help---
+ Framebuffer driver for the MPC8610/MPC5121 chip from Freescale
+
config FB_W100
tristate "W100 frame buffer support"
depends on FB && PXA_SHARPSL
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 83e02b3..fb09b5e 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -113,6 +113,7 @@ obj-$(CONFIG_FB_PS3) += ps3fb.o
obj-$(CONFIG_FB_SM501) += sm501fb.o
obj-$(CONFIG_FB_XILINX) += xilinxfb.o
obj-$(CONFIG_FB_OMAP) += omap/
+obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o
# Platform or fallback drivers go here
obj-$(CONFIG_FB_UVESA) += uvesafb.o
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
new file mode 100644
index 0000000..9eda110
--- /dev/null
+++ b/drivers/video/fsl-diu-fb.c
@@ -0,0 +1,1735 @@
+/*
+ * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Freescale DIU Frame Buffer device driver
+ *
+ * Authors: Hongjun Chen <hong-jun.chen@freescale.com>
+ * Paul Widmer <paul.widmer@freescale.com>
+ * Srikanth Srinivasan <srikanth.srinivasan@freescale.com>
+ * York Sun <yorksun@freescale.com>
+ * Copyright (C) Freescale Semicondutor, Inc. 2007. All rights reserved.
+ *
+ * Based on imxfb.c Copyright (C) 2004 S.Hauer, Pengutronix
+ *
+ * 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/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <asm/uaccess.h>
+
+#include <linux/of_platform.h>
+
+#include <sysdev/fsl_soc.h>
+#include "fsl-diu-fb.h"
+
+/*
+ * These parameters give default parameters
+ * for video output 1024x768,
+ * FIXME - change timing to proper amounts
+ * hsync 31.5kHz, vsync 60Hz
+ */
+static struct fb_videomode __devinitdata fsl_diu_default_mode = {
+ .refresh = 60,
+ .xres = 1024,
+ .yres = 768,
+ .pixclock = 15385,
+ .left_margin = 160,
+ .right_margin = 24,
+ .upper_margin = 29,
+ .lower_margin = 3,
+ .hsync_len = 136,
+ .vsync_len = 6,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+};
+
+static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {
+ {
+ .name = "1024x768-60",
+ .refresh = 60,
+ .xres = 1024,
+ .yres = 768,
+ .pixclock = 15385,
+ .left_margin = 160,
+ .right_margin = 24,
+ .upper_margin = 29,
+ .lower_margin = 3,
+ .hsync_len = 136,
+ .vsync_len = 6,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .name = "1024x768-70",
+ .refresh = 70,
+ .xres = 1024,
+ .yres = 768,
+ .pixclock = 16886,
+ .left_margin = 3,
+ .right_margin = 3,
+ .upper_margin = 2,
+ .lower_margin = 2,
+ .hsync_len = 40,
+ .vsync_len = 18,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .name = "1024x768-75",
+ .refresh = 75,
+ .xres = 1024,
+ .yres = 768,
+ .pixclock = 15009,
+ .left_margin = 3,
+ .right_margin = 3,
+ .upper_margin = 2,
+ .lower_margin = 2,
+ .hsync_len = 80,
+ .vsync_len = 32,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .name = "1280x1024-60",
+ .refresh = 60,
+ .xres = 1280,
+ .yres = 1024,
+ .pixclock = 9375,
+ .left_margin = 38,
+ .right_margin = 128,
+ .upper_margin = 2,
+ .lower_margin = 7,
+ .hsync_len = 216,
+ .vsync_len = 37,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .name = "1280x1024-70",
+ .refresh = 70,
+ .xres = 1280,
+ .yres = 1024,
+ .pixclock = 9380,
+ .left_margin = 6,
+ .right_margin = 6,
+ .upper_margin = 4,
+ .lower_margin = 4,
+ .hsync_len = 60,
+ .vsync_len = 94,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .name = "1280x1024-75",
+ .refresh = 75,
+ .xres = 1280,
+ .yres = 1024,
+ .pixclock = 9380,
+ .left_margin = 6,
+ .right_margin = 6,
+ .upper_margin = 4,
+ .lower_margin = 4,
+ .hsync_len = 60,
+ .vsync_len = 15,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .name = "320x240", /* for AOI only */
+ .refresh = 60,
+ .xres = 320,
+ .yres = 240,
+ .pixclock = 15385,
+ .left_margin = 0,
+ .right_margin = 0,
+ .upper_margin = 0,
+ .lower_margin = 0,
+ .hsync_len = 0,
+ .vsync_len = 0,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .name = "1280x480-60",
+ .refresh = 60,
+ .xres = 1280,
+ .yres = 480,
+ .pixclock = 18939,
+ .left_margin = 353,
+ .right_margin = 47,
+ .upper_margin = 39,
+ .lower_margin = 4,
+ .hsync_len = 8,
+ .vsync_len = 2,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+};
+
+static char *fb_mode = "1024x768-32@60";
+static unsigned long default_bpp = 32;
+static ATOMIC_NOTIFIER_HEAD(fsl_diu_notifier_list);
+static int monitor_port;
+
+#if defined(CONFIG_NOT_COHERENT_CACHE)
+unsigned int *coherence_data;
+phys_addr_t *coherence_data_phy;
+#endif
+
+static DEFINE_SPINLOCK(diu_lock);
+
+struct fsl_diu_data {
+ struct fb_info *fsl_diu_info[FSL_AOI_NUM - 1];
+ /*FSL_AOI_NUM has one dummy AOI */
+ struct device_attribute dev_attr;
+ struct diu_ad *dummy_ad;
+ void *dummy_aoi_virt;
+ unsigned int irq;
+ int fb_enabled;
+ int monitor_port;
+};
+
+struct mfb_info {
+ int index;
+ int type;
+ char *id;
+ int registered;
+ int blank;
+ unsigned long pseudo_palette[16];
+ struct diu_ad *ad;
+ int cursor_reset;
+ unsigned char g_alpha;
+ unsigned int count;
+ 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;
+};
+
+
+static struct mfb_info mfb_template[] = {
+ { /* AOI 0 for plane 0 */
+ .index = 0,
+ .type = MFB_TYPE_OUTPUT,
+ .id = "Panel0",
+ .registered = 0,
+ .count = 0,
+ .x_aoi_d = 0,
+ .y_aoi_d = 0,
+ },
+ { /* AOI 0 for plane 1 */
+ .index = 1,
+ .type = MFB_TYPE_OUTPUT,
+ .id = "Panel1 AOI0",
+ .registered = 0,
+ .g_alpha = 0xff,
+ .count = 0,
+ .x_aoi_d = 0,
+ .y_aoi_d = 0,
+ },
+ { /* AOI 1 for plane 1 */
+ .index = 2,
+ .type = MFB_TYPE_OUTPUT,
+ .id = "Panel1 AOI1",
+ .registered = 0,
+ .g_alpha = 0xff,
+ .count = 0,
+ .x_aoi_d = 0,
+ .y_aoi_d = 480,
+ },
+ { /* AOI 0 for plane 2 */
+ .index = 3,
+ .type = MFB_TYPE_OUTPUT,
+ .id = "Panel2 AOI0",
+ .registered = 0,
+ .g_alpha = 0xff,
+ .count = 0,
+ .x_aoi_d = 640,
+ .y_aoi_d = 0,
+ },
+ { /* AOI 1 for plane 2 */
+ .index = 4,
+ .type = MFB_TYPE_OUTPUT,
+ .id = "Panel2 AOI1",
+ .registered = 0,
+ .g_alpha = 0xff,
+ .count = 0,
+ .x_aoi_d = 640,
+ .y_aoi_d = 480,
+ },
+};
+
+static struct diu_hw dr = {
+ .mode = MFB_MODE1,
+ .reg_lock = __SPIN_LOCK_UNLOCKED(old_style_spin_init),
+};
+
+static struct diu_pool pool;
+
+/* To allocate memory for framebuffer. First try __get_free_pages(). If it
+ * fails, try rh_alloc. The reason is __get_free_pages() cannot allocate
+ * very large memory (more than 4MB). We don't want to allocate all memory
+ * in rheap since small memory allocation/deallocation will fragment the
+ * rheap and make the furture large allocation fail.
+ */
+
+void *fsl_diu_alloc(unsigned long size, phys_addr_t *phys)
+{
+ void *virt;
+
+ pr_debug("size=%lu\n", size);
+
+ virt = (void *)__get_free_pages(GFP_DMA | GFP_ATOMIC, get_order(size));
+ if (virt) {
+ *phys = virt_to_phys(virt);
+ pr_debug("virt %p, phys=%llx\n", virt, (uint64_t) *phys);
+ memset(virt, 0, size);
+ return virt;
+ }
+ if (!diu_ops.diu_mem) {
+ printk(KERN_INFO "%s: no diu_mem."
+ " To reserve more memory, put 'diufb=15M' "
+ "in the command line\n", __func__);
+ return NULL;
+ }
+
+ virt = (void *) rh_alloc(&diu_ops.diu_rh_info, size, "DIU");
+ if (virt) {
+ *phys = virt_to_bus(virt);
+ memset(virt, 0, size);
+ }
+
+ pr_debug("rh virt=%p phys=%lx\n", virt, *phys);
+
+ return virt;
+}
+
+void fsl_diu_free(void *p, unsigned long size)
+{
+ pr_debug("p=%p size=%lu\n", p, size);
+
+ if (!p)
+ return;
+
+ if ((p >= diu_ops.diu_mem) &&
+ (p < (diu_ops.diu_mem + diu_ops.diu_size))) {
+ pr_debug("rh\n");
+ rh_free(&diu_ops.diu_rh_info, (unsigned long) p);
+ } else {
+ pr_debug("dma\n");
+ free_pages((unsigned long)p, get_order(size));
+ }
+}
+
+static int fsl_diu_enable_panel(struct fb_info *info)
+{
+ struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par;
+ struct diu *hw = dr.diu_reg;
+ struct diu_ad *ad = mfbi->ad;
+ struct fsl_diu_data *machine_data = mfbi->parent;
+ int res = 0;
+
+ pr_debug("enable_panel index %d\n", mfbi->index);
+ if (mfbi->type != MFB_TYPE_OFF) {
+ switch (mfbi->index) {
+ case 0: /* plane 0 */
+ if (hw->desc[0] != ad->paddr)
+ out_be32(&(hw->desc[0]), ad->paddr);
+ break;
+ case 1: /* plane 1 AOI 0 */
+ cmfbi = machine_data->fsl_diu_info[2]->par;
+ if (hw->desc[1] != ad->paddr) { /* AOI0 closed */
+ if (cmfbi->count > 0) /* AOI1 open */
+ ad->next_ad =
+ cpu_to_le32(cmfbi->ad->paddr);
+ else
+ ad->next_ad = 0;
+ out_be32(&(hw->desc[1]), ad->paddr);
+ }
+ break;
+ case 3: /* plane 2 AOI 0 */
+ cmfbi = machine_data->fsl_diu_info[4]->par;
+ if (hw->desc[2] != ad->paddr) { /* AOI0 closed */
+ if (cmfbi->count > 0) /* AOI1 open */
+ ad->next_ad =
+ cpu_to_le32(cmfbi->ad->paddr);
+ else
+ ad->next_ad = 0;
+ out_be32(&(hw->desc[2]), ad->paddr);
+ }
+ break;
+ case 2: /* plane 1 AOI 1 */
+ pmfbi = machine_data->fsl_diu_info[1]->par;
+ ad->next_ad = 0;
+ if (hw->desc[1] == machine_data->dummy_ad->paddr)
+ out_be32(&(hw->desc[1]), ad->paddr);
+ else /* AOI0 open */
+ pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
+ break;
+ case 4: /* plane 2 AOI 1 */
+ pmfbi = machine_data->fsl_diu_info[3]->par;
+ ad->next_ad = 0;
+ if (hw->desc[2] == machine_data->dummy_ad->paddr)
+ out_be32(&(hw->desc[2]), ad->paddr);
+ else /* AOI0 was open */
+ pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
+ break;
+ default:
+ res = -EINVAL;
+ break;
+ }
+ } else
+ res = -EINVAL;
+ return res;
+}
+
+static int fsl_diu_disable_panel(struct fb_info *info)
+{
+ struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par;
+ struct diu *hw = dr.diu_reg;
+ struct diu_ad *ad = mfbi->ad;
+ struct fsl_diu_data *machine_data = mfbi->parent;
+ int res = 0;
+
+ switch (mfbi->index) {
+ case 0: /* plane 0 */
+ if (hw->desc[0] != machine_data->dummy_ad->paddr)
+ out_be32(&(hw->desc[0]),
+ machine_data->dummy_ad->paddr);
+ break;
+ case 1: /* plane 1 AOI 0 */
+ cmfbi = machine_data->fsl_diu_info[2]->par;
+ if (cmfbi->count > 0) /* AOI1 is open */
+ out_be32(&(hw->desc[1]), cmfbi->ad->paddr);
+ /* move AOI1 to the first */
+ else /* AOI1 was closed */
+ out_be32(&(hw->desc[1]),
+ machine_data->dummy_ad->paddr);
+ /* close AOI 0 */
+ break;
+ case 3: /* plane 2 AOI 0 */
+ cmfbi = machine_data->fsl_diu_info[4]->par;
+ if (cmfbi->count > 0) /* AOI1 is open */
+ out_be32(&(hw->desc[2]), cmfbi->ad->paddr);
+ /* move AOI1 to the first */
+ else /* AOI1 was closed */
+ out_be32(&(hw->desc[2]),
+ machine_data->dummy_ad->paddr);
+ /* close AOI 0 */
+ break;
+ case 2: /* plane 1 AOI 1 */
+ pmfbi = machine_data->fsl_diu_info[1]->par;
+ if (hw->desc[1] != ad->paddr) {
+ /* AOI1 is not the first in the chain */
+ if (pmfbi->count > 0)
+ /* AOI0 is open, must be the first */
+ pmfbi->ad->next_ad = 0;
+ } else /* AOI1 is the first in the chain */
+ out_be32(&(hw->desc[1]), machine_data->dummy_ad->paddr);
+ /* close AOI 1 */
+ break;
+ case 4: /* plane 2 AOI 1 */
+ pmfbi = machine_data->fsl_diu_info[3]->par;
+ if (hw->desc[2] != ad->paddr) {
+ /* AOI1 is not the first in the chain */
+ if (pmfbi->count > 0)
+ /* AOI0 is open, must be the first */
+ pmfbi->ad->next_ad = 0;
+ } else /* AOI1 is the first in the chain */
+ out_be32(&(hw->desc[2]), machine_data->dummy_ad->paddr);
+ /* close AOI 1 */
+ break;
+ default:
+ res = -EINVAL;
+ break;
+ }
+
+ return res;
+}
+
+static void enable_lcdc(struct fb_info *info)
+{
+ struct diu *hw = dr.diu_reg;
+ struct mfb_info *mfbi = info->par;
+ struct fsl_diu_data *machine_data = mfbi->parent;
+
+ if (!machine_data->fb_enabled) {
+ out_be32(&(hw->diu_mode), dr.mode);
+ machine_data->fb_enabled++;
+ }
+}
+
+static void disable_lcdc(struct fb_info *info)
+{
+ struct diu *hw = dr.diu_reg;
+ struct mfb_info *mfbi = info->par;
+ struct fsl_diu_data *machine_data = mfbi->parent;
+
+ if (machine_data->fb_enabled) {
+ out_be32(&(hw->diu_mode), 0);
+ machine_data->fb_enabled = 0;
+ }
+}
+
+/*
+ * Checks to see if the hardware supports the state requested by var passed
+ * in. This function does not alter the hardware state! If the var passed in
+ * is slightly off by what the hardware can support then we alter the var
+ * PASSED in to what we can do. If the hardware doesn't support mode change
+ * a -EINVAL will be returned by the upper layers.
+ */
+static int fsl_diu_check_var
+ (struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ unsigned long htotal, vtotal;
+ struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par;
+ struct fsl_diu_data *machine_data = mfbi->parent;
+ int index = mfbi->index;
+
+ pr_debug("check_var xres: %d\n", var->xres);
+ pr_debug("check_var yres: %d\n", var->yres);
+
+ if (var->xres_virtual < var->xres)
+ var->xres_virtual = var->xres;
+ if (var->yres_virtual < var->yres)
+ var->yres_virtual = var->yres;
+
+ if (var->xoffset < 0)
+ var->xoffset = 0;
+
+ if (var->yoffset < 0)
+ var->yoffset = 0;
+
+ if (var->xoffset + info->var.xres > info->var.xres_virtual)
+ var->xoffset = info->var.xres_virtual - info->var.xres;
+
+ if (var->yoffset + info->var.yres > info->var.yres_virtual)
+ var->yoffset = info->var.yres_virtual - info->var.yres;
+
+ if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) &&
+ (var->bits_per_pixel != 16))
+ var->bits_per_pixel = default_bpp;
+
+ switch (var->bits_per_pixel) {
+ case 16:
+ var->red.length = 5;
+ var->red.offset = 11;
+ var->red.msb_right = 0;
+
+ var->green.length = 6;
+ var->green.offset = 5;
+ var->green.msb_right = 0;
+
+ var->blue.length = 5;
+ var->blue.offset = 0;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ var->transp.msb_right = 0;
+ break;
+ case 24:
+ var->red.length = 8;
+ var->red.offset = 0;
+ var->red.msb_right = 0;
+
+ var->green.length = 8;
+ var->green.offset = 8;
+ var->green.msb_right = 0;
+
+ var->blue.length = 8;
+ var->blue.offset = 16;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ var->transp.msb_right = 0;
+ break;
+ case 32:
+ var->red.length = 8;
+ var->red.offset = 16;
+ var->red.msb_right = 0;
+
+ var->green.length = 8;
+ var->green.offset = 8;
+ var->green.msb_right = 0;
+
+ var->blue.length = 8;
+ var->blue.offset = 0;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 8;
+ var->transp.offset = 24;
+ var->transp.msb_right = 0;
+
+ break;
+ }
+ /* If the pixclock is below the minimum spec'd value then set to
+ * refresh rate for 60Hz since this is supported by most monitors.
+ * Refer to Documentation/fb/ for calculations.
+ */
+ if ((var->pixclock < MIN_PIX_CLK) || (var->pixclock > MAX_PIX_CLK)) {
+ htotal = var->xres + var->right_margin + var->hsync_len +
+ var->left_margin;
+ vtotal = var->yres + var->lower_margin + var->vsync_len +
+ var->upper_margin;
+ var->pixclock = (vtotal * htotal * 6UL) / 100UL;
+ var->pixclock = KHZ2PICOS(var->pixclock);
+ pr_debug("pixclock set for 60Hz refresh = %u ps\n",
+ var->pixclock);
+ }
+
+ var->height = -1;
+ var->width = -1;
+ var->grayscale = 0;
+
+ /* Copy nonstd field to/from sync for fbset usage */
+ var->sync |= var->nonstd;
+ var->nonstd |= var->sync;
+
+ /* check AOI position */
+ switch (index) {
+ case 0:
+ if (mfbi->x_aoi_d != 0)
+ mfbi->x_aoi_d = 0;
+ if (mfbi->y_aoi_d != 0)
+ mfbi->y_aoi_d = 0;
+ break;
+ case 1: /* AOI 0 */
+ case 3:
+ cmfbi = machine_data->fsl_diu_info[index+1]->par;
+ if ((mfbi->x_aoi_d + var->xres) >
+ machine_data->fsl_diu_info[0]->var.xres)
+ mfbi->x_aoi_d = machine_data->fsl_diu_info[0]->var.xres
+ - var->xres;
+ if (mfbi->x_aoi_d < 0)
+ mfbi->x_aoi_d = 0;
+ if ((var->xres + mfbi->x_aoi_d) >
+ machine_data->fsl_diu_info[0]->var.xres)
+ var->xres = machine_data->fsl_diu_info[0]->var.xres
+ - mfbi->x_aoi_d;
+
+ if (cmfbi->count > 0) { /* AOI1 is open */
+ if ((mfbi->y_aoi_d + var->yres) > cmfbi->y_aoi_d)
+ mfbi->y_aoi_d = cmfbi->y_aoi_d - var->yres;
+ if (mfbi->y_aoi_d < 0)
+ mfbi->y_aoi_d = 0;
+ if ((var->yres + mfbi->y_aoi_d) > cmfbi->y_aoi_d)
+ var->yres = cmfbi->y_aoi_d - mfbi->y_aoi_d;
+ } else { /* AOI1 is close */
+ if ((mfbi->y_aoi_d + var->yres) >
+ machine_data->fsl_diu_info[0]->var.yres)
+ mfbi->y_aoi_d =
+ machine_data->fsl_diu_info[0]->var.yres
+ - var->yres;
+ if (mfbi->y_aoi_d < 0)
+ mfbi->y_aoi_d = 0;
+ if ((var->yres + mfbi->y_aoi_d) >
+ machine_data->fsl_diu_info[0]->var.yres)
+ var->yres =
+ machine_data->fsl_diu_info[0]->var.yres
+ - mfbi->y_aoi_d;
+ }
+ break;
+ case 2: /* AOI 1 */
+ case 4:
+ pmfbi = machine_data->fsl_diu_info[index-1]->par;
+ if ((mfbi->x_aoi_d + var->xres) >
+ machine_data->fsl_diu_info[0]->var.xres)
+ mfbi->x_aoi_d = machine_data->fsl_diu_info[0]->var.xres
+ - var->xres;
+ if (mfbi->x_aoi_d < 0)
+ mfbi->x_aoi_d = 0;
+ if ((var->xres + mfbi->x_aoi_d) >
+ machine_data->fsl_diu_info[0]->var.xres)
+ var->xres = machine_data->fsl_diu_info[0]->var.xres
+ - mfbi->x_aoi_d;
+
+ if (pmfbi->count > 0) { /* AOI0 is open */
+ if ((mfbi->y_aoi_d + var->yres) >
+ machine_data->fsl_diu_info[0]->var.yres)
+ mfbi->y_aoi_d =
+ machine_data->fsl_diu_info[0]->var.yres
+ - var->yres;
+ if (mfbi->y_aoi_d < (pmfbi->y_aoi_d +
+ machine_data->fsl_diu_info[index-1]->var.yres))
+ mfbi->y_aoi_d = pmfbi->y_aoi_d +
+ machine_data->fsl_diu_info[index-1]->var.yres;
+ if ((var->yres + mfbi->y_aoi_d) >
+ machine_data->fsl_diu_info[0]->var.yres)
+ var->yres =
+ machine_data->fsl_diu_info[0]->var.yres
+ - mfbi->y_aoi_d;
+ } else { /* AOI0 is close */
+ if ((mfbi->y_aoi_d + var->yres) >
+ machine_data->fsl_diu_info[0]->var.yres)
+ mfbi->y_aoi_d =
+ machine_data->fsl_diu_info[0]->var.yres
+ - var->yres;
+ if (mfbi->y_aoi_d < 0)
+ mfbi->y_aoi_d = 0;
+ if ((var->yres + mfbi->y_aoi_d) >
+ machine_data->fsl_diu_info[0]->var.yres)
+ var->yres =
+ machine_data->fsl_diu_info[0]->var.yres
+ - mfbi->y_aoi_d;
+ }
+ break;
+ }
+ return 0;
+}
+
+static void set_fix(struct fb_info *info)
+{
+ struct fb_fix_screeninfo *fix = &info->fix;
+ struct fb_var_screeninfo *var = &info->var;
+ struct mfb_info *mfbi = info->par;
+
+ strncpy(fix->id, mfbi->id, strlen(mfbi->id));
+ fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->accel = FB_ACCEL_NONE;
+ fix->visual = FB_VISUAL_TRUECOLOR;
+ fix->xpanstep = 1;
+ fix->ypanstep = 1;
+}
+
+static void update_lcdc(struct fb_info *info)
+{
+ struct fb_var_screeninfo *var = &info->var;
+ struct mfb_info *mfbi = info->par;
+ struct fsl_diu_data *machine_data = mfbi->parent;
+ struct diu *hw;
+ int i, j;
+ char __iomem *cursor_base, *gamma_table_base;
+
+ u32 temp;
+
+ spin_lock_init(&dr.reg_lock);
+ hw = dr.diu_reg;
+
+ if (mfbi->type == MFB_TYPE_OFF) {
+ fsl_diu_disable_panel(info);
+ return;
+ }
+
+ diu_ops.set_monitor_port(machine_data->monitor_port);
+ gamma_table_base = pool.gamma.vaddr;
+ cursor_base = pool.cursor.vaddr;
+ /* Prep for DIU init - gamma table, cursor table */
+
+ for (i = 0; i <= 2; i++)
+ for (j = 0; j <= 255; j++)
+ *gamma_table_base++ = j;
+
+ diu_ops.set_gamma_table(machine_data->monitor_port, pool.gamma.vaddr);
+
+ pr_debug("update-lcdc: HW - %p\n Disabling DIU\n", hw);
+ disable_lcdc(info);
+
+ /* Program DIU registers */
+
+ out_be32(&(hw->gamma), pool.gamma.paddr);
+ out_be32(&(hw->cursor), pool.cursor.paddr);
+
+ out_be32(&(hw->bgnd), 0x007F7F7F); /* BGND */
+ out_be32(&(hw->bgnd_wb), 0); /* BGND_WB */
+ out_be32(&(hw->disp_size), (var->yres << 16 | var->xres));
+ /* DISP SIZE */
+ pr_debug("DIU xres: %d\n", var->xres);
+ pr_debug("DIU yres: %d\n", var->yres);
+
+ out_be32(&(hw->wb_size), 0); /* WB SIZE */
+ out_be32(&(hw->wb_mem_addr), 0); /* WB MEM ADDR */
+
+ /* Horizontal and vertical configuration register */
+ temp = var->left_margin << 22 | /* BP_H */
+ var->hsync_len << 11 | /* PW_H */
+ var->right_margin; /* FP_H */
+
+ out_be32(&(hw->hsyn_para), temp);
+
+ temp = var->upper_margin << 22 | /* BP_V */
+ var->vsync_len << 11 | /* PW_V */
+ var->lower_margin; /* FP_V */
+
+ out_be32(&(hw->vsyn_para), temp);
+
+ pr_debug("DIU right_margin - %d\n", var->right_margin);
+ pr_debug("DIU left_margin - %d\n", var->left_margin);
+ pr_debug("DIU hsync_len - %d\n", var->hsync_len);
+ pr_debug("DIU upper_margin - %d\n", var->upper_margin);
+ pr_debug("DIU lower_margin - %d\n", var->lower_margin);
+ pr_debug("DIU vsync_len - %d\n", var->vsync_len);
+ pr_debug("DIU HSYNC - 0x%08x\n", hw->hsyn_para);
+ pr_debug("DIU VSYNC - 0x%08x\n", hw->vsyn_para);
+
+ diu_ops.set_pixel_clock(var->pixclock);
+
+ out_be32(&(hw->syn_pol), 0); /* SYNC SIGNALS POLARITY */
+ out_be32(&(hw->thresholds), 0x00037800); /* The Thresholds */
+ out_be32(&(hw->int_status), 0); /* INTERRUPT STATUS */
+ out_be32(&(hw->plut), 0x01F5F666);
+
+ /* Enable the DIU */
+ enable_lcdc(info);
+}
+
+static int map_video_memory(struct fb_info *info)
+{
+ phys_addr_t phys;
+
+ pr_debug("info->var.xres_virtual = %d\n", info->var.xres_virtual);
+ pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual);
+ pr_debug("info->fix.line_length = %d\n", info->fix.line_length);
+
+ info->fix.smem_len = info->fix.line_length * info->var.yres_virtual;
+ pr_debug("MAP_VIDEO_MEMORY: smem_len = %d\n", info->fix.smem_len);
+ info->screen_base = fsl_diu_alloc(info->fix.smem_len, &phys);
+ if (info->screen_base == 0) {
+ printk(KERN_ERR "Unable to allocate fb memory\n");
+ return -ENOMEM;
+ }
+ info->fix.smem_start = (unsigned long) phys;
+ info->screen_size = info->fix.smem_len;
+
+ pr_debug("Allocated fb @ paddr=0x%08lx, size=%d.\n",
+ info->fix.smem_start,
+ info->fix.smem_len);
+ pr_debug("screen base %p\n", info->screen_base);
+
+ return 0;
+}
+
+static void unmap_video_memory(struct fb_info *info)
+{
+ fsl_diu_free(info->screen_base, info->fix.smem_len);
+ info->screen_base = 0;
+ info->fix.smem_start = 0;
+ info->fix.smem_len = 0;
+}
+
+/*
+ * Using the fb_var_screeninfo in fb_info we set the resolution of this
+ * particular framebuffer. This function alters the fb_fix_screeninfo stored
+ * in fb_info. It does not alter var in fb_info since we are using that
+ * data. This means we depend on the data in var inside fb_info to be
+ * supported by the hardware. fsl_diu_check_var is always called before
+ * fsl_diu_set_par to ensure this.
+ */
+static int fsl_diu_set_par(struct fb_info *info)
+{
+ unsigned long len;
+ struct fb_var_screeninfo *var = &info->var;
+ struct mfb_info *mfbi = info->par;
+ struct fsl_diu_data *machine_data = mfbi->parent;
+ struct diu_ad *ad = mfbi->ad;
+ struct diu *hw;
+
+ hw = dr.diu_reg;
+
+ set_fix(info);
+ mfbi->cursor_reset = 1;
+
+ len = info->var.yres_virtual * info->fix.line_length;
+ /* Alloc & dealloc each time resolution/bpp change */
+ if (len != info->fix.smem_len) {
+ if (info->fix.smem_start)
+ unmap_video_memory(info);
+ pr_debug("SET PAR: smem_len = %d\n", info->fix.smem_len);
+
+ /* Memory allocation for framebuffer */
+ if (map_video_memory(info)) {
+ printk(KERN_ERR "Unable to allocate fb memory 1\n");
+ return -ENOMEM;
+ }
+ }
+
+ ad->pix_fmt =
+ diu_ops.get_pixel_format(var->bits_per_pixel,
+ machine_data->monitor_port);
+ ad->addr = cpu_to_le32(info->fix.smem_start);
+ ad->src_size_g_alpha = cpu_to_le32((var->yres << 12) |
+ var->xres) | mfbi->g_alpha;
+ /* fix me. AOI should not be greater than display size */
+ ad->aoi_size = cpu_to_le32((var->yres << 16) | var->xres);
+ ad->offset_xyi = 0;
+ ad->offset_xyd = cpu_to_le32((mfbi->y_aoi_d << 16) | mfbi->x_aoi_d);
+
+ /* Disable chroma keying function */
+ ad->ckmax_r = 0;
+ ad->ckmax_g = 0;
+ ad->ckmax_b = 0;
+
+ ad->ckmin_r = 255;
+ ad->ckmin_g = 255;
+ ad->ckmin_b = 255;
+
+ if (mfbi->index == 0)
+ update_lcdc(info);
+ return 0;
+}
+
+/*
+ * Set a single color register. The values supplied have a 16 bit magnitude
+ * which needs to be scaled in this function for the hardware. Things to take
+ * into consideration are how many color registers, if any, are supported with
+ * the current color visual. With truecolor mode no color palettes are
+ * supported. Here a psuedo palette is created which we store the value in
+ * pseudo_palette in struct fb_info. For pseudocolor mode we have a limited
+ * color palette.
+ */
+static int fsl_diu_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp, struct fb_info *info)
+{
+ int ret = 1;
+
+ /*
+ * If greyscale is true, then we convert the RGB value
+ * to greyscale no matter what visual we are using.
+ */
+ if (info->var.grayscale)
+ red = green = blue = (19595 * red + 38470 * green +
+ 7471 * blue) >> 16;
+ switch (info->fix.visual) {
+ case FB_VISUAL_TRUECOLOR:
+ /*
+ * 16-bit True Colour. We encode the RGB value
+ * according to the RGB bitfield information.
+ */
+ if (regno < 16) {
+ u32 *pal = info->pseudo_palette;
+ u32 v;
+
+#define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16)
+ red = CNVT_TOHW(red, info->var.red.length);
+ green = CNVT_TOHW(green, info->var.green.length);
+ blue = CNVT_TOHW(blue, info->var.blue.length);
+ transp = CNVT_TOHW(transp, info->var.transp.length);
+#undef CNVT_TOHW
+ v = (red << info->var.red.offset) |
+ (green << info->var.green.offset) |
+ (blue << info->var.blue.offset) |
+ (transp << info->var.transp.offset);
+
+ pal[regno] = v;
+ ret = 0;
+ }
+ break;
+ case FB_VISUAL_STATIC_PSEUDOCOLOR:
+ case FB_VISUAL_PSEUDOCOLOR:
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Pan (or wrap, depending on the `vmode' field) the display using the
+ * 'xoffset' and 'yoffset' fields of the 'var' structure. If the values
+ * don't fit, return -EINVAL.
+ */
+static int fsl_diu_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ if ((info->var.xoffset == var->xoffset) &&
+ (info->var.yoffset == var->yoffset))
+ return 0; /* No change, do nothing */
+
+ if (var->xoffset < 0 || var->yoffset < 0
+ || var->xoffset + info->var.xres > info->var.xres_virtual
+ || var->yoffset + info->var.yres > info->var.yres_virtual)
+ return -EINVAL;
+
+ info->var.xoffset = var->xoffset;
+ info->var.yoffset = var->yoffset;
+
+ if (var->vmode & FB_VMODE_YWRAP)
+ info->var.vmode |= FB_VMODE_YWRAP;
+ else
+ info->var.vmode &= ~FB_VMODE_YWRAP;
+
+ return 0;
+}
+
+/*
+ * Blank the screen if blank_mode != 0, else unblank. Return 0 if blanking
+ * succeeded, != 0 if un-/blanking failed.
+ * blank_mode == 2: suspend vsync
+ * blank_mode == 3: suspend hsync
+ * blank_mode == 4: powerdown
+ */
+static int fsl_diu_blank(int blank_mode, struct fb_info *info)
+{
+ struct mfb_info *mfbi = info->par;
+
+ mfbi->blank = blank_mode;
+
+ switch (blank_mode) {
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ /* FIXME: fixes to enable_panel and enable lcdc needed */
+ case FB_BLANK_NORMAL:
+ /* fsl_diu_disable_panel(info);*/
+ break;
+ case FB_BLANK_POWERDOWN:
+ /* disable_lcdc(info); */
+ break;
+ case FB_BLANK_UNBLANK:
+ /* fsl_diu_enable_panel(info);*/
+ break;
+ }
+
+ return 0;
+}
+
+static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+{
+ struct mfb_info *mfbi = info->par;
+ struct diu_ad *ad = mfbi->ad;
+ struct mfb_chroma_key ck;
+ unsigned char global_alpha;
+ struct aoi_display_offset aoi_d;
+ __u32 pix_fmt;
+
+ switch (cmd) {
+ case MFB_SET_PIXFMT:
+ if (!arg)
+ return -EINVAL;
+ if (copy_from_user((void *)&pix_fmt, (void *)arg,
+ sizeof(pix_fmt)))
+ return -EFAULT;
+ ad->pix_fmt = pix_fmt;
+ pr_debug("Set pixel format to 0x%08x\n", ad->pix_fmt);
+ break;
+ case MFB_GET_PIXFMT:
+ if (!arg)
+ return -EINVAL;
+ pix_fmt = ad->pix_fmt;
+ if (copy_to_user((void *)arg, (void *)&pix_fmt,
+ sizeof(pix_fmt)))
+ return -EFAULT;
+ pr_debug("get pixel format 0x%08x\n", ad->pix_fmt);
+ break;
+ case MFB_SET_AOID:
+ if (!arg)
+ return -EINVAL;
+ if (copy_from_user((void *)&aoi_d, (void *)arg, sizeof(aoi_d)))
+ return -EFAULT;
+ mfbi->x_aoi_d = aoi_d.x_aoi_d;
+ mfbi->y_aoi_d = aoi_d.y_aoi_d;
+ pr_debug("set AOI display offset of index %d to (%d,%d)\n",
+ mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d);
+ fsl_diu_check_var(&info->var, info);
+ fsl_diu_set_par(info);
+ break;
+ case MFB_GET_AOID:
+ if (!arg)
+ return -EINVAL;
+ aoi_d.x_aoi_d = mfbi->x_aoi_d;
+ aoi_d.y_aoi_d = mfbi->y_aoi_d;
+ if (copy_to_user((void *)arg, (void *)&aoi_d, sizeof(aoi_d)))
+ return -EFAULT;
+ pr_debug("get AOI display offset of index %d (%d,%d)\n",
+ mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d);
+ break;
+ case MFB_GET_ALPHA:
+ if (!arg)
+ return -EINVAL;
+ global_alpha = mfbi->g_alpha;
+ if (copy_to_user((void *)arg, (void *)&global_alpha,
+ sizeof(global_alpha)))
+ return -EFAULT;
+ pr_debug("get global alpha of index %d\n", mfbi->index);
+ break;
+ case MFB_SET_ALPHA:
+ if (!arg)
+ return -EINVAL;
+
+ /* set panel information */
+ if (copy_from_user((void *)&global_alpha, (void *)arg,
+ sizeof(global_alpha)))
+ return -EFAULT;
+ ad->src_size_g_alpha = (ad->src_size_g_alpha & (~0xff)) |
+ (global_alpha & 0xff);
+ mfbi->g_alpha = global_alpha;
+ pr_debug("set global alpha for index %d\n", mfbi->index);
+ break;
+ case MFB_SET_CHROMA_KEY:
+ if (!arg)
+ return -EINVAL;
+
+ /* set panel winformation */
+ if (copy_from_user((void *)&ck, (void *)arg, sizeof(ck)))
+ return -EFAULT;
+
+ if (ck.enable &&
+ (ck.red_max < ck.red_min ||
+ ck.green_max < ck.green_min ||
+ ck.blue_max < ck.blue_min))
+ return -EINVAL;
+
+ if (!ck.enable) {
+ ad->ckmax_r = 0;
+ ad->ckmax_g = 0;
+ ad->ckmax_b = 0;
+ ad->ckmin_r = 255;
+ ad->ckmin_g = 255;
+ ad->ckmin_b = 255;
+ } else {
+ ad->ckmax_r = ck.red_max;
+ ad->ckmax_g = ck.green_max;
+ ad->ckmax_b = ck.blue_max;
+ ad->ckmin_r = ck.red_min;
+ ad->ckmin_g = ck.green_min;
+ ad->ckmin_b = ck.blue_min;
+ }
+ pr_debug("set chroma key\n");
+ break;
+ case FBIOGET_GWINFO:
+ if (mfbi->type == MFB_TYPE_OFF)
+ return -ENODEV;
+
+ if (!arg)
+ return -EINVAL;
+
+ /* get graphic window information */
+ if (copy_to_user((void *)arg, (void *)ad, sizeof(*ad)))
+ return -EFAULT;
+ break;
+ case FBIOGET_HWCINFO:
+ pr_debug("FBIOGET_HWCINFO:0x%08x\n", FBIOGET_HWCINFO);
+ break;
+ case FBIOPUT_MODEINFO:
+ pr_debug("FBIOPUT_MODEINFO:0x%08x\n", FBIOPUT_MODEINFO);
+ break;
+ case FBIOGET_DISPINFO:
+ pr_debug("FBIOGET_DISPINFO:0x%08x\n", FBIOGET_DISPINFO);
+ break;
+
+ default:
+ printk(KERN_ERR "Unknown ioctl command (0x%08X)\n", cmd);
+ return 0;
+ }
+
+ return 0;
+}
+
+/* turn on fb if count == 1
+ */
+static int fsl_diu_open(struct fb_info *info, int user)
+{
+ struct mfb_info *mfbi = info->par;
+ int res = 0;
+
+ spin_lock(&diu_lock);
+ mfbi->count++;
+ if (mfbi->count == 1) {
+ pr_debug("open plane index %d\n", mfbi->index);
+ fsl_diu_check_var(&info->var, info);
+ res = fsl_diu_set_par(info);
+ if (res < 0)
+ mfbi->count--;
+ else {
+ res = fsl_diu_enable_panel(info);
+ if (res < 0)
+ mfbi->count--;
+ }
+ }
+
+ spin_unlock(&diu_lock);
+ return res;
+}
+
+/* turn off fb if count == 0
+ */
+static int fsl_diu_release(struct fb_info *info, int user)
+{
+ struct mfb_info *mfbi = info->par;
+ int res = 0;
+
+ spin_lock(&diu_lock);
+ mfbi->count--;
+ if (mfbi->count == 0) {
+ pr_debug("release plane index %d\n", mfbi->index);
+ res = fsl_diu_disable_panel(info);
+ if (res < 0)
+ mfbi->count++;
+ }
+ spin_unlock(&diu_lock);
+ return res;
+}
+
+static struct fb_ops fsl_diu_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = fsl_diu_check_var,
+ .fb_set_par = fsl_diu_set_par,
+ .fb_setcolreg = fsl_diu_setcolreg,
+ .fb_blank = fsl_diu_blank,
+ .fb_pan_display = fsl_diu_pan_display,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_ioctl = fsl_diu_ioctl,
+ .fb_open = fsl_diu_open,
+ .fb_release = fsl_diu_release,
+};
+
+static int init_fbinfo(struct fb_info *info)
+{
+ struct mfb_info *mfbi = info->par;
+
+ info->device = NULL;
+ info->var.activate = FB_ACTIVATE_NOW;
+ info->fbops = &fsl_diu_ops;
+ info->flags = FBINFO_FLAG_DEFAULT;
+ info->pseudo_palette = &mfbi->pseudo_palette;
+
+ /* Allocate colormap */
+ fb_alloc_cmap(&info->cmap, 16, 0);
+ return 0;
+}
+
+static int install_fb(struct fb_info *info)
+{
+ int rc;
+ struct mfb_info *mfbi = info->par;
+ const char *aoi_mode, *init_aoi_mode = "320x240";
+
+ if (init_fbinfo(info))
+ return -EINVAL;
+
+ if (mfbi->index == 0) /* plane 0 */
+ aoi_mode = fb_mode;
+ 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);
+
+ switch (rc) {
+ case 1:
+ pr_debug("using mode specified in @mode\n");
+ break;
+ case 2:
+ pr_debug("using mode specified in @mode "
+ "with ignored refresh rate\n");
+ break;
+ case 3:
+ pr_debug("using mode default mode\n");
+ break;
+ case 4:
+ pr_debug("using mode from list\n");
+ break;
+ default:
+ pr_debug("rc = %d\n", rc);
+ pr_debug("failed to find mode\n");
+ return -EINVAL;
+ break;
+ }
+
+ pr_debug("xres_virtual %d\n", info->var.xres_virtual);
+ pr_debug("bits_per_pixel %d\n", info->var.bits_per_pixel);
+
+ pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual);
+ pr_debug("info->fix.line_length = %d\n", info->fix.line_length);
+
+ if (mfbi->type == MFB_TYPE_OFF)
+ mfbi->blank = FB_BLANK_NORMAL;
+ else
+ mfbi->blank = FB_BLANK_UNBLANK;
+
+ if (fsl_diu_check_var(&info->var, info)) {
+ printk(KERN_ERR "fb_check_var failed");
+ fb_dealloc_cmap(&info->cmap);
+ return -EINVAL;
+ }
+
+ if (fsl_diu_set_par(info)) {
+ printk(KERN_ERR "fb_set_par failed");
+ fb_dealloc_cmap(&info->cmap);
+ return -EINVAL;
+ }
+
+ if (register_framebuffer(info) < 0) {
+ printk(KERN_ERR "register_framebuffer failed");
+ unmap_video_memory(info);
+ fb_dealloc_cmap(&info->cmap);
+ return -EINVAL;
+ }
+
+ mfbi->registered = 1;
+ printk(KERN_INFO "fb%d: %s fb device registered successfully.\n",
+ info->node, info->fix.id);
+
+ return 0;
+}
+
+static void __exit uninstall_fb(struct fb_info *info)
+{
+ struct mfb_info *mfbi = info->par;
+
+ if (!mfbi->registered)
+ return;
+
+ unregister_framebuffer(info);
+ unmap_video_memory(info);
+ if (&info->cmap)
+ fb_dealloc_cmap(&info->cmap);
+
+ mfbi->registered = 0;
+}
+
+static irqreturn_t fsl_diu_isr(int irq, void *dev_id)
+{
+ struct diu *hw = dr.diu_reg;
+ unsigned int status = in_be32(&(hw->int_status));
+
+ if (status) {
+ /* This is the workaround for underrun */
+ if (status & INT_UNDRUN) {
+ out_be32(&(hw->diu_mode), 0);
+ pr_debug("Err: DIU occurs underrun!\n");
+ udelay(1);
+ out_be32(&(hw->diu_mode), 1);
+ }
+#if defined(CONFIG_NOT_COHERENT_CACHE)
+ else if (status & INT_VSYNC) {
+ int i;
+ unsigned int *ptr;
+ ptr = coherence_data;
+ for (i = 0; i < 1024*8; i++)
+ *ptr++ = 0;
+ }
+#endif
+ return IRQ_HANDLED;
+ }
+ return IRQ_NONE;
+}
+
+static void request_irq_local(int irq)
+{
+ unsigned long status, ints;
+ struct diu *hw;
+
+ hw = dr.diu_reg;
+
+ /* Read to clear the status */
+ status = in_be32(&(hw->int_status));
+
+ if (request_irq(irq, fsl_diu_isr, 0, "diu", 0))
+ pr_info("Request diu IRQ failed.\n");
+ else {
+ ints = INT_PARERR | INT_LS_BF_VS;
+#if !defined(CONFIG_NOT_COHERENT_CACHE)
+ ints |= INT_VSYNC;
+#endif
+ if (dr.mode == MFB_MODE2 || dr.mode == MFB_MODE3)
+ ints |= INT_VSYNC_WB;
+
+ /* Read to clear the status */
+ status = in_be32(&(hw->int_status));
+ out_be32(&(hw->int_mask), ints);
+ }
+}
+
+static void free_irq_local(int irq)
+{
+ struct diu *hw = dr.diu_reg;
+
+ /* Disable all LCDC interrupt */
+ out_be32(&(hw->int_mask), 0x1f);
+
+ free_irq(irq, 0);
+}
+
+#ifdef CONFIG_PM
+/*
+ * Power management hooks. Note that we won't be called from IRQ context,
+ * unlike the blank functions above, so we may sleep.
+ */
+static int fsl_diu_suspend(struct of_device *dev, pm_message_t state)
+{
+ struct fsl_diu_data *machine_data;
+
+ machine_data = dev_get_drvdata(&ofdev->dev);
+ disable_lcdc(machine_data->fsl_diu_info[0]);
+
+ return 0;
+}
+
+static int fsl_diu_resume(struct of_device *dev)
+{
+ struct fsl_diu_data *machine_data;
+
+ machine_data = dev_get_drvdata(&ofdev->dev);
+ enable_lcdc(machine_data->fsl_diu_info[0]);
+
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+/* Align to 64-bit(8-byte), 32-byte, etc. */
+static int allocate_buf(struct diu_addr *buf, u32 size, u32 bytes_align)
+{
+ u32 offset, ssize;
+ u32 mask;
+ dma_addr_t paddr = 0;
+
+ ssize = size + bytes_align;
+ buf->vaddr = dma_alloc_coherent(0, ssize, &paddr, GFP_DMA | GFP_KERNEL);
+ if (!buf->vaddr)
+ return -ENOMEM;
+
+ buf->paddr = (__u32) paddr;
+ memset(buf->vaddr, 0, ssize);
+
+ mask = bytes_align - 1;
+ offset = (u32)buf->paddr & mask;
+ if (offset) {
+ buf->offset = bytes_align - offset;
+ buf->paddr = (u32)buf->paddr + offset;
+ } else
+ buf->offset = 0;
+ return 0;
+}
+
+static void free_buf(struct diu_addr *buf, u32 size, u32 bytes_align)
+{
+ dma_free_coherent(0, size + bytes_align,
+ buf->vaddr, (buf->paddr - buf->offset));
+ return;
+}
+
+static ssize_t store_monitor(struct device *device,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ char **last = NULL;
+ int val, old_monitor_port;
+ struct fsl_diu_data *machine_data =
+ container_of(attr, struct fsl_diu_data, dev_attr);
+
+ val = simple_strtoul(buf, last, 0);
+ old_monitor_port = machine_data->monitor_port;
+ machine_data->monitor_port = diu_ops.set_sysfs_monitor_port(val);
+
+ if (old_monitor_port != machine_data->monitor_port) {
+ /* All AOIs need adjust pixel format
+ * fsl_diu_set_par only change the pixsel format here
+ * unlikely to fail. */
+ fsl_diu_set_par(machine_data->fsl_diu_info[0]);
+ fsl_diu_set_par(machine_data->fsl_diu_info[1]);
+ fsl_diu_set_par(machine_data->fsl_diu_info[2]);
+ fsl_diu_set_par(machine_data->fsl_diu_info[3]);
+ fsl_diu_set_par(machine_data->fsl_diu_info[4]);
+ }
+ return count;
+}
+
+static ssize_t show_monitor(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ struct fsl_diu_data *machine_data =
+ container_of(attr, struct fsl_diu_data, dev_attr);
+ return diu_ops.show_monitor_port(machine_data->monitor_port, buf);
+}
+
+static int fsl_diu_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct device_node *np = ofdev->node;
+ struct mfb_info *mfbi;
+ phys_addr_t dummy_ad_addr;
+ int ret, i, error = 0;
+ struct resource res;
+ struct fsl_diu_data *machine_data;
+
+ machine_data = kzalloc(sizeof(struct fsl_diu_data), GFP_KERNEL);
+ if (!machine_data)
+ return -ENOMEM;
+
+ for (i = 0; i < sizeof(machine_data->fsl_diu_info) /
+ sizeof(struct fb_info *); i++) {
+ machine_data->fsl_diu_info[i] =
+ framebuffer_alloc(sizeof(struct mfb_info), &ofdev->dev);
+ if (!machine_data->fsl_diu_info[i]) {
+ dev_err(&ofdev->dev, "cannot allocate memory\n");
+ ret = -ENOMEM;
+ goto error2;
+ }
+ mfbi = machine_data->fsl_diu_info[i]->par;
+ memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info));
+ mfbi->parent = machine_data;
+ }
+
+ ret = of_address_to_resource(np, 0, &res);
+ if (ret) {
+ dev_err(&ofdev->dev, "could not obtain DIU address\n");
+ goto error;
+ }
+ if (!res.start) {
+ dev_err(&ofdev->dev, "invalid DIU address\n");
+ goto error;
+ }
+ dev_dbg(&ofdev->dev, "%s, res.start: 0x%08x\n", __func__, res.start);
+
+ dr.diu_reg = ioremap(res.start, sizeof(struct diu));
+ if (!dr.diu_reg) {
+ dev_err(&ofdev->dev, "Err: can't map DIU registers!\n");
+ ret = -EFAULT;
+ goto error2;
+ }
+
+ out_be32(&(dr.diu_reg->diu_mode), 0); /* disable DIU anyway*/
+ spin_lock_init(&dr.reg_lock);
+
+ /* Get the IRQ of the DIU */
+ machine_data->irq = irq_of_parse_and_map(np, 0);
+
+ if (!machine_data->irq) {
+ dev_err(&ofdev->dev, "could not get DIU IRQ\n");
+ ret = -EINVAL;
+ goto error;
+ }
+ machine_data->monitor_port = monitor_port;
+
+ /* Area descriptor memory pool aligns to 64-bit boundary */
+ if (allocate_buf(&pool.ad, sizeof(struct diu_ad) * FSL_AOI_NUM, 8))
+ return -ENOMEM;
+
+ /* Get memory for Gamma Table - 32-byte aligned memory */
+ if (allocate_buf(&pool.gamma, 768, 32)) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ /* For performance, cursor bitmap buffer aligns to 32-byte boundary */
+ if (allocate_buf(&pool.cursor, MAX_CURS * MAX_CURS * 2, 32)) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ i = sizeof(machine_data->fsl_diu_info) / sizeof(struct fb_info *);
+ machine_data->dummy_ad = (struct diu_ad *)
+ ((u32)pool.ad.vaddr + pool.ad.offset) + i;
+ machine_data->dummy_ad->paddr = pool.ad.paddr +
+ i * sizeof(struct diu_ad);
+ machine_data->dummy_aoi_virt = fsl_diu_alloc(64, &dummy_ad_addr);
+ if (!machine_data->dummy_aoi_virt) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ machine_data->dummy_ad->addr = cpu_to_le32(dummy_ad_addr);
+ machine_data->dummy_ad->pix_fmt = 0x88882317;
+ machine_data->dummy_ad->src_size_g_alpha = cpu_to_le32((4 << 12) | 4);
+ machine_data->dummy_ad->aoi_size = cpu_to_le32((4 << 16) | 2);
+ machine_data->dummy_ad->offset_xyi = 0;
+ machine_data->dummy_ad->offset_xyd = 0;
+ machine_data->dummy_ad->next_ad = 0;
+ memset(machine_data->dummy_aoi_virt, 0x00, 64);
+
+ 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);
+
+ for (i = 0; i < sizeof(machine_data->fsl_diu_info) /
+ sizeof(struct fb_info *); i++) {
+ machine_data->fsl_diu_info[i]->fix.smem_start = 0;
+ mfbi = machine_data->fsl_diu_info[i]->par;
+ mfbi->ad = (struct diu_ad *)((u32)pool.ad.vaddr
+ + pool.ad.offset) + i;
+ mfbi->ad->paddr = pool.ad.paddr + i * sizeof(struct diu_ad);
+ ret = install_fb(machine_data->fsl_diu_info[i]);
+ if (ret) {
+ dev_err(&ofdev->dev,
+ "Failed to register framebuffer %d\n",
+ i);
+ goto error;
+ }
+ }
+
+ machine_data->dev_attr.attr.name = "monitor";
+ machine_data->dev_attr.attr.mode = S_IRUGO|S_IWUSR;
+ machine_data->dev_attr.show = show_monitor;
+ machine_data->dev_attr.store = store_monitor;
+ error = device_create_file(machine_data->fsl_diu_info[0]->dev,
+ &machine_data->dev_attr);
+ if (error) {
+ dev_err(machine_data->fsl_diu_info[0]->dev,
+ "could not create sysfs %s file\n",
+ machine_data->dev_attr.attr.name);
+ }
+
+ request_irq_local(machine_data->irq);
+ dev_set_drvdata(&ofdev->dev, machine_data);
+ return 0;
+
+error:
+ for (i = sizeof(machine_data->fsl_diu_info) / sizeof(struct fb_info *);
+ i > 0; i--)
+ uninstall_fb(machine_data->fsl_diu_info[i - 1]);
+ if (pool.ad.vaddr)
+ free_buf(&pool.ad, sizeof(struct diu_ad) * FSL_AOI_NUM, 8);
+ if (pool.gamma.vaddr)
+ free_buf(&pool.gamma, 768, 32);
+ if (pool.cursor.vaddr)
+ free_buf(&pool.cursor, MAX_CURS * MAX_CURS * 2, 32);
+ if (machine_data->dummy_aoi_virt)
+ fsl_diu_free(machine_data->dummy_aoi_virt, 64);
+ iounmap(dr.diu_reg);
+
+error2:
+ for (i = 0; i < sizeof(machine_data->fsl_diu_info) /
+ sizeof(struct fb_info *); i++)
+ if (machine_data->fsl_diu_info[i])
+ framebuffer_release(machine_data->fsl_diu_info[i]);
+ kfree(machine_data);
+
+ return ret;
+}
+
+
+static int fsl_diu_remove(struct of_device *ofdev)
+{
+ struct fsl_diu_data *machine_data;
+ int i;
+
+ machine_data = dev_get_drvdata(&ofdev->dev);
+ disable_lcdc(machine_data->fsl_diu_info[0]);
+ free_irq_local(machine_data->irq);
+ for (i = sizeof(machine_data->fsl_diu_info) / sizeof(struct fb_info *);
+ i > 0; i--)
+ uninstall_fb(machine_data->fsl_diu_info[i - 1]);
+ if (pool.ad.vaddr)
+ free_buf(&pool.ad, sizeof(struct diu_ad) * FSL_AOI_NUM, 8);
+ if (pool.gamma.vaddr)
+ free_buf(&pool.gamma, 768, 32);
+ if (pool.cursor.vaddr)
+ free_buf(&pool.cursor, MAX_CURS * MAX_CURS * 2, 32);
+ if (machine_data->dummy_aoi_virt)
+ fsl_diu_free(machine_data->dummy_aoi_virt, 64);
+ iounmap(dr.diu_reg);
+ for (i = 0; i < sizeof(machine_data->fsl_diu_info) /
+ sizeof(struct fb_info *); i++)
+ if (machine_data->fsl_diu_info[i])
+ framebuffer_release(machine_data->fsl_diu_info[i]);
+ kfree(machine_data);
+
+ return 0;
+}
+
+#ifndef MODULE
+static int __init fsl_diu_setup(char *options)
+{
+ char *opt;
+ int val;
+
+ if (!options || !*options)
+ return 0;
+
+ while ((opt = strsep(&options, ",")) != NULL) {
+ if (!*opt)
+ continue;
+ if (!strncmp(opt, "monitor=", 8)) {
+ val = simple_strtoul(opt + 8, NULL, 0);
+ if ((val == 0) || (val == 1) || (val == 2))
+ monitor_port = val;
+ } else if (!strncmp(opt, "bpp=", 4))
+ default_bpp = simple_strtoul(opt + 4, NULL, 0);
+ else
+ fb_mode = opt;
+ }
+
+ return 0;
+}
+#endif
+
+static struct of_device_id fsl_diu_match[] = {
+ {
+ .compatible = "fsl-diu",
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, fsl_diu_match);
+
+static struct of_platform_driver fsl_diu_driver = {
+ .owner = THIS_MODULE,
+ .name = "fsl_diu",
+ .match_table = fsl_diu_match,
+ .probe = fsl_diu_probe,
+ .remove = fsl_diu_remove,
+#ifdef CONFIG_PM
+ .suspend = fsl_diu_suspend,
+ .resume = fsl_diu_resume,
+#endif
+};
+
+static int __init fsl_diu_init(void)
+{
+ int ret;
+#ifndef MODULE
+ char *option;
+ /*
+ * For kernel boot options (in 'video=xxxfb:<options>' format)
+ */
+ if (fb_get_options("fslfb", &option))
+ return -ENODEV;
+ fsl_diu_setup(option);
+#endif
+ printk(KERN_INFO "Freescale DIU driver\n");
+
+#if defined(CONFIG_NOT_COHERENT_CACHE)
+ coherence_data = fsl_diu_alloc(32*1024, &coherence_data_phy);
+ if (!coherence_data) {
+ ret = -ENOMEM;
+ goto error;
+ }
+#endif
+ ret = of_register_platform_driver(&fsl_diu_driver);
+ if (ret) {
+ printk(KERN_ERR
+ "fsl-diu: failed to register platform driver\n");
+ iounmap(dr.diu_reg);
+ }
+ return ret;
+}
+
+static void __exit fsl_diu_exit(void)
+{
+ of_unregister_platform_driver(&fsl_diu_driver);
+#if defined(CONFIG_NOT_COHERENT_CACHE)
+ if (coherence_data)
+ fsl_diu_free(coherence_data, 32*1024);
+#endif
+}
+
+module_init(fsl_diu_init);
+module_exit(fsl_diu_exit);
+
+MODULE_AUTHOR("York Sun <yorksun@freescale.com>");
+MODULE_DESCRIPTION("Freescale DIU framebuffer driver");
+MODULE_LICENSE("GPL");
+
+module_param_named(mode, fb_mode, charp, 0);
+MODULE_PARM_DESC(mode,
+ "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
+module_param_named(bpp, default_bpp, ulong, 0);
+MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified mode");
+module_param_named(monitor, monitor_port, int, 0);
+MODULE_PARM_DESC(monitor,
+ "Specify the monitor port (0, 1 or 2) if supported by the platform");
+
diff --git a/drivers/video/fsl-diu-fb.h b/drivers/video/fsl-diu-fb.h
new file mode 100644
index 0000000..f413b96
--- /dev/null
+++ b/drivers/video/fsl-diu-fb.h
@@ -0,0 +1,224 @@
+/*
+ * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Freescale DIU Frame Buffer device driver
+ *
+ * Authors: Hongjun Chen <hong-jun.chen@freescale.com>
+ * Paul Widmer <paul.widmer@freescale.com>
+ * Srikanth Srinivasan <srikanth.srinivasan@freescale.com>
+ * York Sun <yorksun@freescale.com>
+ * Copyright (C) Freescale Semicondutor, Inc. 2007. All rights reserved.
+ *
+ * Based on imxfb.c Copyright (C) 2004 S.Hauer, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef __FSL_DIU_FB_H__
+#define __FSL_DIU_FB_H__
+
+/* Arbitrary threshold to determine the allocation method
+ * See mpc8610fb_set_par(), map_video_memory(), and unmap_video_memory()
+ */
+#define MEM_ALLOC_THRESHOLD (1024*768*4+32)
+/* Minimum value that the pixel clock can be set to in pico seconds
+ * This is determined by platform clock/3 where the minimum platform
+ * clock is 533MHz. This gives 5629 pico seconds.
+ */
+#define MIN_PIX_CLK 5629
+#define MAX_PIX_CLK 96096
+
+#include <linux/types.h>
+
+struct mfb_alpha {
+ int enable;
+ int alpha;
+};
+
+struct mfb_chroma_key {
+ int enable;
+ __u8 red_max;
+ __u8 green_max;
+ __u8 blue_max;
+ __u8 red_min;
+ __u8 green_min;
+ __u8 blue_min;
+};
+
+struct aoi_display_offset {
+ int x_aoi_d;
+ int y_aoi_d;
+};
+
+#define MFB_SET_CHROMA_KEY _IOW('M', 1, struct mfb_chroma_key)
+#define MFB_WAIT_FOR_VSYNC _IOW('F', 0x20, u_int32_t)
+#define MFB_SET_BRIGHTNESS _IOW('M', 3, __u8)
+
+#define MFB_SET_ALPHA 0x80014d00
+#define MFB_GET_ALPHA 0x40014d00
+#define MFB_SET_AOID 0x80084d04
+#define MFB_GET_AOID 0x40084d04
+#define MFB_SET_PIXFMT 0x80014d08
+#define MFB_GET_PIXFMT 0x40014d08
+
+#define FBIOGET_GWINFO 0x46E0
+#define FBIOPUT_GWINFO 0x46E1
+
+#ifdef __KERNEL__
+#include <linux/spinlock.h>
+
+/*
+ * These are the fields of area descriptor(in DDR memory) for every plane
+ */
+struct diu_ad {
+ /* Word 0(32-bit) in DDR memory */
+/* __u16 comp; */
+/* __u16 pixel_s:2; */
+/* __u16 pallete:1; */
+/* __u16 red_c:2; */
+/* __u16 green_c:2; */
+/* __u16 blue_c:2; */
+/* __u16 alpha_c:3; */
+/* __u16 byte_f:1; */
+/* __u16 res0:3; */
+
+ __be32 pix_fmt; /* hard coding pixel format */
+
+ /* Word 1(32-bit) in DDR memory */
+ __le32 addr;
+
+ /* Word 2(32-bit) in DDR memory */
+/* __u32 delta_xs:11; */
+/* __u32 res1:1; */
+/* __u32 delta_ys:11; */
+/* __u32 res2:1; */
+/* __u32 g_alpha:8; */
+ __le32 src_size_g_alpha;
+
+ /* Word 3(32-bit) in DDR memory */
+/* __u32 delta_xi:11; */
+/* __u32 res3:5; */
+/* __u32 delta_yi:11; */
+/* __u32 res4:3; */
+/* __u32 flip:2; */
+ __le32 aoi_size;
+
+ /* Word 4(32-bit) in DDR memory */
+ /*__u32 offset_xi:11;
+ __u32 res5:5;
+ __u32 offset_yi:11;
+ __u32 res6:5;
+ */
+ __le32 offset_xyi;
+
+ /* Word 5(32-bit) in DDR memory */
+ /*__u32 offset_xd:11;
+ __u32 res7:5;
+ __u32 offset_yd:11;
+ __u32 res8:5; */
+ __le32 offset_xyd;
+
+
+ /* Word 6(32-bit) in DDR memory */
+ __u8 ckmax_r;
+ __u8 ckmax_g;
+ __u8 ckmax_b;
+ __u8 res9;
+
+ /* Word 7(32-bit) in DDR memory */
+ __u8 ckmin_r;
+ __u8 ckmin_g;
+ __u8 ckmin_b;
+ __u8 res10;
+/* __u32 res10:8; */
+
+ /* Word 8(32-bit) in DDR memory */
+ __le32 next_ad;
+
+ /* Word 9(32-bit) in DDR memory, just for 64-bit aligned */
+ __u32 paddr;
+} __attribute__ ((packed));
+
+/* DIU register map */
+struct diu {
+ __be32 desc[3];
+ __be32 gamma;
+ __be32 pallete;
+ __be32 cursor;
+ __be32 curs_pos;
+ __be32 diu_mode;
+ __be32 bgnd;
+ __be32 bgnd_wb;
+ __be32 disp_size;
+ __be32 wb_size;
+ __be32 wb_mem_addr;
+ __be32 hsyn_para;
+ __be32 vsyn_para;
+ __be32 syn_pol;
+ __be32 thresholds;
+ __be32 int_status;
+ __be32 int_mask;
+ __be32 colorbar[8];
+ __be32 filling;
+ __be32 plut;
+} __attribute__ ((packed));
+
+struct diu_hw {
+ struct diu *diu_reg;
+ spinlock_t reg_lock;
+
+ __u32 mode; /* DIU operation mode */
+};
+
+struct diu_addr {
+ __u8 __iomem *vaddr; /* Virtual address */
+ dma_addr_t paddr; /* Physical address */
+ __u32 offset;
+};
+
+struct diu_pool {
+ struct diu_addr ad;
+ struct diu_addr gamma;
+ struct diu_addr pallete;
+ struct diu_addr cursor;
+};
+
+#define FSL_DIU_BASE_OFFSET 0x2C000 /* Offset of DIU */
+#define INT_LCDC 64 /* DIU interrupt number */
+
+#define FSL_AOI_NUM 6 /* 5 AOIs and one dummy AOI */
+ /* 1 for plane 0, 2 for plane 1&2 each */
+
+/* Minimum X and Y resolutions */
+#define MIN_XRES 64
+#define MIN_YRES 64
+
+/* HW cursor parameters */
+#define MAX_CURS 32
+
+/* Modes of operation of DIU */
+#define MFB_MODE0 0 /* DIU off */
+#define MFB_MODE1 1 /* All three planes output to display */
+#define MFB_MODE2 2 /* Plane 1 to display, planes 2+3 written back*/
+#define MFB_MODE3 3 /* All three planes written back to memory */
+#define MFB_MODE4 4 /* Color bar generation */
+
+/* INT_STATUS/INT_MASK field descriptions */
+#define INT_VSYNC 0x01 /* Vsync interrupt */
+#define INT_VSYNC_WB 0x02 /* Vsync interrupt for write back operation */
+#define INT_UNDRUN 0x04 /* Under run exception interrupt */
+#define INT_PARERR 0x08 /* Display parameters error interrupt */
+#define INT_LS_BF_VS 0x10 /* Lines before vsync. interrupt */
+
+/* Panels'operation modes */
+#define MFB_TYPE_OUTPUT 0 /* Panel output to display */
+#define MFB_TYPE_OFF 1 /* Panel off */
+#define MFB_TYPE_WB 2 /* Panel written back to memory */
+#define MFB_TYPE_TEST 3 /* Panel generate color bar */
+
+#endif /* __KERNEL__ */
+#endif /* __FSL_DIU_FB_H__ */
--
1.5.2.2
^ permalink raw reply related
* [PATCH] powerpc32: asm-offsets ptrace cruft
From: Roland McGrath @ 2008-03-19 21:07 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev, Andrew Morton, linux-kernel
These items in asm-offsets.c are not used anywhere. Remove them.
Signed-off-by: Roland McGrath <roland@redhat.com>
---
arch/powerpc/kernel/asm-offsets.c | 4 ----
1 files changed, 0 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 4b749c4..e932b43 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -26,8 +26,6 @@
#ifdef CONFIG_PPC64
#include <linux/time.h>
#include <linux/hardirq.h>
-#else
-#include <linux/ptrace.h>
#endif
#include <asm/io.h>
@@ -60,7 +58,6 @@ int main(void)
DEFINE(AUDITCONTEXT, offsetof(struct task_struct, audit_context));
#else
DEFINE(THREAD_INFO, offsetof(struct task_struct, stack));
- DEFINE(PTRACE, offsetof(struct task_struct, ptrace));
#endif /* CONFIG_PPC64 */
DEFINE(KSP, offsetof(struct thread_struct, ksp));
@@ -80,7 +77,6 @@ int main(void)
DEFINE(PGDIR, offsetof(struct thread_struct, pgdir));
#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
DEFINE(THREAD_DBCR0, offsetof(struct thread_struct, dbcr0));
- DEFINE(PT_PTRACED, PT_PTRACED);
#endif
#ifdef CONFIG_SPE
DEFINE(THREAD_EVR0, offsetof(struct thread_struct, evr[0]));
^ permalink raw reply related
* [PATCH 1/8] ptrace: forced_successful_syscall_return() macro
From: Roland McGrath @ 2008-03-19 21:17 UTC (permalink / raw)
To: Linus Torvalds, Andrew Morton
Cc: linux-arch, tony.luck, linux-ia64, linux-kernel, David Miller,
linuxppc-dev, Paul Mackerras, sparclinux, Ingo Molnar,
Thomas Gleixner, Richard Henderson
This adds the forced_successful_syscall_return() macro, a mate to
force_successful_syscall_return() to test rather than set the condition.
Signed-off-by: Roland McGrath <roland@redhat.com>
---
include/linux/ptrace.h | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index ebe0c17..9272e63 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -124,8 +124,13 @@ int generic_ptrace_pokedata(struct task_struct *tsk, long addr, long data);
* is a no-op and the spurious error condition needs to be filtered out by some
* other means (e.g., in user-level, by passing an extra argument to the
* syscall handler, or something along those lines).
+ *
+ * On architectures that define force_successful_syscall_return(),
+ * forced_successful_syscall_return() should also be defined.
+ * It returns nonzero if force_successful_syscall_return() was just used.
*/
#define force_successful_syscall_return() do { } while (0)
+#define forced_successful_syscall_return() 0
#endif
/*
^ permalink raw reply related
* [PATCH 2/8] alpha ptrace: forced_successful_syscall_return()
From: Roland McGrath @ 2008-03-19 21:18 UTC (permalink / raw)
To: Linus Torvalds, Andrew Morton
Cc: linux-arch, tony.luck, linux-ia64, linux-kernel, David Miller,
linuxppc-dev, Paul Mackerras, sparclinux, Ingo Molnar,
Thomas Gleixner, Richard Henderson
In-Reply-To: <20080319211714.8B14226F995@magilla.localdomain>
Define the forced_successful_syscall_return() macro to
pair with our force_successful_syscall_return() definition.
Signed-off-by: Roland McGrath <roland@redhat.com>
---
include/asm-alpha/ptrace.h | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/include/asm-alpha/ptrace.h b/include/asm-alpha/ptrace.h
index 32c7a5c..1cc330b 100644
--- a/include/asm-alpha/ptrace.h
+++ b/include/asm-alpha/ptrace.h
@@ -77,6 +77,7 @@ extern void show_regs(struct pt_regs *);
((struct pt_regs *) (task_stack_page(task) + 2*PAGE_SIZE) - 1)
#define force_successful_syscall_return() (task_pt_regs(current)->r0 = 0)
+#define forced_successful_syscall_return() (task_pt_regs(current)->r0 == 0)
#endif
^ permalink raw reply related
* [PATCH 4/8] powerpc ptrace: forced_successful_syscall_return()
From: Roland McGrath @ 2008-03-19 21:19 UTC (permalink / raw)
To: Linus Torvalds, Andrew Morton
Cc: linux-arch, tony.luck, linux-ia64, linux-kernel, David Miller,
linuxppc-dev, Paul Mackerras, sparclinux, Ingo Molnar,
Thomas Gleixner, Richard Henderson
In-Reply-To: <20080319211714.8B14226F995@magilla.localdomain>
Define the forced_successful_syscall_return() macro to
pair with our force_successful_syscall_return() definition.
Signed-off-by: Roland McGrath <roland@redhat.com>
---
include/asm-powerpc/ptrace.h | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/include/asm-powerpc/ptrace.h b/include/asm-powerpc/ptrace.h
index 891d689..07dd6fe 100644
--- a/include/asm-powerpc/ptrace.h
+++ b/include/asm-powerpc/ptrace.h
@@ -93,6 +93,7 @@ extern unsigned long profile_pc(struct pt_regs *regs);
do { \
set_thread_flag(TIF_NOERROR); \
} while(0)
+#define forced_successful_syscall_return() (test_thread_flag(TIF_NOERROR))
struct task_struct;
extern unsigned long ptrace_get_reg(struct task_struct *task, int regno);
^ permalink raw reply related
* [PATCH 3/8] ia64 ptrace: forced_successful_syscall_return()
From: Roland McGrath @ 2008-03-19 21:19 UTC (permalink / raw)
To: Linus Torvalds, Andrew Morton
Cc: linux-arch, tony.luck, linux-ia64, linux-kernel, David Miller,
linuxppc-dev, Paul Mackerras, sparclinux, Ingo Molnar,
Thomas Gleixner, Richard Henderson
In-Reply-To: <20080319211714.8B14226F995@magilla.localdomain>
Define the forced_successful_syscall_return() macro to
pair with our force_successful_syscall_return() definition.
Signed-off-by: Roland McGrath <roland@redhat.com>
---
include/asm-ia64/ptrace.h | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/include/asm-ia64/ptrace.h b/include/asm-ia64/ptrace.h
index 4b2a8d4..5e82915 100644
--- a/include/asm-ia64/ptrace.h
+++ b/include/asm-ia64/ptrace.h
@@ -276,6 +276,7 @@ struct switch_stack {
* On ia64, we can clear the user's pt_regs->r8 to force a successful syscall.
*/
# define force_successful_syscall_return() (task_pt_regs(current)->r8 = 0)
+# define forced_successful_syscall_return() (task_pt_regs(current)->r8 == 0)
struct task_struct; /* forward decl */
struct unw_frame_info; /* forward decl */
^ permalink raw reply related
* [PATCH 5/8] sparc64 ptrace: forced_successful_syscall_return()
From: Roland McGrath @ 2008-03-19 21:20 UTC (permalink / raw)
To: Linus Torvalds, Andrew Morton
Cc: linux-arch, tony.luck, linux-ia64, linux-kernel, David Miller,
linuxppc-dev, Paul Mackerras, sparclinux, Ingo Molnar,
Thomas Gleixner, Richard Henderson
In-Reply-To: <20080319211714.8B14226F995@magilla.localdomain>
Define the forced_successful_syscall_return() macro to
pair with our force_successful_syscall_return() definition.
Signed-off-by: Roland McGrath <roland@redhat.com>
---
include/asm-sparc64/ptrace.h | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/include/asm-sparc64/ptrace.h b/include/asm-sparc64/ptrace.h
index 6da1978..3f8826e 100644
--- a/include/asm-sparc64/ptrace.h
+++ b/include/asm-sparc64/ptrace.h
@@ -100,6 +100,8 @@ struct sparc_trapf {
#define force_successful_syscall_return() \
do { current_thread_info()->syscall_noerror = 1; \
} while (0)
+#define forced_successful_syscall_return() \
+ (current_thread_info()->syscall_noerror != 0)
#define user_mode(regs) (!((regs)->tstate & TSTATE_PRIV))
#define instruction_pointer(regs) ((regs)->tpc)
#define regs_return_value(regs) ((regs)->u_regs[UREG_I0])
^ permalink raw reply related
* [PATCH 6/8] ptrace: arch_ptrace -ENOSYS return
From: Roland McGrath @ 2008-03-19 21:20 UTC (permalink / raw)
To: Linus Torvalds, Andrew Morton
Cc: linux-arch, tony.luck, linux-ia64, linux-kernel, David Miller,
linuxppc-dev, Paul Mackerras, sparclinux, Ingo Molnar,
Thomas Gleixner, Richard Henderson
In-Reply-To: <20080319211714.8B14226F995@magilla.localdomain>
The arch_ptrace and compat_arch_ptrace functions can now return
-ENOSYS for requests they do not actually implement in arch
code. Returning -ENOSYS replaces the calls to ptrace_request
and compat_ptrace_request. This leaves more latitude for the
machine-independent ptrace implementation code to change without
requiring any more updates in the arch code.
This change has no effect on the old arch code that still calls
ptrace_request or compat_ptrace_request.
Signed-off-by: Roland McGrath <roland@redhat.com>
---
kernel/ptrace.c | 42 ++++++++++++++++++++++++++----------------
1 files changed, 26 insertions(+), 16 deletions(-)
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 67e392e..60b2b57 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -574,18 +574,21 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
*/
if (!ret)
arch_ptrace_attach(child);
- goto out_put_task_struct;
+ } else {
+ ret = ptrace_check_attach(child, request == PTRACE_KILL);
+ /*
+ * Let the arch handler inspect it first. It returns
+ * -ENOSYS if this is not an arch-specific request.
+ */
+ if (!ret) {
+ ret = arch_ptrace(child, request, addr, data);
+ if (ret == -ENOSYS &&
+ !forced_successful_syscall_return())
+ ret = ptrace_request(child, request,
+ addr, data);
+ }
}
- ret = ptrace_check_attach(child, request == PTRACE_KILL);
- if (ret < 0)
- goto out_put_task_struct;
-
- ret = arch_ptrace(child, request, addr, data);
- if (ret < 0)
- goto out_put_task_struct;
-
- out_put_task_struct:
put_task_struct(child);
out:
unlock_kernel();
@@ -697,14 +700,21 @@ asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid,
*/
if (!ret)
arch_ptrace_attach(child);
- goto out_put_task_struct;
+ } else {
+ ret = ptrace_check_attach(child, request == PTRACE_KILL);
+ /*
+ * Let the arch handler inspect it first. It returns
+ * -ENOSYS if this is not an arch-specific request.
+ */
+ if (!ret) {
+ ret = compat_arch_ptrace(child, request, addr, data);
+ if (ret == -ENOSYS &&
+ !forced_successful_syscall_return())
+ ret = compat_ptrace_request(child, request,
+ addr, data);
+ }
}
- ret = ptrace_check_attach(child, request == PTRACE_KILL);
- if (!ret)
- ret = compat_arch_ptrace(child, request, addr, data);
-
- out_put_task_struct:
put_task_struct(child);
out:
unlock_kernel();
^ permalink raw reply related
* [PATCH 7/8] x86 ptrace: arch_ptrace -ENOSYS return
From: Roland McGrath @ 2008-03-19 21:20 UTC (permalink / raw)
To: Linus Torvalds, Andrew Morton
Cc: linux-arch, tony.luck, linux-ia64, linux-kernel, David Miller,
linuxppc-dev, Paul Mackerras, sparclinux, Ingo Molnar,
Thomas Gleixner, Richard Henderson
In-Reply-To: <20080319211714.8B14226F995@magilla.localdomain>
Return -ENOSYS from arch_ptrace and compat_arch_ptrace
rather than calling ptrace_request or compat_ptrace_request.
Signed-off-by: Roland McGrath <roland@redhat.com>
---
arch/x86/kernel/ptrace.c | 5 +++--
1 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 777d8f9..4d5561c 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -1010,7 +1010,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
#endif
default:
- ret = ptrace_request(child, request, addr, data);
+ ret = -ENOSYS;
break;
}
@@ -1266,7 +1266,8 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
return arch_ptrace(child, request, addr, data);
default:
- return compat_ptrace_request(child, request, addr, data);
+ ret = -ENOSYS;
+ break;
}
return ret;
^ permalink raw reply related
* [PATCH 8/8] powerpc ptrace: arch_ptrace -ENOSYS return
From: Roland McGrath @ 2008-03-19 21:21 UTC (permalink / raw)
To: Linus Torvalds, Andrew Morton
Cc: linux-arch, tony.luck, linux-ia64, linux-kernel, David Miller,
linuxppc-dev, Paul Mackerras, sparclinux, Ingo Molnar,
Thomas Gleixner, Richard Henderson
In-Reply-To: <20080319211714.8B14226F995@magilla.localdomain>
Return -ENOSYS from arch_ptrace and compat_arch_ptrace
rather than calling ptrace_request or compat_ptrace_request.
Signed-off-by: Roland McGrath <roland@redhat.com>
---
arch/powerpc/kernel/ptrace.c | 2 +-
arch/powerpc/kernel/ptrace32.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 2a9fe97..47b701e 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -843,7 +843,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break;
default:
- ret = ptrace_request(child, request, addr, data);
+ ret = -ENOSYS;
break;
}
return ret;
diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c
index 4c1de6a..7383d15 100644
--- a/arch/powerpc/kernel/ptrace32.c
+++ b/arch/powerpc/kernel/ptrace32.c
@@ -306,7 +306,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
break;
default:
- ret = compat_ptrace_request(child, request, addr, data);
+ ret = -ENOSYS;
break;
}
^ permalink raw reply related
* Re: [PATCH 5/8] sparc64 ptrace: forced_successful_syscall_return()
From: David Miller @ 2008-03-19 21:30 UTC (permalink / raw)
To: roland
Cc: linux-arch, tony.luck, linux-ia64, linux-kernel, linuxppc-dev,
tglx, sparclinux, paulus, akpm, torvalds, mingo, rth
In-Reply-To: <20080319212001.2DB8526F995@magilla.localdomain>
From: Roland McGrath <roland@redhat.com>
Date: Wed, 19 Mar 2008 14:20:01 -0700 (PDT)
> Define the forced_successful_syscall_return() macro to
> pair with our force_successful_syscall_return() definition.
>
> Signed-off-by: Roland McGrath <roland@redhat.com>
Acked-by: David S. Miller <davem@davemloft.net>
^ permalink raw reply
* question about of_platform vs 'platform'
From: Mike Hench @ 2008-03-19 21:49 UTC (permalink / raw)
To: linuxppc-dev
Sorry if this is a stupid question
I am new to PPC.
I am trying to make the SPI work on a MPC8313erdb board.
It isn't loading.
To that end, I added a printk to drivers/base/dd.c __driver_match
function
dmesg |grep -i spi
bus: 'of_platform': driver_probe_device: matching device e0007000.spi
with drive
r fsl-elbc
bus: 'platform': driver_probe_device: matching device fsl-usb2-udc.0
with driver
mpc83xx_spi
bus: 'platform': driver_probe_device: matching device mpc83xx_wdt.0 with
driver
mpc83xx_spi
bus: 'platform': driver_probe_device: matching device fsl-i2c.0 with
driver mpc8
3xx_spi
bus: 'platform': driver_probe_device: matching device fsl-i2c.1 with
driver mpc8
3xx_spi
bus: 'platform': driver_probe_device: matching device Fixed MDIO bus.0
with driv
er mpc83xx_spi
it seems there is some sort of mismatch
how did the kernel decide that SPI was an 'of_platform' device.
The driver just uses 'platform' sorts of calls.
As opposed to the mpc52xx driver which uses of_platform.
The DTS file spi entry look similar to the i2c entries.
Those are treated as 'platform' devices.
A nudge/shove in the right direction would be appreciated.
Thanks.
Mike
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox