* Re: [PATCH 2/10] sbc8560: Add v1 device tree source for Wind River SBC8560 board
From: Kumar Gala @ 2008-02-01 14:46 UTC (permalink / raw)
To: David Gibson; +Cc: Paul Gortmaker, linuxppc-dev
In-Reply-To: <20080201075408.GC18684@localhost.localdomain>
On Feb 1, 2008, at 1:54 AM, David Gibson wrote:
> On Thu, Jan 24, 2008 at 06:41:24PM -0500, Paul Gortmaker wrote:
>> This adds a v1 device tree source for the Wind River SBC8560
>> board. The
>> biggest difference between this and the MPC8560ADS reference platform
>> dts is the use of an external 16550 compatible UART instead of the
>> CPM2.
>>
>> Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
>
> [snip]
>> +/dts-v1/;
>> +
>> +/ {
>> + model = "SBC8560";
>> + compatible = "SBC8560";
>
> This is not the conventional format for board-level compatible
> entries, which should generally be "vendor,model" and all in lower
> case.
>
> [snip]
>> + enet0: ethernet@24000 {
>> + cell-index = <0>;
>> + device_type = "network";
>> + model = "TSEC";
>> + compatible = "gianfar";
>
> This looks like the old dodgy gianfar binding, and needs updating
> (mdio node will probably also need changes).
>
> [snip]
>> + localbus@ff705000 {
>> + compatible = "fsl,mpc8560-localbus";
>> + #address-cells = <2>;
>> + #size-cells = <1>;
>> + reg = <0xff705000 0x100>; // BRx, ORx, etc.
>> +
>> + ranges = <
>> + 0x0 0x0 0xff800000 0x0800000 // 8MB boot flash
>> + 0x1 0x0 0xe4000000 0x4000000 // 64MB flash
>> + 0x3 0x0 0x20000000 0x4000000 // 64MB SDRAM
>> + 0x4 0x0 0x24000000 0x4000000 // 64MB SDRAM
>> + 0x5 0x0 0xfc000000 0x0c00000 // EPLD
>> + 0x6 0x0 0xe0000000 0x4000000 // 64MB flash
>> + 0x7 0x0 0x80000000 0x0200000 // ATM1,2
>> + >;
>> +
>> + epld@5,0 {
>
> I'm not entirely convinced on this two-level representation. I think
> the FSL people need to get together and define a binding (or set of
> bindings) for their various chipselect style external bus bridges.
It seems reasonable if you had a FPGA off of the localbus to have a
two level representation. One for the localbus controller on the FSL
part and the child to describe the FPGA.
What are you expecting beyond what we have today? I guess I'm asking
what's missing from the localbus nodes we have?
- k
^ permalink raw reply
* Re: 83xx immap_qe.h -> SIR type def error?
From: Kumar Gala @ 2008-02-01 14:56 UTC (permalink / raw)
To: rmcguire; +Cc: linuxppc-embedded
In-Reply-To: <000001c864c8$4bd81bb0$6405a8c0@absolut>
On Feb 1, 2008, at 5:47 AM, Russell McGuire wrote:
> All Freescale,
>
> Not sure if this is the place to post this, but I have run across
> what I
> consider to be a possible type error in the immap_qe.h file, for the
> asm/powerpc branch.
>
> In the file immap_qe.h
>
> /* SI Routing Tables */
> struct sir {
> u8 tx[0x400];
> u8 rx[0x400];
> u8 res0[0x800];
> }
>
> Shouldn't these types be defined as __be16 ?
>
> According to the Freescale manual this is a 16 bit field, not an 8-bit
> field.
>
> Spent an hour trying to figure out why I couldn't fill this field
> out with
> upper 8 bits last night.
>
> Thoughts?
I'm guessing it was done this way since they are just looked as base
offsets. Where in the UM do you see anything about them being 16-bit
quantities? (I'm really know little about this).
- k
^ permalink raw reply
* pthread / TQM5200 problem
From: Sebastian Theiss @ 2008-02-01 14:56 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <002c01c864d0$a4ad11c0$0101a8c0@tis>
Hi,
Here's some additional information I forgot when originally posting my
question today morning: I'm using the DENX ELDK 3.1.1 and a kernel =
version
2.4.25.
Regards,
Sebastian
-----Urspr=FCngliche Nachricht-----
Von: linuxppc-dev-bounces+st12=3Dinf.tu-dresden.de@ozlabs.org
[mailto:linuxppc-dev-bounces+st12=3Dinf.tu-dresden.de@ozlabs.org] Im =
Auftrag
von Sebastian Theiss
Gesendet: Freitag, 1. Februar 2008 13:48
An: linuxppc-dev@ozlabs.org
Betreff: pthread / TQM5200 problem
Hi all.
I've been having some headache using the pthread library with a TB5200 =
box
(based on a TQM5200 board with a Freescale MPC5200 PowerPC-CPU). I =
created a
small program to pin down the problem and it runs fine on all my Unix- =
and
Linux-machines but fails on the embedded box: The program contains a =
class
CSignal that provides thread-synchronisation based on the
pthread_cond_signal and pthread_cond_wait calls and takes care of the
"spurious wakeup" and "lost signal" problems. The program runs 159
additional threads (that seems to be some internal limit), each of them
continuously increments a field variable and afterwards sleeps until the
main thread wakes it up again. The main thread monitors the whole field =
of
variables that are incremented by the 159 other threads and continuously
wakes them up. When running in the desired way, the program should show =
a
table with 160 entries and each entry (except for the last) should
continuously increase. However, on the box the threads 31 to 64 never =
wake
up, once they call pthread_cond_wait. The code below lacks some error
checking to keep it short, but besides that I don't see what's going =
wrong.
And, the code runs fine on my "real" Linux machines.
Any ideas of what the problem might be and how to fix it? Your I help =
would
be greatly appreciated as I'm rather despaired right now.
Regards,
Sebastian
#include <stdio.h>
#include <pthread.h>
class CSignal
{
public:
CSignal()
{
m_bFlag =3D false;
pthread_mutex_init(&m_Mutex, NULL);
pthread_cond_init(&m_Condition, NULL);
}
~CSignal()
{
pthread_mutex_destroy(&m_Mutex);
pthread_cond_destroy(&m_Condition);
}
public:
void Set(bool bValue =3D true)
{
pthread_mutex_lock(&m_Mutex);
if( m_bFlag =3D bValue ) pthread_cond_broadcast(&m_Condition);
pthread_mutex_unlock(&m_Mutex);
}
void Wait()
{
pthread_mutex_lock(&m_Mutex);
while( !m_bFlag ) pthread_cond_wait(&m_Condition,&m_Mutex);
pthread_mutex_unlock(&m_Mutex);
}
protected:
volatile bool m_bFlag;
pthread_mutex_t m_Mutex;
pthread_cond_t m_Condition;
};
#define THREAD_COUNT 160
unsigned char state[THREAD_COUNT];
CSignal signal[THREAD_COUNT];
void* threadproc(void* pParam)
{
int index =3D (int)pParam;
while( true )
{
state[index]++;
// wait for the signal beeing set
signal[index].Wait();
// reset signal, so that next Wait() will actually case the
thread to sleep again
signal[index].Set(false);
}
}
int main()
{
// clear state field
for( int i =3D 0; i < THREAD_COUNT; i++ )
{
state[i] =3D 0;
}
// run 160 threads (creation of the last thread throws EAGAIN, so
159 (+ the main thread)=20
// seems to be some kind of limit, but that's not the point here)
for( int i =3D 0; i < THREAD_COUNT; i++ )
{
pthread_t id;
printf("create thread %i: %i\n", i, pthread_create(&id,
NULL, threadproc, (void*)i));
}
for(;;)
{
// wake all threads
for( int i =3D 0; i < THREAD_COUNT; i++ )
{
signal[i].Set();
}
// print state of each thread
printf("\033[H");
int thread =3D 0;
for( int i =3D 0; i < 16; i++ )
{
for( int j =3D 0; j < 10; j++, thread++ )
{
printf("%03i/%03i ", thread, state[thread]);
}
printf("\n");
}
}
return 0;
} =20
=20
_________________________________________________________
Technische Universit=E4t Dresden
Fakult=E4t Informatik
Institut f=FCr Angewandte Informatik
Lehrstuhl f=FCr Technische Informationssysteme
D-01062 Dresden
Besucheradresse: N=F6thnitzer Str. 46, Zi. 1079
Telefon +49 351 463-38399
Telefax +49 351 463-38460
st12@inf.tu-dresden.de
_________________________________________________________
=20
_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev
^ permalink raw reply
* Re: External Interrupt
From: Sergei Shtylyov @ 2008-02-01 14:29 UTC (permalink / raw)
To: Marco Stornelli; +Cc: Linuxppc Embedded Mailing List
In-Reply-To: <47A2D424.3090903@coritel.it>
Hello.
Marco Stornelli wrote:
> I used the linux kernel 2.6.10 with a processor MPC8548E. I wrote a
> driver for a device connected with the local bus. This device has an
> external interrupt. In the local bus driver I have used the macro
> MPC85xx_IRQ_EXT<X> to get the interrupt number and pass it to the
> driver and after that register the ISR. Now with a kernel 2.6.21 this
> macro isn't available because in the header file irq.h there is the
> option CONFIG_PPC_MERGE that disable those options. I think this
> problem is related to the migration of ppc code towards powerpc. I
> know that now there is the new device tree source file where I can add
> a device and its interrupt number but I think in this file I should
> describe only the platform device, and this device is not a platform
> device.
How comes that it's not platform device if it hangs off the local bus?
> Then, how can I get now this value? Is there some function to
> call? How can I perform this operation?
Probably irq_alloc_virt()...
WBR, Sergei
^ permalink raw reply
* Re: External Interrupt
From: Sergei Shtylyov @ 2008-02-01 14:28 UTC (permalink / raw)
To: Marco Stornelli; +Cc: Linuxppc Embedded Mailing List
In-Reply-To: <47A2D424.3090903@coritel.it>
Marco Stornelli wrote:
> Hi,
>
> I used the linux kernel 2.6.10 with a processor MPC8548E. I wrote a
> driver for a device connected with the local bus. This device has an
> external interrupt. In the local bus driver I have used the macro
> MPC85xx_IRQ_EXT<X> to get the interrupt number and pass it to the
> driver and after that register the ISR. Now with a kernel 2.6.21 this
> macro isn't available because in the header file irq.h there is the
> option CONFIG_PPC_MERGE that disable those options. I think this
> problem is related to the migration of ppc code towards powerpc. I
> know that now there is the new device tree source file where I can add
> a device and its interrupt number but I think in this file I should
> describe only the platform device, and this device is not a platform
> device.
How comes that it's not platform device if it hangs off the local bus?
> Then, how can I get now this value? Is there some function to
> call? How can I perform this operation?
Probably irq_alloc_virt()...
^ permalink raw reply
* [PATCH] [POWERPC] fsl_soc: add support for "fsl, immr" compatible matching
From: Anton Vorontsov @ 2008-02-01 15:01 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Scott Wood
Unfortunately it's still impossible to remove device_type = "soc"
from the existing device tree, because older u-boots are looking for
it.
Neither we can remove model number from the soc name to heal
arch/powerpc/boot/cuboot-85xx.c, because then dts'es will be
incompatible with older u-boots again.
So, just one machine converted so far: MPC8360E-RDK. It's new machine
so we don't care about backward compatibility yet.
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
Documentation/powerpc/booting-without-of.txt | 18 ++++------
arch/powerpc/boot/dts/mpc836x_rdk.dts | 1 -
arch/powerpc/sysdev/fsl_soc.c | 51 +++++++++++++++-----------
3 files changed, 37 insertions(+), 33 deletions(-)
diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index b5e46ef..410c847 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -32,7 +32,7 @@ Table of Contents
c) The /cpus/* nodes
d) the /memory node(s)
e) The /chosen node
- f) the /soc<SOCname> node
+ f) the /soc node
IV - "dtc", the device tree compiler
@@ -960,20 +960,16 @@ compatibility.
under /chosen called interrupt-controller which had a phandle value
that pointed to the main interrupt controller)
- f) the /soc<SOCname> node
+ f) the /soc node
This node is used to represent a system-on-a-chip (SOC) and must be
present if the processor is a SOC. The top-level soc node contains
- information that is global to all devices on the SOC. The node name
- should contain a unit address for the SOC, which is the base address
- of the memory-mapped register set for the SOC. The name of an soc
- node should start with "soc", and the remainder of the name should
- represent the part number for the soc. For example, the MPC8540's
- soc node would be called "soc8540".
+ information that is global to all devices on the SOC. The name of an
+ soc node should be "soc".
Required properties:
- - device_type : Should be "soc"
+ - compatible : Should be "<cpu-specific>-immr", "fsl,immr", "simple-bus"
- ranges : Should be defined as specified in 1) to describe the
translation of SOC addresses for memory mapped SOC registers.
- bus-frequency: Contains the bus frequency for the SOC node.
@@ -2871,11 +2867,11 @@ Note that the #address-cells and #size-cells for the SoC node
in this example have been explicitly listed; these are likely
not necessary as they are usually the same as the root node.
- soc8540@e0000000 {
+ soc@e0000000 {
#address-cells = <1>;
#size-cells = <1>;
#interrupt-cells = <2>;
- device_type = "soc";
+ compatible = "fsl,mpc8540-immr", "fsl,immr", "simple-bus";
ranges = <00000000 e0000000 00100000>
reg = <e0000000 00003000>;
bus-frequency = <0>;
diff --git a/arch/powerpc/boot/dts/mpc836x_rdk.dts b/arch/powerpc/boot/dts/mpc836x_rdk.dts
index b062f9b..e35200a 100644
--- a/arch/powerpc/boot/dts/mpc836x_rdk.dts
+++ b/arch/powerpc/boot/dts/mpc836x_rdk.dts
@@ -57,7 +57,6 @@
soc@e0000000 {
#address-cells = <1>;
#size-cells = <1>;
- device_type = "soc";
compatible = "fsl,mpc8360-immr", "fsl,immr", "simple-bus";
ranges = <0 0xe0000000 0x200000>;
reg = <0xe0000000 0x200>;
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index e48b20e..721ad2d 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -48,27 +48,31 @@ static phys_addr_t immrbase = -1;
phys_addr_t get_immrbase(void)
{
struct device_node *soc;
+ int size;
+ u32 naddr;
+ const u32 *prop;
if (immrbase != -1)
return immrbase;
- soc = of_find_node_by_type(NULL, "soc");
- if (soc) {
- int size;
- u32 naddr;
- const u32 *prop = of_get_property(soc, "#address-cells", &size);
+ soc = of_find_compatible_node(NULL, NULL, "fsl,immr");
+ if (!soc) {
+ soc = of_find_node_by_type(NULL, "soc");
+ if (!soc)
+ return immrbase;
+ }
- if (prop && size == 4)
- naddr = *prop;
- else
- naddr = 2;
+ prop = of_get_property(soc, "#address-cells", &size);
+ if (prop && size == 4)
+ naddr = *prop;
+ else
+ naddr = 2;
- prop = of_get_property(soc, "ranges", &size);
- if (prop)
- immrbase = of_translate_address(soc, prop + naddr);
+ prop = of_get_property(soc, "ranges", &size);
+ if (prop)
+ immrbase = of_translate_address(soc, prop + naddr);
- of_node_put(soc);
- }
+ of_node_put(soc);
return immrbase;
}
@@ -528,11 +532,13 @@ static int __init mpc83xx_wdt_init(void)
goto nodev;
}
- soc = of_find_node_by_type(NULL, "soc");
-
+ soc = of_find_compatible_node(NULL, NULL, "fsl,immr");
if (!soc) {
- ret = -ENODEV;
- goto nosoc;
+ soc = of_find_node_by_type(NULL, "soc");
+ if (!soc) {
+ ret = -ENODEV;
+ goto nosoc;
+ }
}
freq = of_get_property(soc, "bus-frequency", NULL);
@@ -1375,9 +1381,12 @@ int __init fsl_spi_init(struct spi_board_info *board_infos,
const u32 *freq;
int size;
- np = of_find_node_by_type(NULL, "soc");
- if (!np)
- return -ENODEV;
+ np = of_find_compatible_node(NULL, NULL, "fsl,immr");
+ if (!np) {
+ np = of_find_node_by_type(NULL, "soc");
+ if (!np)
+ return -ENODEV;
+ }
freq = of_get_property(np, "clock-frequency", &size);
if (!freq || size != sizeof(*freq) || *freq == 0) {
--
1.5.2.2
^ permalink raw reply related
* [PATCH] [POWERPC] get rid of `model = "UCC"' in the ucc nodes
From: Anton Vorontsov @ 2008-02-01 15:01 UTC (permalink / raw)
To: linuxppc-dev
It isn't used anywhere, so remove it. If we'll ever need something
like this, we'll use compatible property instead.
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
Rebased on top of recent tree.
Documentation/powerpc/booting-without-of.txt | 1 -
arch/powerpc/boot/dts/mpc832x_mds.dts | 3 ---
arch/powerpc/boot/dts/mpc832x_rdb.dts | 2 --
arch/powerpc/boot/dts/mpc836x_mds.dts | 2 --
arch/powerpc/boot/dts/mpc8568mds.dts | 2 --
5 files changed, 0 insertions(+), 10 deletions(-)
diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index 410c847..dcf9758 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -1675,7 +1675,6 @@ platforms are moved over to use the flattened-device-tree model.
ucc@2000 {
device_type = "network";
compatible = "ucc_geth";
- model = "UCC";
device-id = <1>;
reg = <2000 200>;
interrupts = <a0 0>;
diff --git a/arch/powerpc/boot/dts/mpc832x_mds.dts b/arch/powerpc/boot/dts/mpc832x_mds.dts
index 9bb4083..f8b4a37 100644
--- a/arch/powerpc/boot/dts/mpc832x_mds.dts
+++ b/arch/powerpc/boot/dts/mpc832x_mds.dts
@@ -255,7 +255,6 @@
enet0: ucc@2200 {
device_type = "network";
compatible = "ucc_geth";
- model = "UCC";
cell-index = <3>;
device-id = <3>;
reg = <0x2200 0x200>;
@@ -271,7 +270,6 @@
enet1: ucc@3200 {
device_type = "network";
compatible = "ucc_geth";
- model = "UCC";
cell-index = <4>;
device-id = <4>;
reg = <0x3200 0x200>;
@@ -287,7 +285,6 @@
ucc@2400 {
device_type = "serial";
compatible = "ucc_uart";
- model = "UCC";
device-id = <5>; /* The UCC number, 1-7*/
port-number = <0>; /* Which ttyQEx device */
soft-uart; /* We need Soft-UART */
diff --git a/arch/powerpc/boot/dts/mpc832x_rdb.dts b/arch/powerpc/boot/dts/mpc832x_rdb.dts
index 94f93d2..ea7fcbf 100644
--- a/arch/powerpc/boot/dts/mpc832x_rdb.dts
+++ b/arch/powerpc/boot/dts/mpc832x_rdb.dts
@@ -208,7 +208,6 @@
enet0: ucc@3000 {
device_type = "network";
compatible = "ucc_geth";
- model = "UCC";
cell-index = <2>;
device-id = <2>;
reg = <0x3000 0x200>;
@@ -224,7 +223,6 @@
enet1: ucc@2200 {
device_type = "network";
compatible = "ucc_geth";
- model = "UCC";
cell-index = <3>;
device-id = <3>;
reg = <0x2200 0x200>;
diff --git a/arch/powerpc/boot/dts/mpc836x_mds.dts b/arch/powerpc/boot/dts/mpc836x_mds.dts
index 55f03e8..525423c 100644
--- a/arch/powerpc/boot/dts/mpc836x_mds.dts
+++ b/arch/powerpc/boot/dts/mpc836x_mds.dts
@@ -257,7 +257,6 @@
enet0: ucc@2000 {
device_type = "network";
compatible = "ucc_geth";
- model = "UCC";
cell-index = <1>;
device-id = <1>;
reg = <0x2000 0x200>;
@@ -274,7 +273,6 @@
enet1: ucc@3000 {
device_type = "network";
compatible = "ucc_geth";
- model = "UCC";
cell-index = <2>;
device-id = <2>;
reg = <0x3000 0x200>;
diff --git a/arch/powerpc/boot/dts/mpc8568mds.dts b/arch/powerpc/boot/dts/mpc8568mds.dts
index 97bc048..66087d5 100644
--- a/arch/powerpc/boot/dts/mpc8568mds.dts
+++ b/arch/powerpc/boot/dts/mpc8568mds.dts
@@ -324,7 +324,6 @@
enet2: ucc@2000 {
device_type = "network";
compatible = "ucc_geth";
- model = "UCC";
cell-index = <1>;
device-id = <1>;
reg = <2000 200>;
@@ -341,7 +340,6 @@
enet3: ucc@3000 {
device_type = "network";
compatible = "ucc_geth";
- model = "UCC";
cell-index = <2>;
device-id = <2>;
reg = <3000 200>;
--
1.5.2.2
^ permalink raw reply related
* AW: External Interrupt
From: Lehmann, Hans (Ritter Elektronik) @ 2008-02-01 14:52 UTC (permalink / raw)
To: Marco Stornelli; +Cc: linuxppc-embedded
In-Reply-To: <47A2D424.3090903@coritel.it>
Marco,
ASFAIK there where some changes and you have to get the irq with =
irq_create_mapping() or irq_of_parse_and_map()
Kindly regards
Hans
=20
Mit freundlichen Gr=FC=DFen
Hans Lehmann
Dipl.-Ing. Elektrotechnik
RITTER Elektronik GmbH
Leverkuser Strasse 65
D-42897 Remscheid
Tel. +49 (0) 2191 - 67 32 40
Fax +49 (0) 2191 - 67 14 29
Email hans.lehmann@ritter-elektronik.de
Homepage www.ritter-elektronik.de
Gesch=E4ftsf=FChrer: Manfred A. Wagner, Dr. Uwe Baader
Sitz der Gesellschaft: Oberhausen
HRB 17168 Duisburg USt-ID DE 814009849
-----Urspr=FCngliche Nachricht-----
Von: =
linuxppc-embedded-bounces+hans.lehmann=3Dritter-elektronik.de@ozlabs.org =
[mailto:linuxppc-embedded-bounces+hans.lehmann=3Dritter-elektronik.de@ozl=
abs.org] Im Auftrag von Marco Stornelli
Gesendet: Freitag, 1. Februar 2008 09:11
An: Linuxppc Embedded Mailing List
Betreff: External Interrupt
Hi,
I used the linux kernel 2.6.10 with a processor MPC8548E. I wrote a =
driver for a device connected with the local bus. This device has an =
external interrupt. In the local bus driver I have used the macro =
MPC85xx_IRQ_EXT<X> to get the interrupt number and pass it to the driver =
and after that register the ISR. Now with a kernel 2.6.21 this macro =
isn't available because in the header file irq.h there is the option =
CONFIG_PPC_MERGE that disable those options. I think this problem is =
related to the migration of ppc code towards powerpc. I know that now =
there is the new device tree source file where I can add a device and =
its interrupt number but I think in this file I should describe only =
the platform device, and this device is not a platform device. Then, how =
can I get now this value? Is there some function to call? How can I =
perform this operation?
Thanks in advance.
Marco
_______________________________________________
Linuxppc-embedded mailing list
Linuxppc-embedded@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-embedded
^ permalink raw reply
* Re: External Interrupt
From: Marco Stornelli @ 2008-02-01 15:15 UTC (permalink / raw)
To: Sergei Shtylyov; +Cc: Linuxppc Embedded Mailing List
In-Reply-To: <47A32C9C.3090709@ru.mvista.com>
Sergei Shtylyov ha scritto:
> Marco Stornelli wrote:
>> Hi,
>>
>> I used the linux kernel 2.6.10 with a processor MPC8548E. I wrote a
>> driver for a device connected with the local bus. This device has an
>> external interrupt. In the local bus driver I have used the macro
>> MPC85xx_IRQ_EXT<X> to get the interrupt number and pass it to the
>> driver and after that register the ISR. Now with a kernel 2.6.21 this
>> macro isn't available because in the header file irq.h there is the
>> option CONFIG_PPC_MERGE that disable those options. I think this
>> problem is related to the migration of ppc code towards powerpc. I
>> know that now there is the new device tree source file where I can add
>> a device and its interrupt number but I think in this file I should
>> describe only the platform device, and this device is not a platform
>> device.
>
> How comes that it's not platform device if it hangs off the local bus?
In SoC system generally the platform device are (more or less) the
microprocessor controller like i2c, pci, local bus itself and so on. I
think is like if you consider a PCI board a platform device only because
it hangs off the PCI link.
>
>> Then, how can I get now this value? Is there some function to
>> call? How can I perform this operation?
>
> Probably irq_alloc_virt()...
>
^ permalink raw reply
* Re: PCI configuration with multiple PCI controllers
From: Sergei Shtylyov @ 2008-02-01 14:43 UTC (permalink / raw)
To: Laurent Lagrange; +Cc: linuxppc-dev
In-Reply-To: <000001c864df$63b833c0$a501a8c0@GEGE6600V>
Hello.
Laurent Lagrange wrote:
> I have a MPC8641 based board. I try to use the two PCIe controllers. My
> firmware configures (physically) the PCI buses as follow:
> ------------------+
> MPC8641 PCIe 1 | bus 1 +--------------+
> | --------------> | PCI device 0 |
> BUS 0 | +--------------+
> - - - - - - - - - +
> MPC8641 PCIe 2 | bus 3 +--------------+
> | --------------> | PCI device 1 |
> BUS 2 | +--------------+
> ------------------+
> I launch the Linux image (2.6.23.9). During the Kernel PCI configuration,
> buses behind the 2nd MPC8641 PCIe are skipped because its primary bus don't
> start at bus number 0. The kernel reconfigure the primary bus number of the
> MPC8641 PCIe 2 controller from 2 to 0.
Hm...
> I can patch the kernel to work with my firmware but I don't know if my PCI
> configuration is the good one.
> What is the common way to configure the PCI for Linux when a new controller
> is found: start the bus number to 0 or to the last bus number + 1?
The latter. Otherwise it just won't work.
WBR, Sergei
^ permalink raw reply
* Re: pthread / TQM5200 problem
From: Grant Likely @ 2008-02-01 15:17 UTC (permalink / raw)
To: Sebastian Theiss; +Cc: linuxppc-dev
In-Reply-To: <003c01c864e2$a6b44e40$0101a8c0@tis>
On 2/1/08, Sebastian Theiss <st12@inf.tu-dresden.de> wrote:
> Hi,
>
> Here's some additional information I forgot when originally posting my
> question today morning: I'm using the DENX ELDK 3.1.1 and a kernel version
> 2.4.25.
Ugh. You might have trouble getting support on this list. Almost
everyone here is firmly focused on the 2.6 kernel. Can you upgrade to
a recent kernel version. 2.6.24 is looking really good for mpc5200
work.
Cheers,
g.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [PATCH] [POWERPC] get rid of `model = "UCC"' in the ucc nodes
From: Kumar Gala @ 2008-02-01 15:32 UTC (permalink / raw)
To: Anton Vorontsov; +Cc: linuxppc-dev
In-Reply-To: <20080201150126.GB26545@localhost.localdomain>
On Feb 1, 2008, at 9:01 AM, Anton Vorontsov wrote:
> It isn't used anywhere, so remove it. If we'll ever need something
> like this, we'll use compatible property instead.
>
> Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
> ---
>
> Rebased on top of recent tree.
>
> Documentation/powerpc/booting-without-of.txt | 1 -
> arch/powerpc/boot/dts/mpc832x_mds.dts | 3 ---
> arch/powerpc/boot/dts/mpc832x_rdb.dts | 2 --
> arch/powerpc/boot/dts/mpc836x_mds.dts | 2 --
> arch/powerpc/boot/dts/mpc8568mds.dts | 2 --
> 5 files changed, 0 insertions(+), 10 deletions(-)
>
> diff --git a/Documentation/powerpc/booting-without-of.txt b/
> Documentation/powerpc/booting-without-of.txt
> index 410c847..dcf9758 100644
> --- a/Documentation/powerpc/booting-without-of.txt
> +++ b/Documentation/powerpc/booting-without-of.txt
> @@ -1675,7 +1675,6 @@ platforms are moved over to use the flattened-
> device-tree model.
> ucc@2000 {
> device_type = "network";
> compatible = "ucc_geth";
> - model = "UCC";
> device-id = <1>;
can we change device-id to cell-index?
>
- k
^ permalink raw reply
* Re: External Interrupt
From: Sergei Shtylyov @ 2008-02-01 15:35 UTC (permalink / raw)
To: Marco Stornelli; +Cc: Linuxppc Embedded Mailing List
In-Reply-To: <47A3379F.2090004@coritel.it>
Marco Stornelli wrote:
>>>I used the linux kernel 2.6.10 with a processor MPC8548E. I wrote a
>>>driver for a device connected with the local bus. This device has an
>>>external interrupt. In the local bus driver I have used the macro
>>>MPC85xx_IRQ_EXT<X> to get the interrupt number and pass it to the
>>>driver and after that register the ISR. Now with a kernel 2.6.21 this
>>>macro isn't available because in the header file irq.h there is the
>>>option CONFIG_PPC_MERGE that disable those options. I think this
>>>problem is related to the migration of ppc code towards powerpc. I
>>>know that now there is the new device tree source file where I can add
>>>a device and its interrupt number but I think in this file I should
>>>describe only the platform device, and this device is not a platform
>>>device.
>> How comes that it's not platform device if it hangs off the local bus?
> In SoC system generally the platform device are (more or less) the
> microprocessor controller like i2c, pci, local bus itself and so on.
That's SoC devices but the notion of the platform device is not limited to
SoC device only, rather to all the on-board devices.
> I think is like if you consider a PCI board a platform device only because
> it hangs off the PCI link.
No. PCI devices are detectable/configurable by kernel -- even if they are
on-board chips, they can be found by PCI bus scan (and finally presented as
the device nodes as well), while local bus devices (most probably) not. An
example (that comes to mind) of a device hanging off the local bus and yet
described by the device tree are the flash chips.
WBR, Sergei
^ permalink raw reply
* Re: External Interrupt
From: Marco Stornelli @ 2008-02-01 16:22 UTC (permalink / raw)
To: Sergei Shtylyov; +Cc: Linuxppc Embedded Mailing List
In-Reply-To: <47A33C59.4020509@ru.mvista.com>
Sergei Shtylyov ha scritto:
> Marco Stornelli wrote:
>
>>>> I used the linux kernel 2.6.10 with a processor MPC8548E. I wrote a
>>>> driver for a device connected with the local bus. This device has an
>>>> external interrupt. In the local bus driver I have used the macro
>>>> MPC85xx_IRQ_EXT<X> to get the interrupt number and pass it to the
>>>> driver and after that register the ISR. Now with a kernel 2.6.21 this
>>>> macro isn't available because in the header file irq.h there is the
>>>> option CONFIG_PPC_MERGE that disable those options. I think this
>>>> problem is related to the migration of ppc code towards powerpc. I
>>>> know that now there is the new device tree source file where I can add
>>>> a device and its interrupt number but I think in this file I should
>>>> describe only the platform device, and this device is not a platform
>>>> device.
>
>>> How comes that it's not platform device if it hangs off the local bus?
>
>> In SoC system generally the platform device are (more or less) the
>> microprocessor controller like i2c, pci, local bus itself and so on.
>
> That's SoC devices but the notion of the platform device is not limited to
> SoC device only, rather to all the on-board devices.
>
>> I think is like if you consider a PCI board a platform device only because
>> it hangs off the PCI link.
>
> No. PCI devices are detectable/configurable by kernel -- even if they are
> on-board chips, they can be found by PCI bus scan (and finally presented as
> the device nodes as well), while local bus devices (most probably) not. An
> example (that comes to mind) of a device hanging off the local bus and yet
> described by the device tree are the flash chips.
Yes you are right. The local bus is like i2c, but I've never seen a
device connected with i2c and described with a sub-node of i2c node in
the dts file, however I think it's only philosophy, the most important
thing is that there is a way to get the irq number :)
Thanks for your response.
Regards.
Marco
>
> WBR, Sergei
>
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
>
^ permalink raw reply
* Re: [PATCH] [POWERPC] get rid of `model = "UCC"' in the ucc nodes
From: Grant Likely @ 2008-02-01 16:23 UTC (permalink / raw)
To: Kumar Gala; +Cc: Jon Loeliger, linuxppc-dev, Scott Wood
In-Reply-To: <72B60725-FB4A-42FA-832D-8FD5434B9042@kernel.crashing.org>
On 2/1/08, Kumar Gala <galak@kernel.crashing.org> wrote:
>
> > --- a/Documentation/powerpc/booting-without-of.txt
> > +++ b/Documentation/powerpc/booting-without-of.txt
> > @@ -1675,7 +1675,6 @@ platforms are moved over to use the flattened-
> > device-tree model.
> > ucc@2000 {
> > device_type = "network";
> > compatible = "ucc_geth";
> > - model = "UCC";
> > device-id = <1>;
>
> can we change device-id to cell-index?
<aside>
Here's a thought; do we really need a cell-index at all? (and I'm
talking in general; not just this specific case). I'm starting to
think we should migrate away from using it.
cell-index has been useful for things like clock controllers to know
what offset into a shared clock control register or something like
that and a driver would pass the cell-index value to the shared reg
driver when requesting service. However, I think the information
encoded in cell-index is already encoded in the device tree in a
different manor.
Typically, shared registers and the like are all chip specific and the
behaviour of the shared register drivers usually needs to be tweaked
for different SoCs. Each ip core on an SoC is already uniquely
indexed via the reg property. True, 'reg' is sparse (0x2000, 0x2200,
0x2300, ...) whereas cell-index is tight (0,1,2,3,...), but I don't
think that introduces any additional difficulty.
So, instead of a driver passing it's cell-index value to the shared
reg driver, it would pass it's reg base instead. The shared register
driver could then choose an internal representation that makes sense
for it instead of whatever layout was chosen by the device tree.
Dropping cell-index would mean one less property to keep in sync when
tailoring device trees. (== less complexity for board porters).
Besides, the purpose of cell-index is often misunderstood already by
people trying to use it to describe port numbers (ttyS0, ttyS1, etc).
Thoughts?
</aside>
Cheers,
g.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* RE: [PATCH] [POWERPC] Xilinx: hwicap driver
From: Stephen Neuendorffer @ 2008-02-01 17:31 UTC (permalink / raw)
To: Nathan Lynch; +Cc: linuxppc-dev
In-Reply-To: <20080201055613.GY14201@localdomain>
Thanks,
I realized that on the way home.. That's what I get for trying to
finish something quickly before leaving.. :)
Steve
> -----Original Message-----
> From: Nathan Lynch [mailto:ntl@pobox.com]
> Sent: Thursday, January 31, 2008 9:56 PM
> To: Stephen Neuendorffer
> Cc: linuxppc-dev@ozlabs.org; grant.likely@secretlab.ca;
jacmet@sunsite.dk
> Subject: Re: [PATCH] [POWERPC] Xilinx: hwicap driver
>=20
> Stephen Neuendorffer wrote:
> >
> > +static ssize_t
> > +hwicap_read(struct file *file, char *buf, size_t count, loff_t
*ppos)
> > +{
> > + struct hwicap_drvdata *drvdata =3D file->private_data;
> > + ssize_t bytes_to_read =3D 0;
> > + u32 *kbuf;
> > + u32 words;
> > + u32 bytes_remaining;
> > + int status;
> > +
> > + spin_lock(&hwicap_spinlock);
> > + if (drvdata->is_accessing)
> > + return -EBUSY;
>=20
> Need to unlock before returning (several places in this patch).
>=20
^ permalink raw reply
* [PATCH] [POWERPC][NET][SERIAL] UCCs: replace device-id with cell-index (was: Re: [PATCH] [POWERPC] get rid of `model = "UCC"' in the ucc nodes)
From: Anton Vorontsov @ 2008-02-01 17:33 UTC (permalink / raw)
To: Kumar Gala
Cc: netdev, linuxppc-dev, linux-serial, Li Yang, Jeff Garzik,
Timur Tabi
In-Reply-To: <72B60725-FB4A-42FA-832D-8FD5434B9042@kernel.crashing.org>
On Fri, Feb 01, 2008 at 09:32:38AM -0600, Kumar Gala wrote:
> On Feb 1, 2008, at 9:01 AM, Anton Vorontsov wrote:
>
> >It isn't used anywhere, so remove it. If we'll ever need something
> >like this, we'll use compatible property instead.
> >
> >Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
> >---
> >
> >Rebased on top of recent tree.
> >
> >Documentation/powerpc/booting-without-of.txt | 1 -
> >arch/powerpc/boot/dts/mpc832x_mds.dts | 3 ---
> >arch/powerpc/boot/dts/mpc832x_rdb.dts | 2 --
> >arch/powerpc/boot/dts/mpc836x_mds.dts | 2 --
> >arch/powerpc/boot/dts/mpc8568mds.dts | 2 --
> >5 files changed, 0 insertions(+), 10 deletions(-)
> >
> >diff --git a/Documentation/powerpc/booting-without-of.txt b/
> >Documentation/powerpc/booting-without-of.txt
> >index 410c847..dcf9758 100644
> >--- a/Documentation/powerpc/booting-without-of.txt
> >+++ b/Documentation/powerpc/booting-without-of.txt
> >@@ -1675,7 +1675,6 @@ platforms are moved over to use the flattened-
> >device-tree model.
> > ucc@2000 {
> > device_type = "network";
> > compatible = "ucc_geth";
> >- model = "UCC";
> > device-id = <1>;
>
> can we change device-id to cell-index?
Sure. But let's do this in the separate patch? Because this change
actually touches the code in the two subsystems: net and serial.
I hope everybody will agree to pass it through powerpc tree..?
- - - -
From: Anton Vorontsov <avorontsov@ru.mvista.com>
Subject: [POWERPC][NET][SERIAL] UCCs: replace device-id with cell-index
device-id is worse than cell-index. Probably cell-index isn't
good either, but device-id is worse anyway.
Drivers are modified for backward compatibility's sake.
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
Documentation/powerpc/booting-without-of.txt | 4 ++--
arch/powerpc/boot/dts/mpc832x_mds.dts | 4 +---
arch/powerpc/boot/dts/mpc832x_rdb.dts | 2 --
arch/powerpc/boot/dts/mpc836x_mds.dts | 2 --
arch/powerpc/boot/dts/mpc836x_rdk.dts | 12 ++++++------
arch/powerpc/boot/dts/mpc8568mds.dts | 2 --
drivers/net/ucc_geth.c | 8 +++++++-
drivers/net/ucc_geth_mii.c | 11 ++++++++---
drivers/serial/ucc_uart.c | 16 ++++++++++++----
9 files changed, 36 insertions(+), 25 deletions(-)
diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index dcf9758..7b30798 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -1618,7 +1618,7 @@ platforms are moved over to use the flattened-device-tree model.
"bisync", "atm", or "serial".
- compatible : could be "ucc_geth" or "fsl_atm" and so on.
- model : should be "UCC".
- - device-id : the ucc number(1-8), corresponding to UCCx in UM.
+ - cell-index : the ucc number(1-8), corresponding to UCCx in UM.
- reg : Offset and length of the register set for the device
- interrupts : <a b> where a is the interrupt number and b is a
field that represents an encoding of the sense and level
@@ -1675,7 +1675,7 @@ platforms are moved over to use the flattened-device-tree model.
ucc@2000 {
device_type = "network";
compatible = "ucc_geth";
- device-id = <1>;
+ cell-index = <1>;
reg = <2000 200>;
interrupts = <a0 0>;
interrupt-parent = <700>;
diff --git a/arch/powerpc/boot/dts/mpc832x_mds.dts b/arch/powerpc/boot/dts/mpc832x_mds.dts
index f8b4a37..539e02f 100644
--- a/arch/powerpc/boot/dts/mpc832x_mds.dts
+++ b/arch/powerpc/boot/dts/mpc832x_mds.dts
@@ -256,7 +256,6 @@
device_type = "network";
compatible = "ucc_geth";
cell-index = <3>;
- device-id = <3>;
reg = <0x2200 0x200>;
interrupts = <34>;
interrupt-parent = <&qeic>;
@@ -271,7 +270,6 @@
device_type = "network";
compatible = "ucc_geth";
cell-index = <4>;
- device-id = <4>;
reg = <0x3200 0x200>;
interrupts = <35>;
interrupt-parent = <&qeic>;
@@ -285,7 +283,7 @@
ucc@2400 {
device_type = "serial";
compatible = "ucc_uart";
- device-id = <5>; /* The UCC number, 1-7*/
+ cell-index = <5>; /* The UCC number, 1-7*/
port-number = <0>; /* Which ttyQEx device */
soft-uart; /* We need Soft-UART */
reg = <0x2400 0x200>;
diff --git a/arch/powerpc/boot/dts/mpc832x_rdb.dts b/arch/powerpc/boot/dts/mpc832x_rdb.dts
index ea7fcbf..179c81c 100644
--- a/arch/powerpc/boot/dts/mpc832x_rdb.dts
+++ b/arch/powerpc/boot/dts/mpc832x_rdb.dts
@@ -209,7 +209,6 @@
device_type = "network";
compatible = "ucc_geth";
cell-index = <2>;
- device-id = <2>;
reg = <0x3000 0x200>;
interrupts = <33>;
interrupt-parent = <&qeic>;
@@ -224,7 +223,6 @@
device_type = "network";
compatible = "ucc_geth";
cell-index = <3>;
- device-id = <3>;
reg = <0x2200 0x200>;
interrupts = <34>;
interrupt-parent = <&qeic>;
diff --git a/arch/powerpc/boot/dts/mpc836x_mds.dts b/arch/powerpc/boot/dts/mpc836x_mds.dts
index 525423c..8160ff2 100644
--- a/arch/powerpc/boot/dts/mpc836x_mds.dts
+++ b/arch/powerpc/boot/dts/mpc836x_mds.dts
@@ -258,7 +258,6 @@
device_type = "network";
compatible = "ucc_geth";
cell-index = <1>;
- device-id = <1>;
reg = <0x2000 0x200>;
interrupts = <32>;
interrupt-parent = <&qeic>;
@@ -274,7 +273,6 @@
device_type = "network";
compatible = "ucc_geth";
cell-index = <2>;
- device-id = <2>;
reg = <0x3000 0x200>;
interrupts = <33>;
interrupt-parent = <&qeic>;
diff --git a/arch/powerpc/boot/dts/mpc836x_rdk.dts b/arch/powerpc/boot/dts/mpc836x_rdk.dts
index e35200a..cc56338 100644
--- a/arch/powerpc/boot/dts/mpc836x_rdk.dts
+++ b/arch/powerpc/boot/dts/mpc836x_rdk.dts
@@ -179,7 +179,7 @@
enet0: ucc@2000 {
device_type = "network";
compatible = "ucc_geth";
- device-id = <1>;
+ cell-index = <1>;
reg = <0x2000 0x200>;
interrupts = <32>;
interrupt-parent = <&qeic>;
@@ -194,7 +194,7 @@
enet1: ucc@3000 {
device_type = "network";
compatible = "ucc_geth";
- device-id = <2>;
+ cell-index = <2>;
reg = <0x3000 0x200>;
interrupts = <33>;
interrupt-parent = <&qeic>;
@@ -209,7 +209,7 @@
enet2: ucc@2600 {
device_type = "network";
compatible = "ucc_geth";
- device-id = <7>;
+ cell-index = <7>;
reg = <0x2600 0x200>;
interrupts = <42>;
interrupt-parent = <&qeic>;
@@ -224,7 +224,7 @@
enet3: ucc@3200 {
device_type = "network";
compatible = "ucc_geth";
- device-id = <4>;
+ cell-index = <4>;
reg = <0x3200 0x200>;
interrupts = <35>;
interrupt-parent = <&qeic>;
@@ -271,7 +271,7 @@
device_type = "serial";
compatible = "ucc_uart";
reg = <0x2400 0x200>;
- device-id = <5>;
+ cell-index = <5>;
port-number = <0>;
rx-clock-name = "brg7";
tx-clock-name = "brg8";
@@ -284,7 +284,7 @@
device_type = "serial";
compatible = "ucc_uart";
reg = <0x3400 0x200>;
- device-id = <6>;
+ cell-index = <6>;
port-number = <1>;
rx-clock-name = "brg13";
tx-clock-name = "brg14";
diff --git a/arch/powerpc/boot/dts/mpc8568mds.dts b/arch/powerpc/boot/dts/mpc8568mds.dts
index 66087d5..df4b5e8 100644
--- a/arch/powerpc/boot/dts/mpc8568mds.dts
+++ b/arch/powerpc/boot/dts/mpc8568mds.dts
@@ -325,7 +325,6 @@
device_type = "network";
compatible = "ucc_geth";
cell-index = <1>;
- device-id = <1>;
reg = <2000 200>;
interrupts = <20>;
interrupt-parent = <&qeic>;
@@ -341,7 +340,6 @@
device_type = "network";
compatible = "ucc_geth";
cell-index = <2>;
- device-id = <2>;
reg = <3000 200>;
interrupts = <21>;
interrupt-parent = <&qeic>;
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index fba0811..3a68b94 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -3852,7 +3852,13 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
ugeth_vdbg("%s: IN", __FUNCTION__);
- prop = of_get_property(np, "device-id", NULL);
+ prop = of_get_property(np, "cell-index", NULL);
+ if (!prop) {
+ prop = of_get_property(np, "device-id", NULL);
+ if (!prop)
+ return -ENODEV;
+ }
+
ucc_num = *prop - 1;
if ((ucc_num < 0) || (ucc_num > 7))
return -ENODEV;
diff --git a/drivers/net/ucc_geth_mii.c b/drivers/net/ucc_geth_mii.c
index e3ba14a..e5b17d7 100644
--- a/drivers/net/ucc_geth_mii.c
+++ b/drivers/net/ucc_geth_mii.c
@@ -203,9 +203,14 @@ static int uec_mdio_probe(struct of_device *ofdev, const struct of_device_id *ma
if ((res.start >= tempres.start) &&
(res.end <= tempres.end)) {
/* set this UCC to be the MII master */
- const u32 *id = of_get_property(tempnp, "device-id", NULL);
- if (id == NULL)
- goto bus_register_fail;
+ const u32 *id;
+
+ id = of_get_property(tempnp, "cell-index", NULL);
+ if (!id) {
+ id = of_get_property(tempnp, "device-id", NULL);
+ if (!id)
+ goto bus_register_fail;
+ }
ucc_set_qe_mux_mii_mng(*id - 1);
diff --git a/drivers/serial/ucc_uart.c b/drivers/serial/ucc_uart.c
index e0994f0..5e4310c 100644
--- a/drivers/serial/ucc_uart.c
+++ b/drivers/serial/ucc_uart.c
@@ -1270,10 +1270,18 @@ static int ucc_uart_probe(struct of_device *ofdev,
/* Get the UCC number (device ID) */
/* UCCs are numbered 1-7 */
- iprop = of_get_property(np, "device-id", NULL);
- if (!iprop || (*iprop < 1) || (*iprop > UCC_MAX_NUM)) {
- dev_err(&ofdev->dev,
- "missing or invalid UCC specified in device tree\n");
+ iprop = of_get_property(np, "cell-index", NULL);
+ if (!iprop) {
+ iprop = of_get_property(np, "device-id", NULL);
+ if (!iprop) {
+ dev_err(&ofdev->dev, "UCC is unspecified in "
+ "device tree\n");
+ return -EINVAL;
+ }
+ }
+
+ if ((*iprop < 1) || (*iprop > UCC_MAX_NUM)) {
+ dev_err(&ofdev->dev, "no support for UCC%u\n", *iprop);
kfree(qe_port);
return -ENODEV;
}
--
1.5.2.2
^ permalink raw reply related
* Re: Kernel oops while duming user core.
From: Scott Wood @ 2008-02-01 17:38 UTC (permalink / raw)
To: Nathan Lynch; +Cc: linuxppc-dev
In-Reply-To: <20080131161527.GT14201@localdomain>
On Thu, Jan 31, 2008 at 10:15:27AM -0600, Nathan Lynch wrote:
> Rune Torgersen wrote:
> > Hi
> >
> > I get the following kernel core while a user program I have is dumping
> > core.
> > Any DIeas at what to look for? (this is runnign 2.6.24, arch/powerpc on
> > a 8280)
> > When runnign the program on 2.6.18 arch/ppc, the program gets a sig 11
> > and dumps core.
> > On 2.6.24, I ghet the kernel oops, and then the program hangs sround
> > forever and is unkillable.
>
> Hmm, this is the second report of 2.6.24 crashing in
> __flush_dcache_icache during a core dump; see:
> http://ozlabs.org/pipermail/linuxppc-dev/2007-December/048662.html
>
> Is this easily recreatable?
Yes, this program does it reliably:
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void *threadfn(void *arg)
{
fprintf(stderr, "threadfn\n");
fflush(stderr);
sleep(1);
*(char *)0=0;
return NULL;
}
int main(void)
{
pthread_t thread[4];
int i;
for (i = 0; i < 4; i++)
pthread_create(&thread[0], NULL, threadfn, NULL);
for (;;);
}
^ permalink raw reply
* Re: [PATCH] [POWERPC][NET][SERIAL] UCCs: replace device-id with cell-index
From: Jeff Garzik @ 2008-02-01 17:52 UTC (permalink / raw)
To: avorontsov; +Cc: netdev, linuxppc-dev, linux-serial, Li Yang, Timur Tabi
In-Reply-To: <20080201173331.GA8020@localhost.localdomain>
Anton Vorontsov wrote:
> On Fri, Feb 01, 2008 at 09:32:38AM -0600, Kumar Gala wrote:
>> On Feb 1, 2008, at 9:01 AM, Anton Vorontsov wrote:
>>
>>> It isn't used anywhere, so remove it. If we'll ever need something
>>> like this, we'll use compatible property instead.
>>>
>>> Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
>>> ---
>>>
>>> Rebased on top of recent tree.
>>>
>>> Documentation/powerpc/booting-without-of.txt | 1 -
>>> arch/powerpc/boot/dts/mpc832x_mds.dts | 3 ---
>>> arch/powerpc/boot/dts/mpc832x_rdb.dts | 2 --
>>> arch/powerpc/boot/dts/mpc836x_mds.dts | 2 --
>>> arch/powerpc/boot/dts/mpc8568mds.dts | 2 --
>>> 5 files changed, 0 insertions(+), 10 deletions(-)
>>>
>>> diff --git a/Documentation/powerpc/booting-without-of.txt b/
>>> Documentation/powerpc/booting-without-of.txt
>>> index 410c847..dcf9758 100644
>>> --- a/Documentation/powerpc/booting-without-of.txt
>>> +++ b/Documentation/powerpc/booting-without-of.txt
>>> @@ -1675,7 +1675,6 @@ platforms are moved over to use the flattened-
>>> device-tree model.
>>> ucc@2000 {
>>> device_type = "network";
>>> compatible = "ucc_geth";
>>> - model = "UCC";
>>> device-id = <1>;
>> can we change device-id to cell-index?
>
> Sure. But let's do this in the separate patch? Because this change
> actually touches the code in the two subsystems: net and serial.
>
> I hope everybody will agree to pass it through powerpc tree..?
>
> - - - -
> From: Anton Vorontsov <avorontsov@ru.mvista.com>
> Subject: [POWERPC][NET][SERIAL] UCCs: replace device-id with cell-index
>
> device-id is worse than cell-index. Probably cell-index isn't
> good either, but device-id is worse anyway.
>
> Drivers are modified for backward compatibility's sake.
>
> Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
> ---
> Documentation/powerpc/booting-without-of.txt | 4 ++--
> arch/powerpc/boot/dts/mpc832x_mds.dts | 4 +---
> arch/powerpc/boot/dts/mpc832x_rdb.dts | 2 --
> arch/powerpc/boot/dts/mpc836x_mds.dts | 2 --
> arch/powerpc/boot/dts/mpc836x_rdk.dts | 12 ++++++------
> arch/powerpc/boot/dts/mpc8568mds.dts | 2 --
> drivers/net/ucc_geth.c | 8 +++++++-
> drivers/net/ucc_geth_mii.c | 11 ++++++++---
> drivers/serial/ucc_uart.c | 16 ++++++++++++----
> 9 files changed, 36 insertions(+), 25 deletions(-)
ACK drivers/net
^ permalink raw reply
* [PATCH] [POWERPC] Xilinx: hwicap driver
From: Stephen Neuendorffer @ 2008-02-01 18:22 UTC (permalink / raw)
To: linuxppc-dev, grant.likely, jacmet, ntl
In-Reply-To: <1201827769-7439-1-git-send-email-stephen.neuendorffer@xilinx.com>
This includes code for new fifo-based xps_hwicap in addition to the
older opb_hwicap, which has a significantly different interface. The
common code between the two drivers is largely shared.
Significant differences exists between this driver and what is
supported in the EDK drivers. In particular, most of the
architecture-specific code for reconfiguring individual FPGA resources
has been removed. This functionality is likely better provided in a
user-space support library. In addition, read and write access is
supported. In addition, although the xps_hwicap cores support
interrupt-driver mode, this driver only supports polled operation, in
order to make the code simpler, and since the interrupt processing
overhead is likely to slow down the throughput under Linux.
Signed-off-by: Stephen Neuendorffer <stephen.neuendorffer@xilinx.com>
Fixed to add mutexes, and a few style issues.
---
drivers/char/Kconfig | 7 +
drivers/char/Makefile | 1 +
drivers/char/xilinx_hwicap/Makefile | 7 +
drivers/char/xilinx_hwicap/buffer_icap.c | 380 ++++++++++++
drivers/char/xilinx_hwicap/buffer_icap.h | 57 ++
drivers/char/xilinx_hwicap/fifo_icap.c | 381 ++++++++++++
drivers/char/xilinx_hwicap/fifo_icap.h | 62 ++
drivers/char/xilinx_hwicap/xilinx_hwicap.c | 900 ++++++++++++++++++++++++++++
drivers/char/xilinx_hwicap/xilinx_hwicap.h | 193 ++++++
9 files changed, 1988 insertions(+), 0 deletions(-)
create mode 100644 drivers/char/xilinx_hwicap/Makefile
create mode 100644 drivers/char/xilinx_hwicap/buffer_icap.c
create mode 100644 drivers/char/xilinx_hwicap/buffer_icap.h
create mode 100644 drivers/char/xilinx_hwicap/fifo_icap.c
create mode 100644 drivers/char/xilinx_hwicap/fifo_icap.h
create mode 100644 drivers/char/xilinx_hwicap/xilinx_hwicap.c
create mode 100644 drivers/char/xilinx_hwicap/xilinx_hwicap.h
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index ef1ed5d..157ae2a 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -831,6 +831,13 @@ config DTLK
To compile this driver as a module, choose M here: the
module will be called dtlk.
+config XILINX_HWICAP
+ tristate "Xilinx HWICAP Support"
+ depends on XILINX_VIRTEX
+ help
+ This option enables support for Xilinx Internal Configuration
+ Access Port (ICAP) driver.
+
config R3964
tristate "Siemens R3964 line discipline"
---help---
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 07304d5..3a278a0 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -76,6 +76,7 @@ obj-$(CONFIG_EFI_RTC) += efirtc.o
obj-$(CONFIG_SGI_DS1286) += ds1286.o
obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o
obj-$(CONFIG_DS1302) += ds1302.o
+obj-$(CONFIG_XILINX_HWICAP) += xilinx_hwicap/
ifeq ($(CONFIG_GENERIC_NVRAM),y)
obj-$(CONFIG_NVRAM) += generic_nvram.o
else
diff --git a/drivers/char/xilinx_hwicap/Makefile b/drivers/char/xilinx_hwicap/Makefile
new file mode 100644
index 0000000..5491cbc
--- /dev/null
+++ b/drivers/char/xilinx_hwicap/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the Xilinx OPB hwicap driver
+#
+
+obj-$(CONFIG_XILINX_HWICAP) += xilinx_hwicap_m.o
+
+xilinx_hwicap_m-y := xilinx_hwicap.o fifo_icap.o buffer_icap.o
diff --git a/drivers/char/xilinx_hwicap/buffer_icap.c b/drivers/char/xilinx_hwicap/buffer_icap.c
new file mode 100644
index 0000000..dfea2bd
--- /dev/null
+++ b/drivers/char/xilinx_hwicap/buffer_icap.c
@@ -0,0 +1,380 @@
+/*****************************************************************************
+ *
+ * Author: Xilinx, 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.
+ *
+ * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
+ * AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
+ * SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE,
+ * OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
+ * APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
+ * THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
+ * AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
+ * FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY
+ * WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
+ * IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
+ * REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
+ * INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE.
+ *
+ * Xilinx products are not intended for use in life support appliances,
+ * devices, or systems. Use in such applications is expressly prohibited.
+ *
+ * (c) Copyright 2003-2008 Xilinx Inc.
+ * All rights reserved.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *****************************************************************************/
+
+#include "buffer_icap.h"
+
+/* Indicates how many bytes will fit in a buffer. (1 BRAM) */
+#define XHI_MAX_BUFFER_BYTES 2048
+#define XHI_MAX_BUFFER_INTS (XHI_MAX_BUFFER_BYTES >> 2)
+
+/* File access and error constants */
+#define XHI_DEVICE_READ_ERROR -1
+#define XHI_DEVICE_WRITE_ERROR -2
+#define XHI_BUFFER_OVERFLOW_ERROR -3
+
+#define XHI_DEVICE_READ 0x1
+#define XHI_DEVICE_WRITE 0x0
+
+/* Constants for checking transfer status */
+#define XHI_CYCLE_DONE 0
+#define XHI_CYCLE_EXECUTING 1
+
+/* buffer_icap register offsets */
+
+/* Size of transfer, read & write */
+#define XHI_SIZE_REG_OFFSET 0x800L
+/* offset into bram, read & write */
+#define XHI_BRAM_OFFSET_REG_OFFSET 0x804L
+/* Read not Configure, direction of transfer. Write only */
+#define XHI_RNC_REG_OFFSET 0x808L
+/* Indicates transfer complete. Read only */
+#define XHI_STATUS_REG_OFFSET 0x80CL
+
+/* Constants for setting the RNC register */
+#define XHI_CONFIGURE 0x0UL
+#define XHI_READBACK 0x1UL
+
+/* Constants for the Done register */
+#define XHI_NOT_FINISHED 0x0UL
+#define XHI_FINISHED 0x1UL
+
+#define XHI_BUFFER_START 0
+
+/**
+ * buffer_icap_get_status: Get the contents of the status register.
+ * @parameter base_address: is the base address of the device
+ *
+ * The status register contains the ICAP status and the done bit.
+ *
+ * D8 - cfgerr
+ * D7 - dalign
+ * D6 - rip
+ * D5 - in_abort_l
+ * D4 - Always 1
+ * D3 - Always 1
+ * D2 - Always 1
+ * D1 - Always 1
+ * D0 - Done bit
+ **/
+static inline u32 buffer_icap_get_status(void __iomem *base_address)
+{
+ return in_be32(base_address + XHI_STATUS_REG_OFFSET);
+}
+
+/**
+ * buffer_icap_get_bram: Reads data from the storage buffer bram.
+ * @parameter base_address: contains the base address of the component.
+ * @parameter offset: The word offset from which the data should be read.
+ *
+ * A bram is used as a configuration memory cache. One frame of data can
+ * be stored in this "storage buffer".
+ **/
+static inline u32 buffer_icap_get_bram(void __iomem *base_address,
+ u32 offset)
+{
+ return in_be32(base_address + (offset << 2));
+}
+
+/**
+ * buffer_icap_busy: Return true if the icap device is busy
+ * @parameter base_address: is the base address of the device
+ *
+ * The queries the low order bit of the status register, which
+ * indicates whether the current configuration or readback operation
+ * has completed.
+ **/
+static inline bool buffer_icap_busy(void __iomem *base_address)
+{
+ return (buffer_icap_get_status(base_address) & 1) == XHI_NOT_FINISHED;
+}
+
+/**
+ * buffer_icap_busy: Return true if the icap device is not busy
+ * @parameter base_address: is the base address of the device
+ *
+ * The queries the low order bit of the status register, which
+ * indicates whether the current configuration or readback operation
+ * has completed.
+ **/
+static inline bool buffer_icap_done(void __iomem *base_address)
+{
+ return (buffer_icap_get_status(base_address) & 1) == XHI_FINISHED;
+}
+
+/**
+ * buffer_icap_set_size: Set the size register.
+ * @parameter base_address: is the base address of the device
+ * @parameter data: The size in bytes.
+ *
+ * The size register holds the number of 8 bit bytes to transfer between
+ * bram and the icap (or icap to bram).
+ **/
+static inline void buffer_icap_set_size(void __iomem *base_address,
+ u32 data)
+{
+ out_be32(base_address + XHI_SIZE_REG_OFFSET, data);
+}
+
+/**
+ * buffer_icap_mSetoffsetReg: Set the bram offset register.
+ * @parameter base_address: contains the base address of the device.
+ * @parameter data: is the value to be written to the data register.
+ *
+ * The bram offset register holds the starting bram address to transfer
+ * data from during configuration or write data to during readback.
+ **/
+static inline void buffer_icap_set_offset(void __iomem *base_address,
+ u32 data)
+{
+ out_be32(base_address + XHI_BRAM_OFFSET_REG_OFFSET, data);
+}
+
+/**
+ * buffer_icap_set_rnc: Set the RNC (Readback not Configure) register.
+ * @parameter base_address: contains the base address of the device.
+ * @parameter data: is the value to be written to the data register.
+ *
+ * The RNC register determines the direction of the data transfer. It
+ * controls whether a configuration or readback take place. Writing to
+ * this register initiates the transfer. A value of 1 initiates a
+ * readback while writing a value of 0 initiates a configuration.
+ **/
+static inline void buffer_icap_set_rnc(void __iomem *base_address,
+ u32 data)
+{
+ out_be32(base_address + XHI_RNC_REG_OFFSET, data);
+}
+
+/**
+ * buffer_icap_set_bram: Write data to the storage buffer bram.
+ * @parameter base_address: contains the base address of the component.
+ * @parameter offset: The word offset at which the data should be written.
+ * @parameter data: The value to be written to the bram offset.
+ *
+ * A bram is used as a configuration memory cache. One frame of data can
+ * be stored in this "storage buffer".
+ **/
+static inline void buffer_icap_set_bram(void __iomem *base_address,
+ u32 offset, u32 data)
+{
+ out_be32(base_address + (offset << 2), data);
+}
+
+/**
+ * buffer_icap_device_read: Transfer bytes from ICAP to the storage buffer.
+ * @parameter drvdata: a pointer to the drvdata.
+ * @parameter offset: The storage buffer start address.
+ * @parameter count: The number of words (32 bit) to read from the
+ * device (ICAP).
+ **/
+static int buffer_icap_device_read(struct hwicap_drvdata *drvdata,
+ u32 offset, u32 count)
+{
+
+ s32 retries = 0;
+ void __iomem *base_address = drvdata->base_address;
+
+ if (buffer_icap_busy(base_address))
+ return -EBUSY;
+
+ if ((offset + count) > XHI_MAX_BUFFER_INTS)
+ return -EINVAL;
+
+ /* setSize count*4 to get bytes. */
+ buffer_icap_set_size(base_address, (count << 2));
+ buffer_icap_set_offset(base_address, offset);
+ buffer_icap_set_rnc(base_address, XHI_READBACK);
+
+ while (buffer_icap_busy(base_address)) {
+ retries++;
+ if (retries > XHI_MAX_RETRIES)
+ return -EBUSY;
+ }
+ return 0;
+
+};
+
+/**
+ * buffer_icap_device_write: Transfer bytes from ICAP to the storage buffer.
+ * @parameter drvdata: a pointer to the drvdata.
+ * @parameter offset: The storage buffer start address.
+ * @parameter count: The number of words (32 bit) to read from the
+ * device (ICAP).
+ **/
+static int buffer_icap_device_write(struct hwicap_drvdata *drvdata,
+ u32 offset, u32 count)
+{
+
+ s32 retries = 0;
+ void __iomem *base_address = drvdata->base_address;
+
+ if (buffer_icap_busy(base_address))
+ return -EBUSY;
+
+ if ((offset + count) > XHI_MAX_BUFFER_INTS)
+ return -EINVAL;
+
+ /* setSize count*4 to get bytes. */
+ buffer_icap_set_size(base_address, count << 2);
+ buffer_icap_set_offset(base_address, offset);
+ buffer_icap_set_rnc(base_address, XHI_CONFIGURE);
+
+ while (buffer_icap_busy(base_address)) {
+ retries++;
+ if (retries > XHI_MAX_RETRIES)
+ return -EBUSY;
+ }
+ return 0;
+
+};
+
+/**
+ * buffer_icap_reset: Reset the logic of the icap device.
+ * @parameter drvdata: a pointer to the drvdata.
+ *
+ * Writing to the status register resets the ICAP logic in an internal
+ * version of the core. For the version of the core published in EDK,
+ * this is a noop.
+ **/
+void buffer_icap_reset(struct hwicap_drvdata *drvdata)
+{
+ out_be32(drvdata->base_address + XHI_STATUS_REG_OFFSET, 0xFEFE);
+}
+
+/**
+ * buffer_icap_set_configuration: Load a partial bitstream from system memory.
+ * @parameter drvdata: a pointer to the drvdata.
+ * @parameter data: Kernel address of the partial bitstream.
+ * @parameter size: the size of the partial bitstream in 32 bit words.
+ **/
+int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data,
+ u32 size)
+{
+ int status;
+ s32 buffer_count = 0;
+ s32 num_writes = 0;
+ bool dirty = 0;
+ u32 i;
+ void __iomem *base_address = drvdata->base_address;
+
+ /* Loop through all the data */
+ for (i = 0, buffer_count = 0; i < size; i++) {
+
+ /* Copy data to bram */
+ buffer_icap_set_bram(base_address, buffer_count, data[i]);
+ dirty = 1;
+
+ if (buffer_count < XHI_MAX_BUFFER_INTS - 1) {
+ buffer_count++;
+ continue;
+ }
+
+ /* Write data to ICAP */
+ status = buffer_icap_device_write(
+ drvdata,
+ XHI_BUFFER_START,
+ XHI_MAX_BUFFER_INTS);
+ if (status != 0) {
+ /* abort. */
+ buffer_icap_reset(drvdata);
+ return status;
+ }
+
+ buffer_count = 0;
+ num_writes++;
+ dirty = 0;
+ }
+
+ /* Write unwritten data to ICAP */
+ if (dirty) {
+ /* Write data to ICAP */
+ status = buffer_icap_device_write(drvdata, XHI_BUFFER_START,
+ buffer_count);
+ if (status != 0) {
+ /* abort. */
+ buffer_icap_reset(drvdata);
+ }
+ return status;
+ }
+
+ return 0;
+};
+
+/**
+ * buffer_icap_get_configuration: Read configuration data from the device.
+ * @parameter drvdata: a pointer to the drvdata.
+ * @parameter data: Address of the data representing the partial bitstream
+ * @parameter size: the size of the partial bitstream in 32 bit words.
+ **/
+int buffer_icap_get_configuration(struct hwicap_drvdata *drvdata, u32 *data,
+ u32 size)
+{
+ int status;
+ s32 buffer_count = 0;
+ s32 read_count = 0;
+ u32 i;
+ void __iomem *base_address = drvdata->base_address;
+
+ /* Loop through all the data */
+ for (i = 0, buffer_count = XHI_MAX_BUFFER_INTS; i < size; i++) {
+ if (buffer_count == XHI_MAX_BUFFER_INTS) {
+ u32 words_remaining = size - i;
+ u32 words_to_read =
+ words_remaining <
+ XHI_MAX_BUFFER_INTS ? words_remaining :
+ XHI_MAX_BUFFER_INTS;
+
+ /* Read data from ICAP */
+ status = buffer_icap_device_read(
+ drvdata,
+ XHI_BUFFER_START,
+ words_to_read);
+ if (status != 0) {
+ /* abort. */
+ buffer_icap_reset(drvdata);
+ return status;
+ }
+
+ buffer_count = 0;
+ read_count++;
+ }
+
+ /* Copy data from bram */
+ data[i] = buffer_icap_get_bram(base_address, buffer_count);
+ buffer_count++;
+ }
+
+ return 0;
+};
diff --git a/drivers/char/xilinx_hwicap/buffer_icap.h b/drivers/char/xilinx_hwicap/buffer_icap.h
new file mode 100644
index 0000000..0318495
--- /dev/null
+++ b/drivers/char/xilinx_hwicap/buffer_icap.h
@@ -0,0 +1,57 @@
+/*****************************************************************************
+ *
+ * Author: Xilinx, 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.
+ *
+ * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
+ * AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
+ * SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE,
+ * OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
+ * APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
+ * THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
+ * AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
+ * FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY
+ * WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
+ * IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
+ * REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
+ * INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE.
+ *
+ * Xilinx products are not intended for use in life support appliances,
+ * devices, or systems. Use in such applications is expressly prohibited.
+ *
+ * (c) Copyright 2003-2008 Xilinx Inc.
+ * All rights reserved.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *****************************************************************************/
+
+#ifndef XILINX_BUFFER_ICAP_H_ /* prevent circular inclusions */
+#define XILINX_BUFFER_ICAP_H_ /* by using protection macros */
+
+#include <linux/types.h>
+#include <linux/cdev.h>
+#include <linux/version.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+#include "xilinx_hwicap.h"
+
+void buffer_icap_reset(struct hwicap_drvdata *drvdata);
+
+/* Loads a partial bitstream from system memory. */
+int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data,
+ u32 Size);
+
+/* Loads a partial bitstream from system memory. */
+int buffer_icap_get_configuration(struct hwicap_drvdata *drvdata, u32 *data,
+ u32 Size);
+
+#endif
diff --git a/drivers/char/xilinx_hwicap/fifo_icap.c b/drivers/char/xilinx_hwicap/fifo_icap.c
new file mode 100644
index 0000000..0988314
--- /dev/null
+++ b/drivers/char/xilinx_hwicap/fifo_icap.c
@@ -0,0 +1,381 @@
+/*****************************************************************************
+ *
+ * Author: Xilinx, 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.
+ *
+ * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
+ * AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
+ * SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE,
+ * OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
+ * APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
+ * THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
+ * AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
+ * FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY
+ * WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
+ * IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
+ * REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
+ * INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE.
+ *
+ * Xilinx products are not intended for use in life support appliances,
+ * devices, or systems. Use in such applications is expressly prohibited.
+ *
+ * (c) Copyright 2007-2008 Xilinx Inc.
+ * All rights reserved.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *****************************************************************************/
+
+#include "fifo_icap.h"
+
+/* Register offsets for the XHwIcap device. */
+#define XHI_GIER_OFFSET 0x1C /* Device Global Interrupt Enable Reg */
+#define XHI_IPISR_OFFSET 0x20 /* Interrupt Status Register */
+#define XHI_IPIER_OFFSET 0x28 /* Interrupt Enable Register */
+#define XHI_WF_OFFSET 0x100 /* Write FIFO */
+#define XHI_RF_OFFSET 0x104 /* Read FIFO */
+#define XHI_SZ_OFFSET 0x108 /* Size Register */
+#define XHI_CR_OFFSET 0x10C /* Control Register */
+#define XHI_SR_OFFSET 0x110 /* Status Register */
+#define XHI_WFV_OFFSET 0x114 /* Write FIFO Vacancy Register */
+#define XHI_RFO_OFFSET 0x118 /* Read FIFO Occupancy Register */
+
+/* Device Global Interrupt Enable Register (GIER) bit definitions */
+
+#define XHI_GIER_GIE_MASK 0x80000000 /* Global Interrupt enable Mask */
+
+/**
+ * HwIcap Device Interrupt Status/Enable Registers
+ *
+ * Interrupt Status Register (IPISR) : This register holds the
+ * interrupt status flags for the device. These bits are toggle on
+ * write.
+ *
+ * Interrupt Enable Register (IPIER) : This register is used to enable
+ * interrupt sources for the device.
+ * Writing a '1' to a bit enables the corresponding interrupt.
+ * Writing a '0' to a bit disables the corresponding interrupt.
+ *
+ * IPISR/IPIER registers have the same bit definitions and are only defined
+ * once.
+ */
+#define XHI_IPIXR_RFULL_MASK 0x00000008 /* Read FIFO Full */
+#define XHI_IPIXR_WEMPTY_MASK 0x00000004 /* Write FIFO Empty */
+#define XHI_IPIXR_RDP_MASK 0x00000002 /* Read FIFO half full */
+#define XHI_IPIXR_WRP_MASK 0x00000001 /* Write FIFO half full */
+#define XHI_IPIXR_ALL_MASK 0x0000000F /* Mask of all interrupts */
+
+/* Control Register (CR) */
+#define XHI_CR_SW_RESET_MASK 0x00000008 /* SW Reset Mask */
+#define XHI_CR_FIFO_CLR_MASK 0x00000004 /* FIFO Clear Mask */
+#define XHI_CR_READ_MASK 0x00000002 /* Read from ICAP to FIFO */
+#define XHI_CR_WRITE_MASK 0x00000001 /* Write from FIFO to ICAP */
+
+/* Status Register (SR) */
+#define XHI_SR_CFGERR_N_MASK 0x00000100 /* Config Error Mask */
+#define XHI_SR_DALIGN_MASK 0x00000080 /* Data Alignment Mask */
+#define XHI_SR_RIP_MASK 0x00000040 /* Read back Mask */
+#define XHI_SR_IN_ABORT_N_MASK 0x00000020 /* Select Map Abort Mask */
+#define XHI_SR_DONE_MASK 0x00000001 /* Done bit Mask */
+
+
+#define XHI_WFO_MAX_VACANCY 1024 /* Max Write FIFO Vacancy, in words */
+#define XHI_RFO_MAX_OCCUPANCY 256 /* Max Read FIFO Occupancy, in words */
+/* The maximum amount we can request from fifo_icap_get_configuration
+ at once, in bytes. */
+#define XHI_MAX_READ_TRANSACTION_WORDS 0xFFF
+
+
+/**
+ * fifo_icap_fifo_write: Write data to the write FIFO.
+ * @parameter drvdata: a pointer to the drvdata.
+ * @parameter data: the 32-bit value to be written to the FIFO.
+ *
+ * This function will silently fail if the fifo is full.
+ **/
+static inline void fifo_icap_fifo_write(struct hwicap_drvdata *drvdata,
+ u32 data)
+{
+ dev_dbg(drvdata->dev, "fifo_write: %x\n", data);
+ out_be32(drvdata->base_address + XHI_WF_OFFSET, data);
+}
+
+/**
+ * fifo_icap_fifo_read: Read data from the Read FIFO.
+ * @parameter drvdata: a pointer to the drvdata.
+ *
+ * This function will silently fail if the fifo is empty.
+ **/
+static inline u32 fifo_icap_fifo_read(struct hwicap_drvdata *drvdata)
+{
+ u32 data = in_be32(drvdata->base_address + XHI_RF_OFFSET);
+ dev_dbg(drvdata->dev, "fifo_read: %x\n", data);
+ return data;
+}
+
+/**
+ * fifo_icap_set_read_size: Set the the size register.
+ * @parameter drvdata: a pointer to the drvdata.
+ * @parameter data: the size of the following read transaction, in words.
+ **/
+static inline void fifo_icap_set_read_size(struct hwicap_drvdata *drvdata,
+ u32 data)
+{
+ out_be32(drvdata->base_address + XHI_SZ_OFFSET, data);
+}
+
+/**
+ * fifo_icap_start_config: Initiate a configuration (write) to the device.
+ * @parameter drvdata: a pointer to the drvdata.
+ **/
+static inline void fifo_icap_start_config(struct hwicap_drvdata *drvdata)
+{
+ out_be32(drvdata->base_address + XHI_CR_OFFSET, XHI_CR_WRITE_MASK);
+ dev_dbg(drvdata->dev, "configuration started\n");
+}
+
+/**
+ * fifo_icap_start_readback: Initiate a readback from the device.
+ * @parameter drvdata: a pointer to the drvdata.
+ **/
+static inline void fifo_icap_start_readback(struct hwicap_drvdata *drvdata)
+{
+ out_be32(drvdata->base_address + XHI_CR_OFFSET, XHI_CR_READ_MASK);
+ dev_dbg(drvdata->dev, "readback started\n");
+}
+
+/**
+ * fifo_icap_busy: Return true if the ICAP is still processing a transaction.
+ * @parameter drvdata: a pointer to the drvdata.
+ **/
+static inline u32 fifo_icap_busy(struct hwicap_drvdata *drvdata)
+{
+ u32 status = in_be32(drvdata->base_address + XHI_SR_OFFSET);
+ dev_dbg(drvdata->dev, "Getting status = %x\n", status);
+ return (status & XHI_SR_DONE_MASK) ? 0 : 1;
+}
+
+/**
+ * fifo_icap_write_fifo_vacancy: Query the write fifo available space.
+ * @parameter drvdata: a pointer to the drvdata.
+ *
+ * Return the number of words that can be safely pushed into the write fifo.
+ **/
+static inline u32 fifo_icap_write_fifo_vacancy(
+ struct hwicap_drvdata *drvdata)
+{
+ return in_be32(drvdata->base_address + XHI_WFV_OFFSET);
+}
+
+/**
+ * fifo_icap_read_fifo_occupancy: Query the read fifo available data.
+ * @parameter drvdata: a pointer to the drvdata.
+ *
+ * Return the number of words that can be safely read from the read fifo.
+ **/
+static inline u32 fifo_icap_read_fifo_occupancy(
+ struct hwicap_drvdata *drvdata)
+{
+ return in_be32(drvdata->base_address + XHI_RFO_OFFSET);
+}
+
+/**
+ * fifo_icap_set_configuration: Send configuration data to the ICAP.
+ * @parameter drvdata: a pointer to the drvdata.
+ * @parameter frame_buffer: a pointer to the data to be written to the
+ * ICAP device.
+ * @parameter num_words: the number of words (32 bit) to write to the ICAP
+ * device.
+
+ * This function writes the given user data to the Write FIFO in
+ * polled mode and starts the transfer of the data to
+ * the ICAP device.
+ **/
+int fifo_icap_set_configuration(struct hwicap_drvdata *drvdata,
+ u32 *frame_buffer, u32 num_words)
+{
+
+ u32 write_fifo_vacancy = 0;
+ u32 retries = 0;
+ u32 remaining_words;
+
+ dev_dbg(drvdata->dev, "fifo_set_configuration\n");
+
+ /*
+ * Check if the ICAP device is Busy with the last Read/Write
+ */
+ if (fifo_icap_busy(drvdata))
+ return -EBUSY;
+
+ /*
+ * Set up the buffer pointer and the words to be transferred.
+ */
+ remaining_words = num_words;
+
+ while (remaining_words > 0) {
+ /*
+ * Wait until we have some data in the fifo.
+ */
+ while (write_fifo_vacancy == 0) {
+ write_fifo_vacancy =
+ fifo_icap_write_fifo_vacancy(drvdata);
+ retries++;
+ if (retries > XHI_MAX_RETRIES)
+ return -EIO;
+ }
+
+ /*
+ * Write data into the Write FIFO.
+ */
+ while ((write_fifo_vacancy != 0) &&
+ (remaining_words > 0)) {
+ fifo_icap_fifo_write(drvdata, *frame_buffer);
+
+ remaining_words--;
+ write_fifo_vacancy--;
+ frame_buffer++;
+ }
+ /* Start pushing whatever is in the FIFO into the ICAP. */
+ fifo_icap_start_config(drvdata);
+ }
+
+ /* Wait until the write has finished. */
+ while (fifo_icap_busy(drvdata)) {
+ retries++;
+ if (retries > XHI_MAX_RETRIES)
+ break;
+ }
+
+ dev_dbg(drvdata->dev, "done fifo_set_configuration\n");
+
+ /*
+ * If the requested number of words have not been read from
+ * the device then indicate failure.
+ */
+ if (remaining_words != 0)
+ return -EIO;
+
+ return 0;
+}
+
+/**
+ * fifo_icap_get_configuration: Read configuration data from the device.
+ * @parameter drvdata: a pointer to the drvdata.
+ * @parameter data: Address of the data representing the partial bitstream
+ * @parameter size: the size of the partial bitstream in 32 bit words.
+ *
+ * This function reads the specified number of words from the ICAP device in
+ * the polled mode.
+ */
+int fifo_icap_get_configuration(struct hwicap_drvdata *drvdata,
+ u32 *frame_buffer, u32 num_words)
+{
+
+ u32 read_fifo_occupancy = 0;
+ u32 retries = 0;
+ u32 *data = frame_buffer;
+ u32 remaining_words;
+ u32 words_to_read;
+
+ dev_dbg(drvdata->dev, "fifo_get_configuration\n");
+
+ /*
+ * Check if the ICAP device is Busy with the last Write/Read
+ */
+ if (fifo_icap_busy(drvdata))
+ return -EBUSY;
+
+ remaining_words = num_words;
+
+ while (remaining_words > 0) {
+ words_to_read = remaining_words;
+ /* The hardware has a limit on the number of words
+ that can be read at one time. */
+ if (words_to_read > XHI_MAX_READ_TRANSACTION_WORDS)
+ words_to_read = XHI_MAX_READ_TRANSACTION_WORDS;
+
+ remaining_words -= words_to_read;
+
+ fifo_icap_set_read_size(drvdata, words_to_read);
+ fifo_icap_start_readback(drvdata);
+
+ while (words_to_read > 0) {
+ /* Wait until we have some data in the fifo. */
+ while (read_fifo_occupancy == 0) {
+ read_fifo_occupancy =
+ fifo_icap_read_fifo_occupancy(drvdata);
+ retries++;
+ if (retries > XHI_MAX_RETRIES)
+ return -EIO;
+ }
+
+ if (read_fifo_occupancy > words_to_read)
+ read_fifo_occupancy = words_to_read;
+
+ words_to_read -= read_fifo_occupancy;
+
+ /* Read the data from the Read FIFO. */
+ while (read_fifo_occupancy != 0) {
+ *data++ = fifo_icap_fifo_read(drvdata);
+ read_fifo_occupancy--;
+ }
+ }
+ }
+
+ dev_dbg(drvdata->dev, "done fifo_get_configuration\n");
+
+ return 0;
+}
+
+/**
+ * buffer_icap_reset: Reset the logic of the icap device.
+ * @parameter drvdata: a pointer to the drvdata.
+ *
+ * This function forces the software reset of the complete HWICAP device.
+ * All the registers will return to the default value and the FIFO is also
+ * flushed as a part of this software reset.
+ */
+void fifo_icap_reset(struct hwicap_drvdata *drvdata)
+{
+ u32 reg_data;
+ /*
+ * Reset the device by setting/clearing the RESET bit in the
+ * Control Register.
+ */
+ reg_data = in_be32(drvdata->base_address + XHI_CR_OFFSET);
+
+ out_be32(drvdata->base_address + XHI_CR_OFFSET,
+ reg_data | XHI_CR_SW_RESET_MASK);
+
+ out_be32(drvdata->base_address + XHI_CR_OFFSET,
+ reg_data & (~XHI_CR_SW_RESET_MASK));
+
+}
+
+/**
+ * fifo_icap_flush_fifo: This function flushes the FIFOs in the device.
+ * @parameter drvdata: a pointer to the drvdata.
+ */
+void fifo_icap_flush_fifo(struct hwicap_drvdata *drvdata)
+{
+ u32 reg_data;
+ /*
+ * Flush the FIFO by setting/clearing the FIFO Clear bit in the
+ * Control Register.
+ */
+ reg_data = in_be32(drvdata->base_address + XHI_CR_OFFSET);
+
+ out_be32(drvdata->base_address + XHI_CR_OFFSET,
+ reg_data | XHI_CR_FIFO_CLR_MASK);
+
+ out_be32(drvdata->base_address + XHI_CR_OFFSET,
+ reg_data & (~XHI_CR_FIFO_CLR_MASK));
+}
+
diff --git a/drivers/char/xilinx_hwicap/fifo_icap.h b/drivers/char/xilinx_hwicap/fifo_icap.h
new file mode 100644
index 0000000..4d3068d
--- /dev/null
+++ b/drivers/char/xilinx_hwicap/fifo_icap.h
@@ -0,0 +1,62 @@
+/*****************************************************************************
+ *
+ * Author: Xilinx, 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.
+ *
+ * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
+ * AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
+ * SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE,
+ * OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
+ * APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
+ * THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
+ * AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
+ * FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY
+ * WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
+ * IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
+ * REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
+ * INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE.
+ *
+ * Xilinx products are not intended for use in life support appliances,
+ * devices, or systems. Use in such applications is expressly prohibited.
+ *
+ * (c) Copyright 2007-2008 Xilinx Inc.
+ * All rights reserved.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *****************************************************************************/
+
+#ifndef XILINX_FIFO_ICAP_H_ /* prevent circular inclusions */
+#define XILINX_FIFO_ICAP_H_ /* by using protection macros */
+
+#include <linux/types.h>
+#include <linux/cdev.h>
+#include <linux/version.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+#include "xilinx_hwicap.h"
+
+/* Reads integers from the device into the storage buffer. */
+int fifo_icap_get_configuration(
+ struct hwicap_drvdata *drvdata,
+ u32 *FrameBuffer,
+ u32 NumWords);
+
+/* Writes integers to the device from the storage buffer. */
+int fifo_icap_set_configuration(
+ struct hwicap_drvdata *drvdata,
+ u32 *FrameBuffer,
+ u32 NumWords);
+
+void fifo_icap_reset(struct hwicap_drvdata *drvdata);
+void fifo_icap_flush_fifo(struct hwicap_drvdata *drvdata);
+
+#endif
diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
new file mode 100644
index 0000000..83f2d0b
--- /dev/null
+++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
@@ -0,0 +1,900 @@
+/*****************************************************************************
+ *
+ * Author: Xilinx, 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.
+ *
+ * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
+ * AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
+ * SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE,
+ * OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
+ * APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
+ * THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
+ * AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
+ * FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY
+ * WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
+ * IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
+ * REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
+ * INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE.
+ *
+ * Xilinx products are not intended for use in life support appliances,
+ * devices, or systems. Use in such applications is expressly prohibited.
+ *
+ * (c) Copyright 2002 Xilinx Inc., Systems Engineering Group
+ * (c) Copyright 2004 Xilinx Inc., Systems Engineering Group
+ * (c) Copyright 2007-2008 Xilinx Inc.
+ * All rights reserved.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *****************************************************************************/
+
+/*
+ * This is the code behind /dev/xilinx_icap -- it allows a user-space
+ * application to use the Xilinx ICAP subsystem.
+ *
+ * The following operations are possible:
+ *
+ * open open the port and initialize for access.
+ * release release port
+ * write Write a bitstream to the configuration processor.
+ * read Read a data stream from the configuration processor.
+ *
+ * After being opened, the port is initialized and accessed to avoid a
+ * corrupted first read which may occur with some hardware. The port
+ * is left in a desynched state, requiring that a synch sequence be
+ * transmitted before any valid configuration data. A user will have
+ * exclusive access to the device while it remains open, and the state
+ * of the ICAP cannot be guaranteed after the device is closed. Note
+ * that a complete reset of the core and the state of the ICAP cannot
+ * be performed on many versions of the cores, hence users of this
+ * device should avoid making inconsistent accesses to the device. In
+ * particular, accessing the read interface, without first generating
+ * a write containing a readback packet can leave the ICAP in an
+ * inaccessible state.
+ *
+ * Note that in order to use the read interface, it is first necessary
+ * to write a request packet to the write interface. i.e., it is not
+ * possible to simply readback the bitstream (or any configuration
+ * bits) from a device without specifically requesting them first.
+ * The code to craft such packets is intended to be part of the
+ * user-space application code that uses this device. The simplest
+ * way to use this interface is simply:
+ *
+ * cp foo.bit /dev/xilinx_icap
+ *
+ * Note that unless foo.bit is an appropriately constructed partial
+ * bitstream, this has a high likelyhood of overwriting the design
+ * currently programmed in the FPGA.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <asm/semaphore.h>
+#include <linux/sysctl.h>
+#include <linux/version.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#ifdef CONFIG_OF
+/* For open firmware. */
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#endif
+
+#include "xilinx_hwicap.h"
+#include "buffer_icap.h"
+#include "fifo_icap.h"
+
+#define DRIVER_NAME "xilinx_icap"
+
+#define HWICAP_REGS (0x10000)
+
+/* dynamically allocate device number */
+static int xhwicap_major;
+static int xhwicap_minor;
+#define HWICAP_DEVICES 1
+
+module_param(xhwicap_major, int, S_IRUGO);
+module_param(xhwicap_minor, int, S_IRUGO);
+
+/* An array, which is set to true when the device is registered. */
+static bool probed_devices[HWICAP_DEVICES];
+
+static struct class *icap_class;
+
+#define UNIMPLEMENTED 0xFFFF
+
+static const struct config_registers v2_config_registers = {
+ .CRC = 0,
+ .FAR = 1,
+ .FDRI = 2,
+ .FDRO = 3,
+ .CMD = 4,
+ .CTL = 5,
+ .MASK = 6,
+ .STAT = 7,
+ .LOUT = 8,
+ .COR = 9,
+ .MFWR = 10,
+ .FLR = 11,
+ .KEY = 12,
+ .CBC = 13,
+ .IDCODE = 14,
+ .AXSS = UNIMPLEMENTED,
+ .C0R_1 = UNIMPLEMENTED,
+ .CSOB = UNIMPLEMENTED,
+ .WBSTAR = UNIMPLEMENTED,
+ .TIMER = UNIMPLEMENTED,
+ .BOOTSTS = UNIMPLEMENTED,
+ .CTL_1 = UNIMPLEMENTED,
+};
+
+static const struct config_registers v4_config_registers = {
+ .CRC = 0,
+ .FAR = 1,
+ .FDRI = 2,
+ .FDRO = 3,
+ .CMD = 4,
+ .CTL = 5,
+ .MASK = 6,
+ .STAT = 7,
+ .LOUT = 8,
+ .COR = 9,
+ .MFWR = 10,
+ .FLR = UNIMPLEMENTED,
+ .KEY = UNIMPLEMENTED,
+ .CBC = 11,
+ .IDCODE = 12,
+ .AXSS = 13,
+ .C0R_1 = UNIMPLEMENTED,
+ .CSOB = UNIMPLEMENTED,
+ .WBSTAR = UNIMPLEMENTED,
+ .TIMER = UNIMPLEMENTED,
+ .BOOTSTS = UNIMPLEMENTED,
+ .CTL_1 = UNIMPLEMENTED,
+};
+static const struct config_registers v5_config_registers = {
+ .CRC = 0,
+ .FAR = 1,
+ .FDRI = 2,
+ .FDRO = 3,
+ .CMD = 4,
+ .CTL = 5,
+ .MASK = 6,
+ .STAT = 7,
+ .LOUT = 8,
+ .COR = 9,
+ .MFWR = 10,
+ .FLR = UNIMPLEMENTED,
+ .KEY = UNIMPLEMENTED,
+ .CBC = 11,
+ .IDCODE = 12,
+ .AXSS = 13,
+ .C0R_1 = 14,
+ .CSOB = 15,
+ .WBSTAR = 16,
+ .TIMER = 17,
+ .BOOTSTS = 18,
+ .CTL_1 = 19,
+};
+
+/**
+ * hwicap_command_desync: Send a DESYNC command to the ICAP port.
+ * @parameter drvdata: a pointer to the drvdata.
+ *
+ * This command desynchronizes the ICAP After this command, a
+ * bitstream containing a NULL packet, followed by a SYNCH packet is
+ * required before the ICAP will recognize commands.
+ */
+int hwicap_command_desync(struct hwicap_drvdata *drvdata)
+{
+ u32 buffer[4];
+ u32 index = 0;
+
+ /*
+ * Create the data to be written to the ICAP.
+ */
+ buffer[index++] = hwicap_type_1_write(drvdata->config_regs->CMD) | 1;
+ buffer[index++] = XHI_CMD_DESYNCH;
+ buffer[index++] = XHI_NOOP_PACKET;
+ buffer[index++] = XHI_NOOP_PACKET;
+
+ /*
+ * Write the data to the FIFO and intiate the transfer of data present
+ * in the FIFO to the ICAP device.
+ */
+ return drvdata->config->set_configuration(drvdata,
+ &buffer[0], index);
+}
+
+/**
+ * hwicap_command_capture: Send a CAPTURE command to the ICAP port.
+ * @parameter drvdata: a pointer to the drvdata.
+ *
+ * This command captures all of the flip flop states so they will be
+ * available during readback. One can use this command instead of
+ * enabling the CAPTURE block in the design.
+ */
+int hwicap_command_capture(struct hwicap_drvdata *drvdata)
+{
+ u32 buffer[7];
+ u32 index = 0;
+
+ /*
+ * Create the data to be written to the ICAP.
+ */
+ buffer[index++] = XHI_DUMMY_PACKET;
+ buffer[index++] = XHI_SYNC_PACKET;
+ buffer[index++] = XHI_NOOP_PACKET;
+ buffer[index++] = hwicap_type_1_write(drvdata->config_regs->CMD) | 1;
+ buffer[index++] = XHI_CMD_GCAPTURE;
+ buffer[index++] = XHI_DUMMY_PACKET;
+ buffer[index++] = XHI_DUMMY_PACKET;
+
+ /*
+ * Write the data to the FIFO and intiate the transfer of data
+ * present in the FIFO to the ICAP device.
+ */
+ return drvdata->config->set_configuration(drvdata,
+ &buffer[0], index);
+
+}
+
+/**
+ * hwicap_get_configuration_register: Query a configuration register.
+ * @parameter drvdata: a pointer to the drvdata.
+ * @parameter reg: a constant which represents the configuration
+ * register value to be returned.
+ * Examples: XHI_IDCODE, XHI_FLR.
+ * @parameter RegData: returns the value of the register.
+ *
+ * Sends a query packet to the ICAP and then receives the response.
+ * The icap is left in Synched state.
+ */
+int hwicap_get_configuration_register(struct hwicap_drvdata *drvdata,
+ u32 reg, u32 *RegData)
+{
+ int status;
+ u32 buffer[6];
+ u32 index = 0;
+
+ /*
+ * Create the data to be written to the ICAP.
+ */
+ buffer[index++] = XHI_DUMMY_PACKET;
+ buffer[index++] = XHI_SYNC_PACKET;
+ buffer[index++] = XHI_NOOP_PACKET;
+ buffer[index++] = hwicap_type_1_read(reg) | 1;
+ buffer[index++] = XHI_NOOP_PACKET;
+ buffer[index++] = XHI_NOOP_PACKET;
+
+ /*
+ * Write the data to the FIFO and intiate the transfer of data present
+ * in the FIFO to the ICAP device.
+ */
+ status = drvdata->config->set_configuration(drvdata,
+ &buffer[0], index);
+ if (status)
+ return status;
+
+ /*
+ * Read the configuration register
+ */
+ status = drvdata->config->get_configuration(drvdata, RegData, 1);
+ if (status)
+ return status;
+
+ return 0;
+}
+
+int hwicap_initialize_hwicap(struct hwicap_drvdata *drvdata)
+{
+ int status;
+ u32 idcode;
+
+ dev_dbg(drvdata->dev, "initializing\n");
+
+ /* Abort any current transaction, to make sure we have the
+ * ICAP in a good state. */
+ dev_dbg(drvdata->dev, "Reset...\n");
+ drvdata->config->reset(drvdata);
+
+ dev_dbg(drvdata->dev, "Desync...\n");
+ status = hwicap_command_desync(drvdata);
+ if (status)
+ return status;
+
+ /* Attempt to read the IDCODE from ICAP. This
+ * may not be returned correctly, due to the design of the
+ * hardware.
+ */
+ dev_dbg(drvdata->dev, "Reading IDCODE...\n");
+ status = hwicap_get_configuration_register(
+ drvdata, drvdata->config_regs->IDCODE, &idcode);
+ dev_dbg(drvdata->dev, "IDCODE = %x\n", idcode);
+ if (status)
+ return status;
+
+ dev_dbg(drvdata->dev, "Desync...\n");
+ status = hwicap_command_desync(drvdata);
+ if (status)
+ return status;
+
+ return 0;
+}
+
+static ssize_t
+hwicap_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+{
+ struct hwicap_drvdata *drvdata = file->private_data;
+ ssize_t bytes_to_read = 0;
+ u32 *kbuf;
+ u32 words;
+ u32 bytes_remaining;
+ int status;
+
+ if (down_interruptible(&drvdata->sem))
+ return -ERESTARTSYS;
+
+ if (drvdata->read_buffer_in_use) {
+ /* If there are leftover bytes in the buffer, just */
+ /* return them and don't try to read more from the */
+ /* ICAP device. */
+ bytes_to_read =
+ (count < drvdata->read_buffer_in_use) ? count :
+ drvdata->read_buffer_in_use;
+
+ /* Return the data currently in the read buffer. */
+ if (copy_to_user(buf, drvdata->read_buffer, bytes_to_read)) {
+ status = -EFAULT;
+ goto error;
+ }
+ drvdata->read_buffer_in_use -= bytes_to_read;
+ memcpy(drvdata->read_buffer + bytes_to_read,
+ drvdata->read_buffer, 4 - bytes_to_read);
+ } else {
+ /* Get new data from the ICAP, and return was was requested. */
+ kbuf = (u32 *) get_zeroed_page(GFP_KERNEL);
+ if (!kbuf) {
+ status = -ENOMEM;
+ goto error;
+ }
+
+ /* The ICAP device is only able to read complete */
+ /* words. If a number of bytes that do not correspond */
+ /* to complete words is requested, then we read enough */
+ /* words to get the required number of bytes, and then */
+ /* save the remaining bytes for the next read. */
+
+ /* Determine the number of words to read, rounding up */
+ /* if necessary. */
+ words = ((count + 3) >> 2);
+ bytes_to_read = words << 2;
+
+ if (bytes_to_read > PAGE_SIZE)
+ bytes_to_read = PAGE_SIZE;
+
+ /* Ensure we only read a complete number of words. */
+ bytes_remaining = bytes_to_read & 3;
+ bytes_to_read &= ~3;
+ words = bytes_to_read >> 2;
+
+ status = drvdata->config->get_configuration(drvdata,
+ kbuf, words);
+
+ /* If we didn't read correctly, then bail out. */
+ if (status) {
+ free_page((unsigned long)kbuf);
+ goto error;
+ }
+
+ /* If we fail to return the data to the user, then bail out. */
+ if (copy_to_user(buf, kbuf, bytes_to_read)) {
+ free_page((unsigned long)kbuf);
+ status = -EFAULT;
+ goto error;
+ }
+ memcpy(kbuf, drvdata->read_buffer, bytes_remaining);
+ drvdata->read_buffer_in_use = bytes_remaining;
+ free_page((unsigned long)kbuf);
+ }
+ status = bytes_to_read;
+ error:
+ up(&drvdata->sem);
+ return status;
+}
+
+static ssize_t
+hwicap_write(struct file *file, const char *buf,
+ size_t count, loff_t *ppos)
+{
+ struct hwicap_drvdata *drvdata = file->private_data;
+ ssize_t written = 0;
+ ssize_t left = count;
+ u32 *kbuf;
+ ssize_t len;
+ ssize_t status;
+
+ if (down_interruptible(&drvdata->sem))
+ return -ERESTARTSYS;
+
+ left += drvdata->write_buffer_in_use;
+
+ /* Only write multiples of 4 bytes. */
+ if (left < 4) {
+ status = 0;
+ goto error;
+ }
+
+ kbuf = (u32 *) __get_free_page(GFP_KERNEL);
+ if (!kbuf) {
+ status = -ENOMEM;
+ goto error;
+ }
+
+ while (left > 3) {
+ /* only write multiples of 4 bytes, so there might */
+ /* be as many as 3 bytes left (at the end). */
+ len = left;
+
+ if (len > PAGE_SIZE)
+ len = PAGE_SIZE;
+ len &= ~3;
+
+ if (drvdata->write_buffer_in_use) {
+ memcpy(kbuf, drvdata->write_buffer,
+ drvdata->write_buffer_in_use);
+ if (copy_from_user(
+ (((char *)kbuf) + (drvdata->write_buffer_in_use)),
+ buf + written,
+ len - (drvdata->write_buffer_in_use))) {
+ free_page((unsigned long)kbuf);
+ status = -EFAULT;
+ goto error;
+ }
+ } else {
+ if (copy_from_user(kbuf, buf + written, len)) {
+ free_page((unsigned long)kbuf);
+ status = -EFAULT;
+ goto error;
+ }
+ }
+
+ status = drvdata->config->set_configuration(drvdata,
+ kbuf, len >> 2);
+
+ if (status) {
+ free_page((unsigned long)kbuf);
+ status = -EFAULT;
+ goto error;
+ }
+ if (drvdata->write_buffer_in_use) {
+ len -= drvdata->write_buffer_in_use;
+ left -= drvdata->write_buffer_in_use;
+ drvdata->write_buffer_in_use = 0;
+ }
+ written += len;
+ left -= len;
+ }
+ if ((left > 0) && (left < 4)) {
+ if (!copy_from_user(drvdata->write_buffer,
+ buf + written, left)) {
+ drvdata->write_buffer_in_use = left;
+ written += left;
+ left = 0;
+ }
+ }
+
+ free_page((unsigned long)kbuf);
+ status = written;
+ error:
+ up(&drvdata->sem);
+ return status;
+}
+
+static int hwicap_open(struct inode *inode, struct file *file)
+{
+ struct hwicap_drvdata *drvdata;
+ int status;
+
+ drvdata = container_of(inode->i_cdev, struct hwicap_drvdata, cdev);
+
+ if (down_interruptible(&drvdata->sem))
+ return -ERESTARTSYS;
+
+ drvdata->is_open = 1;
+
+ status = hwicap_initialize_hwicap(drvdata);
+ if (status) {
+ dev_err(drvdata->dev, "Failed to open file");
+ return status;
+ }
+
+ file->private_data = drvdata;
+ drvdata->write_buffer_in_use = 0;
+ drvdata->read_buffer_in_use = 0;
+
+ up(&drvdata->sem);
+
+ return 0;
+}
+
+static int hwicap_release(struct inode *inode, struct file *file)
+{
+ struct hwicap_drvdata *drvdata = file->private_data;
+ int i;
+ int status = 0;
+
+ if (down_interruptible(&drvdata->sem))
+ return -ERESTARTSYS;
+
+ if (drvdata->write_buffer_in_use) {
+ /* Flush write buffer. */
+ for (i = drvdata->write_buffer_in_use; i < 4; i++)
+ drvdata->write_buffer[i] = 0;
+
+ status = drvdata->config->set_configuration(drvdata,
+ (u32 *) drvdata->write_buffer, 1);
+ if (status)
+ goto error;
+ }
+
+ status = hwicap_command_desync(drvdata);
+ if (status)
+ goto error;
+
+ error:
+ drvdata->is_open = 0;
+ up(&drvdata->sem);
+ return status;
+}
+
+static struct file_operations hwicap_fops = {
+ .owner = THIS_MODULE,
+ .write = hwicap_write,
+ .read = hwicap_read,
+ .open = hwicap_open,
+ .release = hwicap_release,
+};
+
+static int __devinit hwicap_setup(struct device *dev, int id,
+ const struct resource *regs_res,
+ const struct hwicap_driver_config *config,
+ const struct config_registers *config_regs)
+{
+ dev_t devt;
+ struct hwicap_drvdata *drvdata = NULL;
+ int retval = 0;
+
+ dev_info(dev, "Xilinx icap port driver\n");
+
+ if (id < 0) {
+ for (id = 0; id < HWICAP_DEVICES; id++)
+ if (!probed_devices[id])
+ break;
+ }
+ if (id < 0 || id >= HWICAP_DEVICES) {
+ dev_err(dev, "%s%i too large\n", DRIVER_NAME, id);
+ return -EINVAL;
+ }
+ if (probed_devices[id]) {
+ dev_err(dev, "cannot assign to %s%i; it is already in use\n",
+ DRIVER_NAME, id);
+ return -EBUSY;
+ }
+
+ probed_devices[id] = 1;
+
+ devt = MKDEV(xhwicap_major, xhwicap_minor + id);
+
+ drvdata = kmalloc(sizeof(struct hwicap_drvdata), GFP_KERNEL);
+ if (!drvdata) {
+ dev_err(dev, "Couldn't allocate device private record\n");
+ return -ENOMEM;
+ }
+ memset((void *)drvdata, 0, sizeof(struct hwicap_drvdata));
+ dev_set_drvdata(dev, (void *)drvdata);
+
+ if (!regs_res) {
+ dev_err(dev, "Couldn't get registers resource\n");
+ retval = -EFAULT;
+ goto failed1;
+ }
+
+ drvdata->mem_start = regs_res->start;
+ drvdata->mem_end = regs_res->end;
+ drvdata->mem_size = regs_res->end - regs_res->start + 1;
+
+ if (!request_mem_region(drvdata->mem_start,
+ drvdata->mem_size, DRIVER_NAME)) {
+ dev_err(dev, "Couldn't lock memory region at %p\n",
+ (void *)regs_res->start);
+ retval = -EBUSY;
+ goto failed1;
+ }
+
+ drvdata->devt = devt;
+ drvdata->dev = dev;
+ drvdata->base_address = ioremap(drvdata->mem_start, drvdata->mem_size);
+ if (!drvdata->base_address) {
+ dev_err(dev, "ioremap() failed\n");
+ goto failed2;
+ }
+
+ drvdata->config = config;
+ drvdata->config_regs = config_regs;
+
+ init_MUTEX(&drvdata->sem);
+ drvdata->is_open = 0;
+
+ dev_info(dev, "ioremap %lx to %p with size %x\n",
+ (unsigned long int)drvdata->mem_start,
+ drvdata->base_address, drvdata->mem_size);
+
+ cdev_init(&drvdata->cdev, &hwicap_fops);
+ drvdata->cdev.owner = THIS_MODULE;
+ retval = cdev_add(&drvdata->cdev, devt, 1);
+ if (retval) {
+ dev_err(dev, "cdev_add() failed\n");
+ goto failed3;
+ }
+ /* devfs_mk_cdev(devt, S_IFCHR|S_IRUGO|S_IWUGO, DRIVER_NAME); */
+ class_device_create(icap_class, NULL, devt, NULL, DRIVER_NAME);
+ return 0; /* success */
+
+ failed3:
+ iounmap(drvdata->base_address);
+
+ failed2:
+ release_mem_region(regs_res->start, drvdata->mem_size);
+
+ failed1:
+ kfree(drvdata);
+
+ return retval;
+}
+
+static struct hwicap_driver_config buffer_icap_config = {
+ .get_configuration = buffer_icap_get_configuration,
+ .set_configuration = buffer_icap_set_configuration,
+ .reset = buffer_icap_reset,
+};
+
+static struct hwicap_driver_config fifo_icap_config = {
+ .get_configuration = fifo_icap_get_configuration,
+ .set_configuration = fifo_icap_set_configuration,
+ .reset = fifo_icap_reset,
+};
+
+static int __devexit hwicap_remove(struct device *dev)
+{
+ struct hwicap_drvdata *drvdata;
+
+ drvdata = (struct hwicap_drvdata *)dev_get_drvdata(dev);
+
+ if (!drvdata)
+ return 0;
+
+ class_device_destroy(icap_class, drvdata->devt);
+ cdev_del(&drvdata->cdev);
+ iounmap(drvdata->base_address);
+ release_mem_region(drvdata->mem_start, drvdata->mem_size);
+ kfree(drvdata);
+ dev_set_drvdata(dev, NULL);
+ probed_devices[MINOR(dev->devt)-xhwicap_minor] = 0;
+
+ return 0; /* success */
+}
+
+static int __devinit hwicap_drv_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ const struct config_registers *regs;
+ const char *family;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ /* It's most likely that we're using V4, if the family is not
+ specified */
+ regs = &v4_config_registers;
+ family = pdev->dev.platform_data;
+
+ if (family) {
+ if (!strcmp(family, "virtex2p")) {
+ regs = &v2_config_registers;
+ } else if (!strcmp(family, "virtex4")) {
+ regs = &v4_config_registers;
+ } else if (!strcmp(family, "virtex5")) {
+ regs = &v5_config_registers;
+ }
+ }
+
+ return hwicap_setup(&pdev->dev, pdev->id, res,
+ &buffer_icap_config, regs);
+}
+
+static int __devexit hwicap_drv_remove(struct platform_device *pdev)
+{
+ return hwicap_remove(&pdev->dev);
+}
+
+static struct platform_driver hwicap_platform_driver = {
+ .probe = hwicap_drv_probe,
+ .remove = hwicap_drv_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ },
+};
+
+/* ---------------------------------------------------------------------
+ * OF bus binding
+ */
+
+#if defined(CONFIG_OF)
+static int __devinit
+hwicap_of_probe(struct of_device *op, const struct of_device_id *match)
+{
+ struct resource res;
+ const unsigned int *id;
+ const char *family;
+ int rc;
+ const struct hwicap_driver_config *config = match->data;
+ const struct config_registers *regs;
+
+ dev_dbg(&op->dev, "hwicap_of_probe(%p, %p)\n", op, match);
+
+ rc = of_address_to_resource(op->node, 0, &res);
+ if (rc) {
+ dev_err(&op->dev, "invalid address\n");
+ return rc;
+ }
+
+ id = of_get_property(op->node, "port-number", NULL);
+
+ /* It's most likely that we're using V4, if the family is not
+ specified */
+ regs = &v4_config_registers;
+ family = of_get_property(op->node, "xlnx,family", NULL);
+
+ if (family) {
+ if (!strcmp(family, "virtex2p")) {
+ regs = &v2_config_registers;
+ } else if (!strcmp(family, "virtex4")) {
+ regs = &v4_config_registers;
+ } else if (!strcmp(family, "virtex5")) {
+ regs = &v5_config_registers;
+ }
+ }
+ return hwicap_setup(&op->dev, id ? *id : -1, &res, config,
+ regs);
+}
+
+static int __devexit hwicap_of_remove(struct of_device *op)
+{
+ return hwicap_remove(&op->dev);
+}
+
+/* Match table for of_platform binding */
+static const struct of_device_id __devinit hwicap_of_match[] = {
+ { .compatible = "xlnx,opb-hwicap-1.00.b", .data = &buffer_icap_config},
+ { .compatible = "xlnx,xps-hwicap-1.00.a", .data = &fifo_icap_config},
+ {},
+};
+MODULE_DEVICE_TABLE(of, hwicap_of_match);
+
+static struct of_platform_driver hwicap_of_driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ .match_table = hwicap_of_match,
+ .probe = hwicap_of_probe,
+ .remove = __devexit_p(hwicap_of_remove),
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+};
+
+/* Registration helpers to keep the number of #ifdefs to a minimum */
+static inline int __devinit hwicap_of_register(void)
+{
+ pr_debug("hwicap: calling of_register_platform_driver()\n");
+ return of_register_platform_driver(&hwicap_of_driver);
+}
+
+static inline void __devexit hwicap_of_unregister(void)
+{
+ of_unregister_platform_driver(&hwicap_of_driver);
+}
+#else /* CONFIG_OF */
+/* CONFIG_OF not enabled; do nothing helpers */
+static inline int __devinit hwicap_of_register(void) { return 0; }
+static inline void __devexit hwicap_of_unregister(void) { }
+#endif /* CONFIG_OF */
+
+static int __devinit hwicap_module_init(void)
+{
+ dev_t devt;
+ int retval;
+
+ icap_class = class_create(THIS_MODULE, "xilinx_config");
+
+ if (xhwicap_major) {
+ devt = MKDEV(xhwicap_major, xhwicap_minor);
+ retval = register_chrdev_region(
+ devt,
+ HWICAP_DEVICES,
+ DRIVER_NAME);
+ if (retval < 0)
+ return retval;
+ } else {
+ retval = alloc_chrdev_region(&devt,
+ xhwicap_minor,
+ HWICAP_DEVICES,
+ DRIVER_NAME);
+ if (retval < 0)
+ return retval;
+ xhwicap_major = MAJOR(devt);
+ }
+
+ retval = platform_driver_register(&hwicap_platform_driver);
+
+ if (retval)
+ goto failed1;
+
+ retval = hwicap_of_register();
+
+ if (retval)
+ goto failed2;
+
+ return retval;
+
+ failed2:
+ platform_driver_unregister(&hwicap_platform_driver);
+
+ failed1:
+ unregister_chrdev_region(devt, HWICAP_DEVICES);
+
+ return retval;
+}
+
+static void __devexit hwicap_module_cleanup(void)
+{
+ dev_t devt = MKDEV(xhwicap_major, xhwicap_minor);
+
+ class_destroy(icap_class);
+
+ platform_driver_unregister(&hwicap_platform_driver);
+
+ hwicap_of_unregister();
+
+ unregister_chrdev_region(devt, HWICAP_DEVICES);
+}
+
+module_init(hwicap_module_init);
+module_exit(hwicap_module_cleanup);
+
+MODULE_AUTHOR("Xilinx, Inc; Xilinx Research Labs Group");
+MODULE_DESCRIPTION("Xilinx ICAP Port Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.h b/drivers/char/xilinx_hwicap/xilinx_hwicap.h
new file mode 100644
index 0000000..b6b47d0
--- /dev/null
+++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.h
@@ -0,0 +1,193 @@
+/*****************************************************************************
+ *
+ * Author: Xilinx, 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.
+ *
+ * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
+ * AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
+ * SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE,
+ * OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
+ * APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
+ * THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
+ * AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
+ * FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY
+ * WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
+ * IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
+ * REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
+ * INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE.
+ *
+ * Xilinx products are not intended for use in life support appliances,
+ * devices, or systems. Use in such applications is expressly prohibited.
+ *
+ * (c) Copyright 2003-2007 Xilinx Inc.
+ * All rights reserved.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *****************************************************************************/
+
+#ifndef XILINX_HWICAP_H_ /* prevent circular inclusions */
+#define XILINX_HWICAP_H_ /* by using protection macros */
+
+#include <linux/types.h>
+#include <linux/cdev.h>
+#include <linux/version.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+
+struct hwicap_drvdata {
+ u32 write_buffer_in_use; /* Always in [0,3] */
+ u8 write_buffer[4];
+ u32 read_buffer_in_use; /* Always in [0,3] */
+ u8 read_buffer[4];
+ u32 mem_start; /* phys. address of the control registers */
+ u32 mem_end; /* phys. address of the control registers */
+ u32 mem_size;
+ void __iomem *base_address;/* virt. address of the control registers */
+
+ struct device *dev;
+ struct cdev cdev; /* Char device structure */
+ dev_t devt;
+
+ const struct hwicap_driver_config *config;
+ const struct config_registers *config_regs;
+ void *private_data;
+ bool is_open;
+ bool is_accessing;
+};
+
+struct hwicap_driver_config {
+ int (*get_configuration)(struct hwicap_drvdata *drvdata, u32 *data,
+ u32 size);
+ int (*set_configuration)(struct hwicap_drvdata *drvdata, u32 *data,
+ u32 size);
+ void (*reset)(struct hwicap_drvdata *drvdata);
+};
+
+/* Number of times to poll the done regsiter */
+#define XHI_MAX_RETRIES 10
+
+/************ Constant Definitions *************/
+
+#define XHI_PAD_FRAMES 0x1
+
+/* Mask for calculating configuration packet headers */
+#define XHI_WORD_COUNT_MASK_TYPE_1 0x7FFUL
+#define XHI_WORD_COUNT_MASK_TYPE_2 0x1FFFFFUL
+#define XHI_TYPE_MASK 0x7
+#define XHI_REGISTER_MASK 0xF
+#define XHI_OP_MASK 0x3
+
+#define XHI_TYPE_SHIFT 29
+#define XHI_REGISTER_SHIFT 13
+#define XHI_OP_SHIFT 27
+
+#define XHI_TYPE_1 1
+#define XHI_TYPE_2 2
+#define XHI_OP_WRITE 2
+#define XHI_OP_READ 1
+
+/* Address Block Types */
+#define XHI_FAR_CLB_BLOCK 0
+#define XHI_FAR_BRAM_BLOCK 1
+#define XHI_FAR_BRAM_INT_BLOCK 2
+
+struct config_registers {
+ u32 CRC;
+ u32 FAR;
+ u32 FDRI;
+ u32 FDRO;
+ u32 CMD;
+ u32 CTL;
+ u32 MASK;
+ u32 STAT;
+ u32 LOUT;
+ u32 COR;
+ u32 MFWR;
+ u32 FLR;
+ u32 KEY;
+ u32 CBC;
+ u32 IDCODE;
+ u32 AXSS;
+ u32 C0R_1;
+ u32 CSOB;
+ u32 WBSTAR;
+ u32 TIMER;
+ u32 BOOTSTS;
+ u32 CTL_1;
+};
+
+/* Configuration Commands */
+#define XHI_CMD_NULL 0
+#define XHI_CMD_WCFG 1
+#define XHI_CMD_MFW 2
+#define XHI_CMD_DGHIGH 3
+#define XHI_CMD_RCFG 4
+#define XHI_CMD_START 5
+#define XHI_CMD_RCAP 6
+#define XHI_CMD_RCRC 7
+#define XHI_CMD_AGHIGH 8
+#define XHI_CMD_SWITCH 9
+#define XHI_CMD_GRESTORE 10
+#define XHI_CMD_SHUTDOWN 11
+#define XHI_CMD_GCAPTURE 12
+#define XHI_CMD_DESYNCH 13
+#define XHI_CMD_IPROG 15 /* Only in Virtex5 */
+#define XHI_CMD_CRCC 16 /* Only in Virtex5 */
+#define XHI_CMD_LTIMER 17 /* Only in Virtex5 */
+
+/* Packet constants */
+#define XHI_SYNC_PACKET 0xAA995566UL
+#define XHI_DUMMY_PACKET 0xFFFFFFFFUL
+#define XHI_NOOP_PACKET (XHI_TYPE_1 << XHI_TYPE_SHIFT)
+#define XHI_TYPE_2_READ ((XHI_TYPE_2 << XHI_TYPE_SHIFT) | \
+ (XHI_OP_READ << XHI_OP_SHIFT))
+
+#define XHI_TYPE_2_WRITE ((XHI_TYPE_2 << XHI_TYPE_SHIFT) | \
+ (XHI_OP_WRITE << XHI_OP_SHIFT))
+
+#define XHI_TYPE2_CNT_MASK 0x07FFFFFF
+
+#define XHI_TYPE_1_PACKET_MAX_WORDS 2047UL
+#define XHI_TYPE_1_HEADER_BYTES 4
+#define XHI_TYPE_2_HEADER_BYTES 8
+
+/* Constant to use for CRC check when CRC has been disabled */
+#define XHI_DISABLED_AUTO_CRC 0x0000DEFCUL
+
+/**
+ * hwicap_type_1_read: Generates a Type 1 read packet header.
+ * @parameter: Register is the address of the register to be read back.
+ *
+ * Generates a Type 1 read packet header, which is used to indirectly
+ * read registers in the configuration logic. This packet must then
+ * be sent through the icap device, and a return packet received with
+ * the information.
+ **/
+static inline u32 hwicap_type_1_read(u32 Register)
+{
+ return (XHI_TYPE_1 << XHI_TYPE_SHIFT) |
+ (Register << XHI_REGISTER_SHIFT) |
+ (XHI_OP_READ << XHI_OP_SHIFT);
+}
+
+/**
+ * hwicap_type_1_write: Generates a Type 1 write packet header
+ * @parameter: Register is the address of the register to be read back.
+ **/
+static inline u32 hwicap_type_1_write(u32 Register)
+{
+ return (XHI_TYPE_1 << XHI_TYPE_SHIFT) |
+ (Register << XHI_REGISTER_SHIFT) |
+ (XHI_OP_WRITE << XHI_OP_SHIFT);
+}
+
+#endif
--
1.5.3.4-dirty
^ permalink raw reply related
* Re: Reminder: removal of arch/ppc
From: Mark A. Greer @ 2008-02-01 18:35 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev list, linuxppc-embedded
In-Reply-To: <3B00BB74-ED5B-4661-B807-79DE6CBEA883@kernel.crashing.org>
On Thu, Jan 31, 2008 at 09:33:09PM -0600, Kumar Gala wrote:
>
> On Jan 31, 2008, at 4:54 PM, Mark A. Greer wrote:
>
> >On Fri, Jan 25, 2008 at 10:55:25AM -0600, Kumar Gala wrote:
> >>Just a reminder that the plan is to remove arch/ppc this summer (June
> >>2008). The following boards still existing over in arch/ppc. Some
> >>of
> >>them have been ported over to arch/powerpc. If you care about one of
> >>these boards and its not ported speak up (it helps if you have access
> >>to the board). Also, if you know a given board is free to die of
> >>bitrot let us know so we know not to worry about it:
> >
> >I guess I'm just not a nice guy but I say let them die. No need
> >to worry. The code really isn't going anywhere -- git-checkout
> >v2.6.<pick your favorite version> and its back.
> >
> >/me's $0.02.
>
> this is where I poke you about the sandpoint port ;)
Heh, I know, I know. jdl was asking me about it a few days ago too.
I haven't forgotten, it just never makes it to the top of my stack.
RSN tho... :)
^ permalink raw reply
* Re: [PATCH 1/5] ehea: fix ehea.h checkpatch complaints
From: Jeff Garzik @ 2008-02-01 18:40 UTC (permalink / raw)
To: Doug Maxey
Cc: Linux PowerPC List, Paul Mackerras, netdev, Jeff Garzik,
Jan-Bernd Themann
In-Reply-To: <1201832451-23634-2-git-send-email-dwm@austin.ibm.com>
Doug Maxey wrote:
> Cc: Jan-Bernd Themann <themann@de.ibm.com>
> Signed-off-by: Doug Maxey <dwm@austin.ibm.com>
> ---
> drivers/net/ehea/ehea.h | 3 +++
> drivers/net/ehea/ehea_hw.h | 8 ++++----
> 2 files changed, 7 insertions(+), 4 deletions(-)
applied 1-5
^ permalink raw reply
* Re: [PATCH for 2.6.25 1/2] [NET] ucc_geth: fix module removal
From: Jeff Garzik @ 2008-02-01 18:40 UTC (permalink / raw)
To: Anton Vorontsov; +Cc: netdev, Li Yang, linuxppc-dev
In-Reply-To: <20080201132248.GA1790@localhost.localdomain>
Anton Vorontsov wrote:
> - uccf should be set to NULL to not double-free memory on
> subsequent calls;
> - ind_hash_q and group_hash_q lists should be initialized in the
> probe() function, instead of struct_init() (called by open()),
> otherwise there will be an oops if ucc_geth_driver removed
> prior 'ifconfig ethX up';
> - add unregister_netdev();
> - reorder geth_remove() steps.
>
> Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
> ---
>
> Hi Li,
>
> You kinda promised that these two patches would hit 2.6.25... ;-)
>
> I've rebased the patches so they apply cleanly on the current tree.
>
> Thanks,
>
> drivers/net/ucc_geth.c | 17 ++++++++++-------
> 1 files changed, 10 insertions(+), 7 deletions(-)
applied 1-2
^ permalink raw reply
* Re: [PATCH] ehea: fix sysfs link compile problem
From: Jeff Garzik @ 2008-02-01 18:40 UTC (permalink / raw)
To: Jan-Bernd Themann
Cc: Thomas Klein, Jan-Bernd Themann, netdev, linux-kernel, linux-ppc,
Christoph Raisch, Marcus Eder, Stefan Roscher
In-Reply-To: <200802011537.42578.ossthema@de.ibm.com>
Jan-Bernd Themann wrote:
> Due to changes in the struct device_driver there is no direct
> access to its kobj any longer. The kobj was used to create
> sysfs links between eHEA ethernet devices and the driver.
> This patch removes the affected sysfs links to resolve
> the build problems.
>
> Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com>
>
>
> ---
> drivers/net/ehea/ehea_main.c | 37 -------------------------------------
> 1 files changed, 0 insertions(+), 37 deletions(-)
applied
^ permalink raw reply
* Re: [PATCH] [POWERPC] Xilinx: hwicap driver
From: Grant Likely @ 2008-02-01 18:42 UTC (permalink / raw)
To: Stephen Neuendorffer; +Cc: linuxppc-dev, ntl
In-Reply-To: <20080201182253.903B5F18046@mail130-sin.bigfish.com>
On 2/1/08, Stephen Neuendorffer <stephen.neuendorffer@xilinx.com> wrote:
> diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
> new file mode 100644
> index 0000000..83f2d0b
> --- /dev/null
> +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
> +static int hwicap_open(struct inode *inode, struct file *file)
> +{
> + struct hwicap_drvdata *drvdata;
> + int status;
> +
> + drvdata = container_of(inode->i_cdev, struct hwicap_drvdata, cdev);
> +
> + if (down_interruptible(&drvdata->sem))
> + return -ERESTARTSYS;
> +
> + drvdata->is_open = 1;
It doesn't look like this flag is used anywhere anymore.
> +
> + status = hwicap_initialize_hwicap(drvdata);
> + if (status) {
> + dev_err(drvdata->dev, "Failed to open file");
> + return status;
returning without up()
> + }
> +
> + file->private_data = drvdata;
> + drvdata->write_buffer_in_use = 0;
> + drvdata->read_buffer_in_use = 0;
> +
> + up(&drvdata->sem);
> +
> + return 0;
> +}
> +
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ 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