* dtc: Generate useful error message for properties after subnodes
From: David Gibson @ 2007-12-04 23:27 UTC (permalink / raw)
To: Jon Loeliger; +Cc: linuxppc-dev
On several occasions, I've accidentally put properties after subnodes
in a dts file. I've then spent ages thinking that the resulting
syntax error was because of something else.
This patch arranges for this specific syntax error to generate a more
specific and useful error message.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Index: dtc/tests/prop-after-subnode.dts
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ dtc/tests/prop-after-subnode.dts 2007-12-05 10:24:52.000000000 +1100
@@ -0,0 +1,9 @@
+/dts-v1/;
+
+/ {
+ node1 {
+ };
+ prop;
+ node2 {
+ };
+};
Index: dtc/dtc-parser.y
===================================================================
--- dtc.orig/dtc-parser.y 2007-12-05 10:12:10.000000000 +1100
+++ dtc/dtc-parser.y 2007-12-05 10:18:26.000000000 +1100
@@ -276,6 +276,11 @@
{
$$ = chain_node($1, $2);
}
+ | subnode propdef
+ {
+ yyerror("syntax error: properties must precede subnodes\n");
+ YYERROR;
+ }
;
subnode:
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
^ permalink raw reply
* Re: ucc_uart: add support for Freescale QUICCEngine UART
From: Scott Wood @ 2007-12-04 23:32 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: linuxppc-dev, Timur Tabi
In-Reply-To: <200712050026.07616.arnd@arndb.de>
Arnd Bergmann wrote:
> From a code clarity perspective, the interesting point is that dma_addr_t is
> what comes back from the functions in dma-mapping.h. If you don't use them,
> a physical address is phys_addr_t.
>
> You can argue that the QS is really a DMA device, but in that case you
> should convert the driver to use the DMA mapping interfaces correctly,
> which I would consider overkill.
Why is it overkill?
-Scott
^ permalink raw reply
* [FDT][PATCH] Fix padding options
From: Kumar Gala @ 2007-12-04 23:36 UTC (permalink / raw)
To: Jon Loeliger; +Cc: linuxppc-dev
"Add an option to pad the blob that is generated" broke the padding
support. We were updating the fdt header after writing it.
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
---
Better commit message for this, since my commit ID is different.
flattree.c | 12 +++++++-----
1 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/flattree.c b/flattree.c
index c860b63..eb9c82c 100644
--- a/flattree.c
+++ b/flattree.c
@@ -399,6 +399,12 @@ void dt_to_blob(FILE *f, struct boot_info *bi, int version,
if (padsize > 0)
padlen = padsize;
+ if (padlen > 0) {
+ int tsize = be32_to_cpu(fdt.totalsize);
+ tsize += padlen;
+ fdt.totalsize = cpu_to_be32(tsize);
+ }
+
/*
* Assemble the blob: start with the header, add with alignment
* the reserve buffer, add the reserve map terminating zeroes,
@@ -414,12 +420,8 @@ void dt_to_blob(FILE *f, struct boot_info *bi, int version,
/*
* If the user asked for more space than is used, pad out the blob.
*/
- if (padlen > 0) {
- int tsize = be32_to_cpu(fdt.totalsize);
- tsize += padlen;
+ if (padlen > 0)
blob = data_append_zeroes(blob, padlen);
- fdt.totalsize = cpu_to_be32(tsize);
- }
fwrite(blob.val, blob.len, 1, f);
--
1.5.3.4
^ permalink raw reply related
* Re: [FDT][PATCH] Print out the total size as part of ftdump
From: Kumar Gala @ 2007-12-04 23:38 UTC (permalink / raw)
To: David Gibson; +Cc: linuxppc-dev, Jon Loeliger
In-Reply-To: <20071204222047.GA5771@localhost.localdomain>
On Dec 4, 2007, at 4:20 PM, David Gibson wrote:
> On Tue, Dec 04, 2007 at 10:33:20AM -0600, Kumar Gala wrote:
>> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
>
> You know, the whole batch of fprintf()s of header information in
> dt_from_blob() are really just a debugging hack that uglifies dtc's
> output. The whole lot could be moved over to ftdump instead, which
> is, after all, *supposed* to be a debugging hack.
Yeah, I realized having a way to dump just the header info was nice.
- k
^ permalink raw reply
* Re: ucc_uart: add support for Freescale QUICCEngine UART
From: Arnd Bergmann @ 2007-12-04 23:39 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev, Timur Tabi
In-Reply-To: <4755E3A6.80704@freescale.com>
On Wednesday 05 December 2007, Scott Wood wrote:
>
> > You can argue that the QS is really a DMA device, but in that case you
> > should convert the driver to use the DMA mapping interfaces correctly,
> > which I would consider overkill.
>
> Why is it overkill?
>
Well, if the QE can never be used with an IOMMU anyway, you don't
lose any functionality by considering it a physical address instead of
a DMA address.
The DMA mapping API is meant for the cases where physical and dma
addresses can be different in the first place.
Arnd <><
^ permalink raw reply
* dtc: Implement path references
From: David Gibson @ 2007-12-04 23:43 UTC (permalink / raw)
To: Jon Loeliger; +Cc: linuxppc-dev
This patch extends dtc syntax to allow references (&label, or
&{/full/path}) directly within property definitions, rather than
inside a cell list. Such references are expanded to the full path of
the referenced node, as a string, instead of to a phandle as
references within cell lists are evaluated.
A testcase is also included.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Index: dtc/tests/run_tests.sh
===================================================================
--- dtc.orig/tests/run_tests.sh 2007-12-05 09:48:12.000000000 +1100
+++ dtc/tests/run_tests.sh 2007-12-05 10:31:51.000000000 +1100
@@ -148,6 +148,9 @@
run_test dtc.sh -I dts -O dtb -o dtc_references_dts0.test.dtb references_dts0.dts
run_test references dtc_references_dts0.test.dtb
+ run_test dtc.sh -I dts -O dtb -o dtc_path-references.test.dtb path-references.dts
+ run_test path-references dtc_path-references.test.dtb
+
# Check -Odts mode preserve all dtb information
for tree in test_tree1.dtb dtc_tree1.test.dtb dtc_escapes.test.dtb ; do
run_test dtc.sh -I dtb -O dts -o odts_$tree.test.dts $tree
Index: dtc/dtc-parser.y
===================================================================
--- dtc.orig/dtc-parser.y 2007-12-05 10:18:26.000000000 +1100
+++ dtc/dtc-parser.y 2007-12-05 10:31:51.000000000 +1100
@@ -192,6 +192,10 @@
{
$$ = data_merge($1, $3);
}
+ | propdataprefix DT_REF
+ {
+ $$ = data_add_marker($1, REF_PATH, $2);
+ }
| propdata DT_LABEL
{
$$ = data_add_marker($1, LABEL, $2);
Index: dtc/dtc.h
===================================================================
--- dtc.orig/dtc.h 2007-12-05 09:02:20.000000000 +1100
+++ dtc/dtc.h 2007-12-05 10:32:26.000000000 +1100
@@ -104,6 +104,7 @@
/* Data blobs */
enum markertype {
REF_PHANDLE,
+ REF_PATH,
LABEL,
};
@@ -139,6 +140,8 @@
struct data data_copy_file(FILE *f, size_t len);
struct data data_append_data(struct data d, const void *p, int len);
+struct data data_insert_at_marker(struct data d, struct marker *m,
+ const void *p, int len);
struct data data_merge(struct data d1, struct data d2);
struct data data_append_cell(struct data d, cell_t word);
struct data data_append_re(struct data d, const struct fdt_reserve_entry *re);
Index: dtc/tests/Makefile.tests
===================================================================
--- dtc.orig/tests/Makefile.tests 2007-12-03 15:33:10.000000000 +1100
+++ dtc/tests/Makefile.tests 2007-12-05 10:31:51.000000000 +1100
@@ -9,7 +9,7 @@
sw_tree1 \
move_and_save mangle-layout \
open_pack rw_tree1 setprop del_property del_node \
- string_escapes references \
+ string_escapes references path-references \
dtbs_equal_ordered
LIB_TESTS = $(LIB_TESTS_L:%=$(TESTS_PREFIX)%)
Index: dtc/tests/path-references.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ dtc/tests/path-references.c 2007-12-05 10:31:51.000000000 +1100
@@ -0,0 +1,83 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Testcase for string references in dtc
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+void check_ref(const void *fdt, int node, const char *checkpath)
+{
+ const char *p;
+ int len;
+
+ p = fdt_getprop(fdt, node, "ref", &len);
+ if (!p)
+ FAIL("fdt_getprop(%d, \"ref\"): %s", node, fdt_strerror(len));
+ if (!streq(p, checkpath))
+ FAIL("'ref' in node at %d has value \"%s\" instead of \"%s\"",
+ node, p, checkpath);
+
+ p = fdt_getprop(fdt, node, "lref", &len);
+ if (!p)
+ FAIL("fdt_getprop(%d, \"lref\"): %s", node, fdt_strerror(len));
+ if (!streq(p, checkpath))
+ FAIL("'lref' in node at %d has value \"%s\" instead of \"%s\"",
+ node, p, checkpath);
+}
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+ const char *p;
+ int len, multilen;
+ int n1, n2;
+
+ test_init(argc, argv);
+ fdt = load_blob_arg(argc, argv);
+
+ n1 = fdt_path_offset(fdt, "/node1");
+ if (n1 < 0)
+ FAIL("fdt_path_offset(/node1): %s", fdt_strerror(n1));
+ n2 = fdt_path_offset(fdt, "/node2");
+ if (n2 < 0)
+ FAIL("fdt_path_offset(/node2): %s", fdt_strerror(n2));
+
+ check_ref(fdt, n1, "/node2");
+ check_ref(fdt, n2, "/node1");
+
+ /* Check multiple reference */
+ multilen = strlen("/node1") + strlen("/node2") + 2;
+ p = fdt_getprop(fdt, 0, "multiref", &len);
+ if (!p)
+ FAIL("fdt_getprop(0, \"multiref\"): %s", fdt_strerror(len));
+ if (len != multilen)
+ FAIL("multiref has wrong length, %d instead of %d",
+ len, multilen);
+ if ((!streq(p, "/node1") || !streq(p + strlen("/node1") + 1, "/node2")))
+ FAIL("multiref has wrong value");
+
+ PASS();
+}
Index: dtc/tests/path-references.dts
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ dtc/tests/path-references.dts 2007-12-05 10:35:55.000000000 +1100
@@ -0,0 +1,14 @@
+/dts-v1/;
+
+/ {
+ /* Check multiple references case */
+ multiref = &n1 , &n2;
+ n1: node1 {
+ ref = &{/node2}; /* reference precedes target */
+ lref = &n2;
+ };
+ n2: node2 {
+ ref = &{/node1}; /* reference after target */
+ lref = &n1;
+ };
+};
Index: dtc/data.c
===================================================================
--- dtc.orig/data.c 2007-12-05 09:02:20.000000000 +1100
+++ dtc/data.c 2007-12-05 10:34:01.000000000 +1100
@@ -202,6 +202,21 @@
return d;
}
+struct data data_insert_at_marker(struct data d, struct marker *m,
+ const void *p, int len)
+{
+ d = data_grow_for(d, len);
+ memmove(d.val + m->offset + len, d.val + m->offset, d.len - m->offset);
+ memcpy(d.val + m->offset, p, len);
+ d.len += len;
+
+ /* Adjust all markers after the one we're inserting at */
+ m = m->next;
+ for_each_marker(m)
+ m->offset += len;
+ return d;
+}
+
struct data data_append_markers(struct data d, struct marker *m)
{
struct marker **mp = &d.markers;
Index: dtc/checks.c
===================================================================
--- dtc.orig/checks.c 2007-12-05 09:48:12.000000000 +1100
+++ dtc/checks.c 2007-12-05 10:33:50.000000000 +1100
@@ -302,11 +302,36 @@
CHECK(phandle_references, NULL, NULL, fixup_phandle_references, NULL, ERROR,
&duplicate_node_names, &explicit_phandles);
+static void fixup_path_references(struct check *c, struct node *dt,
+ struct node *node, struct property *prop)
+{
+ struct marker *m = prop->val.markers;
+ struct node *refnode;
+ char *path;
+
+ for_each_marker_of_type(m, REF_PATH) {
+ assert(m->offset <= prop->val.len);
+
+ refnode = get_node_by_ref(dt, m->ref);
+ if (!refnode) {
+ FAIL(c, "Reference to non-existent node or label \"%s\"\n",
+ m->ref);
+ continue;
+ }
+
+ path = refnode->fullpath;
+ prop->val = data_insert_at_marker(prop->val, m, path,
+ strlen(path) + 1);
+ }
+}
+CHECK(path_references, NULL, NULL, fixup_path_references, NULL, ERROR,
+ &duplicate_node_names);
+
static struct check *check_table[] = {
&duplicate_node_names, &duplicate_property_names,
&name_is_string, &name_properties,
&explicit_phandles,
- &phandle_references,
+ &phandle_references, &path_references,
};
int check_semantics(struct node *dt, int outversion, int boot_cpuid_phys);
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
^ permalink raw reply
* Re: ucc_uart: add support for Freescale QUICCEngine UART
From: Scott Wood @ 2007-12-04 23:44 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: linuxppc-dev, Timur Tabi
In-Reply-To: <200712050039.39153.arnd@arndb.de>
Arnd Bergmann wrote:
> On Wednesday 05 December 2007, Scott Wood wrote:
>>> You can argue that the QS is really a DMA device, but in that
>>> case you should convert the driver to use the DMA mapping
>>> interfaces correctly, which I would consider overkill.
>> Why is it overkill?
>>
>
> Well, if the QE can never be used with an IOMMU anyway,
I'm unconvinced that that will always be the case.
> The DMA mapping API is meant for the cases where physical and dma
> addresses can be different in the first place.
It's also used for noncoherent DMA; while it's unlikely Freescale will
come out with a QE 8xx chip any time soon, there could be hardware bugs
or performance considerations that make it desireable to treat it as
non-coherent.
-Scott
^ permalink raw reply
* Fix Firmware class name collision
From: Timur Tabi @ 2007-12-04 23:45 UTC (permalink / raw)
To: Markus Rechberger, Greg Kroah-Hartman, PowerPC dev list
Markus and Greg,
I've found a problem with this patch that probably affects a number of embedded
PowerPC systems:
http://marc.info/?l=linux-kernel&m=119222892713518&w=2
The problem is that the device name for many PowerPC SoC devices is based on the
physical address. So we have stuff like this:
# ls -l /sys/devices/
drwxr-xr-x 9 root root 0 Nov 9 17:29 e0000000.soc8323
drwxr-xr-x 11 root root 0 Nov 9 17:22 e0100000.qe
[snip]
# ls -l /sys/devices/e0000000.soc8323/
drwxr-xr-x 2 root root 0 Nov 9 17:34 e0000200.wdt
drwxr-xr-x 2 root root 0 Nov 9 17:34 e0000700.pic
drwxr-xr-x 2 root root 0 Nov 9 17:34 e0001400.par_io
drwxr-xr-x 2 root root 0 Nov 9 17:34 e0003000.i2c
drwxr-xr-x 2 root root 0 Nov 9 17:34 e0004500.serial
drwxr-xr-x 2 root root 0 Nov 9 17:34 e0004600.serial
drwxr-xr-x 2 root root 0 Nov 9 17:34 e0030000.crypto
[snip]
With this patch, the device names in /sys/class/firmware look like this:
# ls -l /sys/class/firmware/
drwxr-xr-x 2 root root 0 Nov 9 17:37 firmware-e0102400.u
-rw-r--r-- 1 root root 4096 Nov 9 17:22 timeout
In other words, the only thing you get is the first letter of the device name.
You used to get the whole name. The physical address obviously isn't very helpful.
The problem is the size of the string is only 20 characters:
static inline void fw_setup_device_id(struct device *f_dev, struct device *dev)
{
snprintf(f_dev->bus_id, BUS_ID_SIZE, "firmware-%s", dev->bus_id);
}
Now, there are two solutions:
1) Change the PowerPC device names from physical_address.device_name to
device_name.physical_address (so that e0102400.ucc becomes ucc.e0102400)
2) Change fw_setup_device_id() to something like this:
snprintf(f_dev->bus_id, BUS_ID_SIZE, "fw-%s", dev->bus_id);
which do you think is a better idea?
--
Timur Tabi
Linux kernel developer at Freescale
^ permalink raw reply
* Re: ucc_uart: add support for Freescale QUICCEngine UART
From: Timur Tabi @ 2007-12-04 23:47 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: linuxppc-dev
In-Reply-To: <200712050026.07616.arnd@arndb.de>
Arnd Bergmann wrote:
> You can argue that the QS is really a DMA device, but in that case you
> should convert the driver to use the DMA mapping interfaces correctly,
> which I would consider overkill.
I'm confused. I'm already calling dma_alloc_coherent() and getting a dma_addr_t
back. Why do I need to use mapping functions to convert between virtual and
physical/bus addresses?
--
Timur Tabi
Linux kernel developer at Freescale
^ permalink raw reply
* Re: Fix Firmware class name collision
From: Scott Wood @ 2007-12-04 23:52 UTC (permalink / raw)
To: Timur Tabi; +Cc: PowerPC dev list, Greg Kroah-Hartman, Markus Rechberger
In-Reply-To: <4755E6AC.9020808@freescale.com>
Timur Tabi wrote:
>
> In other words, the only thing you get is the first letter of the device name.
> You used to get the whole name. The physical address obviously isn't very helpful.
The physical address certainly is useful when you have more than one
device of the same name.
> Now, there are two solutions:
>
> 1) Change the PowerPC device names from physical_address.device_name to
> device_name.physical_address (so that e0102400.ucc becomes ucc.e0102400)
So then you'd get "firmware-ucc.e01024". What if there's another ucc at
e0102480? For devices with longer names, you'd have even less
precision in the address.
-Scott
^ permalink raw reply
* Re: ucc_uart: add support for Freescale QUICCEngine UART
From: Arnd Bergmann @ 2007-12-04 23:56 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Timur Tabi
In-Reply-To: <4755E701.3040908@freescale.com>
On Wednesday 05 December 2007, Timur Tabi wrote:
> Arnd Bergmann wrote:
>=20
> > You can argue that the QS is really a DMA device, but in that case you
> > should convert the driver to use the DMA mapping interfaces correctly,
> > which I would consider overkill.
>=20
> I'm confused. =A0I'm already calling dma_alloc_coherent() and getting a d=
ma_addr_t=20
> back. =A0Why do I need to use mapping functions to convert between virtua=
l and=20
> physical/bus addresses?
No, I'm sorry but I'm the one who was confused. The problem I saw was that
you return something offset from "bd_phys" as a dma_addr_t. This would be
a lot easier if you had called it bd_bus or bd_dma instead of bd_phys, but
your code looks absolutely correct upon closer inspection.
Arnd <><
^ permalink raw reply
* [PATCH] [XILINX][HWICAP] Xilinx Internal Configuration Access Port device driver.
From: Stephen Neuendorffer @ 2007-12-04 23:57 UTC (permalink / raw)
To: grant.likely, linuxppc-dev
Supports static platform_device and static device tree configuration.
This is a standalone driver that does not depend on EDK generated
files. However, it is also somewhat different in functionality from
the standard EDK driver.
1) The EDK driver doesn't support readback, which this driver does.
2) The EDK driver supports fine granularity reading and writing, which
this driver does not. The fine granularity support is heavily
architecture independent, which makes it difficult to make the driver
forward compatible. The fine granularity support is also complex and
probably better handled in user space anyway.
Signed-off-by: Stephen Neuendorffer <stephen.neuendorffer@xilinx.com>
---
Grant,
No comments last time... It would be nice if this merged with 2.6.25, I think.
Steve
drivers/char/Kconfig | 5 +
drivers/char/Makefile | 1 +
drivers/char/xilinx_hwicap/Makefile | 7 +
drivers/char/xilinx_hwicap/xhwicap_srp.c | 414 ++++++++++++++++++++
drivers/char/xilinx_hwicap/xilinx_hwicap.c | 565 ++++++++++++++++++++++++++++
drivers/char/xilinx_hwicap/xilinx_hwicap.h | 539 ++++++++++++++++++++++++++
6 files changed, 1531 insertions(+), 0 deletions(-)
create mode 100644 drivers/char/xilinx_hwicap/Makefile
create mode 100644 drivers/char/xilinx_hwicap/xhwicap_srp.c
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 bf18d75..72295cc 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -573,6 +573,11 @@ config HVC_DRIVER
It will automatically be selected if one of the back-end console drivers
is selected.
+config XILINX_HWICAP
+ tristate "Xilinx OPB HWICAP Support"
+ depends on XILINX_VIRTEX
+ help
+ This option enables support for Xilinx Internal Configuration Access Port (ICAP) driver.
config HVC_CONSOLE
bool "pSeries Hypervisor Virtual Console support"
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 07304d5..8cfcbb0 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..818f4e1
--- /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 xhwicap_srp.o
diff --git a/drivers/char/xilinx_hwicap/xhwicap_srp.c b/drivers/char/xilinx_hwicap/xhwicap_srp.c
new file mode 100644
index 0000000..388eefe
--- /dev/null
+++ b/drivers/char/xilinx_hwicap/xhwicap_srp.c
@@ -0,0 +1,414 @@
+/*****************************************************************************
+ *
+ * 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.
+ *
+ *****************************************************************************/
+
+#include "xilinx_hwicap.h"
+
+#define XHI_BUFFER_START 0
+
+/****************************************************************************/
+/**
+ *
+ * Stores data in the storage buffer at the specified address.
+ *
+ * @param InstancePtr - a pointer to the XHwIcap instance to be worked on.
+ *
+ * @param Address - bram word address
+ *
+ * @param Data - data to be stored at address
+ *
+ * @return None.
+ *
+ * @note None.
+ *
+*****************************************************************************/
+void XHwIcap_StorageBufferWrite(struct xhwicap_drvdata *InstancePtr,
+ u32 Address, u32 Data)
+{
+ /* Write data to storage buffer. */
+ XHwIcap_mSetBram(InstancePtr->baseAddress, Address, Data);
+}
+
+/****************************************************************************/
+/**
+ *
+ * Read data from the specified address in the storage buffer..
+ *
+ * @param InstancePtr - a pointer to the XHwIcap instance to be worked on.
+ *
+ * @param Address - bram word address
+ *
+ * @return Data.
+ *
+ * @note None.
+ *
+*****************************************************************************/
+u32 XHwIcap_StorageBufferRead(struct xhwicap_drvdata *InstancePtr, u32 Address)
+{
+ u32 Data;
+
+ /* Read data from address. Multiply Address by 4 since 4 bytes per
+ * word.*/
+ Data = XHwIcap_mGetBram(InstancePtr->baseAddress, Address);
+ return Data;
+
+}
+
+/****************************************************************************/
+/**
+ *
+ * Reads bytes from the device (ICAP) and puts it in the storage buffer.
+ *
+ * @param InstancePtr - a pointer to the XHwIcap instance to be worked on.
+ *
+ * @param Offset - The storage buffer start address.
+ *
+ * @param NumInts - The number of words (32 bit) to read from the
+ * device (ICAP).
+ *
+ *@return int - 0 or -EBUSY or -EINVAL
+ *
+ * @note None.
+ *
+*****************************************************************************/
+int XHwIcap_DeviceRead(struct xhwicap_drvdata *InstancePtr, u32 Offset,
+ u32 NumInts)
+{
+
+ s32 Retries = 0;
+
+ if (XHwIcap_mGetDoneReg(InstancePtr->baseAddress) == XHI_NOT_FINISHED) {
+ return -EBUSY;
+ }
+
+ if ((Offset + NumInts) <= XHI_MAX_BUFFER_INTS) {
+ /* setSize NumInts*4 to get bytes. */
+ XHwIcap_mSetSizeReg((InstancePtr->baseAddress), (NumInts << 2));
+ XHwIcap_mSetOffsetReg((InstancePtr->baseAddress), Offset);
+ XHwIcap_mSetRncReg((InstancePtr->baseAddress), XHI_READBACK);
+
+ while (XHwIcap_mGetDoneReg(InstancePtr->baseAddress) ==
+ XHI_NOT_FINISHED) {
+ Retries++;
+ if (Retries > XHI_MAX_RETRIES) {
+ return -EBUSY;
+ }
+ }
+ } else {
+ return -EINVAL;
+ }
+ return 0;
+
+};
+
+/****************************************************************************/
+/**
+ *
+ * Writes bytes from the storage buffer and puts it in the device (ICAP).
+ *
+ * @param InstancePtr - a pointer to the XHwIcap instance to be worked on.
+ *
+ * @param Offset - The storage buffer start address.
+ *
+ * @param NumInts - The number of words (32 bit) to read from the
+ * device (ICAP).
+ *
+ *@return int - 0 or -EBUSY or -EINVAL
+ *
+ * @note None.
+ *
+*****************************************************************************/
+int XHwIcap_DeviceWrite(struct xhwicap_drvdata *InstancePtr, u32 Offset,
+ u32 NumInts)
+{
+
+ s32 Retries = 0;
+
+ if (XHwIcap_mGetDoneReg(InstancePtr->baseAddress) == XHI_NOT_FINISHED) {
+ return -EBUSY;
+ }
+
+ if ((Offset + NumInts) <= XHI_MAX_BUFFER_INTS) {
+ /* setSize NumInts*4 to get bytes. */
+ XHwIcap_mSetSizeReg((InstancePtr->baseAddress), NumInts << 2);
+ XHwIcap_mSetOffsetReg((InstancePtr->baseAddress), Offset);
+ XHwIcap_mSetRncReg((InstancePtr->baseAddress), XHI_CONFIGURE);
+
+ while (XHwIcap_mGetDoneReg(InstancePtr->baseAddress) ==
+ XHI_NOT_FINISHED) {
+ Retries++;
+ if (Retries > XHI_MAX_RETRIES) {
+ return -EBUSY;
+ }
+ }
+ } else {
+ return -EINVAL;
+ }
+ return 0;
+
+};
+
+/****************************************************************************/
+/**
+ *
+ * Sends a DESYNC command to the ICAP port.
+ *
+ * @param InstancePtr - a pointer to the XHwIcap instance to be worked on.
+ *
+ *@return int - 0 or -EBUSY or -EINVAL
+ *
+ * @note None.
+ *
+*****************************************************************************/
+int XHwIcap_CommandDesync(struct xhwicap_drvdata *InstancePtr)
+{
+ int status;
+
+ XHwIcap_StorageBufferWrite(InstancePtr, 0,
+ (XHwIcap_Type1Write(XHI_CMD) | 1));
+ XHwIcap_StorageBufferWrite(InstancePtr, 1, XHI_CMD_DESYNCH);
+ XHwIcap_StorageBufferWrite(InstancePtr, 2, XHI_NOOP_PACKET);
+ XHwIcap_StorageBufferWrite(InstancePtr, 3, XHI_NOOP_PACKET);
+
+ /* send four words */
+ status = XHwIcap_DeviceWrite(InstancePtr, 0, 4);
+ if (status) {
+ return status;
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+/**
+ *
+ * Sends a CAPTURE command to the ICAP port. This command caputres 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.
+ *
+ * @param InstancePtr - a pointer to the XHwIcap instance to be worked on.
+ *
+ * @return int - 0 or -EBUSY or -EINVAL
+ *
+ * @note None.
+ *
+*****************************************************************************/
+int XHwIcap_CommandCapture(struct xhwicap_drvdata *InstancePtr)
+{
+ int status;
+
+ /* DUMMY and SYNC */
+ XHwIcap_StorageBufferWrite(InstancePtr, 0, XHI_DUMMY_PACKET);
+ XHwIcap_StorageBufferWrite(InstancePtr, 1, XHI_SYNC_PACKET);
+ XHwIcap_StorageBufferWrite(InstancePtr, 2,
+ (XHwIcap_Type1Write(XHI_CMD) | 1));
+ XHwIcap_StorageBufferWrite(InstancePtr, 3, XHI_CMD_GCAPTURE);
+ XHwIcap_StorageBufferWrite(InstancePtr, 4, XHI_DUMMY_PACKET);
+ XHwIcap_StorageBufferWrite(InstancePtr, 5, XHI_DUMMY_PACKET);
+
+ /* send six words */
+ status = XHwIcap_DeviceWrite(InstancePtr, 0, 6);
+ if (status) { /* send six words */
+ return status;
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+/**
+ *
+ * This function returns the value of the specified configuration
+ * register.
+ *
+ * @param InstancePtr - a pointer to the XHwIcap instance to be worked
+ * on.
+ *
+ * @param ConfigReg - A constant which represents the configuration
+ * register value to be returned. Constants specified in xhwicap_i.h. Examples:
+ * XHI_IDCODE, XHI_FLR.
+ *
+ * @return The value of the specified configuration register.
+ *
+ *
+*****************************************************************************/
+
+u32 XHwIcap_GetConfigReg(struct xhwicap_drvdata *InstancePtr, u32 ConfigReg)
+{
+ u32 Packet;
+ int status;
+
+ /* Write bitstream to bram */
+ Packet = XHwIcap_Type1Read(ConfigReg) | 1;
+ XHwIcap_StorageBufferWrite(InstancePtr, 0, XHI_DUMMY_PACKET);
+ XHwIcap_StorageBufferWrite(InstancePtr, 1, XHI_SYNC_PACKET);
+ XHwIcap_StorageBufferWrite(InstancePtr, 2, Packet);
+ XHwIcap_StorageBufferWrite(InstancePtr, 3, XHI_NOOP_PACKET);
+ XHwIcap_StorageBufferWrite(InstancePtr, 4, XHI_NOOP_PACKET);
+
+ /* Transfer Bitstream from Bram to ICAP */
+ status = XHwIcap_DeviceWrite(InstancePtr, 0, 5);
+ if (status) {
+ return status;
+ }
+
+ /* Now readback one word into bram position
+ * XHI_EX_BITSTREAM_LENGTH*/
+ status = XHwIcap_DeviceRead(InstancePtr, 5, 1);
+ if (status) {
+ return status;
+ }
+
+ /* Return the Register value */
+ return XHwIcap_StorageBufferRead(InstancePtr, 5);
+}
+
+/****************************************************************************
+ *
+ * Loads a partial bitstream from system memory.
+ *
+ * @param InstancePtr - a pointer to the XHwIcap instance to be worked on.
+ *
+ * @param Data - Address of the data representing the partial bitstream
+ *
+ * @param Size - the size of the partial bitstream in 32 bit words.
+ *
+ * @return 0, -EFBIG or -EINVAL.
+ *
+ * @note None.
+ *
+*****************************************************************************/
+int XHwIcap_SetConfiguration(struct xhwicap_drvdata *InstancePtr, u32 *Data,
+ u32 Size)
+{
+ int status;
+ s32 BufferCount = 0;
+ s32 NumWrites = 0;
+ bool Dirty = 0;
+ u32 I;
+
+ /* Loop through all the data */
+ for (I = 0, BufferCount = 0; I < Size; I++) {
+
+ /* Copy data to bram */
+ XHwIcap_StorageBufferWrite(InstancePtr, BufferCount, Data[I]);
+ Dirty = 1;
+
+ if (BufferCount == XHI_MAX_BUFFER_INTS - 1) {
+ /* Write data to ICAP */
+ status = XHwIcap_DeviceWrite(InstancePtr, XHI_BUFFER_START,
+ XHI_MAX_BUFFER_INTS);
+ if (status != 0) {
+ /* abort. */
+ XHwIcap_mReset(InstancePtr->baseAddress); return status;
+ }
+
+ BufferCount = 0;
+ NumWrites++;
+ Dirty = 0;
+ } else {
+ BufferCount++;
+ }
+ }
+
+ /* Write unwritten data to ICAP */
+ if (Dirty) {
+ /* Write data to ICAP */
+ status = XHwIcap_DeviceWrite(InstancePtr, XHI_BUFFER_START,
+ BufferCount);
+ if (status != 0) {
+ /* abort. */
+ XHwIcap_mReset(InstancePtr->baseAddress);
+ }
+ return status;
+ }
+
+ return 0;
+};
+
+/****************************************************************************
+ *
+ * Reads Configuration Data from the device.
+ *
+ * @param InstancePtr - a pointer to the XHwIcap instance to be worked on.
+ *
+ * @param Data - Address of the data representing the partial bitstream
+ *
+ * @param Size - the size of the partial bitstream in 32 bit words.
+ *
+ * @return 0, -EFBIG or -EINVAL.
+ *
+ * @note None.
+ *
+*****************************************************************************/
+int XHwIcap_GetConfiguration(struct xhwicap_drvdata *InstancePtr, u32 *Data,
+ u32 Size)
+{
+ int status;
+ s32 BufferCount = 0;
+ s32 NumReads = 0;
+ u32 I;
+
+ /* Loop through all the data */
+ for (I = 0, BufferCount = XHI_MAX_BUFFER_INTS; I < Size; I++) {
+ if (BufferCount == XHI_MAX_BUFFER_INTS) {
+ u32 intsRemaining = Size - I;
+ u32 intsToRead =
+ intsRemaining <
+ XHI_MAX_BUFFER_INTS ? intsRemaining :
+ XHI_MAX_BUFFER_INTS;
+
+ /* Read data from ICAP */
+
+ status =
+ XHwIcap_DeviceRead(InstancePtr, XHI_BUFFER_START,
+ intsToRead);
+ if (status != 0) {
+ /* abort. */
+ XHwIcap_mReset(InstancePtr->baseAddress);
+ return status;
+ }
+
+ BufferCount = 0;
+ NumReads++;
+ }
+
+ /* Copy data from bram */
+ Data[I] = XHwIcap_StorageBufferRead(InstancePtr, BufferCount);
+ BufferCount++;
+ }
+
+ return 0;
+};
diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
new file mode 100644
index 0000000..d42538e
--- /dev/null
+++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
@@ -0,0 +1,565 @@
+/*****************************************************************************
+ *
+ * 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 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.
+ *
+ *****************************************************************************/
+
+/*
+ * xilinx_hwicap.c
+ *
+ * This is the code behind /dev/xilinx_icap/'x' -- it allows a user-space
+ * application to use the Xilinx ICAP subsystem.
+ *
+ * A /dev/xilinx_icap/'x' device node represents an arbitrary device
+ * on port 'x'. The following operations are possible:
+ *
+ * open do nothing, set up default IEEE 1284 protocol to be COMPAT
+ * release release port and unregister device (if necessary)
+ * write Write a bitstream to the configuration processor.
+ * read Read a data stream from the configuration processor.
+ *
+ * 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 <linux/spinlock.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"
+
+#define DRIVER_NAME "xilinx_icap"
+
+#define XHWICAP_REGS (0x10000)
+
+/* dynamically allocate device number */
+static int xhwicap_major = 0;
+static int xhwicap_minor = 0;
+static int xhwicap_no_minors = 4;
+module_param(xhwicap_major, int, S_IRUGO);
+module_param(xhwicap_minor, int, S_IRUGO);
+module_param(xhwicap_no_minors, int, S_IRUGO);
+
+static struct class *icap_class;
+
+int xhwicap_initialize_xhwicap(struct xhwicap_drvdata *drvdata)
+{
+
+ u32 DeviceIdCode;
+ u32 Packet;
+ int Status;
+
+ dev_dbg(drvdata->dev, "Reset...\n");
+
+ /* Abort any current transaction, to make sure we have the ICAP in */
+ /* a good state. */
+ XHwIcap_mReset(drvdata->baseAddress);
+
+ /* Read the IDCODE from ICAP if specified. */
+ {
+ dev_dbg(drvdata->dev, "Reading IDCODE...\n");
+
+ /* Write bitstream to bram */
+ Packet = XHwIcap_Type1Read(XHI_IDCODE) | 1;
+ XHwIcap_StorageBufferWrite(drvdata, 0, XHI_DUMMY_PACKET);
+ XHwIcap_StorageBufferWrite(drvdata, 1, XHI_SYNC_PACKET);
+ XHwIcap_StorageBufferWrite(drvdata, 2, Packet);
+ XHwIcap_StorageBufferWrite(drvdata, 3, XHI_NOOP_PACKET);
+ XHwIcap_StorageBufferWrite(drvdata, 4, XHI_NOOP_PACKET);
+
+ /* Transfer Bitstream from Bram to ICAP */
+ Status = XHwIcap_DeviceWrite(drvdata, 0, 5);
+ if (Status) {
+ return Status;
+ }
+
+ /* Now readback one word into bram position
+ * XHI_EX_BITSTREAM_LENGTH*/
+ Status = XHwIcap_DeviceRead(drvdata, 5, 1);
+ if (Status) {
+ return Status;
+ }
+
+ /* Return the Register value */
+ DeviceIdCode = XHwIcap_StorageBufferRead(drvdata, 5);
+
+ /* Mask out the version section of the DeviceIdCode */
+ DeviceIdCode = DeviceIdCode & 0x0FFFFFFF;
+
+ dev_dbg(drvdata->dev, "Desync...\n");
+ Status = XHwIcap_CommandDesync(drvdata);
+
+ if (Status) {
+ return Status;
+ }
+ }
+
+ /* Abort any current transaction, to make sure we have the ICAP in */
+ /* a good state. */
+ XHwIcap_mReset(drvdata->baseAddress);
+
+ dev_info(drvdata->dev, "Device IDCODE = %x\n", DeviceIdCode);
+
+ return 0;
+}
+
+static ssize_t
+xhwicap_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+{
+ struct xhwicap_drvdata *drvdata = file->private_data;
+ ssize_t bytes_to_read = 0;
+ u32 *kbuf;
+ u32 words;
+ u32 bytes_remaining;
+ int Status;
+
+ 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)) {
+ return -EFAULT;
+ }
+ 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)
+ return -ENOMEM;
+
+ /* 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. */
+ /* BUG: should be count & 3? */
+ bytes_remaining = bytes_to_read & 3;
+ bytes_to_read &= ~3;
+ words = bytes_to_read >> 2;
+
+ Status = XHwIcap_GetConfiguration(drvdata, kbuf, words);
+ /* If we didn't read correctly, then bail out. */
+ if (Status) {
+ free_page((unsigned long)kbuf);
+ return -EFAULT;
+ }
+ /* 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);
+ return -EFAULT;
+ }
+ memcpy(kbuf, drvdata->read_buffer, bytes_remaining);
+ drvdata->read_buffer_in_use = bytes_remaining;
+ free_page((unsigned long)kbuf);
+ }
+ return bytes_to_read;
+}
+
+static ssize_t xhwicap_write(struct file *file, const char *buf,
+ size_t count, loff_t *ppos)
+{
+ struct xhwicap_drvdata *drvdata = file->private_data;
+ ssize_t written = 0;
+ ssize_t left = count;
+ u32 *kbuf;
+ int len;
+ int Status;
+
+ left += drvdata->write_buffer_in_use;
+
+ /* only write multiples of 4 bytes. */
+ if (left < 4)
+ return 0;
+
+ kbuf = (u32 *) __get_free_page(GFP_KERNEL);
+ if (!kbuf)
+ return -ENOMEM;
+
+ 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);
+ return -EFAULT;
+ }
+ } else {
+ if (copy_from_user(kbuf, buf + written, len)) {
+ free_page((unsigned long)kbuf);
+ return -EFAULT;
+ }
+ }
+
+ Status = XHwIcap_SetConfiguration(drvdata, kbuf, len >> 2);
+
+ if (Status) {
+ free_page((unsigned long)kbuf);
+ return -EFAULT;
+ }
+ 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);
+ return written;
+}
+
+static int xhwicap_open(struct inode *inode, struct file *file)
+{
+ struct xhwicap_drvdata *drvdata;
+ int status;
+
+ drvdata = container_of(inode->i_cdev, struct xhwicap_drvdata, cdev);
+
+ status = xhwicap_initialize_xhwicap(drvdata);
+ if (status) {
+ dev_err(drvdata->dev, "Failed to open file");
+ return -status;
+ }
+
+ drvdata->flags = 0;
+ file->private_data = drvdata;
+ drvdata->write_buffer_in_use = 0;
+ drvdata->read_buffer_in_use = 0;
+
+ return 0;
+}
+
+static int xhwicap_release(struct inode *inode, struct file *file)
+{
+ struct xhwicap_drvdata *drvdata = file->private_data;
+ int i;
+ int Status;
+
+ 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 =
+ XHwIcap_SetConfiguration(drvdata,
+ (u32 *) drvdata->write_buffer, 1);
+ if (Status) {
+ return Status;
+ }
+ }
+
+ Status = XHwIcap_CommandDesync(drvdata);
+ if (Status) {
+ return Status;
+ }
+
+ return 0;
+}
+
+static struct file_operations xhwicap_fops = {
+ .owner = THIS_MODULE,
+ .write = xhwicap_write,
+ .read = xhwicap_read,
+ .open = xhwicap_open,
+ .release = xhwicap_release,
+};
+
+static int __init xhwicap_drv_probe(struct device *dev)
+{
+ dev_t devt;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct xhwicap_drvdata *drvdata = NULL;
+ struct resource *regs_res;
+ int retval = 0;
+
+ if (!dev) {
+ return -EINVAL;
+ }
+
+ dev_info(dev, "Xilinx icap port driver\n");
+
+ devt = MKDEV(xhwicap_major, xhwicap_minor + pdev->id);
+
+ drvdata = kmalloc(sizeof(struct xhwicap_drvdata), GFP_KERNEL);
+ if (!drvdata) {
+ dev_err(dev, "Couldn't allocate device private record\n");
+ return -ENOMEM;
+ }
+ memset((void *)drvdata, 0, sizeof(struct xhwicap_drvdata));
+ dev_set_drvdata(dev, (void *)drvdata);
+
+ /* Map the control registers in */
+ regs_res = platform_get_resource(to_platform_device(dev),
+ IORESOURCE_MEM, 0);
+ 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 (drvdata->mem_size < XHWICAP_REGS) {
+ dev_err(dev, "Couldn't get registers resource\n");
+ retval = -EFAULT;
+ goto failed1;
+ }
+
+ 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->baseAddress = ioremap(drvdata->mem_start, drvdata->mem_size);
+ if (!drvdata->baseAddress) {
+ dev_err(dev, "ioremap() failed\n");
+ goto failed2;
+ }
+
+ dev_info(dev, "ioremap %lx to %p with size %x\n",
+ (unsigned long int)drvdata->mem_start,
+ drvdata->baseAddress, drvdata->mem_size);
+
+ cdev_init(&drvdata->cdev, &xhwicap_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->baseAddress);
+
+ failed2:
+ release_mem_region(regs_res->start, drvdata->mem_size);
+
+ failed1:
+ kfree(drvdata);
+
+ return retval;
+}
+
+static int __exit xhwicap_drv_remove(struct device *dev)
+{
+ struct xhwicap_drvdata *drvdata;
+
+ if (!dev)
+ return -EINVAL;
+
+ drvdata = (struct xhwicap_drvdata *)dev_get_drvdata(dev);
+
+ class_device_destroy(icap_class, drvdata->devt);
+ cdev_del(&drvdata->cdev);
+ iounmap(drvdata->baseAddress);
+ release_mem_region(drvdata->mem_start, drvdata->mem_size);
+ kfree(drvdata);
+ dev_set_drvdata(dev, NULL);
+
+ return 0; /* success */
+}
+
+static struct device_driver xhwicap_module_driver = {
+ .name = DRIVER_NAME,
+ .bus = &platform_bus_type,
+
+ .probe = xhwicap_drv_probe,
+ .remove = xhwicap_drv_remove,
+};
+
+static int __init xhwicap_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, xhwicap_no_minors,
+ DRIVER_NAME);
+ } else {
+ retval =
+ alloc_chrdev_region(&devt, xhwicap_minor, xhwicap_no_minors,
+ DRIVER_NAME);
+ xhwicap_major = MAJOR(devt);
+ }
+ if (retval < 0) {
+ xhwicap_major = 0;
+ return retval;
+ }
+
+ retval = driver_register(&xhwicap_module_driver);
+
+ if (retval) {
+ unregister_chrdev_region(devt, xhwicap_no_minors);
+ }
+
+ return retval;
+}
+
+static void __exit xhwicap_module_cleanup(void)
+{
+ dev_t devt = MKDEV(xhwicap_major, xhwicap_minor);
+
+ class_destroy(icap_class);
+
+ driver_unregister(&xhwicap_module_driver);
+
+ unregister_chrdev_region(devt, xhwicap_no_minors);
+}
+
+module_init(xhwicap_module_init);
+module_exit(xhwicap_module_cleanup);
+
+#ifdef CONFIG_OF
+
+static int __init xilinx_hwicap_of_init(void)
+{
+ struct device_node *np;
+ unsigned int i;
+ struct platform_device *pdev;
+ int ret;
+
+ for (np = NULL, i = 0;
+ (np = of_find_compatible_node(np, NULL, "xlnx,opb-hwicap")) != NULL;
+ i++) {
+ struct resource r;
+
+ memset(&r, 0, sizeof(r));
+
+ ret = of_address_to_resource(np, 0, &r);
+ if (ret)
+ goto err;
+ pdev =
+ platform_device_register_simple(DRIVER_NAME, i, &r, 1);
+
+ if (IS_ERR(pdev)) {
+ ret = PTR_ERR(pdev);
+ goto err;
+ }
+ }
+
+ return 0;
+err:
+ return ret;
+}
+
+module_init(xilinx_hwicap_of_init);
+
+#endif
+
+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..80e3fe0
--- /dev/null
+++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.h
@@ -0,0 +1,539 @@
+/*****************************************************************************
+ *
+ * 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 xhwicap_drvdata {
+ u32 flags;
+ 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 *baseAddress;/* virt. address of the control registers */
+
+ struct device *dev;
+ struct cdev cdev; /* Char device structure */
+ dev_t devt;
+};
+
+/***************************** Include Files ********************************/
+
+#define virtex2 0
+#define virtex4 1
+
+#ifdef CONFIG_XILINX_VIRTEX_4_FX
+#define XHI_FAMILY virtex4
+#else
+#define XHI_FAMILY virtex2
+#endif
+
+/************************** 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
+
+/* Addresses of the Configuration Registers */
+#define XHI_CRC 0
+#define XHI_FAR 1
+#define XHI_FDRI 2
+#define XHI_FDRO 3
+#define XHI_CMD 4
+#define XHI_CTL 5
+#define XHI_MASK 6
+#define XHI_STAT 7
+#define XHI_LOUT 8
+#define XHI_COR 9
+#define XHI_MFWR 10
+
+#if XHI_FAMILY == virtex4
+
+#define XHI_CBC 11
+#define XHI_IDCODE 12
+#define XHI_AXSS 13
+#define XHI_NUM_REGISTERS 14
+
+#else
+
+#define XHI_FLR 11
+#define XHI_KEY 12
+#define XHI_CBC 13
+#define XHI_IDCODE 14
+#define XHI_NUM_REGISTERS 15
+
+#endif
+
+/* 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
+
+/* 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
+
+/* Indicates how many bytes will fit in a buffer. (1 BRAM) */
+#define XHI_MAX_BUFFER_BYTES 2048
+#define XHI_MAX_BUFFER_INTS 512
+
+/* Number of frames in different tile types */
+#if XHI_FAMILY == virtex4
+
+#define XHI_GCLK_FRAMES 3
+#define XHI_IOB_FRAMES 30
+#define XHI_DSP_FRAMES 21
+#define XHI_CLB_FRAMES 22
+#define XHI_BRAM_FRAMES 64
+#define XHI_BRAM_INT_FRAMES 20
+
+#else
+
+#define XHI_GCLK_FRAMES 4
+#define XHI_IOB_FRAMES 4
+#define XHI_IOI_FRAMES 22
+#define XHI_CLB_FRAMES 22
+#define XHI_BRAM_FRAMES 64
+#define XHI_BRAM_INT_FRAMES 22
+
+#endif
+
+/* Device Resources */
+#define CLB 0
+#define DSP 1
+#define BRAM 2
+#define BRAM_INT 3
+#define IOB 4
+#define IOI 5
+#define CLK 6
+#define MGT 7
+
+#define BLOCKTYPE0 0
+#define BLOCKTYPE1 1
+#define BLOCKTYPE2 2
+
+/* The number of words reserved for the header in the storage buffer. */
+/* MAY CHANGE FOR V4 */
+#define XHI_HEADER_BUFFER_WORDS 20
+#define XHI_HEADER_BUFFER_BYTES (XHI_HEADER_BUFFER_WORDS << 2)
+
+/* CLB major frames start at 3 for the first column (since we are using
+ * column numbers that start at 1, when the column is added to this offset,
+ * that first one will be 3 as required. */
+#define XHI_CLB_MAJOR_FRAME_OFFSET 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
+
+/* Constant to use for CRC check when CRC has been disabled */
+#define XHI_DISABLED_AUTO_CRC 0x0000DEFCUL
+
+/* Major Row Offset */
+#define XHI_CLB_MAJOR_ROW_OFFSET 96+(32*XHI_HEADER_BUFFER_WORDS)-1
+
+/* Number of times to poll the done regsiter */
+#define XHI_MAX_RETRIES 1000
+
+/************************** Constant Definitions ****************************/
+
+/* XHwIcap 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
+
+/**************************** Type Definitions ******************************/
+
+/***************** Macros (Inline Functions) Definitions ********************/
+
+/****************************************************************************/
+/**
+*
+* Get the contents of the size register.
+*
+* The size register holds the number of 32 bit words to transfer between
+* bram and the icap (or icap to bram).
+*
+* @param BaseAddress is the base address of the device
+*
+* @return A 32-bit value representing the contents of the size
+* register.
+*
+* @note
+*
+* u32 XHwIcap_mGetSizeReg(u32 BaseAddress);
+*
+*****************************************************************************/
+#define XHwIcap_mGetSizeReg(BaseAddress) \
+ (in_be32((u32 *)((BaseAddress) + XHI_SIZE_REG_OFFSET)))
+
+/****************************************************************************/
+/**
+*
+* Get the contents of the bram offset register.
+*
+* The bram offset register holds the starting bram address to transfer
+* data from during configuration or write data to during readback.
+*
+* @param BaseAddress is the base address of the device
+*
+* @return A 32-bit value representing the contents of the bram offset
+* register.
+*
+* @note
+*
+* u32 XHwIcap_mGetOffsetReg(u32 BaseAddress);
+*
+*****************************************************************************/
+#define XHwIcap_mGetOffsetReg(BaseAddress) \
+ (in_be32((u32 *)((BaseAddress + XHI_BRAM_OFFSET_REG_OFFSET))))
+
+/****************************************************************************/
+/**
+*
+* Get the contents of the done register.
+*
+* The done register is set to zero during configuration or readback.
+* When the current configuration or readback completes the done register
+* is set to one.
+*
+* @param BaseAddress is the base address of the device
+*
+* @return A 32-bit value with bit 1 representing done or not
+*
+* @note
+*
+* u32 XHwIcap_mGetDoneReg(u32 BaseAddress);
+*
+*****************************************************************************/
+
+#define XHwIcap_mGetDoneReg(BaseAddress) \
+ (in_be32((u32 *)((BaseAddress + XHI_STATUS_REG_OFFSET))) & 1)
+
+/****************************************************************************/
+/**
+*
+* Get the contents of the status register.
+*
+* 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
+*
+* @param BaseAddress is the base address of the device
+*
+* @return A 32-bit value representing the contents of the status register
+*
+* @note
+*
+* u32 XHwIcap_mGetStatusReg(u32 BaseAddress);
+*
+*****************************************************************************/
+
+#define XHwIcap_mGetStatusReg(BaseAddress) \
+ (in_be32((u32 *)((BaseAddress + XHI_STATUS_REG_OFFSET))))
+
+#define XHwIcap_mReset(BaseAddress) \
+ (out_be32((u32 *)((BaseAddress + XHI_STATUS_REG_OFFSET)), 0xFEFE))
+
+/****************************************************************************/
+/**
+* Reads data from the storage buffer bram.
+*
+* A bram is used as a configuration memory cache. One frame of data can
+* be stored in this "storage buffer".
+*
+* @param BaseAddress - contains the base address of the component.
+*
+* @param Offset - The offset into which the data should be read.
+*
+* @return The value of the specified offset in the bram.
+*
+* @note
+*
+* u32 XHwIcap_mGetBram(u32 BaseAddress, u32 Offset);
+*
+*****************************************************************************/
+#define XHwIcap_mGetBram(BaseAddress, Offset) \
+ (in_be32((u32 *)((BaseAddress+(Offset<<2)))))
+
+/****************************************************************************/
+/**
+* Set the size register.
+*
+* The size register holds the number of 8 bit bytes to transfer between
+* bram and the icap (or icap to bram).
+*
+* @param BaseAddress - contains the base address of the device.
+*
+* @param Data - The size in bytes.
+*
+* @return None.
+*
+* @note
+*
+* void XHwIcap_mSetSizeReg(u32 BaseAddress, u32 Data);
+*
+*****************************************************************************/
+#define XHwIcap_mSetSizeReg(BaseAddress, Data) \
+ (out_be32((u32 *)((BaseAddress) + XHI_SIZE_REG_OFFSET), (Data)))
+
+/****************************************************************************/
+/**
+* Set the bram offset register.
+*
+* The bram offset register holds the starting bram address to transfer
+* data from during configuration or write data to during readback.
+*
+* @param BaseAddress contains the base address of the device.
+*
+* @param Data is the value to be written to the data register.
+*
+* @return None.
+*
+* @note
+*
+* void XHwIcap_mSetOffsetReg(u32 BaseAddress, u32 Data);
+*
+*****************************************************************************/
+#define XHwIcap_mSetOffsetReg(BaseAddress, Data) \
+ (out_be32((u32 *)((BaseAddress) + XHI_BRAM_OFFSET_REG_OFFSET), (Data)))
+
+/****************************************************************************/
+/**
+* Set the RNC (Readback not Configure) 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.
+*
+* @param BaseAddress contains the base address of the device.
+*
+* @param Data is the value to be written to the data register.
+*
+* @return None.
+*
+* @note
+*
+* void XHwIcap_mSetRncReg(u32 BaseAddress, u32 Data);
+*
+*****************************************************************************/
+#define XHwIcap_mSetRncReg(BaseAddress, Data) \
+ (out_be32((u32 *)((BaseAddress) + XHI_RNC_REG_OFFSET), (Data)))
+
+/****************************************************************************/
+/**
+* Write data to the storage buffer bram.
+*
+* A bram is used as a configuration memory cache. One frame of data can
+* be stored in this "storage buffer".
+*
+* @param BaseAddress - contains the base address of the component.
+*
+* @param Offset - The offset into which the data should be written.
+*
+* @param Data - The value to be written to the bram offset.
+*
+* @return None.
+*
+* @note
+*
+* void XHwIcap_mSetBram(u32 BaseAddress, u32 Offset, u32 Data);
+*
+*****************************************************************************/
+#define XHwIcap_mSetBram(BaseAddress, Offset, Data) \
+ (out_be32((u32 *)((BaseAddress+(Offset<<2))), (Data)))
+
+/****************************************************************************/
+/**
+*
+* Generates a Type 1 packet header that reads back the requested configuration
+* register.
+*
+* @param Register is the address of the register to be read back.
+* Register constants are defined in this file.
+*
+* @return Type 1 packet header to read the specified register
+*
+* @note None.
+*
+*****************************************************************************/
+#define XHwIcap_Type1Read(Register) \
+ ((XHI_TYPE_1 << XHI_TYPE_SHIFT) | (Register << XHI_REGISTER_SHIFT) | \
+ (XHI_OP_READ << XHI_OP_SHIFT))
+
+/****************************************************************************/
+/**
+*
+* Generates a Type 1 packet header that writes to the requested
+* configuration register.
+*
+* @param Register is the address of the register to be written to.
+* Register constants are defined in this file.
+*
+* @return Type 1 packet header to write the specified register
+*
+* @note None.
+*
+*****************************************************************************/
+#define XHwIcap_Type1Write(Register) \
+ ((XHI_TYPE_1 << XHI_TYPE_SHIFT) | (Register << XHI_REGISTER_SHIFT) | \
+ (XHI_OP_WRITE << XHI_OP_SHIFT))
+
+/************************** Function Prototypes *****************************/
+
+/* These functions are the ones defined in the lower level
+ * Self-Reconfiguration Platform (SRP) API.
+ */
+
+/* Initializes a XHwIcap instance.. */
+int XHwIcap_Initialize(struct xhwicap_drvdata *InstancePtr, u16 DeviceId,
+ u32 DeviceIdCode);
+
+/* Reads integers from the device into the storage buffer. */
+int XHwIcap_DeviceRead(struct xhwicap_drvdata *InstancePtr, u32 Offset,
+ u32 NumInts);
+
+/* Writes integers to the device from the storage buffer. */
+int XHwIcap_DeviceWrite(struct xhwicap_drvdata *InstancePtr, u32 Offset,
+ u32 NumInts);
+
+/* Writes word to the storage buffer. */
+void XHwIcap_StorageBufferWrite(struct xhwicap_drvdata *InstancePtr,
+ u32 Address, u32 Data);
+
+/* Reads word from the storage buffer. */
+u32 XHwIcap_StorageBufferRead(struct xhwicap_drvdata *InstancePtr, u32 Address);
+
+/* Loads a partial bitstream from system memory. */
+int XHwIcap_SetConfiguration(struct xhwicap_drvdata *InstancePtr, u32 *Data,
+ u32 Size);
+
+/* Loads a partial bitstream from system memory. */
+int XHwIcap_GetConfiguration(struct xhwicap_drvdata *InstancePtr, u32 *Data,
+ u32 Size);
+
+/* Sends a DESYNC command to the ICAP */
+int XHwIcap_CommandDesync(struct xhwicap_drvdata *InstancePtr);
+
+/* Sends a CAPTURE command to the ICAP */
+int XHwIcap_CommandCapture(struct xhwicap_drvdata *InstancePtr);
+
+/* Returns the value of the specified configuration register */
+u32 XHwIcap_GetConfigReg(struct xhwicap_drvdata *InstancePtr, u32 ConfigReg);
+
+#endif
--
1.5.3.4-dirty
^ permalink raw reply related
* Re: [PATCH] [XILINX][HWICAP] Xilinx Internal Configuration Access Port device driver.
From: Grant Likely @ 2007-12-05 0:05 UTC (permalink / raw)
To: Stephen Neuendorffer; +Cc: linuxppc-dev
In-Reply-To: <20071204235725.61AD6A08071@mail81-dub.bigfish.com>
On 12/4/07, Stephen Neuendorffer <stephen.neuendorffer@xilinx.com> wrote:
> Supports static platform_device and static device tree configuration.
> This is a standalone driver that does not depend on EDK generated
> files. However, it is also somewhat different in functionality from
> the standard EDK driver.
>
> 1) The EDK driver doesn't support readback, which this driver does.
> 2) The EDK driver supports fine granularity reading and writing, which
> this driver does not. The fine granularity support is heavily
> architecture independent, which makes it difficult to make the driver
> forward compatible. The fine granularity support is also complex and
> probably better handled in user space anyway.
>
> Signed-off-by: Stephen Neuendorffer <stephen.neuendorffer@xilinx.com>
> ---
>
> Grant,
>
> No comments last time... It would be nice if this merged with 2.6.25, I think.
Sorry Steve, I must have missed it. I'll review and comment.
Cheers,
g.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
grant.likely@secretlab.ca
(403) 399-0195
^ permalink raw reply
* Re: [PATCH 5/7] powerpc: Replace ppc_md.power_off with pm_power_off
From: Mark A. Greer @ 2007-12-05 0:07 UTC (permalink / raw)
To: Grant Likely; +Cc: Paul Mackerras, linuxppc-dev
In-Reply-To: <fa686aa40712041205o39ba4e3epcbc008ea47bd83cc@mail.gmail.com>
On Tue, Dec 04, 2007 at 01:05:46PM -0700, Grant Likely wrote:
> On 12/4/07, Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:
> >
> > On Tue, 2007-12-04 at 11:01 -0700, Mark A. Greer wrote:
> > > On Tue, Dec 04, 2007 at 06:23:09PM +1100, Benjamin Herrenschmidt wrote:
> > > >
> > > > On Mon, 2007-12-03 at 22:48 -0700, Mark A. Greer wrote:
> > > > > From: Mark A. Greer <mgreer@mvista.com>
> > > > >
> > > > > The ppc_md.power_off hook performs the same function that the
> > > > > pm_power_off hook is supposed to. However, it is powerpc-specific
> > > > > and prevents kernel drivers (e.g., IPMI) from changing how a platform
> > > > > is powered off. So, get rid of ppc_md.power_off and replace it with
> > > > > pm_power_off.
> > > >
> > > > I'm less happy with that one... probably aesthetics :-)
> > > >
> > > > Can't we just have the generic code call pm_power_off and ppc_md and
> > > > which ever powers the machine off wins ?
> > >
> > > Yes, that would be easy to do. Seems like duplication though.
> > > If you are sure you're okay with the duplication, I'll do that.
> >
> > Let's ask Paulus what he thinks.
>
> We could simply have the setup code copy the ppc_md.power_off pointer
> into pm_power_off; that we retain the nice assignment in
> define_machine(), but eliminate the duplicated calls.
Hmm, yeah, that would look nice--nicer than what I have. The only
issue I have with it is that we still have duplication and potential
for reassigning the wrong one (e.g., reassigning ppc_md.power_off instead
of pm_power_off in maple/setup.c:maple_use_rtas_reboot_and_halt_if_present()).
We could call both in machine_power_off but that's messy too (IMHO).
Paul, do you have an opinion?
Mark
^ permalink raw reply
* [PATCH 1/11] ibm_newemac: Add BCM5248 and Marvell 88E1111 PHY support
From: Benjamin Herrenschmidt @ 2007-12-05 0:14 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linuxppc-dev
From: Stefan Roese <sr@denx.de>
This patch adds BCM5248 and Marvell 88E1111 PHY support to NEW EMAC driver.
These PHY chips are used on PowerPC 440EPx boards.
The PHY code is based on the previous work by Stefan Roese <sr@denx.de>
Signed-off-by: Stefan Roese <sr@denx.de>
Signed-off-by: Valentine Barshak <vbarshak@ru.mvista.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
drivers/net/ibm_newemac/phy.c | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
Index: linux-work/drivers/net/ibm_newemac/phy.c
===================================================================
--- linux-work.orig/drivers/net/ibm_newemac/phy.c 2007-12-03 11:50:26.000000000 +1100
+++ linux-work/drivers/net/ibm_newemac/phy.c 2007-12-03 11:58:16.000000000 +1100
@@ -306,8 +306,47 @@ static struct mii_phy_def cis8201_phy_de
.ops = &cis8201_phy_ops
};
+static struct mii_phy_def bcm5248_phy_def = {
+
+ .phy_id = 0x0143bc00,
+ .phy_id_mask = 0x0ffffff0,
+ .name = "BCM5248 10/100 SMII Ethernet",
+ .ops = &generic_phy_ops
+};
+
+static int m88e1111_init(struct mii_phy *phy)
+{
+ pr_debug("%s: Marvell 88E1111 Ethernet\n", __FUNCTION__);
+ phy_write(phy, 0x14, 0x0ce3);
+ phy_write(phy, 0x18, 0x4101);
+ phy_write(phy, 0x09, 0x0e00);
+ phy_write(phy, 0x04, 0x01e1);
+ phy_write(phy, 0x00, 0x9140);
+ phy_write(phy, 0x00, 0x1140);
+
+ return 0;
+}
+
+static struct mii_phy_ops m88e1111_phy_ops = {
+ .init = m88e1111_init,
+ .setup_aneg = genmii_setup_aneg,
+ .setup_forced = genmii_setup_forced,
+ .poll_link = genmii_poll_link,
+ .read_link = genmii_read_link
+};
+
+static struct mii_phy_def m88e1111_phy_def = {
+
+ .phy_id = 0x01410CC0,
+ .phy_id_mask = 0x0ffffff0,
+ .name = "Marvell 88E1111 Ethernet",
+ .ops = &m88e1111_phy_ops,
+};
+
static struct mii_phy_def *mii_phy_table[] = {
&cis8201_phy_def,
+ &bcm5248_phy_def,
+ &m88e1111_phy_def,
&genmii_phy_def,
NULL
};
^ permalink raw reply
* [PATCH 2/11] ibm_newemac: Add ET1011c PHY support
From: Benjamin Herrenschmidt @ 2007-12-05 0:14 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linuxppc-dev
From: Stefan Roese <sr@denx.de>
This adds support for the Agere ET1011c PHY as found on the AMCC Taishan
board.
Signed-off-by: Stefan Roese <sr@denx.de>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
drivers/net/ibm_newemac/phy.c | 37 +++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
Index: linux-work/drivers/net/ibm_newemac/phy.c
===================================================================
--- linux-work.orig/drivers/net/ibm_newemac/phy.c 2007-12-03 11:58:16.000000000 +1100
+++ linux-work/drivers/net/ibm_newemac/phy.c 2007-12-03 11:59:53.000000000 +1100
@@ -327,6 +327,42 @@ static int m88e1111_init(struct mii_phy
return 0;
}
+static int et1011c_init(struct mii_phy *phy)
+{
+ u16 reg_short;
+
+ reg_short = (u16)(phy_read(phy, 0x16));
+ reg_short &= ~(0x7);
+ reg_short |= 0x6; /* RGMII Trace Delay*/
+ phy_write(phy, 0x16, reg_short);
+
+ reg_short = (u16)(phy_read(phy, 0x17));
+ reg_short &= ~(0x40);
+ phy_write(phy, 0x17, reg_short);
+
+ phy_write(phy, 0x1c, 0x74f0);
+ return 0;
+}
+
+static struct mii_phy_ops et1011c_phy_ops = {
+ .init = et1011c_init,
+ .setup_aneg = genmii_setup_aneg,
+ .setup_forced = genmii_setup_forced,
+ .poll_link = genmii_poll_link,
+ .read_link = genmii_read_link
+};
+
+static struct mii_phy_def et1011c_phy_def = {
+ .phy_id = 0x0282f000,
+ .phy_id_mask = 0x0fffff00,
+ .name = "ET1011C Gigabit Ethernet",
+ .ops = &et1011c_phy_ops
+};
+
+
+
+
+
static struct mii_phy_ops m88e1111_phy_ops = {
.init = m88e1111_init,
.setup_aneg = genmii_setup_aneg,
@@ -344,6 +380,7 @@ static struct mii_phy_def m88e1111_phy_d
};
static struct mii_phy_def *mii_phy_table[] = {
+ &et1011c_phy_def,
&cis8201_phy_def,
&bcm5248_phy_def,
&m88e1111_phy_def,
^ permalink raw reply
* [PATCH 3/11] ibm_newemac: Fix ZMII refcounting bug
From: Benjamin Herrenschmidt @ 2007-12-05 0:14 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linuxppc-dev
When using ZMII for MDIO only (such as 440GX with RGMII for data and ZMII for
MDIO), the ZMII code would fail to properly refcount, thus triggering a
BUG_ON().
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Stefan Roese <sr@denx.de>
---
drivers/net/ibm_newemac/zmii.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
Index: linux-work/drivers/net/ibm_newemac/zmii.c
===================================================================
--- linux-work.orig/drivers/net/ibm_newemac/zmii.c 2007-11-08 15:45:32.000000000 +1100
+++ linux-work/drivers/net/ibm_newemac/zmii.c 2007-11-08 15:46:21.000000000 +1100
@@ -83,12 +83,14 @@ int __devinit zmii_attach(struct of_devi
ZMII_DBG(dev, "init(%d, %d)" NL, input, *mode);
- if (!zmii_valid_mode(*mode))
+ if (!zmii_valid_mode(*mode)) {
/* Probably an EMAC connected to RGMII,
* but it still may need ZMII for MDIO so
* we don't fail here.
*/
+ dev->users++;
return 0;
+ }
mutex_lock(&dev->lock);
^ permalink raw reply
* [PATCH 4/11] ibm_newemac: Workaround reset timeout when no link
From: Benjamin Herrenschmidt @ 2007-12-05 0:14 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linuxppc-dev
With some PHYs, when the link goes away, the EMAC reset fails due
to the loss of the RX clock I believe.
The old EMAC driver worked around that using some internal chip-specific
clock force bits that are different on various 44x implementations.
This is an attempt at doing it differently, by avoiding the reset when
there is no link, but forcing loopback mode instead. It seems to work
on my Taishan 440GX based board so far.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Stefan Roese <sr@denx.de>
---
drivers/net/ibm_newemac/core.c | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)
Index: linux-work/drivers/net/ibm_newemac/core.c
===================================================================
--- linux-work.orig/drivers/net/ibm_newemac/core.c 2007-11-20 14:46:51.000000000 +1100
+++ linux-work/drivers/net/ibm_newemac/core.c 2007-11-20 14:46:58.000000000 +1100
@@ -464,26 +464,34 @@ static int emac_configure(struct emac_in
{
struct emac_regs __iomem *p = dev->emacp;
struct net_device *ndev = dev->ndev;
- int tx_size, rx_size;
+ int tx_size, rx_size, link = netif_carrier_ok(dev->ndev);
u32 r, mr1 = 0;
DBG(dev, "configure" NL);
- if (emac_reset(dev) < 0)
+ if (!link) {
+ out_be32(&p->mr1, in_be32(&p->mr1)
+ | EMAC_MR1_FDE | EMAC_MR1_ILE);
+ udelay(100);
+ } else if (emac_reset(dev) < 0)
return -ETIMEDOUT;
if (emac_has_feature(dev, EMAC_FTR_HAS_TAH))
tah_reset(dev->tah_dev);
- DBG(dev, " duplex = %d, pause = %d, asym_pause = %d\n",
- dev->phy.duplex, dev->phy.pause, dev->phy.asym_pause);
+ DBG(dev, " link = %d duplex = %d, pause = %d, asym_pause = %d\n",
+ link, dev->phy.duplex, dev->phy.pause, dev->phy.asym_pause);
/* Default fifo sizes */
tx_size = dev->tx_fifo_size;
rx_size = dev->rx_fifo_size;
+ /* No link, force loopback */
+ if (!link)
+ mr1 = EMAC_MR1_FDE | EMAC_MR1_ILE;
+
/* Check for full duplex */
- if (dev->phy.duplex == DUPLEX_FULL)
+ else if (dev->phy.duplex == DUPLEX_FULL)
mr1 |= EMAC_MR1_FDE | EMAC_MR1_MWSW_001;
/* Adjust fifo sizes, mr1 and timeouts based on link speed */
@@ -1165,9 +1173,9 @@ static void emac_link_timer(struct work_
link_poll_interval = PHY_POLL_LINK_ON;
} else {
if (netif_carrier_ok(dev->ndev)) {
- emac_reinitialize(dev);
netif_carrier_off(dev->ndev);
netif_tx_disable(dev->ndev);
+ emac_reinitialize(dev);
emac_print_link_status(dev);
}
link_poll_interval = PHY_POLL_LINK_OFF;
^ permalink raw reply
* [PATCH 5/11] ibm_newemac: Cleanup/Fix RGMII MDIO support detection
From: Benjamin Herrenschmidt @ 2007-12-05 0:14 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linuxppc-dev
More than just "AXON" version of EMAC RGMII supports MDIO, so replace
the current test with a generic property in the device-tree that
indicates such support.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Stefan Roese <sr@denx.de>
---
arch/powerpc/boot/dts/sequoia.dts | 1 +
drivers/net/ibm_newemac/rgmii.c | 20 +++++++++++---------
drivers/net/ibm_newemac/rgmii.h | 5 +++--
3 files changed, 15 insertions(+), 11 deletions(-)
Index: linux-work/drivers/net/ibm_newemac/rgmii.c
===================================================================
--- linux-work.orig/drivers/net/ibm_newemac/rgmii.c 2007-11-12 10:55:54.000000000 +1100
+++ linux-work/drivers/net/ibm_newemac/rgmii.c 2007-11-12 10:56:56.000000000 +1100
@@ -140,7 +140,7 @@ void rgmii_get_mdio(struct of_device *of
RGMII_DBG2(dev, "get_mdio(%d)" NL, input);
- if (dev->type != RGMII_AXON)
+ if (!(dev->flags & EMAC_RGMII_FLAG_HAS_MDIO))
return;
mutex_lock(&dev->lock);
@@ -161,7 +161,7 @@ void rgmii_put_mdio(struct of_device *of
RGMII_DBG2(dev, "put_mdio(%d)" NL, input);
- if (dev->type != RGMII_AXON)
+ if (!(dev->flags & EMAC_RGMII_FLAG_HAS_MDIO))
return;
fer = in_be32(&p->fer);
@@ -250,11 +250,13 @@ static int __devinit rgmii_probe(struct
goto err_free;
}
- /* Check for RGMII type */
+ /* Check for RGMII flags */
+ if (of_get_property(ofdev->node, "has-mdio", NULL))
+ dev->flags |= EMAC_RGMII_FLAG_HAS_MDIO;
+
+ /* CAB lacks the right properties, fix this up */
if (of_device_is_compatible(ofdev->node, "ibm,rgmii-axon"))
- dev->type = RGMII_AXON;
- else
- dev->type = RGMII_STANDARD;
+ dev->flags |= EMAC_RGMII_FLAG_HAS_MDIO;
DBG2(dev, " Boot FER = 0x%08x, SSR = 0x%08x\n",
in_be32(&dev->base->fer), in_be32(&dev->base->ssr));
@@ -263,9 +265,9 @@ static int __devinit rgmii_probe(struct
out_be32(&dev->base->fer, 0);
printk(KERN_INFO
- "RGMII %s %s initialized\n",
- dev->type == RGMII_STANDARD ? "standard" : "axon",
- ofdev->node->full_name);
+ "RGMII %s initialized with%s MDIO support\n",
+ ofdev->node->full_name,
+ (dev->flags & EMAC_RGMII_FLAG_HAS_MDIO) ? "" : "out");
wmb();
dev_set_drvdata(&ofdev->dev, dev);
Index: linux-work/drivers/net/ibm_newemac/rgmii.h
===================================================================
--- linux-work.orig/drivers/net/ibm_newemac/rgmii.h 2007-11-12 10:55:54.000000000 +1100
+++ linux-work/drivers/net/ibm_newemac/rgmii.h 2007-11-12 10:56:56.000000000 +1100
@@ -35,8 +35,9 @@ struct rgmii_regs {
struct rgmii_instance {
struct rgmii_regs __iomem *base;
- /* Type of RGMII bridge */
- int type;
+ /* RGMII bridge flags */
+ int flags;
+#define EMAC_RGMII_FLAG_HAS_MDIO 0x00000001
/* Only one EMAC whacks us at a time */
struct mutex lock;
Index: linux-work/arch/powerpc/boot/dts/sequoia.dts
===================================================================
--- linux-work.orig/arch/powerpc/boot/dts/sequoia.dts 2007-11-12 10:58:38.000000000 +1100
+++ linux-work/arch/powerpc/boot/dts/sequoia.dts 2007-11-12 10:58:47.000000000 +1100
@@ -245,6 +245,7 @@
device_type = "rgmii-interface";
compatible = "ibm,rgmii-440epx", "ibm,rgmii";
reg = <ef601000 8>;
+ has-mdio;
};
EMAC0: ethernet@ef600e00 {
^ permalink raw reply
* [PATCH 6/11] ibm_newemac: Cleanup/fix support for STACR register variants
From: Benjamin Herrenschmidt @ 2007-12-05 0:14 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linuxppc-dev
There are a few variants of the STACR register that affect more than
just the "AXON" version of EMAC. Replace the current test of various
chip models with tests for generic properties in the device-tree.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Stefan Roese <sr@denx.de>
---
arch/powerpc/boot/dts/sequoia.dts | 4 ++++
drivers/net/ibm_newemac/core.c | 23 +++++++++++++----------
drivers/net/ibm_newemac/core.h | 6 +++---
3 files changed, 20 insertions(+), 13 deletions(-)
Index: linux-work/arch/powerpc/boot/dts/sequoia.dts
===================================================================
--- linux-work.orig/arch/powerpc/boot/dts/sequoia.dts 2007-11-20 14:47:01.000000000 +1100
+++ linux-work/arch/powerpc/boot/dts/sequoia.dts 2007-11-20 14:47:02.000000000 +1100
@@ -274,6 +274,8 @@
zmii-channel = <0>;
rgmii-device = <&RGMII0>;
rgmii-channel = <0>;
+ has-inverted-stacr-oc;
+ has-new-stacr-staopc;
};
EMAC1: ethernet@ef600f00 {
@@ -302,6 +304,8 @@
zmii-channel = <1>;
rgmii-device = <&RGMII0>;
rgmii-channel = <1>;
+ has-inverted-stacr-oc;
+ has-new-stacr-staopc;
};
};
};
Index: linux-work/drivers/net/ibm_newemac/core.c
===================================================================
--- linux-work.orig/drivers/net/ibm_newemac/core.c 2007-11-20 14:46:58.000000000 +1100
+++ linux-work/drivers/net/ibm_newemac/core.c 2007-11-20 14:47:02.000000000 +1100
@@ -711,7 +711,7 @@ static int __emac_mdio_read(struct emac_
r = EMAC_STACR_BASE(dev->opb_bus_freq);
if (emac_has_feature(dev, EMAC_FTR_STACR_OC_INVERT))
r |= EMAC_STACR_OC;
- if (emac_has_feature(dev, EMAC_FTR_HAS_AXON_STACR))
+ if (emac_has_feature(dev, EMAC_FTR_HAS_NEW_STACR))
r |= EMACX_STACR_STAC_READ;
else
r |= EMAC_STACR_STAC_READ;
@@ -783,7 +783,7 @@ static void __emac_mdio_write(struct ema
r = EMAC_STACR_BASE(dev->opb_bus_freq);
if (emac_has_feature(dev, EMAC_FTR_STACR_OC_INVERT))
r |= EMAC_STACR_OC;
- if (emac_has_feature(dev, EMAC_FTR_HAS_AXON_STACR))
+ if (emac_has_feature(dev, EMAC_FTR_HAS_NEW_STACR))
r |= EMACX_STACR_STAC_WRITE;
else
r |= EMAC_STACR_STAC_WRITE;
@@ -2480,16 +2480,19 @@ static int __devinit emac_init_config(st
/* Check EMAC version */
if (of_device_is_compatible(np, "ibm,emac4"))
dev->features |= EMAC_FTR_EMAC4;
- if (of_device_is_compatible(np, "ibm,emac-axon")
- || of_device_is_compatible(np, "ibm,emac-440epx"))
- dev->features |= EMAC_FTR_HAS_AXON_STACR
- | EMAC_FTR_STACR_OC_INVERT;
- if (of_device_is_compatible(np, "ibm,emac-440spe"))
+
+ /* Fixup some feature bits based on the device tree */
+ if (of_get_property(np, "has-inverted-stacr-oc", NULL))
dev->features |= EMAC_FTR_STACR_OC_INVERT;
+ if (of_get_property(np, "has-new-stacr-staopc", NULL))
+ dev->features |= EMAC_FTR_HAS_NEW_STACR;
- /* Fixup some feature bits based on the device tree and verify
- * we have support for them compiled in
- */
+ /* CAB lacks the appropriate properties */
+ if (of_device_is_compatible(np, "ibm,emac-axon"))
+ dev->features |= EMAC_FTR_HAS_NEW_STACR |
+ EMAC_FTR_STACR_OC_INVERT;
+
+ /* Enable TAH/ZMII/RGMII features as found */
if (dev->tah_ph != 0) {
#ifdef CONFIG_IBM_NEW_EMAC_TAH
dev->features |= EMAC_FTR_HAS_TAH;
Index: linux-work/drivers/net/ibm_newemac/core.h
===================================================================
--- linux-work.orig/drivers/net/ibm_newemac/core.h 2007-11-20 14:46:51.000000000 +1100
+++ linux-work/drivers/net/ibm_newemac/core.h 2007-11-20 14:47:02.000000000 +1100
@@ -293,9 +293,9 @@ struct emac_instance {
*/
#define EMAC_FTR_HAS_RGMII 0x00000020
/*
- * Set if we have axon-type STACR
+ * Set if we have new type STACR with STAOPC
*/
-#define EMAC_FTR_HAS_AXON_STACR 0x00000040
+#define EMAC_FTR_HAS_NEW_STACR 0x00000040
/* Right now, we don't quite handle the always/possible masks on the
@@ -307,7 +307,7 @@ enum {
EMAC_FTRS_POSSIBLE =
#ifdef CONFIG_IBM_NEW_EMAC_EMAC4
- EMAC_FTR_EMAC4 | EMAC_FTR_HAS_AXON_STACR |
+ EMAC_FTR_EMAC4 | EMAC_FTR_HAS_NEW_STACR |
EMAC_FTR_STACR_OC_INVERT |
#endif
#ifdef CONFIG_IBM_NEW_EMAC_TAH
^ permalink raw reply
* [PATCH 7/11] ibm_newemac: Skip EMACs that are marked unused by the firmware
From: Benjamin Herrenschmidt @ 2007-12-05 0:14 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linuxppc-dev
From: Hugh Blemings <hugh@blemings.org>
Depending on how the 44x processors are wired, some EMAC cells
might not be useable (and not connected to a PHY). However, some
device-trees may choose to still expose them (since their registers
are present in the MMIO space) but with an "unused" property in them.
Signed-off-by: Hugh Blemings <hugh@blemings.org>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
drivers/net/ibm_newemac/core.c | 4 ++++
1 file changed, 4 insertions(+)
Index: linux-work/drivers/net/ibm_newemac/core.c
===================================================================
--- linux-work.orig/drivers/net/ibm_newemac/core.c 2007-11-20 14:47:02.000000000 +1100
+++ linux-work/drivers/net/ibm_newemac/core.c 2007-11-20 14:47:05.000000000 +1100
@@ -2550,6 +2550,10 @@ static int __devinit emac_probe(struct o
struct device_node **blist = NULL;
int err, i;
+ /* Skip unused/unwired EMACS */
+ if (of_get_property(np, "unused", NULL))
+ return -ENODEV;
+
/* Find ourselves in the bootlist if we are there */
for (i = 0; i < EMAC_BOOT_LIST_SIZE; i++)
if (emac_boot_list[i] == np)
^ permalink raw reply
* [PATCH 8/11] ibm_newemac: Correct opb_bus_freq value
From: Benjamin Herrenschmidt @ 2007-12-05 0:14 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linuxppc-dev
From: Valentine Barshak <vbarshak@ru.mvista.com>
The EMAC4_MR1_OBCI(freq) macro expects freg in MHz,
while opb_bus_freq is kept in Hz. Correct this.
Signed-off-by: Valentine Barshak <vbarshak@ru.mvista.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
diff -pruN linux-2.6.orig/drivers/net/ibm_newemac/core.c linux-2.6/drivers/net/ibm_newemac/core.c
--- linux-2.6.orig/drivers/net/ibm_newemac/core.c 2007-11-23 21:27:57.000000000 +0300
+++ linux-2.6/drivers/net/ibm_newemac/core.c 2007-11-23 21:47:53.000000000 +0300
@@ -402,7 +402,7 @@ static u32 __emac_calc_base_mr1(struct e
static u32 __emac4_calc_base_mr1(struct emac_instance *dev, int tx_size, int rx_size)
{
u32 ret = EMAC_MR1_VLE | EMAC_MR1_IST | EMAC4_MR1_TR |
- EMAC4_MR1_OBCI(dev->opb_bus_freq);
+ EMAC4_MR1_OBCI(dev->opb_bus_freq / 1000000);
DBG2(dev, "__emac4_calc_base_mr1" NL);
^ permalink raw reply
* [PATCH 9/11] ibm_newemac: Fix typo reading TAH channel info
From: Benjamin Herrenschmidt @ 2007-12-05 0:14 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linuxppc-dev
From: Valentine Barshak <vbarshak@ru.mvista.com>
This patch fixes a typo in ibm_newemac/core.c
(tah_port should be used instead of tah_ph)
Signed-off-by: Valentine Barshak <vbarshak@ru.mvista.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
drivers/net/ibm_newemac/core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Index: linux-work/drivers/net/ibm_newemac/core.c
===================================================================
--- linux-work.orig/drivers/net/ibm_newemac/core.c 2007-11-26 09:43:04.000000000 +1100
+++ linux-work/drivers/net/ibm_newemac/core.c 2007-11-26 09:43:05.000000000 +1100
@@ -2442,7 +2442,7 @@ static int __devinit emac_init_config(st
if (emac_read_uint_prop(np, "tah-device", &dev->tah_ph, 0))
dev->tah_ph = 0;
if (emac_read_uint_prop(np, "tah-channel", &dev->tah_port, 0))
- dev->tah_ph = 0;
+ dev->tah_port = 0;
if (emac_read_uint_prop(np, "mdio-device", &dev->mdio_ph, 0))
dev->mdio_ph = 0;
if (emac_read_uint_prop(np, "zmii-device", &dev->zmii_ph, 0))
^ permalink raw reply
* [PATCH 10/11] ibm_newemac: Call dev_set_drvdata() before tah_reset()
From: Benjamin Herrenschmidt @ 2007-12-05 0:14 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linuxppc-dev
From: Valentine Barshak <vbarshak@ru.mvista.com>
The patch moves dev_set_drvdata(&ofdev->dev, dev) up before tah_reset(ofdev)
is called to avoid a NULL pointer dereference, since tah_reset uses drvdata.
Signed-off-by: Valentine Barshak <vbarshak@ru.mvista.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
diff -pruN linux-2.6.orig/drivers/net/ibm_newemac/tah.c linux-2.6/drivers/net/ibm_newemac/tah.c
--- linux-2.6.orig/drivers/net/ibm_newemac/tah.c 2007-11-23 21:27:57.000000000 +0300
+++ linux-2.6/drivers/net/ibm_newemac/tah.c 2007-11-23 21:35:12.000000000 +0300
@@ -116,13 +116,14 @@ static int __devinit tah_probe(struct of
goto err_free;
}
+ dev_set_drvdata(&ofdev->dev, dev);
+
/* Initialize TAH and enable IPv4 checksum verification, no TSO yet */
tah_reset(ofdev);
printk(KERN_INFO
"TAH %s initialized\n", ofdev->node->full_name);
wmb();
- dev_set_drvdata(&ofdev->dev, dev);
return 0;
^ permalink raw reply
* [PATCH 11/11] ibm_newemac: Update file headers copyright notices
From: Benjamin Herrenschmidt @ 2007-12-05 0:14 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linuxppc-dev
This updates the copyright notices of the new EMAC driver to
avoid confusion as who is to be blamed for new bugs.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
drivers/net/ibm_newemac/core.c | 5 +++++
drivers/net/ibm_newemac/core.h | 5 +++++
drivers/net/ibm_newemac/debug.c | 5 +++++
drivers/net/ibm_newemac/debug.h | 5 +++++
drivers/net/ibm_newemac/emac.h | 5 +++++
drivers/net/ibm_newemac/mal.c | 5 +++++
drivers/net/ibm_newemac/mal.h | 5 +++++
drivers/net/ibm_newemac/phy.c | 5 +++++
drivers/net/ibm_newemac/phy.h | 5 +++++
drivers/net/ibm_newemac/rgmii.c | 5 +++++
drivers/net/ibm_newemac/rgmii.h | 5 +++++
drivers/net/ibm_newemac/tah.c | 5 +++++
drivers/net/ibm_newemac/tah.h | 5 +++++
drivers/net/ibm_newemac/zmii.c | 5 +++++
drivers/net/ibm_newemac/zmii.h | 5 +++++
15 files changed, 75 insertions(+)
Index: linux-work/drivers/net/ibm_newemac/core.c
===================================================================
--- linux-work.orig/drivers/net/ibm_newemac/core.c 2007-11-30 15:35:50.000000000 +1100
+++ linux-work/drivers/net/ibm_newemac/core.c 2007-11-30 16:03:30.000000000 +1100
@@ -3,6 +3,11 @@
*
* Driver for PowerPC 4xx on-chip ethernet controller.
*
+ * Copyright 2007 Benjamin Herrenschmidt, IBM Corp.
+ * <benh@kernel.crashing.org>
+ *
+ * Based on the arch/ppc version of the driver:
+ *
* Copyright (c) 2004, 2005 Zultys Technologies.
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
*
Index: linux-work/drivers/net/ibm_newemac/core.h
===================================================================
--- linux-work.orig/drivers/net/ibm_newemac/core.h 2007-11-30 15:35:50.000000000 +1100
+++ linux-work/drivers/net/ibm_newemac/core.h 2007-11-30 16:03:23.000000000 +1100
@@ -3,6 +3,11 @@
*
* Driver for PowerPC 4xx on-chip ethernet controller.
*
+ * Copyright 2007 Benjamin Herrenschmidt, IBM Corp.
+ * <benh@kernel.crashing.org>
+ *
+ * Based on the arch/ppc version of the driver:
+ *
* Copyright (c) 2004, 2005 Zultys Technologies.
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
*
Index: linux-work/drivers/net/ibm_newemac/debug.c
===================================================================
--- linux-work.orig/drivers/net/ibm_newemac/debug.c 2007-11-30 15:35:50.000000000 +1100
+++ linux-work/drivers/net/ibm_newemac/debug.c 2007-11-30 16:03:18.000000000 +1100
@@ -3,6 +3,11 @@
*
* Driver for PowerPC 4xx on-chip ethernet controller, debug print routines.
*
+ * Copyright 2007 Benjamin Herrenschmidt, IBM Corp.
+ * <benh@kernel.crashing.org>
+ *
+ * Based on the arch/ppc version of the driver:
+ *
* Copyright (c) 2004, 2005 Zultys Technologies
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
*
Index: linux-work/drivers/net/ibm_newemac/debug.h
===================================================================
--- linux-work.orig/drivers/net/ibm_newemac/debug.h 2007-11-30 15:35:50.000000000 +1100
+++ linux-work/drivers/net/ibm_newemac/debug.h 2007-11-30 16:03:15.000000000 +1100
@@ -3,6 +3,11 @@
*
* Driver for PowerPC 4xx on-chip ethernet controller, debug print routines.
*
+ * Copyright 2007 Benjamin Herrenschmidt, IBM Corp.
+ * <benh@kernel.crashing.org>
+ *
+ * Based on the arch/ppc version of the driver:
+ *
* Copyright (c) 2004, 2005 Zultys Technologies
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
*
Index: linux-work/drivers/net/ibm_newemac/emac.h
===================================================================
--- linux-work.orig/drivers/net/ibm_newemac/emac.h 2007-11-30 15:35:50.000000000 +1100
+++ linux-work/drivers/net/ibm_newemac/emac.h 2007-11-30 16:03:09.000000000 +1100
@@ -3,6 +3,11 @@
*
* Register definitions for PowerPC 4xx on-chip ethernet contoller
*
+ * Copyright 2007 Benjamin Herrenschmidt, IBM Corp.
+ * <benh@kernel.crashing.org>
+ *
+ * Based on the arch/ppc version of the driver:
+ *
* Copyright (c) 2004, 2005 Zultys Technologies.
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
*
Index: linux-work/drivers/net/ibm_newemac/mal.c
===================================================================
--- linux-work.orig/drivers/net/ibm_newemac/mal.c 2007-11-30 15:35:51.000000000 +1100
+++ linux-work/drivers/net/ibm_newemac/mal.c 2007-11-30 16:03:02.000000000 +1100
@@ -3,6 +3,11 @@
*
* Memory Access Layer (MAL) support
*
+ * Copyright 2007 Benjamin Herrenschmidt, IBM Corp.
+ * <benh@kernel.crashing.org>
+ *
+ * Based on the arch/ppc version of the driver:
+ *
* Copyright (c) 2004, 2005 Zultys Technologies.
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
*
Index: linux-work/drivers/net/ibm_newemac/mal.h
===================================================================
--- linux-work.orig/drivers/net/ibm_newemac/mal.h 2007-11-30 15:35:51.000000000 +1100
+++ linux-work/drivers/net/ibm_newemac/mal.h 2007-11-30 16:02:55.000000000 +1100
@@ -3,6 +3,11 @@
*
* Memory Access Layer (MAL) support
*
+ * Copyright 2007 Benjamin Herrenschmidt, IBM Corp.
+ * <benh@kernel.crashing.org>
+ *
+ * Based on the arch/ppc version of the driver:
+ *
* Copyright (c) 2004, 2005 Zultys Technologies.
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
*
Index: linux-work/drivers/net/ibm_newemac/phy.c
===================================================================
--- linux-work.orig/drivers/net/ibm_newemac/phy.c 2007-11-30 15:35:51.000000000 +1100
+++ linux-work/drivers/net/ibm_newemac/phy.c 2007-11-30 16:02:47.000000000 +1100
@@ -8,6 +8,11 @@
* This file should be shared with other drivers or eventually
* merged as the "low level" part of miilib
*
+ * Copyright 2007 Benjamin Herrenschmidt, IBM Corp.
+ * <benh@kernel.crashing.org>
+ *
+ * Based on the arch/ppc version of the driver:
+ *
* (c) 2003, Benjamin Herrenscmidt (benh@kernel.crashing.org)
* (c) 2004-2005, Eugene Surovegin <ebs@ebshome.net>
*
Index: linux-work/drivers/net/ibm_newemac/phy.h
===================================================================
--- linux-work.orig/drivers/net/ibm_newemac/phy.h 2007-11-30 15:35:51.000000000 +1100
+++ linux-work/drivers/net/ibm_newemac/phy.h 2007-11-30 16:02:32.000000000 +1100
@@ -3,6 +3,11 @@
*
* Driver for PowerPC 4xx on-chip ethernet controller, PHY support
*
+ * Copyright 2007 Benjamin Herrenschmidt, IBM Corp.
+ * <benh@kernel.crashing.org>
+ *
+ * Based on the arch/ppc version of the driver:
+ *
* Benjamin Herrenschmidt <benh@kernel.crashing.org>
* February 2003
*
Index: linux-work/drivers/net/ibm_newemac/rgmii.c
===================================================================
--- linux-work.orig/drivers/net/ibm_newemac/rgmii.c 2007-11-30 15:35:51.000000000 +1100
+++ linux-work/drivers/net/ibm_newemac/rgmii.c 2007-11-30 16:02:23.000000000 +1100
@@ -3,6 +3,11 @@
*
* Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge support.
*
+ * Copyright 2007 Benjamin Herrenschmidt, IBM Corp.
+ * <benh@kernel.crashing.org>
+ *
+ * Based on the arch/ppc version of the driver:
+ *
* Copyright (c) 2004, 2005 Zultys Technologies.
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
*
Index: linux-work/drivers/net/ibm_newemac/rgmii.h
===================================================================
--- linux-work.orig/drivers/net/ibm_newemac/rgmii.h 2007-11-30 15:35:51.000000000 +1100
+++ linux-work/drivers/net/ibm_newemac/rgmii.h 2007-11-30 16:02:19.000000000 +1100
@@ -3,6 +3,11 @@
*
* Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge support.
*
+ * Copyright 2007 Benjamin Herrenschmidt, IBM Corp.
+ * <benh@kernel.crashing.org>
+ *
+ * Based on the arch/ppc version of the driver:
+ *
* Based on ocp_zmii.h/ibm_emac_zmii.h
* Armin Kuster akuster@mvista.com
*
Index: linux-work/drivers/net/ibm_newemac/tah.c
===================================================================
--- linux-work.orig/drivers/net/ibm_newemac/tah.c 2007-11-30 15:35:51.000000000 +1100
+++ linux-work/drivers/net/ibm_newemac/tah.c 2007-11-30 16:02:11.000000000 +1100
@@ -3,6 +3,11 @@
*
* Driver for PowerPC 4xx on-chip ethernet controller, TAH support.
*
+ * Copyright 2007 Benjamin Herrenschmidt, IBM Corp.
+ * <benh@kernel.crashing.org>
+ *
+ * Based on the arch/ppc version of the driver:
+ *
* Copyright 2004 MontaVista Software, Inc.
* Matt Porter <mporter@kernel.crashing.org>
*
Index: linux-work/drivers/net/ibm_newemac/tah.h
===================================================================
--- linux-work.orig/drivers/net/ibm_newemac/tah.h 2007-11-30 15:35:51.000000000 +1100
+++ linux-work/drivers/net/ibm_newemac/tah.h 2007-11-30 16:02:06.000000000 +1100
@@ -3,6 +3,11 @@
*
* Driver for PowerPC 4xx on-chip ethernet controller, TAH support.
*
+ * Copyright 2007 Benjamin Herrenschmidt, IBM Corp.
+ * <benh@kernel.crashing.org>
+ *
+ * Based on the arch/ppc version of the driver:
+ *
* Copyright 2004 MontaVista Software, Inc.
* Matt Porter <mporter@kernel.crashing.org>
*
Index: linux-work/drivers/net/ibm_newemac/zmii.c
===================================================================
--- linux-work.orig/drivers/net/ibm_newemac/zmii.c 2007-11-30 15:35:51.000000000 +1100
+++ linux-work/drivers/net/ibm_newemac/zmii.c 2007-11-30 16:01:53.000000000 +1100
@@ -3,6 +3,11 @@
*
* Driver for PowerPC 4xx on-chip ethernet controller, ZMII bridge support.
*
+ * Copyright 2007 Benjamin Herrenschmidt, IBM Corp.
+ * <benh@kernel.crashing.org>
+ *
+ * Based on the arch/ppc version of the driver:
+ *
* Copyright (c) 2004, 2005 Zultys Technologies.
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
*
Index: linux-work/drivers/net/ibm_newemac/zmii.h
===================================================================
--- linux-work.orig/drivers/net/ibm_newemac/zmii.h 2007-11-30 15:35:51.000000000 +1100
+++ linux-work/drivers/net/ibm_newemac/zmii.h 2007-11-30 16:01:33.000000000 +1100
@@ -3,6 +3,11 @@
*
* Driver for PowerPC 4xx on-chip ethernet controller, ZMII bridge support.
*
+ * Copyright 2007 Benjamin Herrenschmidt, IBM Corp.
+ * <benh@kernel.crashing.org>
+ *
+ * Based on the arch/ppc version of the driver:
+ *
* Copyright (c) 2004, 2005 Zultys Technologies.
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
*
^ 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