LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH] Add aliases node to 8641hpcn DTS file.
From: Vitaly Bordug @ 2007-12-05 18:05 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev@ozlabs.org
In-Reply-To: <fa686aa40712050938j2d286655o94534a00131872e2@mail.gmail.com>

On Wed, 5 Dec 2007 10:38:38 -0700
Grant Likely wrote:

> >
> > +       aliases {
> > +               ethernet0 = &enet0;
> > +               ethernet1 = &enet1;
> > +               ethernet2 = &enet2;
> > +               ethernet3 = &enet3;
> > +               serial0 = &serial0;
> > +               serial1 = &serial1;
> > +               pci0 = &pci0;
> > +               pci1 = &pci1;
> > +       };  
> 
> I had thought aliases were supposed to be full paths to nodes instead
> of phandles.  Was I wrong?
no, but dwg did a patch for dtc to do that dirty work for you, resolving labels. I am also curious if such a change made it in
dtc git (working with full path aliases now). dtc should prolly get tagged and next sub-rev to be clear if it supports aliases or not.

-- 
Sincerely, Vitaly

^ permalink raw reply

* Re: [PATCH] Add aliases node to 8641hpcn DTS file.
From: Grant Likely @ 2007-12-05 18:15 UTC (permalink / raw)
  To: Jon Loeliger; +Cc: linuxppc-dev@ozlabs.org
In-Reply-To: <1196877907.8544.15.camel@ld0161-tx32>

On 12/5/07, Jon Loeliger <jdl@freescale.com> wrote:
> On Wed, 2007-12-05 at 11:38, Grant Likely wrote:
> > I had thought aliases were supposed to be full paths to nodes instead
> > of phandles.  Was I wrong?
>
> Indeed, that is correct.  And they are!
>
> Grant, you need to keep up, man.  Just this morning
> I pushed Gibson's patch to DTC to support this. :-)

Heh; I'm so behind.  Thanks for the clarification.

g.


-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
grant.likely@secretlab.ca
(403) 399-0195

^ permalink raw reply

* Re: Uboot and ML410
From: Grant Likely @ 2007-12-05 18:16 UTC (permalink / raw)
  To: khollan; +Cc: linuxppc-embedded
In-Reply-To: <14177109.post@talk.nabble.com>

On 12/5/07, khollan <khollan@daktronics.com> wrote:
>
> Hi
>
> Is there a patch to include support for the ml410 in the Main git tree of
> u-boot?  I tried compiling Xilinx's tree but it seems it won't compile
> correctly with my version of make (3.81).

I don't think there is.

>  Also is there any support for the
> Hard TEMAC in u-boot?  I tried looking for both of these questions but a lot
> of the threads were unanswered questions.  Thanks for your help

No, unfortunately nobody has got a hard TEMAC driver into u-boot mainline.

Cheers,
g.

-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
grant.likely@secretlab.ca
(403) 399-0195

^ permalink raw reply

* Re: [PATCH] Add aliases node to 8641hpcn DTS file.
From: Josh Boyer @ 2007-12-05 18:31 UTC (permalink / raw)
  To: Jon Loeliger; +Cc: linuxppc-dev@ozlabs.org
In-Reply-To: <1196877907.8544.15.camel@ld0161-tx32>

On Wed, 05 Dec 2007 12:05:07 -0600
Jon Loeliger <jdl@freescale.com> wrote:

> On Wed, 2007-12-05 at 11:38, Grant Likely wrote:
> 
> > >
> > > +       aliases {
> > > +               ethernet0 = &enet0;
> > > +               ethernet1 = &enet1;
> > > +               ethernet2 = &enet2;
> > > +               ethernet3 = &enet3;
> > > +               serial0 = &serial0;
> > > +               serial1 = &serial1;
> > > +               pci0 = &pci0;
> > > +               pci1 = &pci1;
> > > +       };
> > 
> > I had thought aliases were supposed to be full paths to nodes instead
> > of phandles.  Was I wrong?
> 
> Indeed, that is correct.  And they are!
> 
> => fdt addr c00000
> => fdt print /aliases
> aliases {
>         ethernet0 = "/soc8641@f8000000/ethernet@24000";
>         ethernet1 = "/soc8641@f8000000/ethernet@25000";
>         ethernet2 = "/soc8641@f8000000/ethernet@26000";
>         ethernet3 = "/soc8641@f8000000/ethernet@27000";
>         serial0 = "/soc8641@f8000000/serial@4500";
>         serial1 = "/soc8641@f8000000/serial@4600";
>         pci0 = "/pcie@f8008000";
>         pci1 = "/pcie@f8009000";
> };
> => bootm 1000000 - c00000
> 
> Grant, you need to keep up, man.  Just this morning
> I pushed Gibson's patch to DTC to support this. :-)

So now the in-kernel version of DTC needs to support this.

josh

^ permalink raw reply

* Re: [PATCH v2 2/4] [libata] pata_of_platform: OF-Platform PATA device driver
From: Scott Wood @ 2007-12-05 18:39 UTC (permalink / raw)
  To: Paul Mundt
  Cc: Olof Johansson, linux-ide, Jeff Garzik, Arnd Bergmann,
	linuxppc-dev
In-Reply-To: <20071205004841.GA25905@linux-sh.org>

On Wed, Dec 05, 2007 at 09:48:41AM +0900, Paul Mundt wrote:
> On Tue, Dec 04, 2007 at 02:01:21PM -0600, Olof Johansson wrote:
> > On Tue, Dec 04, 2007 at 10:49:21PM +0300, Anton Vorontsov wrote:
> > >  	tristate "Generic platform device PATA support"
> > > -	depends on EMBEDDED || ARCH_RPC
> > > +	depends on EMBEDDED || ARCH_PPC
> > 
> > It needs to be || PPC, not || ARCH_PPC.
> > 
> Wrong. It needs to be EMBEDDED || ARCH_RPC || PPC.

Why is it dependent on anything other than platform bus support and ATA?

-Scott

^ permalink raw reply

* Re: drivers/net/iseries_veth.c dubious sysfs usage
From: Greg KH @ 2007-12-05 21:41 UTC (permalink / raw)
  To: Michael Ellerman
  Cc: linuxppc-dev, Kyle A. Lucke, paulus, linux-kernel, David Gibson
In-Reply-To: <1196853031.6759.7.camel@concordia>

On Wed, Dec 05, 2007 at 10:10:31PM +1100, Michael Ellerman wrote:
> On Wed, 2007-12-05 at 01:30 -0800, Greg KH wrote:
> > In doing a massive kobject cleanup of the kernel tree, I ran across the
> > iseries_veth.c driver.
> > 
> > It looks like the driver is creating a number of subdirectories under
> > the driver sysfs directory.  This is odd and probably wrong.  You want
> > these virtual connections to show up in the main sysfs device tree, not
> > under the driver directory.
> > 
> > I'll be glad to totally guess and try to move it around in the sysfs
> > tree, but odds are I'll get it all wrong as I can't really test this
> > out :)
> > 
> > Any hints on what this driver is trying to do in this sysfs directories?
> 
> I wrote the code, I think, but it's been a while - I'll have a look at
> it tomorrow.

Yes, can you send me the sysfs tree output of the driver directory, and
what exactly the different files in there are supposed to be used for?

> Why is it "odd and probably wrong" to create subdirectories under the
> driver in sysfs?

Because a driver does not have "devices" under it in the sysfs tree.
All devices liven in the /sys/devices/ tree so we can properly manage
them that way.  A driver will then bind to a device, and the driver core
will set up the linkages in sysfs properly so that everthing looks
uniform.

By creating subdirectories associated with a driver, this breaks the
model that the entire rest of the kernel is using, which is something
that you really don't want to be doing :)

How about describing what you were trying to achieve with these
directories and files?

thanks,

greg k-h

^ permalink raw reply

* RE: Uboot and ML410
From: John Hahn @ 2007-12-05 21:01 UTC (permalink / raw)
  To: linuxppc-embedded
In-Reply-To: <14177109.post@talk.nabble.com>

We are also using 3.81 make (Centos 5 distro) with ELDK 4.1 version
downloaded from www.denx.de and have had no problems using the u-boot.zip
srcs from www.xilinx.com/ml410_p, though we use uboot for our ml403 based
development, we can build u-boot for ml403_config as well as ml410_config.


Cheers

John
_________________
John S Hahn
BCF Semiconductor



> -----Original Message-----
> From: linuxppc-embedded-bounces+jhahn=bcfsemi.com@ozlabs.org
> [mailto:linuxppc-embedded-bounces+jhahn=bcfsemi.com@ozlabs.org] On
> Behalf Of khollan
> Sent: Wednesday, December 05, 2007 10:00 AM
> To: linuxppc-embedded@ozlabs.org
> Subject: Uboot and ML410
> 
> 
> Hi
> 
> Is there a patch to include support for the ml410 in the Main git tree
> of u-boot?  I tried compiling Xilinx's tree but it seems it won't
> compile correctly with my version of make (3.81).  Also is there any
> support for the Hard TEMAC in u-boot?  I tried looking for both of
> these questions but a lot of the threads were unanswered questions.
> Thanks for your help
> 
> kholland
> --

^ permalink raw reply

* Re: [PATCH] Add aliases node to 8641hpcn DTS file.
From: Mark A. Greer @ 2007-12-05 22:28 UTC (permalink / raw)
  To: Jon Loeliger; +Cc: linuxppc-dev@ozlabs.org
In-Reply-To: <1196875970.8544.12.camel@ld0161-tx32>

On Wed, Dec 05, 2007 at 11:32:50AM -0600, Jon Loeliger wrote:

> diff --git a/arch/powerpc/boot/dts/mpc8641_hpcn.dts b/arch/powerpc/boot/dts/mpc8641_hpcn.dts
> index abb26dc..b039f21 100644
> --- a/arch/powerpc/boot/dts/mpc8641_hpcn.dts
> +++ b/arch/powerpc/boot/dts/mpc8641_hpcn.dts
> @@ -16,6 +16,17 @@
>  	#address-cells = <1>;
>  	#size-cells = <1>;
>  
> +	aliases {
> +		ethernet0 = &enet0;
> +		ethernet1 = &enet1;
> +		ethernet2 = &enet2;
> +		ethernet3 = &enet3;
> +		serial0 = &serial0;
> +		serial1 = &serial1;
> +		pci0 = &pci0;
> +		pci1 = &pci1;
> +	};
> +
>  	cpus {
>  		#address-cells = <1>;
>  		#size-cells = <0>;
> @@ -107,7 +118,7 @@
>  			};
>  		};
>  
> -		ethernet@24000 {
> +		enet0: ethernet@24000 {
>  			#address-cells = <1>;
>  			#size-cells = <0>;
>  			device_type = "network";

This is probably a dumb question but I'll ask it anyway.

What's the point of 'aliases' when you already have labels?
E.g., why not just use enet0 instead of making an ethernet0 alias?

Mark

^ permalink raw reply

* Re: [PATCH] Add aliases node to 8641hpcn DTS file.
From: David Gibson @ 2007-12-05 22:33 UTC (permalink / raw)
  To: Mark A. Greer; +Cc: linuxppc-dev@ozlabs.org
In-Reply-To: <20071205222816.GA3725@mag.az.mvista.com>

On Wed, Dec 05, 2007 at 03:28:16PM -0700, Mark A. Greer wrote:
> On Wed, Dec 05, 2007 at 11:32:50AM -0600, Jon Loeliger wrote:
> 
> > diff --git a/arch/powerpc/boot/dts/mpc8641_hpcn.dts b/arch/powerpc/boot/dts/mpc8641_hpcn.dts
> > index abb26dc..b039f21 100644
> > --- a/arch/powerpc/boot/dts/mpc8641_hpcn.dts
> > +++ b/arch/powerpc/boot/dts/mpc8641_hpcn.dts
> > @@ -16,6 +16,17 @@
> >  	#address-cells = <1>;
> >  	#size-cells = <1>;
> >  
> > +	aliases {
> > +		ethernet0 = &enet0;
> > +		ethernet1 = &enet1;
> > +		ethernet2 = &enet2;
> > +		ethernet3 = &enet3;
> > +		serial0 = &serial0;
> > +		serial1 = &serial1;
> > +		pci0 = &pci0;
> > +		pci1 = &pci1;
> > +	};
> > +
> >  	cpus {
> >  		#address-cells = <1>;
> >  		#size-cells = <0>;
> > @@ -107,7 +118,7 @@
> >  			};
> >  		};
> >  
> > -		ethernet@24000 {
> > +		enet0: ethernet@24000 {
> >  			#address-cells = <1>;
> >  			#size-cells = <0>;
> >  			device_type = "network";
> 
> This is probably a dumb question but I'll ask it anyway.
> 
> What's the point of 'aliases' when you already have labels?
> E.g., why not just use enet0 instead of making an ethernet0 alias?

The aliase information is available in the output tree, whereas labels
are only internal to dtc (well, except for asm output).

I'm planning to add support later to automatically generate aliases
from specially marked labels.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

^ permalink raw reply

* Re: dtc: RFC: Fix some lexical problems with references
From: Josh Boyer @ 2007-12-05 22:34 UTC (permalink / raw)
  To: David Gibson; +Cc: linuxppc-dev
In-Reply-To: <20071122061007.GA22888@localhost.localdomain>

On Thu, 22 Nov 2007 17:10:07 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:

> The recent change to the lexer to only recognize property and node
> names in the appropriate context removed a number of lexical warts in
> our language that would have gotten ugly as we add expression support
> and so forth.
> 
> But there's one nasty one remaining: references can contain a full
> path, including the various problematic node name characters (',', '+'
> and '-', for example).  This would cause trouble with expressions, and
> it also causes trouble with the patch I'm working on to allow
> expanding references to paths rather than phandles.  This patch
> therefore reworks the lexer to mitigate these problems.
> 
> 	- References to labels cause no problems.  These are now
> recognized separately from references to full paths.  No syntax change
> here.
> 
> 	- References to full paths, including problematic characters
> are allowed by "quoting" the path with braces
> e.g. &{/pci@10000/somedevice@3,8000}.  The braces protect any internal
> problematic characters from being confused with operators or whatever.
> 
> 	- For compatibility with existing dts files, in v0 dts files
> we allow bare references to paths as before &/foo/bar/whatever - but
> *only* if the path contains no troublesome characters.  Specifically
> only [a-zA-Z0-9_@/] are allowed.
> 
> This is an incompatible change to the dts-v1 format, but since AFAIK
> no-one has yet switched to dts-v1 files, I think we can get away with
> it.  Better to make the transition when people to convert to v1, and
> get rid of the problematic old syntax.
> 
> Strictly speaking, it's also an incompatible change to the v0 format,
> since some path references that were allowed before are no longer
> allowed.  I suspect no-one has been using the no-longer-supported
> forms (certainly none of the kernel dts files will cause trouble).  We
> might need to think about this harder, though.
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>

So this breaks some of the in-kernel DTS files.  Example, bamboo.dts on
line 19 produces:

bamboo.dts: 19 syntax error
FATAL ERROR: Couldn't read input tree

I tried quoting the path with {} but that didn't seem to work.

josh

^ permalink raw reply

* [PATCH v2] qe: add ability to upload QE firmware
From: Timur Tabi @ 2007-12-05 22:41 UTC (permalink / raw)
  To: arnd, galak, linuxppc-dev; +Cc: Timur Tabi

Define the layout of a binary blob that contains a QE firmware and instructions
on how to upload it.  Add function qe_upload_firmware() to parse the blob
and perform the actual upload.  Fully define 'struct rsp' in immap_qe.h to
include the actual RISC Special Registers.

Signed-off-by: Timur Tabi <timur@freescale.com>
---

Updated to add information on a new 'firmware' child node to the QE node,
and added code to parse that node.  This allows U-Boot to upload a firmware
and pass the data to the kernel.

This patch is for Kumar's for-2.6.25 branch.  This code is necessary for
my QE UART driver.

 Documentation/powerpc/00-INDEX        |    3 +
 Documentation/powerpc/qe_firmware.txt |  295 +++++++++++++++++++++++++++++++++
 arch/powerpc/platforms/Kconfig        |    1 +
 arch/powerpc/sysdev/qe_lib/qe.c       |  240 +++++++++++++++++++++++++++
 include/asm-powerpc/immap_qe.h        |   34 ++++-
 include/asm-powerpc/qe.h              |   61 +++++++
 6 files changed, 632 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/powerpc/qe_firmware.txt

diff --git a/Documentation/powerpc/00-INDEX b/Documentation/powerpc/00-INDEX
index 94a3c57..3be84aa 100644
--- a/Documentation/powerpc/00-INDEX
+++ b/Documentation/powerpc/00-INDEX
@@ -28,3 +28,6 @@ sound.txt
 	- info on sound support under Linux/PPC
 zImage_layout.txt
 	- info on the kernel images for Linux/PPC
+qe_firmware.txt
+	- describes the layout of firmware binaries for the Freescale QUICC
+	  Engine and the code that parses and uploads the microcode therein.
diff --git a/Documentation/powerpc/qe_firmware.txt b/Documentation/powerpc/qe_firmware.txt
new file mode 100644
index 0000000..8962664
--- /dev/null
+++ b/Documentation/powerpc/qe_firmware.txt
@@ -0,0 +1,295 @@
+	   Freescale QUICC Engine Firmware Uploading
+	   -----------------------------------------
+
+(c) 2007 Timur Tabi <timur at freescale.com>,
+    Freescale Semiconductor
+
+Table of Contents
+=================
+
+  I - Software License for Firmware
+
+  II - Microcode Availability
+
+  III - Description and Terminology
+
+  IV - Microcode Programming Details
+
+  V - Firmware Structure Layout
+
+  VI - Sample Code for Creating Firmware Files
+
+Revision Information
+====================
+
+November 30, 2007: Rev 1.0 - Initial version
+
+I - Software License for Firmware
+=================================
+
+Each firmware file comes with its own software license.  For information on
+the particular license, please see the license text that is distributed with
+the firmware.
+
+II - Microcode Availability
+===========================
+
+Firmware files are distributed through various channels.  Some are available on
+http://opensource.freescale.com.  For other firmware files, please contact
+your Freescale representative or your operating system vendor.
+
+III - Description and Terminology
+================================
+
+In this document, the term 'microcode' refers to the sequence of 32-bit
+integers that compose the actual QE microcode.
+
+The term 'firmware' refers to a binary blob that contains the microcode as
+well as other data that
+
+	1) describes the microcode's purpose
+	2) describes how and where to upload the microcode
+	3) specifies the values of various registers
+	4) includes additional data for use by specific device drivers
+
+Firmware files are binary files that contain only a firmware.
+
+IV - Microcode Programming Details
+===================================
+
+The QE architecture allows for only one microcode present in I-RAM for each
+RISC processor.  To replace any current microcode, a full QE reset (which
+disables the microcode) must be performed first.
+
+QE microcode is uploaded using the following procedure:
+
+1) The microcode is placed into I-RAM at a specific location, using the
+   IRAM.IADD and IRAM.IDATA registers.
+
+2) The CERCR.CIR bit is set to 0 or 1, depending on whether the firmware
+   needs split I-RAM.  Split I-RAM is only meaningful for SOCs that have
+   QEs with multiple RISC processors, such as the 8360.  Splitting the I-RAM
+   allows each processor to run a different microcode, effectively creating an
+   asymmetric multiprocessing (AMP) system.
+
+3) The TIBCR trap registers are loaded with the addresses of the trap handlers
+   in the microcode.
+
+4) The RSP.ECCR register is programmed with the value provided.
+
+5) If necessary, device drivers that need the virtual traps and extended mode
+   data will use them.
+
+Virtual Microcode Traps
+
+These virtual traps are conditional branches in the microcode.  These are
+"soft" provisional introduced in the ROMcode in order to enable higher
+flexibility and save h/w traps If new features are activated or an issue is
+being fixed in the RAM package utilizing they should be activated.  This data
+structure signals the microcode which of these virtual traps is active.
+
+This structure contains 6 words that the application should copy to some
+specific been defined.  This table describes the structure.
+
+	---------------------------------------------------------------
+	| Offset in |                  | Destination Offset | Size of |
+	|   array   |     Protocol     |   within PRAM      | Operand |
+	--------------------------------------------------------------|
+	|     0     | Ethernet         |      0xF8          | 4 bytes |
+	|           | interworking     |                    |         |
+	---------------------------------------------------------------
+	|     4     | ATM              |      0xF8          | 4 bytes |
+	|           | interworking     |                    |         |
+	---------------------------------------------------------------
+	|     8     | PPP              |      0xF8          | 4 bytes |
+	|           | interworking     |                    |         |
+	---------------------------------------------------------------
+	|     12    | Ethernet RX      |      0x22          | 1 byte  |
+	|           | Distributor Page |                    |         |
+	---------------------------------------------------------------
+	|     16    | ATM Globtal      |      0x28          | 1 byte  |
+	|           | Params Table     |                    |         |
+	---------------------------------------------------------------
+	|     20    | Insert Frame     |      0xF8          | 4 bytes |
+	---------------------------------------------------------------
+
+
+Extended Modes
+
+This is a double word bit array (64 bits) that defines special functionality
+which has an impact on the softwarew drivers.  Each bit has its own impact
+and has special instructions for the s/w associated with it.  This structure is
+described in this table:
+
+	-----------------------------------------------------------------------
+	| Bit #  |     Name     |   Description                               |
+	-----------------------------------------------------------------------
+	|   0    | General      | Indicates that prior to each host command   |
+	|        | push command | given by the application, the software must |
+	|        |              | assert a special host command (push command)|
+	|        |              | CECDR = 0x00800000.                         |
+	|        |              | CECR = 0x01c1000f.                          |
+	-----------------------------------------------------------------------
+	|   1    | UCC ATM      | Indicates that after issuing ATM RX INIT    |
+	|        | RX INIT      | command, the host must issue another special|
+	|        | push command | command (push command) and immediately      |
+	|        |              | following that re-issue the ATM RX INIT     |
+	|        |              | command. (This makes the sequence of        |
+	|        |              | initializing the ATM receiver a sequence of |
+	|        |              | three host commands)                        |
+	|        |              | CECDR = 0x00800000.                         |
+	|        |              | CECR = 0x01c1000f.                          |
+	-----------------------------------------------------------------------
+	|   2    | Add/remove   | Indicates that following the specific host  |
+	|        | command      | command: "Add/Remove entry in Hash Lookup   |
+	|        | validation   | Table" used in Interworking setup, the user |
+	|        |              | must issue another command.                 |
+	|        |              | CECDR = 0xce000003.                         |
+	|        |              | CECR = 0x01c10f58.                          |
+	-----------------------------------------------------------------------
+	|   3    | General push | Indicates that the s/w has to initialize    |
+	|        | command      | some pointers in the Ethernet thread pages  |
+	|        |              | which are used when Header Compression is   |
+	|        |              | activated.  The full details of these       |
+	|        |              | pointers is located in the software drivers.|
+	-----------------------------------------------------------------------
+	|   4    | General push | Indicates that after issuing Ethernet TX    |
+	|        | command      | INIT command, user must issue this command  |
+	|        |              | for each SNUM of Ethernet TX thread.        |
+	|        |              | CECDR = 0x00800003.                         |
+	|        |              | CECR = 0x7'b{0}, 8'b{Enet TX thread SNUM},  |
+	|        |              |        1'b{1}, 12'b{0}, 4'b{1}              |
+	-----------------------------------------------------------------------
+	| 5 - 31 |     N/A      | Reserved, set to zero.                      |
+	-----------------------------------------------------------------------
+
+V - Firmware Structure Layout
+==============================
+
+QE microcode from Freescale is typically provided as a header file.  This
+header file contains macros that define the microcode binary itself as well as
+some other data used in uploading that microcode.  The format of these files
+do not lend themselves to simple inclusion into other code.  Hence,
+the need for a more portable format.  This section defines that format.
+
+Instead of distributing a header file, the microcode and related data are
+embedded into a binary blob.  This blob is passed to the qe_upload_firmware()
+function, which parses the blob and performs everything necessary to upload
+the microcode.
+
+All integers are big-endian.  See the comments for function
+qe_upload_firmware() for up-to-date implementation information.
+
+This structure supports versioning, where the version of the structure is
+embedded into the structure itself.  To ensure forward and backwards
+compatibility, all versions of the structure must use the same 'qe_header'
+structure at the beginning.
+
+'header' (type: struct qe_header):
+	The 'length' field is the size, in bytes, of the entire structure,
+	including all the microcode embedded in it, as well as the CRC (if
+	present).
+
+	The 'magic' field is an array of three bytes that contains the letters
+	'Q', 'E', and 'F'.  This is an identifier that indicates that this
+	structure is a QE Firmware structure.
+
+	The 'version' field is a single byte that indicates the version of this
+	structure.  If the layout of the structure should ever need to be
+	changed to add support for additional types of microcode, then the
+	version number should also be changed.
+
+The 'id' field is a null-terminated string(suitable for printing) that
+identifies the firmware.
+
+The 'count' field indicates the number of 'microcode' structures.  There
+must be one and only one 'microcode' structure for each RISC processor.
+Therefore, this field also represents the number of RISC processors for this
+SOC.
+
+The 'soc' structure contains the SOC numbers and revisions used to match
+the microcode to the SOC itself.  Normally, the microcode loader should
+check the data in this structure with the SOC number and revisions, and
+only upload the microcode if there's a match.  However, this check is not
+made on all platforms.
+
+Although it is not recommended, you can specify '0' in the soc.model
+field to skip matching SOCs altogether.
+
+The 'model' field is a 16-bit number that matches the actual SOC. The
+'major' and 'minor' fields are the major and minor revision numbrs,
+respectively, of the SOC.
+
+For example, to match the 8323, revision 1.0:
+     soc.model = 8323
+     soc.major = 1
+     soc.minor = 0
+
+'padding' is neccessary for structure alignment.  This field ensures that the
+'extended_modes' field is aligned on a 64-bit boundary.
+
+'extended_modes' is a bitfield that defines special functionality which has an
+impact on the device drivers.  Each bit has its own impact and has special
+instructions for the driver associated with it.  This field is stored in
+the QE library and available to any driver that calles qe_get_firmware_info().
+
+'vtraps' is an array of 8 words that contain virtual trap values for each
+virtual traps.  As with 'extended_modes', this field is stored in the QE
+library and available to any driver that calles qe_get_firmware_info().
+
+'microcode' (type: struct qe_microcode):
+	For each RISC processor there is one 'microcode' structure.  The first
+	'microcode' structure is for the first RISC, and so on.
+
+	The 'id' field is a null-terminated string suitable for printing that
+	identifies this particular microcode.
+
+	'traps' is an array of 16 words that contain hardware trap values
+	for each of the 16 traps.  If trap[i] is 0, then this particular
+	trap is to be ignored (i.e. not written to TIBCR[i]).  The entire value
+	is written as-is to the TIBCR[i] register, so be sure to set the EN
+	and T_IBP bits if necessary.
+
+	'eccr' is the value to program into the ECCR register.
+
+	'iram_offset' is the offset into IRAM to start writing the
+	microcode.
+
+	'count' is the number of 32-bit words in the microcode.
+
+	'code_offset' is the offset, in bytes, from the beginning of this
+	structure where the microcode itself can be found.  The first
+	microcode binary should be located immediately after the 'microcode'
+	array.
+
+	'major', 'minor', and 'revision' are the major, minor, and revision
+	version numbers, respectively, of the microcode.  If all values are 0,
+	then these fields are ignored.
+
+	'reserved' is necessary for structure alignment.  Since 'microcode'
+	is an array, the 64-bit 'extended_modes' field needs to be aligned
+	on a 64-bit boundary, and this can only happen if the size of
+	'microcode' is a multiple of 8 bytes.  To ensure that, we add
+	'reserved'.
+
+After the last microcode is a 32-bit CRC.  It can be calculated using
+this algorithm:
+
+u32 crc32(const u8 *p, unsigned int len)
+{
+	unsigned int i;
+	u32 crc = 0;
+
+	while (len--) {
+	   crc ^= *p++;
+	   for (i = 0; i < 8; i++)
+		   crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
+	}
+	return crc;
+}
+
+VI - Sample Code for Creating Firmware Files
+============================================
+
+A Python program that creates firmware binaries from the header files normally
+distributed by Freescale can be found on http://opensource.freescale.com.
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index ea22cad..18f101b 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -265,6 +265,7 @@ config TAU_AVERAGE
 config QUICC_ENGINE
 	bool
 	select PPC_LIB_RHEAP
+	select CRC32
 	help
 	  The QUICC Engine (QE) is a new generation of communications
 	  coprocessors on Freescale embedded CPUs (akin to CPM in older chips).
diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c
index 1df3b4a..497eb88 100644
--- a/arch/powerpc/sysdev/qe_lib/qe.c
+++ b/arch/powerpc/sysdev/qe_lib/qe.c
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
+#include <linux/crc32.h>
 #include <asm/irq.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -362,3 +363,242 @@ void *qe_muram_addr(unsigned long offset)
 	return (void *)&qe_immr->muram[offset];
 }
 EXPORT_SYMBOL(qe_muram_addr);
+
+/* The maximum number of RISCs we support */
+#define MAX_QE_RISC     2
+
+/* Firmware information stored here for qe_get_firmware_info() */
+static struct qe_firmware_info qe_firmware_info;
+
+/*
+ * Set to 1 if QE firmware has been uploaded, and therefore
+ * qe_firmware_info contains valid data.
+ */
+static int qe_firmware_uploaded;
+
+/*
+ * Upload a QE microcode
+ *
+ * This function is a worker function for qe_upload_firmware().  It does
+ * the actual uploading of the microcode.
+ */
+static void qe_upload_microcode(const void *base,
+	const struct qe_microcode *ucode)
+{
+	const __be32 *code = base + be32_to_cpu(ucode->code_offset);
+	unsigned int i;
+
+	if (ucode->major || ucode->minor || ucode->revision)
+		printk(KERN_INFO "qe-firmware: "
+			"uploading microcode '%s' version %u.%u.%u\n",
+			ucode->id, ucode->major, ucode->minor, ucode->revision);
+	else
+		printk(KERN_INFO "qe-firmware: "
+			"uploading microcode '%s'\n", ucode->id);
+
+	/* Use auto-increment */
+	out_be32(&qe_immr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
+		QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
+
+	for (i = 0; i < be32_to_cpu(ucode->count); i++)
+		out_be32(&qe_immr->iram.idata, be32_to_cpu(code[i]));
+}
+
+/*
+ * Upload a microcode to the I-RAM at a specific address.
+ *
+ * See Documentation/powerpc/qe-firmware.txt for information on QE microcode
+ * uploading.
+ *
+ * Currently, only version 1 is supported, so the 'version' field must be
+ * set to 1.
+ *
+ * The SOC model and revision are not validated, they are only displayed for
+ * informational purposes.
+ *
+ * 'calc_size' is the calculated size, in bytes, of the firmware structure and
+ * all of the microcode structures, minus the CRC.
+ *
+ * 'length' is the size that the structure says it is, including the CRC.
+ */
+int qe_upload_firmware(const struct qe_firmware *firmware)
+{
+	unsigned int i;
+	unsigned int j;
+	u32 crc;
+	size_t calc_size = sizeof(struct qe_firmware);
+	size_t length;
+	const struct qe_header *hdr;
+
+	if (!firmware) {
+		printk(KERN_ERR "qe-firmware: invalid pointer\n");
+		return -EINVAL;
+	}
+
+	hdr = &firmware->header;
+	length = be32_to_cpu(hdr->length);
+
+	/* Check the magic */
+	if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
+	    (hdr->magic[2] != 'F')) {
+		printk(KERN_ERR "qe-firmware: not a microcode\n");
+		return -EPERM;
+	}
+
+	/* Check the version */
+	if (hdr->version != 1) {
+		printk(KERN_ERR "qe-firmware: unsupported version\n");
+		return -EPERM;
+	}
+
+	/* Validate some of the fields */
+	if ((firmware->count < 1) || (firmware->count >= MAX_QE_RISC)) {
+		printk(KERN_ERR "qe-firmware: invalid data\n");
+		return -EINVAL;
+	}
+
+	/* Validate the length and check if there's a CRC */
+	calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
+
+	for (i = 0; i < firmware->count; i++)
+		/*
+		 * For situations where the second RISC uses the same microcode
+		 * as the first, the 'code_offset' and 'count' fields will be
+		 * zero, so it's okay to add those.
+		 */
+		calc_size += sizeof(__be32) *
+			be32_to_cpu(firmware->microcode[i].count);
+
+	/* Validate the length */
+	if (length != calc_size + sizeof(__be32)) {
+		printk(KERN_ERR "qe-firmware: invalid length\n");
+		return -EPERM;
+	}
+
+	/* Validate the CRC */
+	crc = be32_to_cpu(*(__be32 *)((void *)firmware + calc_size));
+	if (crc != crc32(0, firmware, calc_size)) {
+		printk(KERN_ERR "qe-firmware: firmware CRC is invalid\n");
+		return -EIO;
+	}
+
+	/*
+	 * If the microcode calls for it, split the I-RAM.
+	 */
+	if (!firmware->split)
+		setbits16(&qe_immr->cp.cercr, QE_CP_CERCR_CIR);
+
+	if (firmware->soc.model)
+		printk(KERN_INFO
+			"qe-firmware: firmware '%s' for %u V%u.%u\n",
+			firmware->id, be16_to_cpu(firmware->soc.model),
+			firmware->soc.major, firmware->soc.minor);
+	else
+		printk(KERN_INFO "qe-firmware: firmware '%s'\n",
+			firmware->id);
+
+	/*
+	 * The QE only supports one microcode per RISC, so clear out all the
+	 * saved microcode information and put in the new.
+	 */
+	memset(&qe_firmware_info, 0, sizeof(qe_firmware_info));
+	strcpy(qe_firmware_info.id, firmware->id);
+	qe_firmware_info.extended_modes = firmware->extended_modes;
+	memcpy(qe_firmware_info.vtraps, firmware->vtraps,
+		sizeof(firmware->vtraps));
+
+	/* Loop through each microcode. */
+	for (i = 0; i < firmware->count; i++) {
+		const struct qe_microcode *ucode = &firmware->microcode[i];
+
+		/* Upload a microcode if it's present */
+		if (ucode->code_offset)
+			qe_upload_microcode(firmware, ucode);
+
+		/* Program the traps for this processor */
+		for (j = 0; j < 16; j++) {
+			u32 trap = be32_to_cpu(ucode->traps[j]);
+
+			if (trap)
+				out_be32(&qe_immr->rsp[i].tibcr[j], trap);
+		}
+
+		/* Enable traps */
+		out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
+	}
+
+	qe_firmware_uploaded = 1;
+
+	return 0;
+}
+EXPORT_SYMBOL(qe_upload_firmware);
+
+/*
+ * Get info on the currently-loaded firmware
+ *
+ * This function also checks the device tree to see if the boot loader has
+ * uploaded a firmware already.
+ */
+struct qe_firmware_info *qe_get_firmware_info(void)
+{
+	static int initialized;
+
+	/*
+	 * If we haven't checked yet, and a driver hasn't uploaded a firmware
+	 * yet, then check the device tree for information.
+	 */
+	do {
+		struct device_node *qe;
+		struct device_node *fw = NULL;
+		const char *sprop;
+		const u32 *iprop;
+
+		if (initialized || qe_firmware_uploaded)
+			break;
+
+		initialized = 1;
+
+		qe = of_find_node_by_type(NULL, "qe");
+		if (!qe)
+			break;
+
+		/* Find the 'firmware' child node */
+		while ((fw = of_get_next_child(qe, fw)))
+			if (strcmp(fw->name, "firmware") == 0)
+				break;
+
+		/* Did we find the 'firmware' node? */
+		if (!fw) {
+			of_node_put(qe);
+			break;
+		}
+
+		qe_firmware_uploaded = 1;
+
+		/* Copy the data into qe_firmware_info*/
+		sprop = of_get_property(fw, "id", NULL);
+		if (sprop)
+			strncpy(qe_firmware_info.id, sprop,
+				sizeof(qe_firmware_info.id) - 1);
+
+		iprop = of_get_property(fw, "extended_modes", NULL);
+		if (iprop)
+			qe_firmware_info.extended_modes =
+				(u64) iprop[0] << 32 | iprop[1];
+
+		iprop = of_get_property(fw, "virtual_traps", NULL);
+		if (iprop) {
+			unsigned int i = 0;
+
+			for (; i < ARRAY_SIZE(qe_firmware_info.vtraps); i++)
+				qe_firmware_info.vtraps[i] = iprop[i];
+		}
+
+		of_node_put(fw);
+		of_node_put(qe);
+	} while (0);
+
+	return qe_firmware_uploaded ? &qe_firmware_info : NULL;
+}
+EXPORT_SYMBOL(qe_get_firmware_info);
+
diff --git a/include/asm-powerpc/immap_qe.h b/include/asm-powerpc/immap_qe.h
index aba9806..82a4526 100644
--- a/include/asm-powerpc/immap_qe.h
+++ b/include/asm-powerpc/immap_qe.h
@@ -393,9 +393,39 @@ struct dbg {
 	u8	res2[0x48];
 } __attribute__ ((packed));
 
-/* RISC Special Registers (Trap and Breakpoint) */
+/*
+ * RISC Special Registers (Trap and Breakpoint).  These are described in
+ * the QE Developer's Handbook.
+ */
 struct rsp {
-	u32	reg[0x40];	/* 64 32-bit registers */
+	__be32 tibcr[16];	/* Trap/instruction breakpoint control regs */
+	u8 res0[64];
+	__be32 ibcr0;
+	__be32 ibs0;
+	__be32 ibcnr0;
+	u8 res1[4];
+	__be32 ibcr1;
+	__be32 ibs1;
+	__be32 ibcnr1;
+	__be32 npcr;
+	__be32 dbcr;
+	__be32 dbar;
+	__be32 dbamr;
+	__be32 dbsr;
+	__be32 dbcnr;
+	u8 res2[12];
+	__be32 dbdr_h;
+	__be32 dbdr_l;
+	__be32 dbdmr_h;
+	__be32 dbdmr_l;
+	__be32 bsr;
+	__be32 bor;
+	__be32 bior;
+	u8 res3[4];
+	__be32 iatr[4];
+	__be32 eccr;		/* Exception control configuration register */
+	__be32 eicr;
+	u8 res4[0x100-0xf8];
 } __attribute__ ((packed));
 
 struct qe_immap {
diff --git a/include/asm-powerpc/qe.h b/include/asm-powerpc/qe.h
index bcf60be..35c7b8d 100644
--- a/include/asm-powerpc/qe.h
+++ b/include/asm-powerpc/qe.h
@@ -93,6 +93,58 @@ unsigned long qe_muram_alloc_fixed(unsigned long offset, int size);
 void qe_muram_dump(void);
 void *qe_muram_addr(unsigned long offset);
 
+/* Structure that defines QE firmware binary files.
+ *
+ * See Documentation/powerpc/qe-firmware.txt for a description of these
+ * fields.
+ */
+struct qe_firmware {
+	struct qe_header {
+		__be32 length;  /* Length of the entire structure, in bytes */
+		u8 magic[3];    /* Set to { 'Q', 'E', 'F' } */
+		u8 version;     /* Version of this layout. First ver is '1' */
+	} header;
+	u8 id[62];      /* Null-terminated identifier string */
+	u8 split;	/* 0 = shared I-RAM, 1 = split I-RAM */
+	u8 count;       /* Number of microcode[] structures */
+	struct {
+		__be16 model;   	/* The SOC model  */
+		u8 major;       	/* The SOC revision major */
+		u8 minor;       	/* The SOC revision minor */
+	} __attribute__ ((packed)) soc;
+	u8 padding[4];			/* Reserved, for alignment */
+	__be64 extended_modes;		/* Extended modes */
+	__be32 vtraps[8];		/* Virtual trap addresses */
+	u8 reserved[4];			/* Reserved, for future expansion */
+	struct qe_microcode {
+		u8 id[32];      	/* Null-terminated identifier */
+		__be32 traps[16];       /* Trap addresses, 0 == ignore */
+		__be32 eccr;    	/* The value for the ECCR register */
+		__be32 iram_offset;     /* Offset into I-RAM for the code */
+		__be32 count;   	/* Number of 32-bit words of the code */
+		__be32 code_offset;     /* Offset of the actual microcode */
+		u8 major;       	/* The microcode version major */
+		u8 minor;       	/* The microcode version minor */
+		u8 revision;		/* The microcode version revision */
+		u8 padding;		/* Reserved, for alignment */
+		u8 reserved[4];		/* Reserved, for future expansion */
+	} __attribute__ ((packed)) microcode[1];
+	/* All microcode binaries should be located here */
+	/* CRC32 should be located here, after the microcode binaries */
+} __attribute__ ((packed));
+
+struct qe_firmware_info {
+	char id[64];		/* Firmware name */
+	u32 vtraps[8];		/* Virtual trap addresses */
+	u64 extended_modes;	/* Extended modes */
+};
+
+/* Upload a firmware to the QE */
+int qe_upload_firmware(const struct qe_firmware *firmware);
+
+/* Obtain information on the uploaded firmware */
+struct qe_firmware_info *qe_get_firmware_info(void);
+
 /* Buffer descriptors */
 struct qe_bd {
 	__be16 status;
@@ -328,6 +380,15 @@ enum comm_dir {
 
 #define QE_SDEBCR_BA_MASK	0x01FFFFFF
 
+/* Communication Processor */
+#define QE_CP_CERCR_MEE		0x8000	/* Multi-user RAM ECC enable */
+#define QE_CP_CERCR_IEE		0x4000	/* Instruction RAM ECC enable */
+#define QE_CP_CERCR_CIR		0x0800	/* Common instruction RAM */
+
+/* I-RAM */
+#define QE_IRAM_IADD_AIE	0x80000000	/* Auto Increment Enable */
+#define QE_IRAM_IADD_BADDR	0x00080000	/* Base Address */
+
 /* UPC */
 #define UPGCR_PROTOCOL	0x80000000	/* protocol ul2 or pl2 */
 #define UPGCR_TMS	0x40000000	/* Transmit master/slave mode */
-- 
1.5.2.4

^ permalink raw reply related

* Re: dtc: RFC: Fix some lexical problems with references
From: Josh Boyer @ 2007-12-05 22:44 UTC (permalink / raw)
  To: Josh Boyer; +Cc: linuxppc-dev, David Gibson
In-Reply-To: <20071205163409.77fba42b@zod.rchland.ibm.com>

On Wed, 5 Dec 2007 16:34:09 -0600
Josh Boyer <jwboyer@linux.vnet.ibm.com> wrote:

> On Thu, 22 Nov 2007 17:10:07 +1100
> David Gibson <david@gibson.dropbear.id.au> wrote:
> 
> > The recent change to the lexer to only recognize property and node
> > names in the appropriate context removed a number of lexical warts in
> > our language that would have gotten ugly as we add expression support
> > and so forth.
> > 
> > But there's one nasty one remaining: references can contain a full
> > path, including the various problematic node name characters (',', '+'
> > and '-', for example).  This would cause trouble with expressions, and
> > it also causes trouble with the patch I'm working on to allow
> > expanding references to paths rather than phandles.  This patch
> > therefore reworks the lexer to mitigate these problems.
> > 
> > 	- References to labels cause no problems.  These are now
> > recognized separately from references to full paths.  No syntax change
> > here.
> > 
> > 	- References to full paths, including problematic characters
> > are allowed by "quoting" the path with braces
> > e.g. &{/pci@10000/somedevice@3,8000}.  The braces protect any internal
> > problematic characters from being confused with operators or whatever.
> > 
> > 	- For compatibility with existing dts files, in v0 dts files
> > we allow bare references to paths as before &/foo/bar/whatever - but
> > *only* if the path contains no troublesome characters.  Specifically
> > only [a-zA-Z0-9_@/] are allowed.
> > 
> > This is an incompatible change to the dts-v1 format, but since AFAIK
> > no-one has yet switched to dts-v1 files, I think we can get away with
> > it.  Better to make the transition when people to convert to v1, and
> > get rid of the problematic old syntax.
> > 
> > Strictly speaking, it's also an incompatible change to the v0 format,
> > since some path references that were allowed before are no longer
> > allowed.  I suspect no-one has been using the no-longer-supported
> > forms (certainly none of the kernel dts files will cause trouble).  We
> > might need to think about this harder, though.
> > 
> > Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> 
> So this breaks some of the in-kernel DTS files.  Example, bamboo.dts on
> line 19 produces:
> 
> bamboo.dts: 19 syntax error
> FATAL ERROR: Couldn't read input tree
> 
> I tried quoting the path with {} but that didn't seem to work.

Nevermind, the quoting worked.

josh

^ permalink raw reply

* Re: [PATCH v2] qe: add ability to upload QE firmware
From: Arnd Bergmann @ 2007-12-05 23:31 UTC (permalink / raw)
  To: Timur Tabi; +Cc: linuxppc-dev
In-Reply-To: <11968944871776-git-send-email-timur@freescale.com>

On Wednesday 05 December 2007, Timur Tabi wrote:
> Define the layout of a binary blob that contains a QE firmware and instru=
ctions
> on how to upload it. =A0Add function qe_upload_firmware() to parse the bl=
ob
> and perform the actual upload. =A0Fully define 'struct rsp' in immap_qe.h=
 to
> include the actual RISC Special Registers.
>=20
> Signed-off-by: Timur Tabi <timur@freescale.com>

The code looks entirely fine to me, but after looking at it, it occurred to
me that you may want to think about having support for autoloading
the firmware based on a property in the device tree. For the spidernet
driver on the Cell blade, we first also did an implementation that called
request_firmware to load the microcode into the spider chip, but we later
added a property (24kb long in our case) that simply contained the whole
blob in the the device tree.
This made it _much_ easier to support things like NFS root and distribution
installers and avoided all licensing problems because the blob can now
be shipped with the board instead of as part of the GPL software.

Of course, that approach does not help you if the blob is not GPL compatible
and you are relying on the dts file to be linked into the kernel, but it
may be good if your driver supports it anyway so you can pass it down from
the system boot loader to the kernel. In your driver, it's just a few lines
of extra code and you can of course still leave the request_firmware call
in place for other scenarios.

	Arnd <><

^ permalink raw reply

* Re: [PATCH v2] qe: add ability to upload QE firmware
From: Timur Tabi @ 2007-12-05 23:37 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linuxppc-dev
In-Reply-To: <200712060031.43171.arnd@arndb.de>

Arnd Bergmann wrote:

> Of course, that approach does not help you if the blob is not GPL compatible
> and you are relying on the dts file to be linked into the kernel, 

Well, the blobs will never be GPL compatible, which is why I created the 
firmware binary format.  Previously, the firmware was shipped as header files 
with code like this:

#define MPC8323_R1_0_UC_PATCH   \
{   \
	  0xb3ff0006   \
	, 0xffffffff   \
	, 0xb3ff0009   \
	, 0xffffffff   \
	, 0xb3ff000c   \
	, 0xffffffff   \

and so on.

To address the issue of loading the firmware before the kernel boots, I have 
ported qe_upload_firmware() to U-Boot, and provided a command-line command for 
uploading a firmware at an address in flash.  The blob can be placed in flash, 
and then a boot script will load it.  The U-Boot version of qe_upload_firmware() 
will also create the 'firmware' node in the device tree.

-- 
Timur Tabi
Linux kernel developer at Freescale

^ permalink raw reply

* [patch] Windfarm plateform module for PowerMac12,1
From: Étienne Bersac @ 2007-12-05 23:37 UTC (permalink / raw)
  To: linuxppc-dev

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

Hi everyone,

Finally, i had time, skills and help from Benjamin Herrenschmidt to
implement the Windfarm plateform module for PowerMac12,1 named
windfarm-pm121. This plateform is used in iMac G5 iSight models (17" and
20").

I review the patch a couple of time, especially the hex values which are
copied from Darwin code. The patch passes thru checkpatch.pl with one
error :) :

Missing Signed-off-by: line(s)


Here is the patch :



diff --git a/arch/powerpc/configs/g5_defconfig b/arch/powerpc/configs/g5_defconfig
index 0a6fa1f..7125837 100644
--- a/arch/powerpc/configs/g5_defconfig
+++ b/arch/powerpc/configs/g5_defconfig
@@ -656,6 +656,7 @@ CONFIG_WINDFARM=y
 CONFIG_WINDFARM_PM81=y
 CONFIG_WINDFARM_PM91=y
 CONFIG_WINDFARM_PM112=y
+CONFIG_WINDFARM_PM121=y
 # CONFIG_PMAC_RACKMETER is not set
 CONFIG_NETDEVICES=y
 # CONFIG_NETDEVICES_MULTIQUEUE is not set
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index 77f50b6..2d028e6 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -234,6 +234,14 @@ config WINDFARM_PM112
 	  which are the recent dual and quad G5 machines using the
 	  970MP dual-core processor.
 
+config WINDFARM_PM121
+	tristate "Support for thermal management on PowerMac12,1"
+	depends on WINDFARM && I2C && PMAC_SMU
+	select I2C_POWERMAC
+	help
+	  This driver provides thermal control for the PowerMac12,1
+	  which is the iMac G5 (iSight) 970MP
+
 config ANSLCD
 	tristate "Support for ANS LCD display"
 	depends on ADB_CUDA && PPC_PMAC
diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile
index 2dfc3f4..e3132ef 100644
--- a/drivers/macintosh/Makefile
+++ b/drivers/macintosh/Makefile
@@ -42,4 +42,9 @@ obj-$(CONFIG_WINDFARM_PM112)	+= windfarm_pm112.o windfarm_smu_sat.o \
 				   windfarm_smu_sensors.o \
 				   windfarm_max6690_sensor.o \
 				   windfarm_lm75_sensor.o windfarm_pid.o
+obj-$(CONFIG_WINDFARM_PM121)	+= windfarm_pm121.o windfarm_smu_sat.o \
+				   windfarm_smu_controls.o \
+				   windfarm_smu_sensors.o \
+				   windfarm_max6690_sensor.o \
+				   windfarm_lm75_sensor.o windfarm_pid.o
 obj-$(CONFIG_PMAC_RACKMETER)	+= rack-meter.o
diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c
index 7e10c3a..b92b959 100644
--- a/drivers/macintosh/windfarm_lm75_sensor.c
+++ b/drivers/macintosh/windfarm_lm75_sensor.c
@@ -127,6 +127,12 @@ static struct wf_lm75_sensor *wf_lm75_create(struct i2c_adapter *adapter,
 	 */
 	if (!strcmp(loc, "Hard drive") || !strcmp(loc, "DRIVE BAY"))
 		lm->sens.name = "hd-temp";
+	else if (!strcmp(loc, "Incoming Air Temp"))
+		lm->sens.name = "incoming-air-temp";
+	else if (!strcmp(loc, "ODD Temp"))
+		lm->sens.name = "optical-drive-temp";
+	else if (!strcmp(loc, "HD Temp"))
+		lm->sens.name = "hard-drive-temp";
 	else
 		goto fail;
 
diff --git a/drivers/macintosh/windfarm_max6690_sensor.c b/drivers/macintosh/windfarm_max6690_sensor.c
index 5f03aab..c2b6d1c 100644
--- a/drivers/macintosh/windfarm_max6690_sensor.c
+++ b/drivers/macintosh/windfarm_max6690_sensor.c
@@ -77,10 +77,11 @@ static struct wf_sensor_ops wf_max6690_ops = {
 	.owner		= THIS_MODULE,
 };
 
-static void wf_max6690_create(struct i2c_adapter *adapter, u8 addr)
+static void wf_max6690_create(struct i2c_adapter *adapter, u8 addr,
+			      const char *loc)
 {
 	struct wf_6690_sensor *max;
-	char *name = "backside-temp";
+	char *name = NULL;
 
 	max = kzalloc(sizeof(struct wf_6690_sensor), GFP_KERNEL);
 	if (max == NULL) {
@@ -89,6 +90,15 @@ static void wf_max6690_create(struct i2c_adapter *adapter, u8 addr)
 		return;
 	}
 
+	if (!strcmp(loc, "BACKSIDE"))
+		name = "backside-temp";
+	else if (!strcmp(loc, "NB Ambient"))
+		name = "north-bridge-temp";
+	else if (!strcmp(loc, "GPU Ambient"))
+		name = "gpu-temp";
+	else
+		goto fail;
+
 	max->sens.ops = &wf_max6690_ops;
 	max->sens.name = name;
 	max->i2c.addr = addr >> 1;
@@ -138,9 +148,7 @@ static int wf_max6690_attach(struct i2c_adapter *adapter)
 		if (loc == NULL || addr == 0)
 			continue;
 		printk("found max6690, loc=%s addr=0x%02x\n", loc, addr);
-		if (strcmp(loc, "BACKSIDE"))
-			continue;
-		wf_max6690_create(adapter, addr);
+		wf_max6690_create(adapter, addr, loc);
 	}
 
 	return 0;
diff --git a/drivers/macintosh/windfarm_pm121.c b/drivers/macintosh/windfarm_pm121.c
new file mode 100644
index 0000000..0cb4b3e
--- /dev/null
+++ b/drivers/macintosh/windfarm_pm121.c
@@ -0,0 +1,1052 @@
+/*
+ * Windfarm PowerMac thermal control. iMac G5 iSight
+ *
+ * (c) Copyright 2007 Étienne Bersac <bersace@gmail.com>
+ *
+ * Bits & pieces from windfarm_pm81.c by (c) Copyright 2005 Benjamin
+ * Herrenschmidt, IBM Corp. <benh@kernel.crashing.org>
+ *
+ * Released under the term of the GNU GPL v2.
+ *
+ *
+ *
+ * PowerMac12,1
+ * ============
+ *
+ *
+ * The algorithm used is the PID control algorithm, used the same way
+ * the published Darwin code does, using the same values that are
+ * present in the Darwin 8.10 snapshot property lists (note however
+ * that none of the code has been re-used, it's a complete
+ * re-implementation
+ *
+ * There is two models using PowerMac12,1. Model 2 is iMac G5 iSight
+ * 17" while Model 3 is iMac G5 20". They do have both the same
+ * controls with a tiny difference. The control-ids of hard-drive-fan
+ * and cpu-fan is swapped.
+ *
+ *
+ * Target Correction :
+ *
+ * controls have a target correction calculated as :
+ *
+ * new_min = ((((average_power * slope) >> 16) + offset) >> 16) + min_value
+ * new_value = max(new_value, max(new_min, 0))
+ *
+ * OD Fan control correction.
+ *
+ * # model_id: 2
+ *   offset		: -19563152
+ *   slope		:  1956315
+ *
+ * # model_id: 3
+ *   offset		: -15650652
+ *   slope		:  1565065
+ *
+ * HD Fan control correction.
+ *
+ * # model_id: 2
+ *   offset		: -15650652
+ *   slope		:  1565065
+ *
+ * # model_id: 3
+ *   offset		: -19563152
+ *   slope		:  1956315
+ *
+ * CPU Fan control correction.
+ *
+ * # model_id: 2
+ *   offset		: -25431900
+ *   slope		:  2543190
+ *
+ * # model_id: 3
+ *   offset		: -15650652
+ *   slope		:  1565065
+ *
+ *
+ * Target rubber-banding :
+ *
+ * Some controls have a target correction which depends on another
+ * control value. The correction is computed in the following way :
+ *
+ * new_min = ref_value * slope + offset
+ *
+ * ref_value is the value of the reference control. If new_min is
+ * greater than 0, then we correct the target value using :
+ *
+ * new_target = max (new_target, new_min >> 16)
+ *
+ *
+ * # model_id : 2
+ *   control	: cpu-fan
+ *   ref	: optical-drive-fan
+ *   offset	: -15650652
+ *   slope	: 1565065
+ *
+ * # model_id : 3
+ *   control	: optical-drive-fan
+ *   ref	: hard-drive-fan
+ *   offset	: -32768000
+ *   slope	: 65536
+ *
+ *
+ * In order to have the moste efficient correction with those
+ * dependencies, we must trigger HD loop before OD loop before CPU
+ * loop.
+ *
+ *
+ * The various control loops found in Darwin config file are:
+ *
+ * HD Fan control loop.
+ *
+ * # model_id: 2
+ *   control        : hard-drive-fan
+ *   sensor         : hard-drive-temp
+ *   PID params     : G_d = 0x00000000
+ *                    G_p = 0x002D70A3
+ *                    G_r = 0x00019999
+ *                    History = 2 entries
+ *                    Input target = 0x370000
+ *                    Interval = 5s
+ *
+ * # model_id: 3
+ *   control        : hard-drive-fan
+ *   sensor         : hard-drive-temp
+ *   PID params     : G_d = 0x00000000
+ *                    G_p = 0x002170A3
+ *                    G_r = 0x00019999
+ *                    History = 2 entries
+ *                    Input target = 0x370000
+ *                    Interval = 5s
+ *
+ * OD Fan control loop.
+ *
+ * # model_id: 2
+ *   control        : optical-drive-fan
+ *   sensor         : optical-drive-temp
+ *   PID params     : G_d = 0x00000000
+ *                    G_p = 0x001FAE14
+ *                    G_r = 0x00019999
+ *                    History = 2 entries
+ *                    Input target = 0x320000
+ *                    Interval = 5s
+ *
+ * # model_id: 3
+ *   control        : optical-drive-fan
+ *   sensor         : optical-drive-temp
+ *   PID params     : G_d = 0x00000000
+ *                    G_p = 0x001FAE14
+ *                    G_r = 0x00019999
+ *                    History = 2 entries
+ *                    Input target = 0x320000
+ *                    Interval = 5s
+ *
+ * GPU Fan control loop.
+ *
+ * # model_id: 2
+ *   control        : hard-drive-fan
+ *   sensor         : gpu-temp
+ *   PID params     : G_d = 0x00000000
+ *                    G_p = 0x002A6666
+ *                    G_r = 0x00019999
+ *                    History = 2 entries
+ *                    Input target = 0x5A0000
+ *                    Interval = 5s
+ *
+ * # model_id: 3
+ *   control        : cpu-fan
+ *   sensor         : gpu-temp
+ *   PID params     : G_d = 0x00000000
+ *                    G_p = 0x0010CCCC
+ *                    G_r = 0x00019999
+ *                    History = 2 entries
+ *                    Input target = 0x500000
+ *                    Interval = 5s
+ *
+ * KODIAK (aka northbridge) Fan control loop.
+ *
+ * # model_id: 2
+ *   control        : optical-drive-fan
+ *   sensor         : north-bridge-temp
+ *   PID params     : G_d = 0x00000000
+ *                    G_p = 0x003BD70A
+ *                    G_r = 0x00019999
+ *                    History = 2 entries
+ *                    Input target = 0x550000
+ *                    Interval = 5s
+ *
+ * # model_id: 3
+ *   control        : hard-drive-fan
+ *   sensor         : north-bridge-temp
+ *   PID params     : G_d = 0x00000000
+ *                    G_p = 0x0030F5C2
+ *                    G_r = 0x00019999
+ *                    History = 2 entries
+ *                    Input target = 0x550000
+ *                    Interval = 5s
+ *
+ * CPU Fan control loop.
+ *
+ *   control        : cpu-fan
+ *   sensors        : cpu-temp, cpu-power
+ *   PID params     : from SDB partition
+ *
+ *
+ * CPU Slew control loop.
+ *
+ *   control        : cpufreq-clamp
+ *   sensor         : cpu-temp
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/kmod.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/sections.h>
+#include <asm/smu.h>
+
+#include "windfarm.h"
+#include "windfarm_pid.h"
+
+#define VERSION "0.4"
+
+#undef	DEBUG
+
+#ifdef DEBUG
+#define DBG(args...)	printk(args)
+#else
+#define DBG(args...)	do { } while (0)
+#endif
+
+static int pm121_mach_model;	/* machine model id */
+
+/* Controls & sensors */
+static struct wf_sensor	*sensor_cpu_power;
+static struct wf_sensor	*sensor_cpu_temp;
+static struct wf_sensor	*sensor_cpu_voltage;
+static struct wf_sensor	*sensor_cpu_current;
+static struct wf_sensor	*sensor_gpu_temp;
+static struct wf_sensor	*sensor_north_bridge_temp;
+static struct wf_sensor	*sensor_hard_drive_temp;
+static struct wf_sensor	*sensor_optical_drive_temp;
+static struct wf_sensor	*sensor_incoming_air_temp; /* unused ! */
+
+enum {
+	FAN_CPU,
+	FAN_HD,
+	FAN_OD,
+	CPUFREQ,
+	N_CONTROLS
+};
+static struct wf_control *controls[N_CONTROLS] = {};
+
+/* Set to kick the control loop into life */
+static int pm121_all_controls_ok, pm121_all_sensors_ok, pm121_started;
+
+enum {
+	FAILURE_FAN		= 1 << 0,
+	FAILURE_SENSOR		= 1 << 1,
+	FAILURE_OVERTEMP	= 1 << 2
+};
+
+/* All sys loops. Note the HD before the OD loop in order to have it
+   run before. */
+enum {
+	LOOP_GPU,		/* control = hd or cpu, but luckily,
+				   it doesn't matter */
+	LOOP_HD,		/* control = hd */
+	LOOP_KODIAK,		/* control = hd or od */
+	LOOP_OD,		/* control = od */
+	N_LOOPS
+};
+
+static const char *loop_names[N_LOOPS] = {
+	"GPU",
+	"HD",
+	"KODIAK",
+	"OD",
+};
+
+#define	PM121_NUM_CONFIGS	2
+
+static unsigned int pm121_failure_state;
+static int pm121_readjust, pm121_skipping;
+static s32 average_power;
+
+struct pm121_correction {
+	int	offset;
+	int	slope;
+};
+
+struct pm121_correction corrections[N_CONTROLS][PM121_NUM_CONFIGS] = {
+	/* FAN_OD */
+	{
+		/* MODEL 2 */
+		{ .offset	= -19563152,
+		  .slope	=  1956315
+		},
+		/* MODEL 3 */
+		{ .offset	= -15650652,
+		  .slope	=  1565065
+		},
+	},
+	/* FAN_HD */
+	{
+		/* MODEL 2 */
+		{ .offset	= -15650652,
+		  .slope	=  1565065
+		},
+		/* MODEL 3 */
+		{ .offset	= -19563152,
+		  .slope	=  1956315
+		},
+	},
+	/* FAN_CPU */
+	{
+		/* MODEL 2 */
+		{ .offset	= -25431900,
+		  .slope	=  2543190
+		},
+		/* MODEL 3 */
+		{ .offset	= -15650652,
+		  .slope	=  1565065
+		},
+	},
+	/* CPUFREQ has no correction (and is not implemented at all) */
+};
+
+struct pm121_connection {
+	unsigned int	control_id;
+	unsigned int	ref_id;
+	struct pm121_correction	correction;
+};
+
+static struct pm121_connection pm121_connections[] = {
+	/* MODEL 2 */
+	{ .control_id	= FAN_CPU,
+	  .ref_id	= FAN_OD,
+	  { .offset	= -32768000,
+	    .slope	=  65536
+	  }
+	},
+	/* MODEL 3 */
+	{ .control_id	= FAN_OD,
+	  .ref_id	= FAN_HD,
+	  { .offset	= -32768000,
+	    .slope	=  65536
+	  }
+	},
+};
+
+/* pointer to the current model connection */
+static struct pm121_connection *pm121_connection;
+
+/*
+ * ****** System Fans Control Loop ******
+ *
+ */
+
+/* Since each loop handles only one control and we want to avoid
+ * writing virtual control, we store the control correction with the
+ * loop params. Some data are not set, there are common to all loop
+ * and thus, hardcoded.
+ */
+struct pm121_sys_param {
+	/* purely informative since we use mach_model-2 as index */
+	int			model_id;
+	struct wf_sensor	**sensor; /* use sensor_id instead ? */
+	s32			gp, itarget;
+	unsigned int		control_id;
+};
+
+static struct pm121_sys_param
+pm121_sys_all_params[N_LOOPS][PM121_NUM_CONFIGS] = {
+	/* GPU Fan control loop */
+	{
+		{ .model_id	= 2,
+		  .sensor	= &sensor_gpu_temp,
+		  .gp		= 0x002A6666,
+		  .itarget	= 0x5A0000,
+		  .control_id	= FAN_HD,
+		},
+		{ .model_id	= 3,
+		  .sensor	= &sensor_gpu_temp,
+		  .gp		= 0x0010CCCC,
+		  .itarget	= 0x500000,
+		  .control_id	= FAN_CPU,
+		},
+	},
+	/* HD Fan control loop */
+	{
+		{ .model_id	= 2,
+		  .sensor	= &sensor_hard_drive_temp,
+		  .gp		= 0x002D70A3,
+		  .itarget	= 0x370000,
+		  .control_id	= FAN_HD,
+		},
+		{ .model_id	= 3,
+		  .sensor	= &sensor_hard_drive_temp,
+		  .gp		= 0x002170A3,
+		  .itarget	= 0x370000,
+		  .control_id	= FAN_HD,
+		},
+	},
+	/* KODIAK Fan control loop */
+	{
+		{ .model_id	= 2,
+		  .sensor	= &sensor_north_bridge_temp,
+		  .gp		= 0x003BD70A,
+		  .itarget	= 0x550000,
+		  .control_id	= FAN_OD,
+		},
+		{ .model_id	= 3,
+		  .sensor	= &sensor_north_bridge_temp,
+		  .gp		= 0x0030F5C2,
+		  .itarget	= 0x550000,
+		  .control_id	= FAN_HD,
+		},
+	},
+	/* OD Fan control loop */
+	{
+		{ .model_id	= 2,
+		  .sensor	= &sensor_optical_drive_temp,
+		  .gp		= 0x001FAE14,
+		  .itarget	= 0x320000,
+		  .control_id	= FAN_OD,
+		},
+		{ .model_id	= 3,
+		  .sensor	= &sensor_optical_drive_temp,
+		  .gp		= 0x001FAE14,
+		  .itarget	= 0x320000,
+		  .control_id	= FAN_OD,
+		},
+	},
+};
+
+/* the hardcoded values */
+#define	PM121_SYS_GD		0x00000000
+#define	PM121_SYS_GR		0x00019999
+#define	PM121_SYS_HISTORY_SIZE	2
+#define	PM121_SYS_INTERVAL	5
+
+/* State data used by the system fans control loop
+ */
+struct pm121_sys_state {
+	int			ticks;
+	s32			setpoint;
+	struct wf_pid_state	pid;
+};
+
+struct pm121_sys_state *pm121_sys_state[N_LOOPS] = {};
+
+/*
+ * ****** CPU Fans Control Loop ******
+ *
+ */
+
+#define PM121_CPU_INTERVAL	1
+
+/* State data used by the cpu fans control loop
+ */
+struct pm121_cpu_state {
+	int			ticks;
+	s32			setpoint;
+	struct wf_cpu_pid_state	pid;
+};
+
+static struct pm121_cpu_state *pm121_cpu_state;
+
+
+
+/*
+ * ***** Implementation *****
+ *
+ */
+
+/* correction the value using the output-low-bound correction algo */
+static s32 pm121_correct(s32 new_setpoint,
+			 unsigned int control_id,
+			 s32 min)
+{
+	s32 new_min;
+	struct pm121_correction *correction;
+	correction = &corrections[control_id][pm121_mach_model - 2];
+
+	new_min = (average_power * correction->slope) >> 16;
+	new_min += correction->offset;
+	new_min = (new_min >> 16) + min;
+
+	return max(new_setpoint, max(new_min, 0));
+}
+
+static s32 pm121_connect(unsigned int control_id, s32 setpoint)
+{
+	s32 new_min, value, new_setpoint;
+
+	if (pm121_connection->control_id == control_id) {
+		controls[control_id]->ops->get_value(controls[control_id],
+						     &value);
+		new_min = value * pm121_connection->correction.slope;
+		new_min += pm121_connection->correction.offset;
+		if (new_min > 0) {
+			new_setpoint = max(setpoint, (new_min >> 16));
+			if (new_setpoint != setpoint) {
+				DBG("pm121: %s depending on %s, "
+				    "corrected from %d to %d RPM\n",
+				    controls[control_id]->name,
+				    controls[pm121_connection->ref_id]->name,
+				    (int) setpoint, (int) new_setpoint);
+			}
+		} else
+			new_setpoint = setpoint;
+	}
+	/* no connection */
+	else
+		new_setpoint = setpoint;
+
+	return new_setpoint;
+}
+
+/* FAN LOOPS */
+static void pm121_create_sys_fans(int loop_id)
+{
+	struct pm121_sys_param *param = NULL;
+	struct wf_pid_param pid_param;
+	struct wf_control *control = NULL;
+	int i;
+
+	/* First, locate the params for this model */
+	for (i = 0; i < PM121_NUM_CONFIGS; i++) {
+		param = &(pm121_sys_all_params[loop_id][i]);
+		if (param->model_id == pm121_mach_model)
+			break;
+	}
+
+	/* No params found, put fans to max */
+	if (param == NULL) {
+		printk(KERN_WARNING "pm121: %s fan config not found "
+		       " for this machine model\n",
+		       loop_names[loop_id]);
+		goto fail;
+	}
+
+	control = controls[param->control_id];
+
+	/* Alloc & initialize state */
+	pm121_sys_state[loop_id] = kmalloc(sizeof(struct pm121_sys_state),
+					   GFP_KERNEL);
+	if (pm121_sys_state[loop_id] == NULL) {
+		printk(KERN_WARNING "pm121: Memory allocation error\n");
+		goto fail;
+	}
+	pm121_sys_state[loop_id]->ticks = 1;
+
+	/* Fill PID params */
+	pid_param.gd		= PM121_SYS_GD;
+	pid_param.gp		= param->gp;
+	pid_param.gr		= PM121_SYS_GR;
+	pid_param.interval	= PM121_SYS_INTERVAL;
+	pid_param.history_len	= PM121_SYS_HISTORY_SIZE;
+	pid_param.itarget	= param->itarget;
+	pid_param.min		= control->ops->get_min(control);
+	pid_param.max		= control->ops->get_max(control);
+
+	wf_pid_init(&pm121_sys_state[loop_id]->pid, &pid_param);
+
+	DBG("pm121: %s Fan control loop initialized.\n"
+	    "       itarged=%d.%03d, min=%d RPM, max=%d RPM\n",
+	    loop_names[loop_id], FIX32TOPRINT(pid_param.itarget),
+	    pid_param.min, pid_param.max);
+	return;
+
+ fail:
+	/* note that this is not optimal since another loop may still
+	   control the same control */
+	printk(KERN_WARNING "pm121: failed to set up %s loop "
+	       "setting \"%s\" to max speed.\n",
+	       loop_names[loop_id], control->name);
+
+	if (control)
+		wf_control_set_max(control);
+}
+
+static void pm121_sys_fans_tick(int loop_id)
+{
+	struct pm121_sys_param *param;
+	struct pm121_sys_state *st;
+	struct wf_sensor *sensor;
+	struct wf_control *control;
+	s32 temp, new_setpoint;
+	int rc;
+
+	param = &(pm121_sys_all_params[loop_id][pm121_mach_model-2]);
+	st = pm121_sys_state[loop_id];
+	sensor = *(param->sensor);
+	control = controls[param->control_id];
+
+	if (--st->ticks != 0) {
+		if (pm121_readjust)
+			goto readjust;
+		return;
+	}
+	st->ticks = PM121_SYS_INTERVAL;
+
+	rc = sensor->ops->get_value(sensor, &temp);
+	if (rc) {
+		printk(KERN_WARNING "windfarm: %s sensor error %d\n",
+		       sensor->name, rc);
+		pm121_failure_state |= FAILURE_SENSOR;
+		return;
+	}
+
+	DBG("pm121: %s Fan tick ! %s: %d.%03d\n",
+	    loop_names[loop_id], sensor->name,
+	    FIX32TOPRINT(temp));
+
+	new_setpoint = wf_pid_run(&st->pid, temp);
+
+	/* correction */
+	new_setpoint = pm121_correct(new_setpoint,
+				     param->control_id,
+				     st->pid.param.min);
+	/* linked corretion */
+	new_setpoint = pm121_connect(param->control_id, new_setpoint);
+
+	if (new_setpoint == st->setpoint)
+		return;
+	st->setpoint = new_setpoint;
+	DBG("pm121: %s corrected setpoint: %d RPM\n",
+	    control->name, (int)new_setpoint);
+ readjust:
+	if (control && pm121_failure_state == 0) {
+		rc = control->ops->set_value(control, st->setpoint);
+		if (rc) {
+			printk(KERN_WARNING "windfarm: %s fan error %d\n",
+			       control->name, rc);
+			pm121_failure_state |= FAILURE_FAN;
+		}
+	}
+}
+
+
+/* CPU LOOP */
+static void pm121_create_cpu_fans(void)
+{
+	struct wf_cpu_pid_param pid_param;
+	const struct smu_sdbp_header *hdr;
+	struct smu_sdbp_cpupiddata *piddata;
+	struct smu_sdbp_fvt *fvt;
+	struct wf_control *fan_cpu;
+	s32 tmax, tdelta, maxpow, powadj;
+
+	fan_cpu = controls[FAN_CPU];
+
+	/* First, locate the PID params in SMU SBD */
+	hdr = smu_get_sdb_partition(SMU_SDB_CPUPIDDATA_ID, NULL);
+	if (hdr == 0) {
+		printk(KERN_WARNING "pm121: CPU PID fan config not found.\n");
+		goto fail;
+	}
+	piddata = (struct smu_sdbp_cpupiddata *)&hdr[1];
+
+	/* Get the FVT params for operating point 0 (the only supported one
+	 * for now) in order to get tmax
+	 */
+	hdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL);
+	if (hdr) {
+		fvt = (struct smu_sdbp_fvt *)&hdr[1];
+		tmax = ((s32)fvt->maxtemp) << 16;
+	} else
+		tmax = 0x5e0000; /* 94 degree default */
+
+	/* Alloc & initialize state */
+	pm121_cpu_state = kmalloc(sizeof(struct pm121_cpu_state),
+				  GFP_KERNEL);
+	if (pm121_cpu_state == NULL)
+		goto fail;
+	pm121_cpu_state->ticks = 1;
+
+	/* Fill PID params */
+	pid_param.interval = PM121_CPU_INTERVAL;
+	pid_param.history_len = piddata->history_len;
+	if (pid_param.history_len > WF_CPU_PID_MAX_HISTORY) {
+		printk(KERN_WARNING "pm121: History size overflow on "
+		       "CPU control loop (%d)\n", piddata->history_len);
+		pid_param.history_len = WF_CPU_PID_MAX_HISTORY;
+	}
+	pid_param.gd = piddata->gd;
+	pid_param.gp = piddata->gp;
+	pid_param.gr = piddata->gr / pid_param.history_len;
+
+	tdelta = ((s32)piddata->target_temp_delta) << 16;
+	maxpow = ((s32)piddata->max_power) << 16;
+	powadj = ((s32)piddata->power_adj) << 16;
+
+	pid_param.tmax = tmax;
+	pid_param.ttarget = tmax - tdelta;
+	pid_param.pmaxadj = maxpow - powadj;
+
+	pid_param.min = fan_cpu->ops->get_min(fan_cpu);
+	pid_param.max = fan_cpu->ops->get_max(fan_cpu);
+
+	wf_cpu_pid_init(&pm121_cpu_state->pid, &pid_param);
+
+	DBG("pm121: CPU Fan control initialized.\n");
+	DBG("       ttarged=%d.%03d, tmax=%d.%03d, min=%d RPM, max=%d RPM,\n",
+	    FIX32TOPRINT(pid_param.ttarget), FIX32TOPRINT(pid_param.tmax),
+	    pid_param.min, pid_param.max);
+
+	return;
+
+ fail:
+	printk(KERN_WARNING "pm121: CPU fan config not found, max fan speed\n");
+
+	if (controls[CPUFREQ])
+		wf_control_set_max(controls[CPUFREQ]);
+	if (fan_cpu)
+		wf_control_set_max(fan_cpu);
+}
+
+
+static void pm121_cpu_fans_tick(struct pm121_cpu_state *st)
+{
+	s32 new_setpoint, temp, power;
+	struct wf_control *fan_cpu = NULL;
+	int rc;
+
+	if (--st->ticks != 0) {
+		if (pm121_readjust)
+			goto readjust;
+		return;
+	}
+	st->ticks = PM121_CPU_INTERVAL;
+
+	fan_cpu = controls[FAN_CPU];
+
+	rc = sensor_cpu_temp->ops->get_value(sensor_cpu_temp, &temp);
+	if (rc) {
+		printk(KERN_WARNING "pm121: CPU temp sensor error %d\n",
+		       rc);
+		pm121_failure_state |= FAILURE_SENSOR;
+		return;
+	}
+
+	rc = sensor_cpu_power->ops->get_value(sensor_cpu_power, &power);
+	if (rc) {
+		printk(KERN_WARNING "pm121: CPU power sensor error %d\n",
+		       rc);
+		pm121_failure_state |= FAILURE_SENSOR;
+		return;
+	}
+
+	DBG("pm121: CPU Fans tick ! CPU temp: %d.%03d°C, power: %d.%03d\n",
+	    FIX32TOPRINT(temp), FIX32TOPRINT(power));
+
+#ifdef HACKED_OVERTEMP
+#define	MAX	0x4a0000
+#else
+#define	MAX	st->pid.param.tmax
+#endif
+	if (temp > MAX)
+		pm121_failure_state |= FAILURE_OVERTEMP;
+
+#undef	MAX
+
+	new_setpoint = wf_cpu_pid_run(&st->pid, power, temp);
+
+	/* correction */
+	new_setpoint = pm121_correct(new_setpoint,
+				     FAN_CPU,
+				     st->pid.param.min);
+
+	/* connected correction */
+	new_setpoint = pm121_connect(FAN_CPU, new_setpoint);
+
+	if (st->setpoint == new_setpoint)
+		return;
+	st->setpoint = new_setpoint;
+	DBG("pm121: CPU corrected setpoint: %d RPM\n", (int)new_setpoint);
+
+ readjust:
+	if (fan_cpu && pm121_failure_state == 0) {
+		rc = fan_cpu->ops->set_value(fan_cpu, st->setpoint);
+		if (rc) {
+			printk(KERN_WARNING "pm121: %s fan error %d\n",
+			       fan_cpu->name, rc);
+			pm121_failure_state |= FAILURE_FAN;
+		}
+	}
+}
+
+/*
+ * ****** Common ******
+ *
+ */
+
+static void pm121_tick(void)
+{
+	unsigned int last_failure = pm121_failure_state;
+	unsigned int new_failure;
+	s32 total_power;
+	int i;
+
+	if (!pm121_started) {
+		DBG("pm121: creating control loops !\n");
+		for (i = 0; i < N_LOOPS; i++)
+			pm121_create_sys_fans(i);
+
+		pm121_create_cpu_fans();
+		pm121_started = 1;
+	}
+
+	/* skipping ticks */
+	if (pm121_skipping && --pm121_skipping)
+		return;
+
+	/* compute average power */
+	total_power = 0;
+	for (i = 0; i < pm121_cpu_state->pid.param.history_len; i++)
+		total_power += pm121_cpu_state->pid.powers[i];
+
+	average_power = total_power / pm121_cpu_state->pid.param.history_len;
+
+
+	pm121_failure_state = 0;
+	for (i = 0 ; i < N_LOOPS; i++) {
+		if (pm121_sys_state[i])
+			pm121_sys_fans_tick(i);
+	}
+
+	if (pm121_cpu_state)
+		pm121_cpu_fans_tick(pm121_cpu_state);
+
+	pm121_readjust = 0;
+	new_failure = pm121_failure_state & ~last_failure;
+
+	/* If entering failure mode, clamp cpufreq and ramp all
+	 * fans to full speed.
+	 */
+	if (pm121_failure_state && !last_failure) {
+		for (i = 0; i < N_CONTROLS; i++) {
+			if (controls[i])
+				wf_control_set_max(controls[i]);
+		}
+	}
+
+	/* If leaving failure mode, unclamp cpufreq and readjust
+	 * all fans on next iteration
+	 */
+	if (!pm121_failure_state && last_failure) {
+		if (controls[CPUFREQ])
+			wf_control_set_min(controls[CPUFREQ]);
+		pm121_readjust = 1;
+	}
+
+	/* Overtemp condition detected, notify and start skipping a couple
+	 * ticks to let the temperature go down
+	 */
+	if (new_failure & FAILURE_OVERTEMP) {
+		wf_set_overtemp();
+		pm121_skipping = 2;
+	}
+
+	/* We only clear the overtemp condition if overtemp is cleared
+	 * _and_ no other failure is present. Since a sensor error will
+	 * clear the overtemp condition (can't measure temperature) at
+	 * the control loop levels, but we don't want to keep it clear
+	 * here in this case
+	 */
+	if (new_failure == 0 && last_failure & FAILURE_OVERTEMP)
+		wf_clear_overtemp();
+}
+
+
+
+
+#define	pm121_register_control(control, match, id)			\
+	if (controls[id] == NULL && !strcmp(control->name,match)) {	\
+		if (wf_get_control(control) == 0)			\
+			controls[id] = control;				\
+	}								\
+	all = all && controls[id];
+
+static void pm121_new_control(struct wf_control *ct)
+{
+	int all = 1;
+
+	if (pm121_all_controls_ok)
+		return;
+
+	pm121_register_control(ct, "optical-drive-fan",	FAN_OD);
+	pm121_register_control(ct, "hard-drive-fan",	FAN_HD);
+	pm121_register_control(ct, "cpu-fan",		FAN_CPU);
+	pm121_register_control(ct, "cpufreq-clamp",	CPUFREQ);
+
+	if (all)
+		pm121_all_controls_ok = 1;
+}
+#undef pm121_register_control
+
+
+
+
+#define	pm121_register_sensor(sensor, match, var)		\
+	if (var == NULL && !strcmp(sensor->name,match)) {	\
+		if (wf_get_sensor(sensor) == 0)			\
+			var = sensor;				\
+	}							\
+	all = all && var;
+
+static void pm121_new_sensor(struct wf_sensor *sr)
+{
+	int all = 1;
+
+	if (pm121_all_sensors_ok)
+		return;
+
+	pm121_register_sensor(sr, "cpu-temp",
+			      sensor_cpu_temp);
+	pm121_register_sensor(sr, "cpu-current",
+			      sensor_cpu_current);
+	pm121_register_sensor(sr, "cpu-voltage",
+			      sensor_cpu_voltage);
+	pm121_register_sensor(sr, "cpu-power",
+			      sensor_cpu_power);
+	pm121_register_sensor(sr, "hard-drive-temp",
+			      sensor_hard_drive_temp);
+	pm121_register_sensor(sr, "optical-drive-temp",
+			      sensor_optical_drive_temp);
+	pm121_register_sensor(sr, "incoming-air-temp",
+			      sensor_incoming_air_temp);
+	pm121_register_sensor(sr, "north-bridge-temp",
+			      sensor_north_bridge_temp);
+	pm121_register_sensor(sr, "gpu-temp",
+			      sensor_gpu_temp);
+
+	if (all)
+		pm121_all_sensors_ok = 1;
+}
+
+#undef pm121_register_sensor
+
+
+
+static int pm121_notify(struct notifier_block *self,
+			unsigned long event, void *data)
+{
+	switch (event) {
+	case WF_EVENT_NEW_CONTROL:
+		DBG("pm121: new control %s detected\n",
+		    ((struct wf_control *)data)->name);
+		pm121_new_control(data);
+		break;
+	case WF_EVENT_NEW_SENSOR:
+		DBG("pm121: new sensor %s detected\n",
+		    ((struct wf_sensor *)data)->name);
+		pm121_new_sensor(data);
+		break;
+	case WF_EVENT_TICK:
+		if (pm121_all_controls_ok && pm121_all_sensors_ok)
+			pm121_tick();
+		break;
+	}
+
+	return 0;
+}
+
+static struct notifier_block pm121_events = {
+	.notifier_call	= pm121_notify,
+};
+
+static int pm121_init_pm(void)
+{
+	const struct smu_sdbp_header *hdr;
+
+	hdr = smu_get_sdb_partition(SMU_SDB_SENSORTREE_ID, NULL);
+	if (hdr != 0) {
+		struct smu_sdbp_sensortree *st =
+			(struct smu_sdbp_sensortree *)&hdr[1];
+		pm121_mach_model = st->model_id;
+	}
+
+	pm121_connection = &pm121_connections[pm121_mach_model - 2];
+
+	printk(KERN_INFO "pm121: Initializing for iMac G5 iSight model ID %d\n",
+	       pm121_mach_model);
+
+	return 0;
+}
+
+
+static int pm121_probe(struct platform_device *ddev)
+{
+	wf_register_client(&pm121_events);
+
+	return 0;
+}
+
+static int __devexit pm121_remove(struct platform_device *ddev)
+{
+	wf_unregister_client(&pm121_events);
+	return 0;
+}
+
+static struct platform_driver pm121_driver = {
+	.probe = pm121_probe,
+	.remove = __devexit_p(pm121_remove),
+	.driver = {
+		.name = "windfarm",
+		.bus = &platform_bus_type,
+	},
+};
+
+
+static int __init pm121_init(void)
+{
+	int rc = -ENODEV;
+
+	if (machine_is_compatible("PowerMac12,1"))
+		rc = pm121_init_pm();
+
+	if (rc == 0) {
+#ifdef MODULE
+		request_module("windfarm_smu_controls");
+		request_module("windfarm_smu_sensors");
+		request_module("windfarm_smu_sat");
+		request_module("windfarm_lm75_sensor");
+		request_module("windfarm_max6690_sensor");
+		request_module("windfarm_cpufreq_clamp");
+
+#endif /* MODULE */
+		platform_driver_register(&pm121_driver);
+	}
+
+	return rc;
+}
+
+static void __exit pm121_exit(void)
+{
+
+	platform_driver_unregister(&pm121_driver);
+}
+
+
+module_init(pm121_init);
+module_exit(pm121_exit);
+
+MODULE_AUTHOR("Étienne Bersac <bersace@gmail.com>");
+MODULE_DESCRIPTION("Thermal control logic for iMac G5 (iSight)");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/macintosh/windfarm_smu_controls.c b/drivers/macintosh/windfarm_smu_controls.c
index 58c2590..961fa0e 100644
--- a/drivers/macintosh/windfarm_smu_controls.c
+++ b/drivers/macintosh/windfarm_smu_controls.c
@@ -218,6 +218,10 @@ static struct smu_fan_control *smu_fan_create(struct device_node *node,
 		fct->ctrl.name = "cpu-fan";
 	else if (!strcmp(l, "Hard Drive") || !strcmp(l, "Hard drive"))
 		fct->ctrl.name = "drive-bay-fan";
+	else if (!strcmp(l, "HDD Fan")) /* seen on iMac G5 iSight */
+		fct->ctrl.name = "hard-drive-fan";
+	else if (!strcmp(l, "ODD Fan")) /* same */
+		fct->ctrl.name = "optical-drive-fan";
 
 	/* Unrecognized fan, bail out */
 	if (fct->ctrl.name == NULL)


Thank you,
Étienne.
-- 
E Ultreïa !

[-- Attachment #2: Ceci est une partie de message numériquement signée --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply related

* Re: [PATCH 1/7] Set archdata.dma_data for direct DMA in cell_dma_dev_setup()
From: Arnd Bergmann @ 2007-12-05 23:38 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <ac4252cfbaa0c1a3534443007417dfc43b597eb5.1196839256.git.michael@ellerman.id.au>

On Wednesday 05 December 2007, Michael Ellerman wrote:
> Store a pointer to the direct_dma_offset in each device's dma_data
> in the case where we're using the direct DMA ops.
> 
> Signed-off-by: Michael Ellerman <michael@ellerman.id.au>

Acked-by: Arnd Bergmann <arnd@arndb.de>

^ permalink raw reply

* Re: [PATCH 2/7] Add celleb_dma_dev_setup()
From: Arnd Bergmann @ 2007-12-05 23:40 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <f4d0ac13491bbe6834fe1f8d4bf86c04754f3774.1196839256.git.michael@ellerman.id.au>

On Wednesday 05 December 2007, Michael Ellerman wrote:
> Celleb always uses dma_direct_ops, and sets dma_direct_offset, so it too
> should set dma_data to dma_direct_offset.
> 
> Currently there's no pci_dma_dev_setup() routine for Celleb so add one.
> 
> Signed-off-by: Michael Ellerman <michael@ellerman.id.au>

Acked-by: Arnd Bergmann <arnd@arndb.de>

^ permalink raw reply

* Re: [PATCH 3/7] Use archdata.dma_data in dma_direct_ops
From: Arnd Bergmann @ 2007-12-05 23:40 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <ed0aab681311a3c6d53354d39a6c4aea5b77b133.1196839256.git.michael@ellerman.id.au>

On Wednesday 05 December 2007, Michael Ellerman wrote:
> Now that all platforms using dma_direct_offset setup the archdata.dma_data
> correctly, we can change the dma_direct_ops to retrieve the offset from
> the dma_data, rather than directly from the global.
> 
> Signed-off-by: Michael Ellerman <michael@ellerman.id.au>

Acked-by: Arnd Bergmann <arnd@arndb.de>

^ permalink raw reply

* Re: [PATCH 4/7] Have cell use its own dma_direct_offset variable
From: Arnd Bergmann @ 2007-12-05 23:40 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <4058299ab263711f8d57d53b23a11b363db33395.1196839256.git.michael@ellerman.id.au>

On Wednesday 05 December 2007, Michael Ellerman wrote:
> Rather than using the global variable, have cell use its own variable to
> store the direct DMA offset.
> 
> Signed-off-by: Michael Ellerman <michael@ellerman.id.au>

Acked-by: Arnd Bergmann <arnd@arndb.de>

^ permalink raw reply

* Re: [PATCH 5/7] Have celleb use its own dma_direct_offset variable
From: Arnd Bergmann @ 2007-12-05 23:41 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <2b8d160d8baf8570781441808cd117dd5e34f703.1196839256.git.michael@ellerman.id.au>

On Wednesday 05 December 2007, Michael Ellerman wrote:
> Rather than using the global variable, have celleb use its own variable to
> store the direct DMA offset.
> 
> Signed-off-by: Michael Ellerman <michael@ellerman.id.au>

Arnd Bergmann <arnd@arndb.de>

^ permalink raw reply

* Re: [PATCH 6/7] Remove the global dma_direct_offset
From: Arnd Bergmann @ 2007-12-05 23:41 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <854cf7522a012469ff1af0b90e874cb96c4d1a37.1196839256.git.michael@ellerman.id.au>

On Wednesday 05 December 2007, Michael Ellerman wrote:
> We no longer need the global dma_direct_offset, update the comment to
> reflect the new reality.
> 
> Signed-off-by: Michael Ellerman <michael@ellerman.id.au>

Acked-by: Arnd Bergmann <arnd@arndb.de>

^ permalink raw reply

* Re: [PATCH 7/7] Remove bogus comment in dma_direct_alloc_coherent()
From: Arnd Bergmann @ 2007-12-05 23:41 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <d35bdbd4be04065ab67b93b7a6a876a000dc4cf1.1196839256.git.michael@ellerman.id.au>

On Wednesday 05 December 2007, Michael Ellerman wrote:
> Since commit c80d9133e99de1af607314107910a2a1645efb17 (Make direct DMA use
> node local allocations) went in this comment makes no sense.
> 
> Signed-off-by: Michael Ellerman <michael@ellerman.id.au>

Acked-by: Arnd Bergmann <arnd@arndb.de>

^ permalink raw reply

* Re: [PATCH v2] qe: add ability to upload QE firmware
From: Arnd Bergmann @ 2007-12-05 23:56 UTC (permalink / raw)
  To: Timur Tabi; +Cc: linuxppc-dev
In-Reply-To: <4757362F.7040404@freescale.com>

On Thursday 06 December 2007, Timur Tabi wrote:
> Arnd Bergmann wrote:
>=20
> > Of course, that approach does not help you if the blob is not GPL compa=
tible
> > and you are relying on the dts file to be linked into the kernel,=20
>=20
> Well, the blobs will never be GPL compatible, which is why I created the=
=20
> firmware binary format.

Well, you never know if someone might be willing to reverse-engineer
them and provide free replacements ;-). But that wasn't my point.

> To address the issue of loading the firmware before the kernel boots, I h=
ave=20
> ported qe_upload_firmware() to U-Boot, and provided a command-line comman=
d for=20
> uploading a firmware at an address in flash. =A0The blob can be placed in=
 flash,=20
> and then a boot script will load it. =A0The U-Boot version of qe_upload_f=
irmware()=20
> will also create the 'firmware' node in the device tree.

What does the firmware node contain then? The way I read it, you only put
metadata about the uploaded firmware in there, but not the blob itself, rig=
ht?

Is there a case where you don't need the firmware in order to start the
kernel, but still want to provide it in flash? In that case, I think it
would really be better to just put the blob into the tree and only
have the fw loading code in the kernel instead of duplicating it in the boot
loader.

Regarding the question whether the firmware should be a device node or
a property of another node, I'd prefer a simple property, because the
firmware itself is not really a device you can access, but I don't care
much about that.

	Arnd <><

^ permalink raw reply

* kernel_thread pid - stuck (after VFS: Mounted root (ext2 filesystem).)
From: Siva Prasad @ 2007-12-06  0:00 UTC (permalink / raw)
  To: linuxppc-dev, linuxppc-embedded

Hi,

I am trying to bring up 8641 based on 2.6.19 kernel.

My system hangs after printing the message "VFS: Mounted root (ext2
filesystem)." I tried to follow down the path to identify where it is
hanging, and ended up at the following...

init/do_mounts_initrd.c: handle_initrd() function
.
.
.
        pid =3D kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);
        if (pid > 0) {
                while (pid !=3D (sivaval =3D sys_wait4(-1, NULL, 0, =
NULL)))
                      yield();
        }
.
.
.

It never comes out of this while loop and stuck for ever. Pid value
returned by kernel_thread is 193. I am not sure why that should be equal
to sys_wait4()'s return value, in order to proceed further. As you can
imagine, it repeatedly goes and executes sys_wait4, only to go and
execute again as the condition stays true (pid is not the same as return
value of sys_wait4).

Can some one throw some ideas, as to what might be the problem, and a
possible resolution to this.

Boot Log below
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
Using MPC86xx HPCN machine description
Total memory =3D 1024MB; using 2048kB for hash table (at cfe00000)
Linux version 2.6.19 (sprasad@cider.bivio.net) (gcc version 4.1.1
20060525 (Red Hat 4.1.1-1)) #183 SMP Wed Dec 5 15:51:59 PST 2007
Found initrd at 0xc6000000:0xc62f912a
Found legacy serial port 0 for /soc8641@ff700000/serial@4500
  mem=3Dff704500, taddr=3Dff704500, irq=3D1a, clk=3D598500000, speed=3D0
Found MPC86xx PCIE host bridge at 0x00000000ff708000. Firmware bus
number: 0->254
Found MPC86xx PCIE host bridge at 0x00000000ff709000. Firmware bus
number: 0->255
MPC86xx HPCN board from Freescale Semiconductor
Zone PFN ranges:
  DMA             0 ->   196608
  Normal     196608 ->   196608
  HighMem    196608 ->   262144
early_node_map[1] active PFN ranges
    0:        0 ->   262144
Built 1 zonelists.  Total pages: 260096
Kernel command line: console=3DttyS0,115200 root=3D/dev/sda8
mpic: Setting up MPIC " MPIC     " version 1.2 at ff740000, max 2 CPUs
mpic: ISU size: 16, shift: 4, mask: f
mpic: Initializing for 80 sources
PID hash table entries: 4096 (order: 12, 16384 bytes)
generic_calibrate_decr: 7 ppc_tb_freq =3D 150000000.
generic_calibrate_decr: 7 ppc_proc_freq =3D 1649267441.
time_init: decrementer frequency =3D 150.000000 MHz
time_init: processor frequency   =3D 1649.267441 MHz
Console: colour dummy device 80x25
Dentry cache hash table entries: 131072 (order: 7, 524288 bytes)
Inode-cache hash table entries: 65536 (order: 6, 262144 bytes)
Memory: 1030352k/1048576k available (2740k kernel code, 279760k
reserved, 232k data, 129k bss, 156k init)
Mount-cache hash table entries: 512
mpic: requesting IPIs ...=20
Processor 1 is stuck.
Brought up 1 CPUs
checking if image is initramfs...it isn't (no cpio magic); looks like an
initrd
Freeing initrd memory: 3044k freed
NET: Registered protocol family 16
PCI: Probing PCI hardware
PCI: 0000:00:00.0: class b20 doesn't match header type 01. Ignoring
class.
PCI: Cannot allocate resource region 1 of PCI bridge 1
PCI: Cannot allocate resource region 2 of PCI bridge 1
PCI: Cannot allocate resource region 1 of device 0000:01:00.0
PCI: Cannot allocate resource region 3 of device 0000:01:00.0
PCI: Failed to allocate mem resource #1:4000@0 for 0000:01:00.0
PCI: Failed to allocate mem resource #3:10000@0 for 0000:01:00.0
bus mdio_bus: add driver Generic PHY
Generic PHY: Registered new driver
SCSI subsystem initialized
bus i2c: add driver i2c_adapter
NET: Registered protocol family 2
IP route cache hash table entries: 32768 (order: 5, 131072 bytes)
TCP established hash table entries: 131072 (order: 8, 1048576 bytes)
TCP bind hash table entries: 65536 (order: 7, 524288 bytes)
TCP: Hash tables configured (established 131072 bind 65536)
TCP reno registered
highmem bounce pool size: 64 pages
io scheduler noop registered
io scheduler deadline registered (default)
io scheduler cfq registered
bus pci: add driver pcieport-driver
Serial: 8250/16550 driver $Revision: 1.90 $ 1 ports, IRQ sharing enabled
bus platform: add driver serial8250
serial8250.0: ttyS0 at MMIO 0xff704500 (irq =3D 26) is a 16550A
bus pci: add driver serial
RAMDISK driver initialized: 16 RAM disks of 131072K size 1024 blocksize
loop: loaded (max 8 devices)
bus mdio_bus: add driver Vitesse VSC8244
Vitesse VSC8244: Registered new driver
Uniform Multi-Platform E-IDE driver Revision: 7.00alpha2
ide: Assuming 33MHz system bus speed for PIO modes; override with
idebus=3Dxx
bus pci: add driver ALI15x3_IDE
bus ide: add driver ide-disk
bus ide: add driver ide-cdrom
bus scsi: add driver sd
bus pci: add driver ahci
bus platform: add driver fsl-i2c
bus i2c: add driver eeprom
TCP cubic registered
Initializing XFRM netlink socket
NET: Registered protocol family 1
NET: Registered protocol family 10
IPv6 over IPv4 tunneling driver
NET: Registered protocol family 17
RAMDISK: Compressed image found at block 0
VFS: Mounted root (ext2 filesystem).
<<<<<< hangs here >>>>>>

^ permalink raw reply

* Re: [PATCH v2] qe: add ability to upload QE firmware
From: Timur Tabi @ 2007-12-06  0:05 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linuxppc-dev
In-Reply-To: <200712060056.39368.arnd@arndb.de>

Arnd Bergmann wrote:

> What does the firmware node contain then? The way I read it, you only put
> metadata about the uploaded firmware in there, but not the blob itself, right?

That's correct.  The meta-data is only the information that a device driver 
would need to identify and interact with the microcode.

> Is there a case where you don't need the firmware in order to start the
> kernel, but still want to provide it in flash?

I don't think you'll ever need the firmware to *start* the kernel.

> In that case, I think it
> would really be better to just put the blob into the tree and only
> have the fw loading code in the kernel instead of duplicating it in the boot
> loader.

That would require the firmware to present in RAM for all time, since the device 
tree cannot be unloaded.  Besides, you might need to have the firmware loaded in 
U-Boot anyway.  If your console is connected to the QE, then you'll need the 
UART firmware loaded before you can see anything.  That's why U-Boot needs its 
own version.

> Regarding the question whether the firmware should be a device node or
> a property of another node, I'd prefer a simple property, because the
> firmware itself is not really a device you can access, but I don't care
> much about that.

Technically, the firmware could be considered a device on the QE, because it's 
loaded into I-RAM and it can significantly alter the behavior of the device. 
Having it its own node also lets me compartmentalize it.  If I want to expand 
the node and add more properties, it's cleaner.

-- 
Timur Tabi
Linux kernel developer at Freescale

^ permalink raw reply


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